gdi3d / mute-spotify-ads-mac-osx

Mute Mac (osx) computer audio when Spotify plays an AD
https://gdi3d.github.io/mute-spotify-ads-mac-osx/
MIT License
120 stars 16 forks source link

Script not working on Mojave #2

Closed MickHardins closed 4 years ago

MickHardins commented 4 years ago

I've found that using the --no-backtrace option prevent the script from running on OSX Mojave. Removing the option will let you run the script but ads are not muted.

gdi3d commented 4 years ago

Thanks for reporting the error. I'm not using Mojave here. Please test the following:

  1. I'm assuming you're Spotify app and not the web
  2. Try to run osascript -e 'set volume output muted true' on the terminal and check if your audio get muted.
  3. If that doesn't work, we could try a call to debug it together since I don't have access to Mojave. You can contact me at https://getadvice.github.io/adriano.galello.html
MickHardins commented 4 years ago

Just checked it and the volume gets muted correctly. I suspect it is something related to differences in the log stream command

gdi3d commented 4 years ago

Probably the event that I'm looking for in the stream is not showing up and that's causing the script to fail.

Open the console app and in the search bar type mediaremoted and hit enter. Open an use Spotify. When and ad appears pause it and go to the console to look for an event that looks like this one:

Set: origin-YOUR-PC-NAME-2020.local-1280262988/client-com.spotify.client-22342 (Spotify)/player-MediaRemote-DefaultPlayer setting nowPlayingItem to <<MRContentItem: 0x7f9d4110d010> {
    identifier = "20A9B5FC-D7E1-4B7B-81E8-41B02381E387";
    metadata =     {
        "__playbackRate" = 1;
        "__title" = Advertisement;
        albumName = "";
        artworkAvailable = 0;
        "custom: calculatedElapsedTime" = "00:00:00 (0.053113)";
        "custom: delta" = "00:00:00 (0.001099)";
        "custom: remainingTime" = "00:00:30 (30.014000)";
        discNumber = 0;
        duration = "00:00:30 (30.066000)";
        elapsedTime = "00:00:00 (0.052000)";
        elapsedTimeTimestamp = "2020-10-02 16:54:56 +0000";
        mediaSubType = 0;
        mediaType = 1;
        nowPlayingInfo =         {
        };
        nowPlayingInfoData = "{length = 4, bytes = 0x62706c69}...{length = 4, bytes = 0x000000cb}:261 bytes";
        playbackRate = 1;
        title = Advertisement;
        totalDiscCount = 0;
MickHardins commented 4 years ago

it seems that the fiefd __title is gone from the event object. Maybe ads can be identified from the fact that they have no artwork and their duration is usually < 30 sec? (Not, sure, just guessing)

[MRDNowPlayingPlayerClient] Client at path origin-####-1280262988/client-com.spotify.client-27743 (Spotify)/player-MediaRemote-DefaultPlayer is setting playbackQueue <_MRPlaybackQueueProtobuf: 0x7fac9540b4a0> {
    contentItem =     (
                {
            identifier = "BD9F7664-5843-4F07-9200-A70F482B9416";
            metadata =             {
                "__playbackRate" = 0;
                albumName = "";
                artworkAvailable = 0;
                "custom: calculatedElapsedTime" = "00:00:07 (7.950000)";
                "custom: delta" = "00:00:00 (0.001473)";
                "custom: remainingTime" = "00:00:12 (12.050000)";
                discNumber = 0;
                duration = "00:00:20 (20.000000)";
                elapsedTime = "00:00:07 (7.950000)";
                elapsedTimeTimestamp = "2020-10-04 16:05:10 +0000";
                mediaSubType = 0;
                mediaType = 1;
                nowPlayingInfo =                 {
                    kMRMediaRemoteNowPlayingInfoContentItemIdentifier = "BD9F7664-5843-4F07-9200
gdi3d commented 4 years ago

The __title is not a problem. I look at the albumName property.

Cloud you search for this event also filtering by mediaremoted?:

Set: origin-YOUR-PC-NAME.local-1280262988/client-com.spotify.client-54198 (Spotify)/player-MediaRemote-DefaultPlayer setting nowPlayingItem to <<MRContentItem: 0x7f9d4100e680> {
    identifier = "68224407-9AE0-4812-B555-F48025B2DB76";
    metadata =     {
        "__playbackRate" = 0;
        "__title" = "Cabez\U00f3n";
        albumName = Divididos;
        artworkAvailable = 0;
        "custom: calculatedElapsedTime" = "00:02:13 (133.411000)";
        "custom: delta" = "00:00:00 (0.017619)";
        "custom: remainingTime" = "00:00:03 (3.589000)";
        discNumber = 1;
        duration = "00:02:17 (137.000000)";
        elapsedTime = "00:02:13 (133.411000)";
        elapsedTimeTimestamp = "2020-10-04 17:26:56 +0000";
        mediaSubType = 0;
        mediaType = 1;
        nowPlayingInfo =         {
        };
        nowPlayingInfoData = "{length = 4, bytes = 0x62706c69}...{length = 4, bytes = 0x000000cb}:261 bytes";
        playbackRate = 0;
        title = "Cabez\U00f3n";
        totalDiscCount = 0>

Because I only check once I see that event to prevent muting the audio in other scenario where for example your web browser is showing and Ad.

Here's a quick explication on how the code works:

  1. Check for events filtering by mediaremoted process
  2. If the script comes across the event pasted above (using regex to detected the nowPlayingItem string amongs other stuffs) raise a flag (event_present named in the code) to start examining the incoming events because an Ad could be about to played.
  3. Check if it's an Ad or not (by using the first event that I showed before). Mute/Unmute and reset the flag event_present

ps: I've discovered that after a while Spotify stops autoplaying songs. Surely this is because it detects that Ads had been muted and refuse to keep going. The same happens when you block dns. The solution that I'm testing now is to lower the volume to 1 during the ad and restore it after to see if that can finally overcome the problem.

MickHardins commented 4 years ago

I think I didn't get what you mean by searching that event. Do you refer to the event with that specific identifier or for a generic playback event? In the latter case here you are:

[MRDNowPlayingPlayerClient] Client at path origin-####-1280262988/client-com.spotify.client-27743 (Spotify)/player-MediaRemote-DefaultPlayer is setting playbackQueue <_MRPlaybackQueueProtobuf: 0x7fac98109300> {
    contentItem =     (
                {
            identifier = "1D74B80D-2F86-46D1-9920-0B871C0B849C";
            metadata =             {
                "__playbackRate" = 1;
                albumName = "The Dark Side Of The Moon [Remastered] (Remastered Version)";
                artworkAvailable = 0;
                "custom: calculatedElapsedTime" = "00:00:00 (0.002703)";
                "custom: delta" = "00:00:00 (0.002676)";
                "custom: remainingTime" = "00:06:22 (382.834000)";
                discNumber = 1;
                duration = "00:06:22 (382.834000)";
                elapsedTime = "00:00:00 (0.000000)";
                elapsedTimeTimestamp = "2020-10-05 13:40:49 +0000";
                mediaSubType = 0;
                mediaType = 1;
                nowPlayingInfo =                 {
                    kMRMediaRemoteN
gdi3d commented 4 years ago

The event that I first look for it's the one that starts like:

Set: origin-YOUR-PC-NAME.local-1280262988/client-com.spotify.client-54198 (Spotify)/player-MediaRemote-DefaultPlayer setting nowPlayingItem to <<MRContentItem: 0x7f9d4100e680> {

The important part here is the nowPlayingItem, the one that you share says playbackQueue

MickHardins commented 4 years ago

Even when ads start playing I don't have those events, all I see are sequences of events like the ones below:

Posted Active Now Playing Notification kMRMediaRemoteSupportedCommandsDidChangeNotification for path origin-######-1280262988/client-com.spotify.client-44588 (Spotify)/player-MediaRemote-DefaultPlayer

Posted Active Now Playing Notification kMRNowPlayingPlaybackQueueChangedNotification for path origin-#####-1280262988/client-com.spotify.client-44588 (Spotify)/player-MediaRemote-DefaultPlayer

Posted Active Now Playing Notification kMRMediaRemoteNowPlayingInfoDidChangeNotification for path origin-#####-1280262988/client-com.spotify.client-44588 (Spotify)/player-MediaRemote-DefaultPlayer

com.apple.NowPlayingTouchUI-40324 is requesting playbackQueue for origin-#####-1280262988/client-org.mozilla.firefox-40308 (Firefox)/player-MediaRemote-DefaultPlayer with request E9BEB0BC-476D-4210-905F-0C4D606F6A56 NowPlayingTouchUI-40324 /M/L/A600.000000x600.000000/R[0:1]

PlaybackQueue request E9BEB0BC-476D-4210-905F-0C4D606F6A56 NowPlayingTouchUI-40324 /M/L/A600.000000x600.000000/R[0:1] being handled by cache

[MRDNowPlayingPlayerClient] Client at path origin-#####-1280262988/client-com.spotify.client-44588 (Spotify)/player-MediaRemote-DefaultPlayer is setting playbackQueue <_MRPlaybackQueueProtobuf: 0x7fac95603580> {
    contentItem =     (
                {
            identifier = "4BC8B074-CE33-4585-93F0-786F63CB150E";
            metadata =             {
                "__playbackRate" = 1;
                albumName = "";
                artworkAvailable = 0;
                "custom: calculatedElapsedTime" = "00:00:00 (0.144692)";
                "custom: delta" = "00:00:00 (0.003540)";
                "custom: remainingTime" = "00:00:29 (29.952000)";
                discNumber = 0;
                duration = "00:00:30 (30.093000)";
                elapsedTime = "00:00:00 (0.141000)";
                elapsedTimeTimestamp = "2020-10-06 14:31:47 +0000";
                mediaSubType = 0;
                mediaType = 1;
                nowPlayingInfo =                 {
                    kMRMediaRemoteNowPlayingInfoContentItemIdentifier = "4BC8B074-CE33-4585-93F0
gdi3d commented 4 years ago

That could explain it. I think I can create a patch for this scenario but it's gonna eat up a little bit of CPU.

Could try the following?:

On line 22:

if [ $event_present -eq 1 ]; then

Replace that with:

event_present=1
if [ $event_present -eq 1 ]; then

This way you'll skip the search for that event and only focus on the Ad part.

If that works I can create a new version that check for OS version and skip that part on Mojave.

MickHardins commented 4 years ago

I can confirm you that the version below is working. Note that I removed the --no-backtrace option. Thanks for your help in throubleshooting this!

#!/bin/bash
AD_REG="albumName = \"\";"
SONG_REG="albumName = (\w+|\".+\");"

SPOTIFY_EVENT="com\.spotify\.client.+nowPlayingItem.+{"

echo
echo "Spotify Ads will be muted while this program is running!"
echo "Press Ctrl+c to close this program or close the terminal window"
echo
echo "You can check updates for this program at https://gdi3d.github.io/mute-spotify-ads-mac-osx/"

event_present=0

log stream --process "mediaremoted" --type "log" --color none --style compact | \

    while read STREAM_LINE
    do
        if grep -q -E "$SPOTIFY_EVENT" <<< "$STREAM_LINE"; then
            event_present=1
        fi
        event_present=1
        if [ $event_present -eq 1 ]; then
            if grep -q -E "$AD_REG" <<< "$STREAM_LINE"; then
                # We found and Ad OMG!! Let mute this shit!
                echo ">> 🔇 Ad found! Your audio is muted now!."
                osascript -e 'set volume output muted true'
                event_present=0

            elif grep -q -E "$SONG_REG" <<< "$STREAM_LINE"; then
                # Ad is gone. Unmute!
                echo ">> 🔈 Song is playing 😀. Audio is unmuted now."
                osascript -e 'set volume output muted false'
                event_present=0
            fi

        fi
    done
gdi3d commented 4 years ago

Hey! Great news!

I will update the script to prevent this bug in Mojave in the next release. I'm still testing out the volume feature that I mentioned before.

Thanks you too for your time and feedback ;)

gdi3d commented 4 years ago

Fixed

gdi3d commented 4 years ago

Hey, just a friendly note to let you know that I've added and auto update feature. You just need to re-install it to have this option available.

MickHardins commented 4 years ago

Thank you for letting me know this, will install asap. :+1: