Skip to content

Commit cdfbe53

Browse files
authored
Merge pull request #216 from feedbee/shared2
Refactoring of shared.js: plugin-api.js proposal
2 parents f666078 + 8a1041f commit cdfbe53

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+885
-1033
lines changed

README.md

+63-15
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ Allows your keyboard media keys (play/pause, next, previous) to work
33
when you're listening to music on various streaming websites.
44

55
# Supported Sites
6+
67
* 163 Music
7-
* 22tracks
88
* 8tracks
99
* Amazon Cloud Player
1010
* Bandcamp
@@ -22,53 +22,60 @@ when you're listening to music on various streaming websites.
2222
* iloveradio.de
2323
* Jamstash
2424
* Jango.com
25-
* JB Hi-Fi Now
26-
* Livestream.com
2725
* Mixcloud
28-
* Music Choice
26+
* Music Choice (untested)
2927
* Myspace
3028
* Myzuka.fm
3129
* Naxos Music Library
3230
* Netflix
33-
* Noon Pacific
31+
* Noon Pacific (untested)
3432
* NRK Radio
3533
* Ok.ru
36-
* Overcast
34+
* Overcast (untested)
3735
* Pandora
3836
* Phish Tracks
3937
* Picarto.tv
40-
* Plex
38+
* Plex (untested)
4139
* Pocketcasts.com
4240
* Prostopleer
4341
* Qobuz
44-
* Rdio
4542
* Relax-Hub.com
4643
* Saavn.com
4744
* Slacker
4845
* Sirius XM Radio
4946
* SomaFM
50-
* Songza
5147
* Soundcloud
5248
* Sowndhaus
5349
* Spotify
5450
* Spreaker
5551
* Streamsquid
5652
* Subsonic (and Madsonic)
57-
* Superplayer.fm
58-
* Synology Audio Station v.5
53+
* Superplayer.fm (untested)
54+
* Synology Audio Station v.5 (untested)
5955
* thesixtyone
60-
* Tidal
61-
* Tracksflow.com
56+
* Tidal (untested)
6257
* tunein.com
6358
* Twitch.tv
6459
* Ustream.tv
6560
* vk.com (Vkontakte)
61+
* XFINITY (untested)
6662
* Xiami Music
6763
* YouTube
6864
* Zvooq
6965
* Яндекс.Музыка (Yandex.Music)
7066
* Яндекс.Радио (Yandex.Radio)
7167

