用于静音应用程序的脚本

我的目标是能够使Spotify应用程序静音,而不是整个系统。 使用命令: ps -C spotify -o pid=我能够找到Spotify的进程ID,在这种情况下,ID是"22981" 。 使用该进程ID,我想从此列表中搜索: pacmd list-sink-inputs 。 该命令返回如下列表:

 eric@eric-desktop:~$ pacmd list-sink-inputs Welcome to PulseAudio! Use "help" for usage information. >>> 1 sink input(s) available. index: 0 driver:  flags: START_CORKED state: RUNNING sink: 1  volume: 0: 100% 1: 100% 0: -0.00 dB 1: -0.00 dB balance 0.00 muted: no current latency: 1019.80 ms requested latency: 371.52 ms sample spec: s16le 2ch 44100Hz channel map: front-left,front-right Stereo resample method: (null) module: 8 client: 10  properties: media.role = "music" media.name = "Spotify" application.name = "Spotify" native-protocol.peer = "UNIX socket client" native-protocol.version = "26" application.process.id = "22981" application.process.user = "eric" application.process.host = "eric-desktop" application.process.binary = "spotify" window.x11.display = ":0" application.language = "en_US.UTF-8" application.process.machine_id = "058c89ad77c15e1ce0dd5a7800000012" application.process.session_id = "058c89ad77c15e1ce0dd5a7800000012-1345692739.486413-85297109" application.icon_name = "spotify-linux-512x512" module-stream-restore.id = "sink-input-by-media-role:music" 

现在我想将application.process.id = "22981"与sink输入索引相关联,在这种情况下是index: 0 。 现在使用该索引号,我将需要运行此命令: pacmd set-sink-input-mute 0 1静音Spotify和pacmd set-sink-input-mute 0 0取消静音Spotify。 对于这些命令,第一个数字需要用前面找到的索引号替换,下一个数字是打开或关闭静音的布尔值。 我怎样才能将它完全放入脚本中,这样我就可以获得一个命令来静音/取消静音Spotify应用程序?

编辑:下面的两个脚本按预期工作,有人可以添加一个切换,检查muted: yesmuted: no ,然后静音或取消静音?

编辑:我能够修改格伦杰克曼的脚本来添加切换:

 #!/bin/bash main() { local action=toggle while getopts :mu option; do case "$option" in m) action=mute ;; u) action=unmute ;; ?) usage 1 "invalid option: -$OPTARG" ;; esac done shift $((OPTIND - 1)) local pid=$(pidof "$1") if [[ -z "$pid" ]]; then echo "error: no running processes for: $1" >&2 elif [[ "$1" ]]; then $action "$1" else usage 1 "specify an application name" fi } usage() { [[ "$2" ]] && echo "error: $2" echo "Usage: $0 [-m | -u] appname" echo "Default: toggle mute" echo "Arguments:" echo "-m = mute application" echo "-u = unmute application" exit $1 } toggle() { local status=$(get_status "$1") if [[ "$status" == "yes" ]]; then unmute "$1" elif [[ "$status" == "no" ]]; then mute "$1" fi } mute() { adjust_muteness "$1" 1; } unmute() { adjust_muteness "$1" 0; } adjust_muteness() { local index=$(get_index "$1") local status=$(get_status "$1") [[ "$index" ]] && pacmd set-sink-input-mute "$index" $2 >/dev/null } get_index() { local pid=$(pidof "$1") pacmd list-sink-inputs | awk -v pid=$pid ' $1 == "index:" {idx = $2} $1 == "application.process.id" && $3 == "\"" pid "\"" {print idx; exit} ' } get_status() { local pid=$(pidof "$1") pacmd list-sink-inputs | awk -v pid=$pid ' $1 == "muted:" {idx = $2} $1 == "application.process.id" && $3 == "\"" pid "\"" {print idx; exit} ' } main "$@" 

这是我对你有趣的挑战的看法:

 #!/bin/bash main() { local action=mute while getopts :hu option; do case "$option" in h) usage 0 ;; u) action=unmute ;; ?) usage 1 "invalid option: -$OPTARG" ;; esac done shift $((OPTIND - 1)) if [[ "$1" ]]; then $action "$1" else usage 1 "specify an application name" fi } usage() { [[ "$2" ]] && echo "error: $2" echo "usage: $0 [-h] [-u] appname" echo "where: -u = ummute application (default action is to mute)" exit $1 } mute() { adjust_muteness "$1" 1; } unmute() { adjust_muteness "$1" 0; } adjust_muteness() { local index=$(get_index "$1") [[ "$index" ]] && pacmd set-sink-input-mute "$index" $2 >/dev/null } get_index() { local pid=$(pidof "$1") if [[ -z "$pid" ]]; then echo "error: no running processes for: $1" >&2 else pacmd list-sink-inputs | awk -v pid=$pid ' $1 == "index:" {idx = $2} $1 == "application.process.id" && $3 == "\"" pid "\"" {print idx; exit} ' fi } main "$@" 

