Script untuk Membisukan Aplikasi


14

Tujuan saya adalah untuk dapat menonaktifkan aplikasi Spotify, bukan keseluruhan sistem. Menggunakan perintah: ps -C spotify -o pid=Saya dapat menemukan ID proses Spotify, dalam hal ini ID tersebut "22981". Dengan proses yang ID saya ingin mencari dari daftar ini: pacmd list-sink-inputs. Perintah itu mengembalikan daftar seperti ini:

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"

Sekarang saya ingin mengkorelasikan application.process.id = "22981"ke indeks input wastafel yang dalam hal ini adalah index: 0. Sekarang dengan nomor indeks itu maka saya perlu menjalankan perintah ini: pacmd set-sink-input-mute 0 1untuk menonaktifkan Spotify dan pacmd set-sink-input-mute 0 0unmute Spotify. Untuk perintah-perintah itu, nomor pertama harus diganti dengan nomor indeks yang ditemukan sebelumnya, dan nomor berikutnya adalah boolean untuk menghidupkan atau mematikan bisu. Bagaimana saya bisa memasukkan ini seluruhnya ke dalam skrip, sehingga saya bisa mendapatkan perintah untuk menonaktifkan / mengaktifkan suara aplikasi Spotify?

EDIT: Kedua skrip di bawah berfungsi seperti yang diharapkan, dapatkah seseorang menambahkan toggle yang akan memeriksa muted: yesatau muted: nodan kemudian membisukan atau mengaktifkan suara yang sesuai?

EDIT: Saya dapat memodifikasi skrip glenn jackman untuk menambahkan toggle:

#!/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 "$@"

mengapa tidak digunakan pactl list sink-inputs? maka itu akan berfungsi melalui jaringan.
Janus Troelsen

Jawaban:


13

Inilah pendapat saya tentang tantangan menarik Anda:

#!/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 "$@"

Ini berfungsi dengan baik juga
era878

@ era878, saya suka ide beralih menjadi aksi default. Namun get_statusfungsi Anda hanya akan menemukan garis "tidak bersuara" tanpa memeriksa silang bahwa status itu milik aplikasi yang sesuai. Baca kembali get_indexfungsi saya untuk detailnya.
glenn jackman

3
keterampilan awk yang bagus :)
hytromo

@glennjackman, Yup, saya menemukan itu setelah beberapa saat. Saya percaya bahwa skrip yang baru saja saya posting berfungsi dengan benar sekarang.
era878

1
Rincian: awk -v var=val. Awk loop atas garis, 1 demi 1, mencoba untuk mencocokkan $1 == ...pernyataan mana pun, mengeksekusi kode dalam tanda kurung pada pertandingan, dan melanjutkan. Pernyataan pertama cocok dengan baris yang memiliki kata pertama index:, dan menyimpan kata kedua (SINK INDEX) dalam idxvariabel. Jadi idxditimpa oleh index: <SINK INDEX>baris berikutnya sampai awk cocok dengan pernyataan kedua ( $1= application.process.id, $2= =, $3= <expected pid val>). Ketika pernyataan kedua ini cocok, awk mencetak idx(yang merupakan baris terakhir yang cocok dengan pernyataan pertama index:) dan keluar.
KrisWebDev

7

terima kasih untuk solusinya! Saya berhasil menggunakan skrip yang disediakan di sini untuk memperbaiki masalah saya. Karena saya harus sedikit memodifikasinya, di sini saya bergabung dengan versi yang ditingkatkan.

Alasan skrip asli tidak berfungsi untuk saya adalah karena beberapa aplikasi dapat memiliki beberapa contoh, yaitu beberapa PID, tetapi mungkin hanya satu dari mereka yang menghasilkan suara, dan dengan demikian sebenarnya terhubung ke Pulseaudio. Karena skrip hanya menggunakan PID pertama yang ditemukan, biasanya akan / tidak / membisukan aplikasi yang diinginkan.

Jadi di sini adalah versi di mana argumennya adalah nama aplikasi yang terdaftar di PulseAudio. Anda dapat menemukan nama ini dengan menjalankan pacmd list-sink-inputsperintah dan mencari application.namebidang.

Solusi alternatif adalah dengan menonaktifkan / mengaktifkan semua PID yang memiliki nama aplikasi yang sama.

#!/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 "$@"

6

Meskipun pertanyaannya adalah meminta naskah, saya ingin meninggalkan ini di sini.

Saya telah menulis aplikasi C yang melakukan ini di Ubuntu. Bahkan lebih baik, ia duduk di baki indikator (menggunakan libappindicator) dan memeriksa apa yang diputar Spotify, dalam interval pendek. Jika memutar iklan (mengecek daftar hitam), itu membisukan Spotify. Jika iklan baru sedang diputar, Anda cukup klik Bungkam pada menu indikator dan itu menambahkannya ke daftar hitam.

Apa yang dilakukannya adalah mencari jendela X, yang akan XFetchNamedikembalikan Spotify - Linux Preview. Kemudian panggilan XGetWindowPropertyuntuk menanyakan _NET_WM_ICON_NAMEproperti dari jendela itu, yang mengembalikan string dalam "Spotify – <Artist> – <Song>"format. Saat memutar iklan, iklan itu mengembalikan sesuatu seperti ini:

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

Itu memelihara Pohon Pencarian Ternary dari daftar iklan, untuk secara efisien memeriksa apakah judul saat ini ada dalam daftar.

Itu juga menggunakan PulseAudio Asynchronous API untuk meminta sink-inputsdan set-mute:

pa_context_get_sink_input_info_list()
pa_context_set_sink_input_mute()

Karena ini hanya kode C yang sederhana, ia ringan. Lihat kode sumber dan .debpaket Ubuntu di: indicator-muteads . Itu mungkin akan mengalahkan skrip shell dengan 2-3 kali lipat.


tidak bekerja dengan versi 1.0.11
Janus Troelsen

4

Pertama-tama, cara "lebih benar" untuk menemukan PID aplikasi seperti spotify, adalah dengan menggunakan:

pidof spotify

Saya telah membangun sebuah skrip yang melakukan pekerjaan itu, saya tidak tahu apakah itu cara terbaik untuk melakukannya, tetapi ia bekerja dengan sempurna:

#!/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

Anda dapat bekerja dengan adalah sebagai:

./mute_application.sh spotify mute

atau

./mute_application.sh spotify unmute

Diuji dengan Audacious dan Vlc berjalan dan mematikan / membunyikan hanya satu dari mereka.


Skrip sempurna, berfungsi seperti yang diharapkan
era878

1

Saya benar-benar tidak bisa skrip, tetapi saya telah memodifikasi skrip hakermania untuk membuat skrip lain.

Yang ini akan menambah atau mengurangi volume aplikasi spesifik dengan kenaikan 5%:

sunting: sebenarnya, ini berfungsi selalu mengubah aplikasi yang terakhir dibuka. Ide ide?

#!/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

0

Skrip yang diedit untuk membisukan semua input aplikasi (beberapa proses) dan default untuk beralih:

#!/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 "$@"
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.