Skip to content

Commit 6a3446b

Browse files
committed
feat: add TIDAL support
Closes #23
1 parent 38d23a0 commit 6a3446b

File tree

7 files changed

+82
-30
lines changed

7 files changed

+82
-30
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# <img valign="middle" src="./etc/spotishush-logo.svg" width="32" height="32"> SpotiShush
22

3-
SpotiShush is a browser extension that automatically mutes audio ads on [Spotify Web Player](https://open.spotify.com/) and [Deezer](https://www.deezer.com/).
3+
SpotiShush is a browser extension that automatically mutes audio ads on [Spotify Web Player](https://open.spotify.com/), [Deezer](https://www.deezer.com/) and [TIDAL](https://listen.tidal.com/).
44

55
## Installation
66

@@ -10,15 +10,15 @@ Pick the right one for your browser:
1010

1111
[![Mozilla Add-on](https://img.shields.io/amo/v/spotishush?label=MOZILLA+FIREFOX&style=for-the-badge)](https://addons.mozilla.org/firefox/addon/spotishush/)
1212

13-
No additional configuration is required! You just have to reload any Spotify or Deezer tab in your browser.
13+
No additional configuration is required! You just have to reload any Spotify, Deezer or TIDAL tab in your browser.
1414

1515
---
1616

1717
## FAQ
1818

1919
### Why not use an Ad Blocker instead?
2020

21-
While ads can sometimes be annoying (especially in audio format), I believe Spotify and Deezer both offer an awesome service for non-paying users. And I also believe that if most people used an ad-blocker, the free modality would probably be much more limited.
21+
While ads can sometimes be annoying (especially in audio format), I believe Spotify, Deezer and TIDAL offer an awesome service for non-paying users. And I also believe that if most people used an ad-blocker, the free modality would probably be much more limited.
2222

2323
### How does it work?
2424

src/_locales/en/messages.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"ext_desc": {
3-
"message": "Mutes audio ads on Spotify and Deezer.",
3+
"message": "Mutes audio ads on Spotify, Deezer and TIDAL.",
44
"description": "Extension description"
55
}
66
}

src/_locales/pt_BR/messages.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"ext_desc": {
3-
"message": "Silencia propagandas de áudio no Spotify e Deezer."
3+
"message": "Silencia propagandas de áudio no Spotify, Deezer e TIDAL."
44
}
55
}

src/manifest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
{
2323
"matches": [
2424
"https://open.spotify.com/*",
25-
"https://www.deezer.com/*"
25+
"https://www.deezer.com/*",
26+
"https://listen.tidal.com/*"
2627
],
2728
"js": [
2829
"browser-polyfill.min.js",

src/spotishush.js

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,45 +10,94 @@
1010
} catch (error) {
1111
SpotiShush.debug(error.message)
1212
}
13-
// Deezer
14-
if (window.location.hostname === 'www.deezer.com') {
15-
window.addEventListener('sasVideoStart', deezerRunBeforeAds)
16-
window.addEventListener('sasVideoEnd', deezerRunAfterAds)
17-
window.addEventListener('adError', deezerRunAfterAds)
13+
switch (window.location.hostname) {
14+
case 'www.deezer.com': {
15+
window.addEventListener('sasVideoStart', deezerRunBeforeAds)
16+
window.addEventListener('sasVideoEnd', deezerRunAfterAds)
17+
window.addEventListener('adError', deezerRunAfterAds)
1818

19-
// Well, that was easy...
20-
SpotiShush.log('Monitoring ads now!')
19+
// Well, that was easy...
20+
SpotiShush.log('Monitoring ads now!')
21+
break
22+
}
23+
case 'open.spotify.com': {
24+
SpotiShush.log('Waiting for player controls to be ready...')
2125

22-
return
23-
}
24-
// Spotify
25-
SpotiShush.log('Waiting for player controls to be ready...')
26+
// Spotify's "Now Playing" bar
27+
const nowPlaying = await lazySelector('div.Root__now-playing-bar')
2628

27-
const nowPlaying = await spotifyControlsReady()
29+
try {
30+
spotifySetupAdsObserver(nowPlaying)
31+
} catch (error) {
32+
SpotiShush.log('Unable to set up ads monitor:', error.message)
33+
return
34+
}
35+
SpotiShush.log('Success. Monitoring ads now!')
36+
break
37+
}
38+
case 'listen.tidal.com': {
39+
SpotiShush.log('Waiting for repeat button to be ready...')
2840

29-
try {
30-
setupAdsObserver(nowPlaying)
31-
} catch (error) {
32-
SpotiShush.log('Unable to set up ads monitor:', error.message)
33-
return
41+
// TIDAL's repeat button
42+
const repeatButton = await lazySelector('div#playbackControlBar > button[data-test=repeat]')
43+
44+
tidalSetupAdsObserver(repeatButton)
45+
46+
SpotiShush.log('Success. Monitoring ads now!')
47+
// On TIDAL, ads are persistent through a page reload, so here we manually
48+
// trigger our ads observer function to determine if there's an ad in our queue.
49+
repeatButton.type = repeatButton.getAttribute('type')
50+
break
51+
}
52+
default:
53+
break
3454
}
35-
SpotiShush.log('Success. Monitoring ads now!')
3655

37-
function spotifyControlsReady (checkInterval) {
56+
function lazySelector (selector, checkInterval) {
3857
return new Promise((resolve) => {
3958
const id = setInterval(() => {
40-
const nowPlaying = document.querySelector('div.Root__now-playing-bar')
59+
const element = document.querySelector(selector)
4160

42-
if (nowPlaying !== null) {
61+
if (element !== null) {
4362
clearInterval(id)
44-
resolve(nowPlaying)
63+
resolve(element)
4564
}
4665
}, checkInterval || 500)
4766
})
4867
}
4968

69+
function tidalSetupAdsObserver (repeatButton) {
70+
const mo = new MutationObserver(async (mutations) => {
71+
SpotiShush.debug('mutations:', mutations)
72+
73+
if (repeatButton.disabled) {
74+
// TIDAL disables the repeat button when an ad is playing.
75+
SpotiShush.log('Ad detected!')
76+
try {
77+
await browser.runtime.sendMessage({ action: 'mute' })
78+
} catch (error) {
79+
SpotiShush.debug(error.message)
80+
return
81+
}
82+
SpotiShush.log('Tab muted.')
83+
} else {
84+
SpotiShush.log('Not an ad!')
85+
try {
86+
await browser.runtime.sendMessage({ action: 'unmute' })
87+
} catch (error) {
88+
SpotiShush.debug(error.message)
89+
return
90+
}
91+
SpotiShush.log('Tab unmuted.')
92+
}
93+
})
94+
mo.observe(repeatButton, {
95+
attributes: true
96+
})
97+
}
98+
5099
// Detect ads by observing mutations in the `data-testid` HTML attribute of Spotify's player controls.
51-
function setupAdsObserver (nowPlaying) {
100+
function spotifySetupAdsObserver (nowPlaying) {
52101
const footerObj = nowPlaying.firstElementChild
53102

54103
if (footerObj === null) {

web-ext-chromium.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ module.exports = Object.assign(defaultConfig, {
2828
],
2929
startUrl: [
3030
'https://accounts.spotify.com/en/login?continue=https://open.spotify.com/',
31-
'https://www.deezer.com/us/login/email?redirect_type=page&redirect_link=/us/playlist/1996494362'
31+
'https://www.deezer.com/us/login/email?redirect_type=page&redirect_link=/us/playlist/1996494362',
32+
'https://listen.tidal.com/my-collection/mixes'
3233
]
3334
}
3435
})

web-ext-firefox.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ module.exports = Object.assign(defaultConfig, {
3333
startUrl: [
3434
'https://accounts.spotify.com/en/login?continue=https://open.spotify.com/',
3535
'https://www.deezer.com/us/login/email?redirect_type=page&redirect_link=/us/playlist/1996494362',
36+
'https://listen.tidal.com/my-collection/mixes',
3637
'about:debugging#/runtime/this-firefox'
3738
]
3839
}

0 commit comments

Comments
 (0)