Skip to content

Instantly share code, notes, and snippets.

@ztmr
Last active August 29, 2015 14:03
Show Gist options
  • Save ztmr/7ee289a9d0957714996e to your computer and use it in GitHub Desktop.
Save ztmr/7ee289a9d0957714996e to your computer and use it in GitHub Desktop.
Spotify AdKiller written in Perl. It will simply mute Spotify's PulseAudio sink once the current track is about to end (= running over its official length) and unmute once a new track has started playing. What a naive solution to cut the advertisement injected at the end of the track!
#!/usr/bin/env perl
#
# $Id: $
#
# Module: spotify-adkiller -- Naive Spotify AdKiller
# Created: 03-JUL-2014 19:54
# Author: tmr
#
# TODO:
# - listen for Seeked and PlayPause signals to freeze/boost countdown
# (not easy in Perl since it is no multithreaded by default)
# - since the Spotify app does not seem to implement Position
# method (it is always zero), we should Seek(0) right after
# we start to ensure that we have started countdown from the beginning
# of the track
use strict;
use warnings;
use Net::DBus;
use IO::Handle;
my $bus = Net::DBus->session ();
my $service = $bus->get_service ("org.mpris.MediaPlayer2.spotify");
my $object = $service->get_object ("/");
my $spotifySinkCmd = <<EOF;
pactl list \\
| grep -E '(^Sink Input)|(media.name = \\"Spotify\\"\$)' \\
| awk '/Spotify/ {print a} {a = \$0}' \\
| cut -c 13- | tr -d '\\n'
EOF
my $spotifySinkId = `$spotifySinkCmd`;
my $muteCmd = "pactl set-sink-input-mute $spotifySinkId yes";
my $unMuteCmd = "pactl set-sink-input-mute $spotifySinkId no";
my $position = 0;
my $prevTrack = undef;
my %COLOR = ();
$COLOR{'OK'} = "\033[1;49;34m";
$COLOR{'WARN'} = "\033[33;01m";
$COLOR{'NO'} = "\033[0m";
$COLOR{'STD'} = $COLOR{'NO'}."\033[38;5;242m";
autoflush STDOUT 1;
while (1) {
my $metadata = $object->GetMetadata ();
# xesam:title
# String: The track title.
# http://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata/#index18h4
my $title = $metadata->{'xesam:title'} || '';
# mpris:length
# 64-bit integer: The duration of the track in microseconds.
# http://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata/#index2h4
my $length = ($metadata->{'mpris:length'} || 0) / (1000 * 1000);
# The track has just changed -- the original track with
# possibly injected advertisement has ended, so we can unmute
# and continue playing the new track.
if (defined ($prevTrack) and ($title ne $prevTrack)) {
printf $COLOR{'STD'}."INFO: The track has changed: [%s] -> [%s]...\n",
$prevTrack, $title;
$position = -1;
`$unMuteCmd`;
}
# If the original track is over it's time, we expect there is
# an advertisement injected -- no matter if it really is,
# we mute the channel preventively
# Otherwise, we just pass the track counting down its end.
if (++$position >= $length) {
printf $COLOR{'WARN'}."DROP: '%s' %d/%d\r",
$title, $position, $length;
`$muteCmd`;
}
else {
printf $COLOR{'OK'}."PASS: '%s' for %d/%d\r",
$title, $position, $length;
#`$unMuteCmd`;
}
sleep (1);
$prevTrack = $title;
}
# vim: fdm=syntax:fdn=3:tw=74:ts=2:syn=perl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment