era*_*878 17 command-line bash scripts pulseaudio
我的目标是能够静音 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: <protocol-native.c>
flags: START_CORKED
state: RUNNING
sink: 1 <alsa_output.pci-0000_00_1b.0.analog-stereo>
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 <Spotify>
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"
Run Code Online (Sandbox Code Playgroud)
现在我想将 与application.process.id = "22981"
接收器输入索引相关联,在这种情况下是index: 0
. 现在有了这个索引号,我就需要运行这个命令:pacmd set-sink-input-mute 0 1
静音 Spotify 和pacmd set-sink-input-mute 0 0
取消静音 Spotify。对于这些命令,第一个数字需要替换为之前找到的索引号,下一个数字是打开或关闭静音的布尔值。我怎样才能把它完全放到一个脚本中,这样我就可以得到一个命令来静音/取消静音 Spotify 应用程序?
编辑:
下面的两个脚本都按预期工作,有人可以添加一个切换来检查muted: yes
或muted: no
然后相应地静音或取消静音吗?
编辑: 我能够修改 glenn jackman 的脚本以添加切换:
#!/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 "$@"
Run Code Online (Sandbox Code Playgroud)
gle*_*man 15
这是我对您的有趣挑战的看法:
#!/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 "$@"
Run Code Online (Sandbox Code Playgroud)
小智 8
感谢您的解决方案!我设法使用此处提供的脚本来解决我的问题。由于我不得不对它们进行一些修改,因此我在这里加入了改进版本。
原始脚本对我不起作用的原因是因为某些应用程序可以有多个实例,即多个 PID,但可能只有其中一个产生声音,因此实际上连接到 Pulseaudio。由于脚本只使用找到的第一个 PID,它通常会 /not/ 静音所需的应用程序。
所以这是一个版本,其中参数是在 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 "$@"
Run Code Online (Sandbox Code Playgroud)
小智 6
即使问题是要求脚本,我还是想把它留在这里。
我已经编写了一个在 Ubuntu 上执行此操作的 C 应用程序。更好的是,它位于指示器托盘上(使用libappindicator
)并在短时间内检查 Spotify 正在播放的内容。如果它正在播放广告(检查黑名单),它会使 Spotify 静音。如果正在播放新广告,您只需单击指示器菜单上的静音并将其添加到黑名单中。
它的作用是寻找一个 X 窗口,它XFetchName
返回Spotify - Linux Preview
. 然后它调用XGetWindowProperty
查询_NET_WM_ICON_NAME
那个窗口的属性,它返回一个"Spotify – <Artist> – <Song>"
格式的字符串。播放广告时,它返回如下内容:
"Spotify – Spotify – Premium Free Trial Cancel Any Time"
Run Code Online (Sandbox Code Playgroud)
它维护广告列表的三元搜索树,以有效检查当前标题是否在列表中。
它还使用PulseAudio 异步 API来查询sink-inputs
和set-mute
:
pa_context_get_sink_input_info_list()
pa_context_set_sink_input_mute()
Run Code Online (Sandbox Code Playgroud)
因为它只是简单的 C 代码,所以它是轻量级的。查看源代码和 Ubuntu.deb
包:indicator-muteads。它可能会比 shell 脚本高 2-3 个数量级。