एक अनुप्रयोग म्यूट करने के लिए स्क्रिप्ट


14

मेरा लक्ष्य Spotify एप्लिकेशन को म्यूट करने में सक्षम होना है, न कि पूरे सिस्टम को। कमांड का उपयोग करना: ps -C spotify -o pid=मैं Spotify की प्रक्रिया आईडी खोजने में सक्षम हूं, इस मामले में आईडी है "22981"। उस प्रक्रिया आईडी के साथ मैं इस सूची से खोजना चाहूंगा 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"

अब मैं application.process.id = "22981"सिंक इनपुट इंडेक्स से संबंधित करना चाहूंगा जो इस मामले में है index: 0। अब उस सूचकांक संख्या के साथ मुझे इस आदेश को चलाने की आवश्यकता होगी: pacmd set-sink-input-mute 0 1Spotify को म्यूट pacmd set-sink-input-mute 0 0करने के लिए और Spotify को अनम्यूट करने के लिए। उन आदेशों के लिए, पहले नंबर को पहले पाए गए इंडेक्स नंबर से बदलना होगा, और अगला नंबर म्यूट को चालू या बंद करने के लिए बूलियन है। मैं इसे पूरी तरह से एक स्क्रिप्ट में कैसे डाल सकता हूं, इसलिए मैं Spotify एप्लिकेशन को म्यूट / अनम्यूट करने के लिए कमांड प्राप्त कर सकता हूं?

संपादित करें: नीचे दी गई दोनों लिपियाँ उम्मीद के मुताबिक काम करती हैं, क्या कोई ऐसा टॉगल जोड़ सकता है जो जाँच करे muted: yesया muted: 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 "$@"

उपयोग क्यों नहीं pactl list sink-inputs? तब यह नेटवर्क पर काम करेगा।
Janus Troelsen

जवाबों:


13

यहाँ अपनी दिलचस्प चुनौती पर ले जा रहा हूँ:

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

यह पूरी तरह से अच्छी तरह से काम करता है

@ युग878, मुझे टॉगल का विचार डिफ़ॉल्ट क्रिया पसंद है। हालाँकि, आपका get_statusकार्य केवल क्रॉस-चेकिंग के बिना "मौन" लाइनों को खोज लेगा जो कि स्थिति उपयुक्त अनुप्रयोग से संबंधित है। get_indexविवरण के लिए मेरे फ़ंक्शन को फिर से पढ़ें ।
ग्लेन जैकमैन

3
अच्छा
अजीब

@glennjackman, Yup, मुझे लगा कि थोड़ी देर के बाद बाहर। मुझे विश्वास है कि अभी जो स्क्रिप्ट मैंने पोस्ट की है वह सही ढंग से काम करती है।
युग878

1
विवरण: awk -v var=val। Awk लाइनों पर लूप्स, 1 बाय 1, किसी भी $1 == ...स्टेटमेंट से मिलान करने की कोशिश करता है , मैच पर ब्रैकेट में कोड निष्पादित करता है, और जारी रखता है। पहला कथन उन लाइनों पर मेल खाता है जिनका पहला शब्द है index:, और दूसरा शब्द (SINK INDEX) को idxचर में संग्रहीत करता है । तो idxअगली index: <SINK INDEX>पंक्ति तक ओवरराइट हो जाता है जब तक कि awk दूसरे कथन ( $1= application.process.id, $2= =, $3= <expected pid val>) से मेल नहीं खाता । जब यह 2 स्टेटमेंट मेल खाता है, तो awk प्रिंट्स idx(जो कि आखिरी लाइन है जो पहले स्टेटमेंट से मेल खाता है index:) और बाहर निकलता है।
क्रिस्बडेव

7

समाधान के लिए धन्यवाद! मैंने अपनी समस्या को ठीक करने के लिए यहां दी गई लिपियों का उपयोग करने में कामयाबी हासिल की। चूंकि मुझे उन्हें थोड़ा संशोधित करना था, इसलिए मैं यहां बेहतर संस्करण में शामिल हुआ।