68+
# Untested Sites (after latest changes)
69+
70+
* Music Choice (account is needed)
71+
* Noon Pacific (account is needed)
72+
* Overcast (account is needed)
73+
* Plex (can't simulate click, not working)
74+
* Superplayer.fm (regional restrictions)
75+
* Synology (special environment is needed)
76+
* Tidal (regional restrictions)
77+
* XFINITY (account is needed)
78+
7279
# Usage
7380

7481
1. Install extension from the [chrome web store][crx].
@@ -112,8 +119,49 @@ document.addEventListener("MediaNext", function () {
112119
});
113120
```
114121

115-
# Please contribute!
122+
# Please, contribute!
123+
124+
* Looking for plugins for other music players. Create Pull Requests to contribute. Create Issues to inform us about
125+
broken sites (but PR is preferable).
126+
127+
Plugin creation is simple. If you have found a website with media content, that isn't supported by keysocket, just
128+
write a plugin by yourself and create new Pull Request to share it with others. How to do it?
129+
130+
First of all, determine the fixed part of website's URL, where a media content is shown. In `extension/manifest.json`
131+
add an item into `content_scripts` array like this:
132+
133+
```
134+
{
135+
"matches": ["*://example.com/player*"],
136+
"js": ["plugin-api.js", "keysocket-example-service-name.js"]
137+
},
138+
```
139+
140+
Create new file into `extension` folder using the pattern `keysocket-example-service-name.js` (use your service name to
141+
replace `example-service-name` part). Write plugin's code there. Check other plugins for examples.
142+
143+
Typically, plugin can interact with a player using either button press simulation or public API call. The second option
144+
implies you writing custom JS code to talk to player, while the first one requires just to mention DOM selectors to
145+
configure keysocket.
146+
147+
```javascript
148+
keySocket.init('example-service-name', {
149+
"play-pause": '...',
150+
"prev": '...',
151+
"next": '...',
152+
"stop": '...'
153+
});
154+
```
155+
156+
In the code above two arguments were passed to `keySocket.init` function. The first argument is a plugin name, it used for
157+
logging and can be anything you want. The second argument is a map used to bind keysocket events (which is caused by
158+
user pressing control keys) to buttons or code, that handles this event. The events are `play-pause`, `prev`, `next`
159+
and `stop`. Any of them can be omitted in the map.
160+
161+
So, passing a function as an event handler, you set the code, that will be called when event is thrown. Passing anything
162+
else, which expected to be a string, you define DOM selector to look up for a DOM object to simulate click on it.
116163

117-
* Looking for adapters for other music players.
164+
Different websites require different approaches to dial with them. So, make a research to find the best solution in
165+
your case. Look through the other plugins (`extension/keysocket-*.js` files) for the reference.
118166

119167
[crx]: https://chrome.google.com/webstore/detail/fphfgdknbpakeedbaenojjdcdoajihik

extension/keysocket-163.js

+8-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
function onKeyPress(key) {
2-
if (key === NEXT) {
3-
var nextButton = document.querySelector('.m-playbar .nxt');
4-
simulateClick(nextButton);
5-
} else if (key === PLAY) {
6-
var playPauseButton = document.querySelector('.m-playbar .ply');
7-
simulateClick(playPauseButton);
8-
} else if (key === PREV) {
9-
var backButton = document.querySelector('.m-playbar .prv');
10-
simulateClick(backButton);
1+
keySocket.init(
2+
"163",
3+
{
4+
"play-pause": ".m-playbar .ply",
5+
"prev": ".m-playbar .prv",
6+
"next": ".m-playbar .nxt"
7+
// stop is omitted
118
}
12-
}
9+
);
+8-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
function onKeyPress(key) {
2-
if (key === NEXT) {
3-
var nextButton = document.querySelector('.button.icon-fastForward');
4-
simulateClick(nextButton);
5-
} else if (key === PLAY) {
6-
var playPauseButton = document.querySelector(".button.playButton");
7-
simulateClick(playPauseButton);
8-
} else if (key === PREV) {
9-
var backButton = document.querySelector('.button.icon-fastBackward');
10-
simulateClick(backButton);
1+
keySocket.init(
2+
"amazon-cloud-player",
3+
{
4+
"play-pause": ".button.playButton",
5+
"prev": ".button.icon-fastBackward",
6+
"next": ".button.icon-fastForward"
7+
// stop is omitted
118
}
12-
}
9+
);

extension/keysocket-bandcamp.js

+8-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
var playTarget = '.inline_player .playbutton';
2-
var nextTarget = '.inline_player .nextbutton';
3-
var prevTarget = '.inline_player .prevbutton';
4-
5-
function onKeyPress(key) {
6-
if (key === PREV) {
7-
simulateClick(document.querySelector(prevTarget));
8-
} else if (key === NEXT) {
9-
simulateClick(document.querySelector(nextTarget));
10-
} else if (key === PLAY) {
11-
simulateClick(document.querySelector(playTarget));
1+
keySocket.init(
2+
"bandcamp",
3+
{
4+
"play-pause": ".inline_player .playbutton",
5+
"prev": ".inline_player .prevbutton",
6+
"next": ".inline_player .nextbutton"
7+
// stop is omitted
128
}
13-
}
9+
);

extension/keysocket-birp.js

+8-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
function onKeyPress(key) {
2-
if (key === NEXT) {
3-
var nextButton = document.getElementById('fap-next');
4-
simulateClick(nextButton);
5-
} else if (key === PLAY) {
6-
var playPauseButton = document.getElementById('fap-play-pause');
7-
simulateClick(playPauseButton);
8-
} else if (key === PREV) {
9-
var backButton = document.getElementById('fap-previous');
10-
simulateClick(backButton);
1+
keySocket.init(
2+
"birp",
3+
{
4+
"play-pause": "#playbtn",
5+
"prev": ".fa-fast-backward",
6+
"next": ".fa-fast-forward"
7+
// stop is omitted
118
}
12-
}
9+
);

extension/keysocket-bop.js

-12
This file was deleted.

extension/keysocket-bugs.js

+8-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
function onKeyPress(key) {
2-
if (key === NEXT) {
3-
var nextButton = document.getElementsByTagName('button')[4];
4-
simulateClick(nextButton);
5-
} else if (key === PLAY) {
6-
var playPauseButton = document.getElementsByTagName('button')[3];
7-
simulateClick(playPauseButton);
8-
} else if (key === PREV) {
9-
var backButton = document.getElementsByTagName('button')[2];
10-
simulateClick(backButton);
1+
keySocket.init(
2+
"bugs",
3+
{
4+
"play-pause": ".btnPlay > button, .btnStop > button",
5+
"prev": ".btnPrev > button",
6+
"next": ".btnNext > button"
7+
// stop is omitted
118
}
12-
}
9+
);

extension/keysocket-builtin-player.js

+16-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1-
function onKeyPress(key) {
2-
var videoElement = document.getElementsByTagName("video")[0];
3-
4-
if (key === PLAY) {
5-
if (videoElement.paused) {
6-
videoElement.play();
7-
}
8-
else {
9-
videoElement.pause();
1+
keySocket.init(
2+
"builtin-player",
3+
{
4+
"play-pause": function () {
5+
var videoElement = document.getElementsByTagName("video")[0];
6+
7+
if (videoElement.paused) {
8+
videoElement.play();
9+
}
10+
else {
11+
videoElement.pause();
12+
}
1013
}
14+
// prev is skipped
15+
// next is skipped
16+
// stop is omitted
1117
}
12-
}
18+
);

extension/keysocket-deezer.js

+8-36
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,9 @@
1-
function onKeyPress(key) {
2-
if (document.getElementById('player_control_play')) { // old deezer style
3-
if (key === NEXT) {
4-
var nextButton = document.getElementById('player_control_next');
5-
simulateClick(nextButton);
6-
} else if (key === PLAY) {
7-
var isPlaying = document.getElementById('player_control_play').style.display === 'none';
8-
var playPauseButton = null;
9-
if (isPlaying) {
10-
playPauseButton = document.getElementById('player_control_pause');
11-
} else {
12-
playPauseButton = document.getElementById('player_control_play');
13-
}
14-
simulateClick(playPauseButton);
15-
} else if (key === PREV) {
16-
var backButton = document.getElementById('player_control_prev');
17-
simulateClick(backButton);
18-
}
19-
} else { // new deezer style
20-
if (key === NEXT) {
21-
var nextButton = document.getElementsByClassName('control-next')[0];
22-
simulateClick(nextButton);
23-
} else if (key === PLAY) {
24-
var isPlaying = document.getElementsByClassName('control-play')[0] ? false : true;
25-
var playPauseButton = null;
26-
if (isPlaying) {
27-
playPauseButton = document.getElementsByClassName('control-pause')[0];
28-
} else {
29-
playPauseButton = document.getElementsByClassName('control-play')[0];
30-
}
31-
simulateClick(playPauseButton);
32-
} else if (key === PREV) {
33-
var backButton = document.getElementsByClassName('control-prev')[0];
34-
simulateClick(backButton);
35-
}
1+
keySocket.init(
2+
"deezer",
3+
{
4+
"play-pause": ".control-play, .control-pause",
5+
"prev": ".control-prev",
6+
"next": ".control-next"
7+
// stop is omitted
368
}
37-
}
9+
);
+8-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
function onKeyPress(key) {
2-
if (key === PLAY) {
3-
var playPauseButton = document.querySelector('#webplayer-region .controls a:first-child');
4-
simulateClick(playPauseButton);
1+
keySocket.init(
2+
"digitallyimported",
3+
{
4+
"play-pause": "#webplayer-region .controls a:first-child"
5+
// prev is skipped
6+
// next is skipped
7+
// stop is omitted
58
}
6-
}
9+
);

0 commit comments

Comments
 (0)