Add embedded sharing to Google Play Music from Chrome ext.
This commit is contained in:
parent
93ae893400
commit
dbc7f4806d
9 changed files with 170 additions and 37 deletions
BIN
chrome/icon-blue-128.png
Normal file
BIN
chrome/icon-blue-128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7 KiB |
BIN
chrome/icon-blue-16.png
Normal file
BIN
chrome/icon-blue-16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
BIN
chrome/icon-blue-48.png
Normal file
BIN
chrome/icon-blue-48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4 KiB |
|
@ -1,19 +1,31 @@
|
|||
{
|
||||
"name" : "Match Audio",
|
||||
"version" : "0.2.2",
|
||||
"version" : "0.3.1",
|
||||
"description" : "Match Audio makes sharing from music services better.",
|
||||
"background" : {
|
||||
"persistent": false,
|
||||
"scripts": [ "background.js" ]
|
||||
"scripts": [
|
||||
"src/background.js"
|
||||
]
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["https://play.google.com/music/*"],
|
||||
"js": ["src/lib/selector-listener.js", "src/google.js"]
|
||||
}
|
||||
],
|
||||
"page_action" : {
|
||||
"default_icon": {
|
||||
"16": "icon-16.png",
|
||||
"48": "icon-48.png",
|
||||
"128": "icon-128.png"
|
||||
}
|
||||
},
|
||||
"default_title": "Find matches for this music on Match Audio"
|
||||
},
|
||||
"permissions" : [ "declarativeContent", "https://match.audio/" ],
|
||||
"permissions" : [
|
||||
"declarativeContent",
|
||||
"https://play.google.com/music"
|
||||
],
|
||||
"icons": {
|
||||
"16": "icon-16.png",
|
||||
"48": "icon-48.png",
|
||||
|
|
|
@ -1,45 +1,36 @@
|
|||
"use strict";
|
||||
const apiUrl = 'https://match.audio';
|
||||
|
||||
chrome.runtime.onInstalled.addListener(function() {
|
||||
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
|
||||
chrome.runtime.onInstalled.addListener(() => {
|
||||
chrome.declarativeContent.onPageChanged.removeRules(undefined, () => {
|
||||
chrome.declarativeContent.onPageChanged.addRules([
|
||||
{
|
||||
conditions: [
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'beatsmusic.com', pathPrefix: "/album" },
|
||||
pageUrl: { hostEquals: 'www.deezer.com', pathPrefix: '/album' },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'beatsmusic.com', pathPrefix: "/track" },
|
||||
pageUrl: { hostEquals: 'www.deezer.com', pathPrefix: '/track' },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'deezer.com', pathPrefix: "/album" },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'deezer.com', pathPrefix: "/track" },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostEquals: 'play.google.com', pathPrefix: "/music" },
|
||||
pageUrl: { hostEquals: 'play.google.com', pathPrefix: '/music' },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostEquals: 'itunes.apple.com', pathPrefix: "/music" },
|
||||
pageUrl: { hostEquals: 'itunes.apple.com', pathPrefix: '/music' },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'rdio.com' },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'rd.io' },
|
||||
pageUrl: { hostSuffix: 'spotify.com', pathPrefix: '/album' },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'spotify.com', pathPrefix: "/album" },
|
||||
pageUrl: { hostSuffix: 'spotify.com', pathPrefix: '/track' },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'spotify.com', pathPrefix: "/track" },
|
||||
pageUrl: { hostEquals: 'music.microsoft.com', pathPrefix: '/track' },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'music.xbox.com', pathPrefix: "/track" },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'music.xbox.com', pathPrefix: "/album" },
|
||||
pageUrl: { hostEquals: 'music.microsoft.com', pathPrefix: '/album' },
|
||||
}),
|
||||
new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { hostSuffix: 'youtube.com' },
|
||||
|
@ -53,17 +44,18 @@ chrome.runtime.onInstalled.addListener(function() {
|
|||
});
|
||||
|
||||
chrome.pageAction.onClicked.addListener(function(tab) {
|
||||
var params = "url=" + encodeURI(tab.url);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "https://match.audio/search", true);
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
var match = JSON.parse(xhr.response);
|
||||
if (match.id) {
|
||||
chrome.tabs.create({ url: "https://match.audio/" + match.service + "/" + match.type + "/" + match.id});
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(params);
|
||||
chrome.pageAction.setIcon({tabId: tab.id, path: 'icon-blue-128.png'}, () => {
|
||||
const headers = new Headers();
|
||||
headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
|
||||
fetch(apiUrl + '/search', {method: 'POST', mode: 'cors', headers, body: 'url=' + encodeURI(tab.url)}).then((response) => {
|
||||
response.json().then((match) => {
|
||||
chrome.pageAction.setIcon({tabId: tab.id, path: 'icon-128.png'});
|
||||
if (match.id) {
|
||||
chrome.tabs.create({ url: apiUrl + '/' + match.service + '/' + match.type + '/' + match.id});
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
chrome.pageAction.setIcon({tabId: tab.id, path: 'icon-128.png'});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
51
chrome/src/google.js
Normal file
51
chrome/src/google.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
const apiUrl = 'https://match.audio';
|
||||
|
||||
var button = document.createElement('button');
|
||||
button.className = 'share-button';
|
||||
button.setAttribute('aria-label', 'Share to Match Audio');
|
||||
|
||||
var buttonContent = document.createElement('div');
|
||||
buttonContent.className = 'button-content';
|
||||
button.appendChild(buttonContent);
|
||||
|
||||
var paperRipple = document.createElement('paper-ripple');
|
||||
paperRipple.class = 'circle';
|
||||
buttonContent.appendChild(paperRipple);
|
||||
|
||||
var background = document.createElement('div');
|
||||
background.id = 'background';
|
||||
background.className = 'style-scope paper-ripple';
|
||||
paperRipple.appendChild(background);
|
||||
|
||||
var waves = document.createElement('div');
|
||||
waves.id = 'waves';
|
||||
waves.className = 'style-scope paper-ripple';
|
||||
paperRipple.appendChild(waves);
|
||||
|
||||
var img = document.createElement('img');
|
||||
img.src = 'https://match.audio/images/logo-128.png';
|
||||
img.height = 48;
|
||||
buttonContent.appendChild(img)
|
||||
|
||||
var buttonLabel = document.createElement('div');
|
||||
buttonLabel.className = 'button-label';
|
||||
buttonLabel.setAttribute('aria-hidden', true);
|
||||
buttonLabel.innerText = 'Match Audio';
|
||||
buttonContent.appendChild(buttonLabel);
|
||||
|
||||
// select the target node
|
||||
document.addSelectorListener('.share-buttons', (event) => {
|
||||
var input = event.target.parentElement.querySelector('paper-input input');
|
||||
// Check that it's an album or track, and not a playlist
|
||||
const match = input.value.match(/https:\/\/play\.google\.com\/music\/m\/([a-zA-Z0-9]+)/);
|
||||
if (match) {
|
||||
event.target.insertBefore(button, event.target.firstChild);
|
||||
button.addEventListener('click', (event) => {
|
||||
if (match[1].startsWith('T')) { // Track
|
||||
window.open(apiUrl + '/google/track/' + match[1], '_blank');
|
||||
} else if (match[1].startsWith('B')) { // Album
|
||||
window.open(apiUrl + '/google/album/' + match[1], '_blank');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
77
chrome/src/lib/selector-listener.js
Normal file
77
chrome/src/lib/selector-listener.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
var events = {},
|
||||
selectors = {},
|
||||
styles = document.createElement('style'),
|
||||
keyframes = document.createElement('style'),
|
||||
head = document.getElementsByTagName('head')[0],
|
||||
startNames = ['animationstart', 'oAnimationStart', 'MSAnimationStart', 'webkitAnimationStart'],
|
||||
startEvent = function(event){
|
||||
event.selector = (events[event.animationName] || {}).selector;
|
||||
((this.selectorListeners || {})[event.animationName] || []).forEach(function(fn){
|
||||
fn.call(this, event);
|
||||
}, this);
|
||||
},
|
||||
prefix = (function() {
|
||||
var duration = 'animation-duration: 0.001s;',
|
||||
name = 'animation-name: SelectorListener !important;',
|
||||
computed = window.getComputedStyle(document.documentElement, ''),
|
||||
pre = (Array.prototype.slice.call(computed).join('').match(/moz|webkit|ms/)||(computed.OLink===''&&['o']))[0];
|
||||
return {
|
||||
css: '-' + pre + '-',
|
||||
properties: '{' + duration + name + '-' + pre + '-' + duration + '-' + pre + '-' + name + '}',
|
||||
keyframes: !!(window.CSSKeyframesRule || window[('WebKit|Moz|MS|O').match(new RegExp('(' + pre + ')', 'i'))[1] + 'CSSKeyframesRule'])
|
||||
};
|
||||
})();
|
||||
|
||||
styles.type = keyframes.type = 'text/css';
|
||||
head.appendChild(styles);
|
||||
head.appendChild(keyframes);
|
||||
|
||||
HTMLDocument.prototype.addSelectorListener = HTMLElement.prototype.addSelectorListener = function(selector, fn){
|
||||
var key = selectors[selector],
|
||||
listeners = this.selectorListeners = this.selectorListeners || {};
|
||||
|
||||
if (key) events[key].count++;
|
||||
else {
|
||||
key = selectors[selector] = 'SelectorListener-' + new Date().getTime();
|
||||
var node = document.createTextNode('@' + (prefix.keyframes ? prefix.css : '') + 'keyframes ' + key + ' {'
|
||||
+'from { outline-color: #fff; } to { outline-color: #000; }'
|
||||
+ '}');
|
||||
keyframes.appendChild(node);
|
||||
styles.sheet.insertRule(selector + prefix.properties.replace(/SelectorListener/g, key), 0);
|
||||
events[key] = { count: 1, selector: selector, keyframe: node, rule: styles.sheet.cssRules[0] };
|
||||
}
|
||||
|
||||
if (listeners.count) listeners.count++;
|
||||
else {
|
||||
listeners.count = 1;
|
||||
startNames.forEach(function(name){
|
||||
this.addEventListener(name, startEvent, false);
|
||||
}, this);
|
||||
}
|
||||
|
||||
(listeners[key] = listeners[key] || []).push(fn);
|
||||
};
|
||||
|
||||
HTMLDocument.prototype.removeSelectorListener = HTMLElement.prototype.removeSelectorListener = function(selector, fn){
|
||||
var listeners = this.selectorListeners || {},
|
||||
key = selectors[selector],
|
||||
listener = listeners[key] || [],
|
||||
index = listener.indexOf(fn);
|
||||
|
||||
if (index > -1){
|
||||
var event = events[selectors[selector]];
|
||||
event.count--;
|
||||
if (!event.count){
|
||||
styles.sheet.deleteRule(styles.sheet.cssRules.item(event.rule));
|
||||
keyframes.removeChild(event.keyframe);
|
||||
delete events[key];
|
||||
delete selectors[selector];
|
||||
}
|
||||
|
||||
listeners.count--;
|
||||
listener.splice(index, 1);
|
||||
if (!listeners.count) startNames.forEach(function(name){
|
||||
this.removeEventListener(name, startEvent, false);
|
||||
}, this);
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue