Skip to content
This repository has been archived by the owner on Feb 26, 2021. It is now read-only.

Commit

Permalink
Fix #320, convert YouTube to be a music service
Browse files Browse the repository at this point in the history
This doesn't remove the old YouTube service yet, nor does it complete everything about making it a service.
  • Loading branch information
ianb committed Sep 26, 2019
1 parent 5eb7bbf commit d5121eb
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 9 deletions.
5 changes: 5 additions & 0 deletions extension/background/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ this.content = (function() {
const NO_RECEIVER_MESSAGE =
"Could not establish connection. Receiving end does not exist";
const exports = {};

exports.lazyInject = async function(tabId, scripts) {
if (!tabId) {
throw new Error(`Invalid tabId: ${tabId}`);
}
if (typeof scripts === "string") {
scripts = [scripts];
}
Expand Down Expand Up @@ -43,5 +47,6 @@ this.content = (function() {
scriptKey,
});
};

return exports;
})();
1 change: 1 addition & 0 deletions extension/background/intentParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ this.intentParser = (function() {

const ENTITY_TYPES = {
serviceName: serviceList.allServiceNames(),
musicServiceName: serviceList.musicServiceNames(),
};

const Matcher = (exports.Matcher = class Matcher {
Expand Down
9 changes: 9 additions & 0 deletions extension/background/serviceList.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ this.serviceList = (function() {
return bang;
};

// Note these are maintained separately from the services in extension/services/*, because
// those are all loaded too late to be used here
exports.musicServiceNames = function() {
return ["youtube", "spotify"];
};

exports.Service = class Service {
constructor(context) {
this.context = context;
Expand Down Expand Up @@ -181,6 +187,9 @@ this.serviceList = (function() {
let bestScore = 0;
for (const name in services) {
const service = services[name];
if (service.skipAutodetect) {
continue;
}
if (!service.baseUrl) {
throw new Error(`Service ${service.name} has no .baseUrl`);
}
Expand Down
46 changes: 37 additions & 9 deletions extension/intents/music/music.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,45 @@
/* globals intentRunner, serviceList */
/* globals intentRunner, serviceList, log */

this.intents.music = (function() {
const exports = {};
const SERVICES = {};
exports.register = function(service) {
if (!service.id) {
log.error("Bad music service, no id:", service);
throw new Error("Invalid service: no id");
}
if (SERVICES[service.id]) {
throw new Error(
`Attempt to register two music services with id ${service.id}`
);
}
SERVICES[service.id] = service;
};

async function getService(context) {
let ServiceClass;
if (context.slots.service) {
ServiceClass = SERVICES[context.slots.service.toLowerCase()];
if (!ServiceClass) {
throw new Error(
`[service] slot refers to unknown service: ${context.slots.service}`
);
}
} else {
ServiceClass = await serviceList.getService("music", SERVICES);
}
return new ServiceClass(context);
}

intentRunner.registerIntent({
name: "music.play",
examples: ["Play Green Day"],
match: `
play [query] on [service:musicServiceName]
play [query]
`,
async run(context) {
const Service = await serviceList.getService("music", SERVICES);
const service = new Service(context);
const service = await getService(context);
await service.playQuery(context.slots.query);
},
});
Expand All @@ -24,12 +48,12 @@ this.intents.music = (function() {
name: "music.pause",
examples: ["Pause music"],
match: `
pause [service:musicServiceName]
pause music
stop music
`,
async run(context) {
const Service = await serviceList.getService("music", SERVICES);
const service = new Service(context);
const service = await getService(context);
await service.pause();
},
});
Expand All @@ -38,14 +62,16 @@ this.intents.music = (function() {
name: "music.unpause",
examples: ["Unpause", "continue music", "play music"],
match: `
unpause [service:musicServiceName]
continue [service:musicServiceName]
play [service:musicServiceName]
unpause
continue music
play music
`,
priority: "high",
async run(context) {
const Service = await serviceList.getService("music", SERVICES);
const service = new Service(context);
const service = await getService(context);
await service.unpause();
},
});
Expand All @@ -54,13 +80,15 @@ this.intents.music = (function() {
name: "music.focus",
examples: ["Open music"],
match: `
open [service:musicServiceName]
show [service:musicServiceName]
focus [service:musicServiceName]
open music
show music
focus music
`,
async run(context) {
const Service = await serviceList.getService("music", SERVICES);
const service = new Service(context);
const service = await getService(context);
await service.activateOrOpen();
},
});
Expand Down
25 changes: 25 additions & 0 deletions extension/services/youtube/player.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* globals helpers */

this.player = (function() {
class Player extends helpers.Runner {
action_play() {
const button = this.querySelector("button.ytp-large-play-button");
console.log("clicking button", button);
button.click();
console.log("clicked");
}

action_pause() {
const button = this.querySelector(
"buttonytp-play-button[aria-label^='Pause']"
);
button.click();
}

action_unpause() {
this.action_play();
}
}

Player.register();
})();
34 changes: 34 additions & 0 deletions extension/services/youtube/youtube.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* globals intents, serviceList, searching, content */

this.services.youtube = (function() {
class YouTube extends serviceList.Service {
async playQuery(query) {
this.tab = await browser.tabs.create({
url: searching.googleSearchUrl(`${query} youtube.com`, true),
active: true,
});
browser.tabs.update(this.tab.id, { muted: true });
await content.lazyInject(this.tab.id, "/services/youtube/player.js");
await this.callTab("play");
}

async pause() {
await this.initTab("/services/spotify/player.js");
await this.callTab("pause");
}

async unpause() {
await this.initTab("/services/spotify/player.js");
await this.callTab("unpause");
}
}

Object.assign(YouTube, {
id: "youtube",
title: "YouTube",
baseUrl: "https://www.youtube.com",
skipAutodetect: true,
});

intents.music.register(YouTube);
})();

0 comments on commit d5121eb

Please sign in to comment.