Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Composite Refactoring with Strategies #157

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
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() {
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
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
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
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