即使问题是要求脚本,我想把它留在这里。

我编写了一个在Ubuntu上执行此操作的C应用程序。 更好的是,它位于指示器托盘上(使用libappindicator )并在短时间内检查Spotify正在播放的内容。 如果它正在播放广告(检查黑名单),它会使Spotify静音。 如果正在播放新广告,只需点击指标菜单上的静音,然后将其添加到黑名单。

它的作用是查找X窗口, XFetchName返回Spotify - Linux Preview 。 然后它调用XGetWindowProperty来查询该窗口的_NET_WM_ICON_NAME属性,该属性返回"Spotify – "格式的字符串。 播放广告时,它返回如下内容:

 "Spotify – Spotify – Premium Free Trial Cancel Any Time" 

它维护广告列表的三元搜索树 ,以有效地检查当前标题是否在列表中。

它还使用PulseAudio Asynchronous API来查询sink-inputsset-mute

 pa_context_get_sink_input_info_list() pa_context_set_sink_input_mute() 

由于它只是简单的C代码,因此重量轻。 查看源代码和Ubuntu .deb包: indicator-muteads 。 它可能会击败shell脚本2-3个数量级。

谢谢你的解决方案! 我设法使用这里提供的脚本来解决我的问题。 由于我不得不稍微修改它们,所以我加入了改进版本。

原始脚本对我不起作用的原因是因为某些应用程序可能有多个实例,即几个PID,但可能只有其中一个产生声音,因此实际连接到Pulseaudio。 由于脚本仅使用找到的第一个PID,因此通常/不会/静音所需的应用程序。

所以这是一个版本,其中参数是在PulseAudio中注册的应用程序名称。 您可以通过运行pacmd list-sink-inputs命令找到此名称,并查找application.name字段。

另一种解决方案是将所有具有相同应用程序名称的PID静音/取消静音。

 #!/bin/bash # Adapter from glenn jackman on http://askubuntu.com/questions/180612/script-to-mute-an-application # to depend directly on the name of the PulseAudio client # rather than the application name (several instances of one application could # run while only one is connected to PulseAudio) # Possible further improvement: it could be useful to also mute all clients having # the specified name. Here, only the first one is muted. #!/bin/bash main() { local action=mute while getopts :hu option; do case "$option" in h) usage 0 ;; u) action=unmute ;; ?) usage 1 "invalid option: -$OPTARG" ;; esac done shift $((OPTIND - 1)) if [[ "$1" ]]; then $action "$1" else usage 1 "specify the name of a PulseAudio client" fi } usage() { [[ "$2" ]] && echo "error: $2" echo "usage: $0 [-h] [-u] appname" echo "where: -u = ummute application (default action is to mute)" exit $1 } mute() { adjust_muteness "$1" 1; } unmute() { adjust_muteness "$1" 0; } adjust_muteness() { local index=$(get_index "$1") if [[ -z "$index" ]]; then echo "error: no PulseAudio sink named $1 was found" >&2 else [[ "$index" ]] && pacmd set-sink-input-mute "$index" $2 >/dev/null fi } get_index() { # local pid=$(pidof "$1") # if [[ -z "$pid" ]]; then # echo "error: no running processes for: $1" >&2 # else pacmd list-sink-inputs | awk -v name=$1 ' $1 == "index:" {idx = $2} $1 == "application.name" && $3 == "\"" name "\"" {print idx; exit} ' # fi } main "$@" 

首先,找到应用程序的PID(如spotify)的“更正确”的方法是使用:

 pidof spotify 

