Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-webstore-upload');

// watcher
grunt.registerTask('default', [ 'watch' ]);
// pack & run dev version locally
grunt.registerTask('pack', [ 'rollup', 'zip' ]);

// CI stuff below

// Alias task for release
grunt.registerTask('makeRelease', function (type) {
type = type ? type : 'patch'; // Default release type
Expand All @@ -109,10 +116,8 @@ module.exports = function(grunt) {
grunt.task.run('exec:push_release');
});

grunt.registerTask('default', [ 'watch' ]);
// to make release run this one
grunt.registerTask('build', [ 'makeRelease' ]);
grunt.registerTask('pack', [ 'rollup', 'zip' ]);
// only should be run by CI, not manually
grunt.registerTask('deploy', ['pack', 'webstore_upload']);
};
3 changes: 0 additions & 3 deletions src/background/models/ProvidersList.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,10 @@ export const ProvidersList = [
'musicforprogramming.net',
'muzebra.com',
'netflix.com',
'new.vk.com',
'open.spotify.com',
'play.google.com',
'play.mubert.com',
'play.spotify.com',
'player.vimeo.com',
'pleer.net',
'podcasts.apple.com',
'promodj.com',
'radio.garden',
Expand Down
86 changes: 86 additions & 0 deletions src/content/Control.Strategies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@

import { Status } from './Status.Types.js';

export class BaseControlStrategy {
static play() {}
static pause() {}
}


export class clickSelector extends BaseControlStrategy {
static play(className) {
let element = document.querySelector(className);
if (!element) {
return;
}

element.click();
}

static pause(className) {
clickSelector.play(className);
}
}

/* class for standard audio/video media elements */
export class mediaToggle extends BaseControlStrategy {
static play(className) {
let element = document.querySelector(className);
element && element.paused && element.play();
}

static pause(className) {
let element = document.querySelector(className);
element && !element.paused && element.pause();
}
}

/* clicking the storedSelector, injected by the Service */
export class clickStoredSelector extends BaseControlStrategy {
static play() {
if (this.selector) {
this.selector.click();
}
}

static pause() {
clickStoredSelector.play.call(this);
}
}

/* custom for jouele, based on its buttons position */
export class joueleStoredSelector extends BaseControlStrategy {
static pause() {
Comment thread
beshur marked this conversation as resolved.
clickStoredSelector.pause.call(this);
}

static play() {
if (this.selector) {
this.selector.previousSibling.click();
}
}
}


export class oneOfTheVideos extends BaseControlStrategy {
static getVideosArray() {
return Array.from(document.getElementsByTagName('video'));
}

static pause() {
oneOfTheVideos.getVideosArray()
.filter((player) => !player.paused)
.forEach((player) => {
player.pause();
});
}

static play() {
oneOfTheVideos.getVideosArray()
.filter((player) => player.paused && player.played.length > 0)
.forEach((player) => {
player.play();
});
}

}
26 changes: 26 additions & 0 deletions src/content/Service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* Base Service class */
export class Service {
/**
@param options {Object}
@param options.statusStrategy {Class}
@param options.statusArgs {Array} (optional)
@param options.controlStrategy {Class}
@param options.playArgs {Array} (optional)
@param options.pauseArgs {Array} (optional)
*/
constructor(options) {
this.options = options;
}

getStatus() {
return this.options.statusStrategy.getStatus.apply(this, this.options.statusArgs);
}

play() {
this.options.controlStrategy.play.apply(this, this.options.playArgs);
}

pause() {
this.options.controlStrategy.pause.apply(this, this.options.pauseArgs);
}
}
219 changes: 219 additions & 0 deletions src/content/ServicesRegistry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
import { Service } from './Service.js';
import * as StatusStrategies from './Status.Strategies.js';
import * as ControlStrategies from './Control.Strategies.js';

// #TODO: move it to build-time
function oneSelectorHelper(hosts, statusArgs, playArgs, pauseArgs) {
return {
hosts,
options: {
statusStrategy: StatusStrategies.checkSelector,
statusArgs: [ statusArgs ],
controlStrategy: ControlStrategies.clickSelector,
playArgs: [ playArgs ],
pauseArgs: [ pauseArgs ]
}
};
}

function getOneSelector() {
return [
[
[ 'vimeo.com', 'player.vimeo.com' ],
'.play.state-playing',
'.play.state-paused',
'.play.state-playing'
], [
[ 'vk.com' ],
'.top_audio_player.top_audio_player_playing',
'.top_audio_player_play',
'.top_audio_player_play'
], [
[ 'muzebra.com' ],
'.player.jp-state-playing',
'.player.jp-play',
'.player.jp-pause'
], [
[ 'music.yandex.ru', 'music.yandex.ua' ],
'.player-controls__btn_play.player-controls__btn_pause',
'.player-controls__btn_play',
'.player-controls__btn_pause'
], [
[ 'mixcloud.com' ],
'.player-control.pause-state',
'.player-control',
'.player-control'
], [
[ 'soundcloud.com' ],
'.playControl.playing',
'.playControl',
'.playControl.playing'
], [
[ 'jazzradio.com', 'rockradio.com', 'radiotunes.com', 'classicalradio.com', 'zenradio.com' ],
'#play-button .icon-pause',
'#play-button .ctl',
'#play-button .ctl'
], [
[ 'v5player.slipstreamradio.com', 'accuradio.com' ],
'#playerPauseButton',
'#playerPlayButton',
'#playerPauseButton'
], [
[ 'open.spotify.com' ],
".control-button[class*='pause']",
".control-button[class*='play']",
".control-button[class*='pause']"
], [
[ 'bandcamp.com' ],
'.inline_player .playbutton.playing',
'.inline_player .playbutton',
'.inline_player .playbutton.playing'
], [
[ 'promodj.com' ],
'.playerr_bigplaybutton .playerr_bigpausebutton',
'.playerr_bigplaybutton .playerr_bigplaybutton',
'.playerr_bigplaybutton .playerr_bigpausebutton'
], [
[ 'courses.prometheus.org.ua' ],
'.video-controls .video_control.pause',
'.video-controls .video_control.play',
'.video-controls .video_control.pause'
], [
[ 'coursera.org' ],
'.c-video-control.vjs-control.vjs-playing',
'.c-video-control.vjs-control.vjs-paused',
'.c-video-control.vjs-control.vjs-playing'
], [
[ 'di.fm' ],
'#webplayer-region .controls .icon-pause',
'#webplayer-region .controls .icon-play',
'#webplayer-region .controls .icon-pause'
], [
[ 'audible.ca', 'audible.com', 'audible.com.au' ],
'#adbl-cloud-player-controls .adblPauseButton:not(.bc-hidden)',
'#adbl-cloud-player-controls .adblPauseButton:not(.bc-hidden)',
'#adbl-cloud-player-controls .adblPauseButton:not(.bc-hidden)'
], [
[ 'coub.com' ],
'.coub.active[play-state="playing"]',
'.coub.active .viewer__replay',
'.coub.active .viewer__click',
], [
[ 'livestream.com' ],
'.playback-control .play-holder.lsp-hidden',
'.playback-control .play-holder',
'.playback-control .pause-holder'
], [
[ 'beatport.com' ],
'#Player__pause-button',
'#Player__play-button',
'#Player__pause-button'
], [
[ 'radio.garden' ],
'.icon-toggle.mod-mute .icon-button.mod-sound',
'.icon-toggle.mod-mute .icon-button.mod-muted',
'.icon-toggle.mod-mute .icon-button.mod-sound'
]
].map(item => oneSelectorHelper.apply(null, item));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow, looks like a magic :)
maybe simple declarative way, like radiolist.com.ua below?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, in this case you should always remember what's 2, 3, 4 arguments for.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's true, but it will be very redundant with the amount of services that we have


}

