permute 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #!/usr/bin/env python
  2. ## Written by demure (demuredemeanor)
  3. ## This program depends on pactl to work
  4. ## This tool makes per application muting a simple and fast process.
  5. from __future__ import print_function ## Needed for python2/3 print
  6. import sys ## Needed for argv
  7. import subprocess ## Need for running `pactl`
  8. import re ## Needed for regex
  9. ## Get overall sink state
  10. def get_state():
  11. state = {}
  12. ## Get current sink states, decode needed for python3 strong types
  13. stream = subprocess.check_output(["pactl", "list", "sink-inputs"]).decode('utf-8')
  14. ## Take "Sink Input" and application.process.binary and assign to dict.
  15. ## Assign mute state for each sink
  16. for nums,bins,mutes in zip(re.findall("Sink Input #(\d+)", stream),\
  17. re.findall("application.process.binary\s=\s\"(\S+)\"", stream),\
  18. re.findall("Mute:\s(\w+)", stream)):
  19. state.update({nums:[bins, mutes]})
  20. return state
  21. ## Print Sink Numbers, binary name, and mute state -- if present
  22. def print_state():
  23. state = get_state()
  24. if bool(state):
  25. for sink in state:
  26. print("Sink Number:", sink, "\tMuted:", state[sink][1], "\tbin:", state[sink][0])
  27. else:
  28. print("No applications are reported to be outputting souund.")
  29. return
  30. ## Checks if sink exists, then toggles if present
  31. def mute_toggle(sink):
  32. state = get_state()
  33. if sink in state:
  34. subprocess.check_output(["pactl", "set-sink-input-mute", sink, "toggle"])
  35. else:
  36. print("Sink number [" + sink + "] not found!")
  37. return
  38. ## Checks state for string, if single result will pass to mute_toggle
  39. def string_to_sink(string):
  40. state = get_state()
  41. matches=[]
  42. for nums in state:
  43. if state[nums][0] == string:
  44. matches.append(nums)
  45. if len(matches) > 1:
  46. print("Too many matches!")
  47. elif len(matches) == 0:
  48. print("No matches.")
  49. else:
  50. mute_toggle(matches[0])
  51. return
  52. ## Parse the command line arguments
  53. def parse_argv(argv):
  54. arg1=argv[1]
  55. ## Single augment
  56. if len(argv) == 2:
  57. ## Option list
  58. if arg1 == "-l" or arg1 == "--list" or arg1 == "list":
  59. print_state()
  60. return
  61. ## Option mute fail
  62. if arg1 == "-m" or arg1 == "--mute" or arg1 == "mute":
  63. print("Missing SINK number!")
  64. msg_help()
  65. return
  66. ## Option string fail
  67. if arg1 == "-s" or arg1 == "--string" or arg1 == "string":
  68. print("Missing string NAME!")
  69. return
  70. ## Option help
  71. if arg1 == "-h" or arg1 == "--help" or arg1 == "help":
  72. msg_help()
  73. return
  74. ## Option version
  75. if arg1 == "-V" or arg1 == "--version" or arg1 == "version":
  76. msg_version()
  77. return
  78. ## Run -m if only sink number passed
  79. if re.match("^(\d+)$", arg1):
  80. mute_toggle(arg1)
  81. return
  82. ## If they get here, the didn't match; print help.
  83. print("["+arg1+"] is not a valid option!")
  84. msg_help()
  85. return
  86. ## Two Augments
  87. elif len(argv) == 3:
  88. arg2=argv[2]
  89. ## Option mute
  90. if arg1 == "-m" or arg1 == "--mute" or arg1 == "mute":
  91. if re.match("^(\d+)$", arg2):
  92. mute_toggle(arg2)
  93. else:
  94. print("["+arg2+"] is not a valid sink input!")
  95. msg_help()
  96. return
  97. ## Option string
  98. if arg1 == "-s" or arg1 == "--string" or arg1 == "string":
  99. string_to_sink(arg2)
  100. else:
  101. print("["+arg1+"] is not a valid option!")
  102. msg_help()
  103. return
  104. ## Too many Augments
  105. else:
  106. print("Too many augments!")
  107. msg_help()
  108. return
  109. ## Print help message
  110. def msg_help():
  111. help_msg=\
  112. """
  113. Usage: premute [OPTION...]
  114. When run without OPTION, will output sink list
  115. When run with SINK as option, will mute SINK number
  116. -l, --list List Sink Inputs
  117. -m, --mute SINK Mute Sink number
  118. -s, --string NAME Attempt bin name mute
  119. -V, --version Display version information
  120. -h, --help Display this help message
  121. """
  122. print(help_msg)
  123. return
  124. ## Print version number message
  125. def msg_version():
  126. version_msg="permute version: 0.2.0"
  127. print(version_msg)
  128. return
  129. ## Main
  130. def main(argv):
  131. if len(argv) > 1:
  132. parse_argv(argv)
  133. else:
  134. print_state()
  135. if __name__ == '__main__':
  136. main(sys.argv)