मूल स्क्रिप्ट मेरे लिए काम नहीं कर रही है क्योंकि कुछ अनुप्रयोगों में कई उदाहरण हो सकते हैं, यानी कई पीआईडी, लेकिन शायद उनमें से केवल एक ध्वनि का उत्पादन कर रहा है, और इस तरह वास्तव में पल्सेडियो से जुड़ा हुआ है। चूंकि स्क्रिप्ट में केवल पहले पीआईडी ​​का उपयोग किया गया था, यह आम तौर पर वांछित एप्लिकेशन को म्यूट / नहीं / म्यूट करता है।

तो यहाँ एक संस्करण है जहाँ तर्क अनुप्रयोग नाम है जैसा कि PulseAudio में पंजीकृत है। आप इस नाम को pacmd list-sink-inputsकमांड चलाकर और application.nameफ़ील्ड खोज सकते हैं।

एक वैकल्पिक समाधान उन सभी पीआईडी ​​को म्यूट / अनम्यूट करना होगा जिनका एक ही नाम है।

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

भले ही यह सवाल स्क्रिप्ट के लिए पूछ रहा हो, फिर भी मैं इसे यहां छोड़ना चाहता था।

मैंने एक सी एप्लिकेशन लिखा है जो उबंटू पर करता है। इससे भी बेहतर, यह संकेतक ट्रे पर बैठता है (उपयोग करके libappindicator) और जांचता है कि स्पॉटिफ़ क्या खेल रहा है, छोटे अंतराल पर। यदि यह एक विज्ञापन (एक ब्लैकलिस्ट के खिलाफ जाँच) खेल रहा है तो यह Spotify को म्यूट करता है। यदि कोई नया विज्ञापन चलाया जा रहा है, तो आप बस संकेतक मेनू पर म्यूट पर क्लिक करें और इसे ब्लैकलिस्ट में जोड़ देता है।

यह क्या करता है, एक एक्स विंडो के लिए दिखता है, जिसके लिए XFetchNameरिटर्न देता है Spotify - Linux Preview। फिर यह उस विंडो XGetWindowPropertyकी _NET_WM_ICON_NAMEसंपत्ति को क्वेरी करने के लिए कहता है , जो "Spotify – <Artist> – <Song>"प्रारूप में एक स्ट्रिंग देता है । विज्ञापन खेलते समय, यह कुछ इस तरह से लौटता है:

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

यह विज्ञापनों की सूची का टर्नरी सर्च ट्री बनाए रखता है , ताकि यह पता लगाया जा सके कि सूची में वर्तमान शीर्षक है या नहीं।

यह भी उपयोग करता पल्सऑडियो अतुल्यकालिक एपीआई क्वेरी करने के लिए sink-inputsऔर set-mute:

pa_context_get_sink_input_info_list()
pa_context_set_sink_input_mute()

चूंकि यह सिर्फ सरल सी कोड है, यह हल्के वजन का है। स्रोत कोड और उबंटू .debपैकेज की जाँच करें : संकेतक-मीडिस । यह संभवतः परिमाण के 2-3 आदेशों द्वारा एक शेल स्क्रिप्ट को हरा देगा।


संस्करण 1.0.11 के साथ काम नहीं करता है
Janus Troelsen

4

सबसे पहले, "अधिक सही" आवेदन के पीआईडी ​​को स्पॉटिफाई की तरह खोजने के लिए, इसका उपयोग करना है:

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

दोनों दुस्साहस और Vlc के साथ परीक्षण किया गया और उनमें से केवल एक को म्यूट / अनम्यूट करना।


परफेक्ट स्क्रिप्ट, उम्मीद के
मुताबिक

1

मैं वास्तव में स्क्रिप्ट नहीं कर सकता, लेकिन मैंने दूसरी बनाने के लिए हकरमैनिया की स्क्रिप्ट को संशोधित किया है।

यह 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

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 "$@"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.