我已经建立了一个完成这项工作的脚本,我不知道它是否是最好的方法,但它完美无缺:

 #!/bin/bash # Script to mute an application using PulseAudio, depending solely on # process name, constructed as answer on askubuntu.com: # http://askubuntu.com/questions/180612/script-to-mute-an-application #It works as: mute_application.sh vlc mute OR mute_application.sh vlc unmute if [ -z "$1" ]; then echo "Please provide me with an application name" exit 1 fi if [ -z "$2" ]; then echo "Please provide me with an action mute/unmute after the application name" exit 1 fi if ! [[ "$2" == "mute" || "$2" == "unmute" ]]; then echo "The 2nd argument must be mute/unmute" exit 1 fi process_id=$(pidof "$1") if [ $? -ne 0 ]; then echo "There is no such process as "$1"" exit 1 fi temp=$(mktemp) pacmd list-sink-inputs > $temp inputs_found=0; current_index=-1; while read line; do if [ $inputs_found -eq 0 ]; then inputs=$(echo -ne "$line" | awk '{print $2}') if [[ "$inputs" == "to" ]]; then continue fi inputs_found=1 else if [[ "${line:0:6}" == "index:" ]]; then current_index="${line:7}" elif [[ "${line:0:25}" == "application.process.id = " ]]; then if [[ "${line:25}" == "\"$process_id\"" ]]; then #index found... break; fi fi fi done < $temp rm -f $temp if [ $current_index -eq -1 ]; then echo "Could not find "$1" in the processes that output sound." exit 1 fi #muting... if [[ "$2" == "mute" ]]; then pacmd set-sink-input-mute "$current_index" 1 > /dev/null 2>&1 else pacmd set-sink-input-mute "$current_index" 0 > /dev/null 2>&1 fi exit 0 

您可以使用如下:

 ./mute_application.sh spotify mute 

要么

 ./mute_application.sh spotify unmute 

经过Audacious和Vlc运行测试,并且只对其中一个进行静音/取消静音。

我真的不能编写脚本,但我修改了hakermania的脚本来创建另一个脚本。

这个将以5%的增量增加或减少特定应用程序的音量:

编辑:实际上,它正在改变最后打开的应用程序。 想法?

 #!/bin/bash # Script to increase or decrease an individual application's volume using PulseAudio, depending solely on # process name, based on another script by hakermania, constructed as answer on askubuntu.com: # http://askubuntu.com/questions/180612/script-to-mute-an-application # It works as: change_app_volume.sh vlc increase OR change_app_volume.sh vlc decrease # Set desired increments in lines #66 and #68 if [ -z "$1" ]; then echo "Please provide me with an application name" exit 1 fi if [ -z "$2" ]; then echo "Please provide me with an action increase/decrease after the application name" exit 1 fi if ! [[ "$2" == "increase" || "$2" == "decrease" ]]; then echo "The 2nd argument must be increase/decrease" exit 1 fi process_id=$(pidof "$1") if [ $? -ne 0 ]; then echo "There is no such process as "$1"" exit 1 fi temp=$(mktemp) pacmd list-sink-inputs > $temp inputs_found=0; current_index=-1; while read line; do if [ $inputs_found -eq 0 ]; then inputs=$(echo -ne "$line" | awk '{print $2}') if [[ "$inputs" == "to" ]]; then continue fi inputs_found=1 else if [[ "${line:0:6}" == "index:" ]]; then current_index="${line:7}" elif [[ "${line:0:25}" == "application.process.id = " ]]; then if [[ "${line:25}" == "\"$process_id\"" ]]; then #index found... break; fi fi fi done < $temp rm -f $temp if [ $current_index -eq -1 ]; then echo "Could not find "$1" in the processes that output sound." exit 1 fi #increase/decrease... if [[ "$2" == "increase" ]]; then pactl set-sink-input-volume "$current_index" +5% > /dev/null 2>&1 else pactl set-sink-input-volume "$current_index" -5% > /dev/null 2>&1 fi exit 0 

编辑脚本以静音应用程序的所有输入(多个进程)并默认切换:

 #!/bin/bash main() { local action=toggle while getopts :hu option; do case "$option" in h) usage 0 ;; m) action=mute ;; u) action=unmute ;; ?) usage 1 "invalid option: -$OPTARG" ;; esac done shift $((OPTIND - 1)) if [[ "$1" ]]; then $action "$1" else usage 1 "specify an application name" fi } usage() { [[ "$2" ]] && echo "error: $2" echo "usage: $0 [-h] [-u] appname" echo "where: -u = ummute , -m = mute (default action is to toggle)" exit $1 } mute() { adjust_muteness "$1" 1; } unmute() { adjust_muteness "$1" 0; } toggle() { adjust_muteness "$1" toggle; } adjust_muteness() { clients=$(pactl list clients short | awk '/[0-9]+.*'$1'.*/{print $1}') inputs=$(pactl list sink-inputs short) for c in $clients; do for i in $(printf '%s' "$inputs" | awk '/[0-9]+\s[0-9]+\s'$c'/{print $1}'); do pactl set-sink-input-mute $i $2 & done done } main "$@"