-
-
Save humitos/bfc241857b1f87576ca6355ab7653ad0 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*- | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
# Author: Manuel Kaufmann <[email protected]> | |
# Date: 29 October 2016 | |
# Release: 0.5 | |
# DESCRIPTION: | |
# | |
# This program allows you to do not listen to Spotify Ads withuot having a paid | |
# account. It's not too much intelligent right now, so you have to add the | |
# Artists you usually listen to or the name of the Spotify Ads you want to mute. | |
# | |
# How it works? It just mute the sound system when it detects an Ads is being | |
# played. How? By reading the window's title and check against all the known | |
# names and Ads you have defined and using some dumb pre-defined rules that fail | |
# in some cases. | |
from __future__ import division, print_function, unicode_literals | |
import commands | |
import os | |
import sys | |
import time | |
HOSTNAME = commands.getoutput('hostname') | |
TERMINAL_ENCODING = commands.getoutput('locale charmap') | |
WMCTRL_WINDOW_LIST = "wmctrl -l -x | grep 'spotify.Spotify' | grep -v 'grep'" | |
MUTE_COMMAND = "amixer -q -D pulse sset Master mute" | |
UNMUTE_COMMAND = "amixer -q -D pulse sset Master unmute" | |
SPOTIFY_OPEN_COMMAND = "ps -ef | grep Spotify | grep -v grep | wc -l" | |
MUTED = False | |
SPOTIFY_OPENED = False | |
SONGS_PLAYED = [] | |
# Time in seconds | |
SLEEP_BEFORE_UNMUTE = 1.5 | |
SLEEP_BETWEEN_EACH_CHECK = 0.1 | |
SLEEP_WHEN_SPOTIFY_CLOSED = 5 | |
# Define the names of the Artists, Songs, etc you usually listen to here | |
KNOWN_TITLES = ( | |
# Titles that I found with problems matching dumb rules | |
['Emir Kusturica'], | |
['Jarabe De Palo'], | |
['Bob Marley'], | |
['Queen'], | |
['Soda Stereo'], | |
# Titles I want to be sure that are valid | |
map( | |
lambda x: '- {}'.format(x), | |
['Remastered', 'Extended Version', 'En Vivo', 'MTV Unplugged', 'Acoustic', 'Versión Acústica', 'Live', | |
'Directo', 'directo', 'unplugged', 'en directo', 'Unplugged Version', 'Live/Unplugged', 'Instrumental', | |
'Remasterizado', 'BBC'], | |
), | |
# ... | |
) | |
# Define the names of the Ads you usually listen to and want to avoid here | |
ADS_TITLES = ( | |
# ... | |
['REYKON'], | |
) | |
def mute(): | |
global MUTED | |
MUTED = True | |
os.system(MUTE_COMMAND) | |
def unmute(): | |
global MUTED | |
MUTED = False | |
os.system(UNMUTE_COMMAND) | |
def is_spotify_opened(): | |
global SPOTIFY_OPENED | |
output = commands.getoutput(SPOTIFY_OPEN_COMMAND) | |
SPOTIFY_OPENED = bool(int(output)) # 0 is closed | |
return SPOTIFY_OPENED | |
def is_known_title(spotify_title): | |
if spotify_title.isupper(): | |
# most of the ads are upper case | |
return False | |
if len(spotify_title.split()) == 1: | |
# some of the ads are just one word | |
return False | |
# check for known Ads | |
for title in ADS_TITLES: | |
for t in title: | |
if t in spotify_title: | |
return False | |
if len(spotify_title.split(' - ')) == 2: | |
# most of the songs are in the form "Artist - Title" | |
return True | |
# check for known Artists or Songs | |
for title in KNOWN_TITLES: | |
for t in title: | |
if t in spotify_title: | |
return True | |
return False | |
def check_spotify_ads(): | |
output = commands.getoutput(WMCTRL_WINDOW_LIST) | |
try: | |
output = output.decode(TERMINAL_ENCODING) | |
_, spotify_title = output.split(HOSTNAME) | |
except (ValueError, UnicodeDecodeError) as e: | |
print('*** ERROR: {} ***'.format(e)) | |
print('*** Command Output: {} ***'.format(output)) | |
return | |
spotify_title = spotify_title.strip() | |
known_title = is_known_title(spotify_title) | |
if (spotify_title not in SONGS_PLAYED and known_title) or (not MUTED and not known_title): | |
print('Playing:', spotify_title) | |
if spotify_title not in SONGS_PLAYED and known_title: | |
SONGS_PLAYED.append(spotify_title) | |
if known_title: | |
if MUTED: | |
time.sleep(SLEEP_BEFORE_UNMUTE) # the window title changes before the song starts | |
unmute() | |
else: | |
if not MUTED: | |
print('Sound MUTED.') | |
mute() | |
if __name__ == '__main__': | |
try: | |
while True: | |
if not is_spotify_opened(): | |
print('Spotify not running. Sleeping...') | |
time.sleep(SLEEP_WHEN_SPOTIFY_CLOSED) | |
continue | |
check_spotify_ads() | |
time.sleep(SLEEP_BETWEEN_EACH_CHECK) | |
except KeyboardInterrupt: | |
if MUTED: | |
print('\nUnmuting...', end=' ') | |
unmute() | |
print('\nBye.') | |
sys.exit(0) |
I found many of the ads are in "words - words" format (ie: SIA - Staylist), those will always fail.
I've never seen one of those. It depends on the place from where you are connected to internet.
IMHO, you should check for KNOWN_TITLES first (or at least before the upper-score rule), since that's the most bullet proof rule. Then try the ADS_TITLES rule, and then the others.
The thing is that I want to check as less as possible things to make it work fast. The two first rules works like a champ for me and are really dumb but super fast:
- everything in uppercase
- ads with just one word
Also, there are many legit songs with the "artist - song - acoustic/cover/etc" format so it may be better to check if there are two or more upper-score instead of just two.
For this, I added a map
inside the KNOWN_TITLES
in the 0.5 version:
map(
lambda x: '- {}'.format(x),
['Remastered', 'Extended Version', 'En Vivo', 'MTV Unplugged', 'Acoustic', 'Versión Acústica', 'Live',
'Directo', 'directo', 'unplugged', 'en directo', 'Unplugged Version', 'Live/Unplugged', 'Instrumental',
'Remasterizado', 'BBC'],
),
Sorry for the late response, I don't know why, but I see this comment today.
@juancarlospaco have you ever tried one of those? do you use them regularly?
@humitos Everyday, they are near top on Arch repo.
Piola! Me voy a armar un "mostrador" de letras basándome en el concepto inverso de esto 😸
@humitos thank you very much for sharing this!
I found many of the ads are in "words - words" format (ie: SIA - Staylist), those will always fail. IMHO, you should check for
KNOWN_TITLES
first (or at least before the upper-score rule), since that's the most bullet proof rule. Then try theADS_TITLES
rule, and then the others. Also, there are many legit songs with the "artist - song - acoustic/cover/etc" format so it may be better to check if there are two or more upper-score instead of just two.EDIT. Actually you would have to remove the upper-score rule for the above to work, or make a setting to disable it.