export const servicesRegistry = () => {

return getOneSelector().concat([
{
hosts: [ 'radiolist.com.ua' ],
options: {
statusStrategy: StatusStrategies.checkSelectorAndStore,
statusArgs: [ '.jouele-status-playing .jouele-info-control-button-icon_pause' ],
controlStrategy: ControlStrategies.joueleStoredSelector
}
}, {
hosts: [ 'megogo.net' ],
options: {
statusStrategy: StatusStrategies.mediaSelector,
statusArgs: [ 'video[class*="player:video"]' ],
controlStrategy: ControlStrategies.mediaToggle,
playArgs: [ 'video[class*="player:video"]' ],
pauseArgs: [ 'video[class*="player:video"]' ]
}
}, {
hosts: [ 'dailymotion.com' ],
options: {
statusStrategy: StatusStrategies.mediaSelector,
statusArgs: [ '#dmp_Video' ],
controlStrategy: ControlStrategies.mediaToggle,
playArgs: [ '#dmp_Video' ],
pauseArgs: [ '#dmp_Video' ]
}
}, {
hosts: [ 'netflix.com' ],
options: {
statusStrategy: StatusStrategies.mediaSelector,
statusArgs: [ '.VideoContainer video' ],
controlStrategy: ControlStrategies.mediaToggle,
playArgs: [ '.VideoContainer video' ],
pauseArgs: [ '.VideoContainer video' ]
}
}, {
hosts: [ 'egghead.io' ],
options: {
statusStrategy: StatusStrategies.mediaSelector,
statusArgs: [ '.bitmovinplayer-container video' ],
controlStrategy: ControlStrategies.mediaToggle,
playArgs: [ '.bitmovinplayer-container video' ],
pauseArgs: [ '.bitmovinplayer-container video' ]
}
}, {
hosts: [ 'udemy.com' ],
options: {
statusStrategy: StatusStrategies.mediaSelector,
statusArgs: [ 'video' ],
controlStrategy: ControlStrategies.mediaToggle,
playArgs: [ 'video' ],
pauseArgs: [ 'video' ]
}
}, {
hosts: [ 'musicforprogramming.net' ],
options: {
statusStrategy: StatusStrategies.mediaSelector,
statusArgs: [ '#player' ],
controlStrategy: ControlStrategies.mediaToggle,
playArgs: [ '#player' ],
pauseArgs: [ '#player' ]
}
}, {
hosts: [ 'netflix.com' ],
options: {
statusStrategy: StatusStrategies.mediaSelector,
statusArgs: [ '.VideoContainer video' ],
controlStrategy: ControlStrategies.mediaToggle,
playArgs: [ '.VideoContainer video' ],
pauseArgs: [ '.VideoContainer video' ]
}
}, {
hosts: [ 'hearthis.at' ],
options: {
statusStrategy: StatusStrategies.checkSelector,
statusArgs: [ 'body.play' ],
controlStrategy: { /* custom */},
}
}, {
hosts: ['ted.com', 'facebook.com', 'kickstarter.com', 'music.youtube.com' ],
options: {
statusStrategy: StatusStrategies.oneOfTheVideosPlaying,
controlStrategy: ControlStrategies.oneOfTheVideos,
}
},
])
};

export function getService(domain) {
const matchedService = servicesRegistry().find(serviceConfig => serviceConfig.hosts.includes(domain));

if (!matchedService) {
return;
}

return new Service(matchedService.options);
}
Loading