v0.2: use webpack, and DOM mutations to properly handle YT navigation

This commit is contained in:
Ealhad 2018-08-10 11:53:33 +02:00
parent c54f8260fe
commit 7d97eb5885
9 changed files with 4711 additions and 85 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
extension/dist
node_modules

View File

@ -1,34 +0,0 @@
/* This file is part of PeerTubeify.
*
* PeerTubeify is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PeerTubeify is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerTubeify. If not, see <https://www.gnu.org/licenses/>.
*/
function search(query) {
return new Promise((resolve, reject) => {
fetch(`https://peertube.video/api/v1/videos/search?search=${encodeURIComponent(query)}`)
.then(res => res.json())
.then(function(data) {
if (data.total > 0) {
resolve(data.data[0]);
} else {
reject(new Error('No results.'))
}
})
});
};
browser.runtime.onMessage.addListener(function(message, sender) {
return search(message.query)
});

View File

@ -1,19 +1,18 @@
{
"manifest_version": 2,
"name": "PeerTubeify",
"version": "0.1.0",
"version": "0.2.0",
"description": "On YouTube, displays a link to the same video on PeerTube, if it exists.",
"homepage_url": "https://gitlab.com/Ealhad/peertubeify",
"permissions": [
"activeTab",
"notifications",
"<all_urls>"
],
"background": {
"scripts": ["background.js"]
"scripts": ["dist/background.js"]
},
"content_scripts": [{
"matches": ["*://*.youtube.com/watch*"],
"js": ["youtube.js"]
"matches": ["*://*.youtube.com/*"],
"js": ["dist/youtube.js"]
}]
}

4531
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

24
package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "peertubeify",
"version": "0.2.0",
"description": "PeerTubeify is a browser extension to help discovering which YouTube videos are also available on PeerTube.",
"main": "webpack.config.js",
"dependencies": {},
"devDependencies": {
"lodash": "^4.17.10",
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0"
},
"scripts": {
"build": "webpack --display-error-details --progress --colors",
"build:watch": "npm run build -- -w"
},
"repository": {
"type": "git",
"url": "git+ssh://git@gitlab.com/Ealhad/peertubeify.git"
},
"bugs": {
"url": "https://gitlab.com/Ealhad/peertubeify/issues"
},
"homepage": "https://gitlab.com/Ealhad/peertubeify#README"
}

37
src/background.js Normal file
View File

@ -0,0 +1,37 @@
/* This file is part of PeerTubeify.
*
* PeerTubeify is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* PeerTubeify is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* PeerTubeify. If not, see <https://www.gnu.org/licenses/>.
*/
const buildSearchURL = query => `https://peertube.video/api/v1/videos/search?search=${encodeURIComponent(query)}`;
function search(query) {
return new Promise((resolve, reject) => {
fetch(buildSearchURL(query))
.then(res => res.json())
.then(function(data) {
if (data.total > 0) {
const video = data.data[0]
resolve(video);
} else {
reject(new Error('No results.'))
}
})
});
};
browser.runtime.onMessage.addListener(function(message, sender) {
return search(message.query)
});

82
src/youtube.js Normal file
View File

@ -0,0 +1,82 @@
/* This file is part of PeerTubeify.
*
* PeerTubeify is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* PeerTubeify is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* PeerTubeify. If not, see <https://www.gnu.org/licenses/>.
*/
import _ from 'lodash/fp';
const watchURL = (host, uuid) => `https://${host}/videos/watch/${uuid}`;
const thumbnailURL = (host, path) => `https://${host}${path}`;
const LINK_ID = 'peertube-link';
function peertubeify(query) {
browser.runtime.sendMessage({
query
}).then(video => {
removeVideoLink();
const link = videoLink(video);
document.querySelector('.title').insertAdjacentElement('afterend', link);
});
}
const throttledPeertubify = _.throttle(1000, peertubeify);
const observer = new MutationObserver(function(mutationsList) {
for (const mutation of mutationsList) {
if (mutation.target.classList.contains('ytp-title-link')) {
for (const node of mutation.addedNodes) {
if (node.nodeType == Node.TEXT_NODE) {
throttledPeertubify(node.textContent);
}
}
}
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
})
function htmlToElement(html) {
const template = document.createElement('template');
template.innerHTML = html.trim();
return template.content.firstChild;
}
function videoLink(video) {
const url = watchURL(video.account.host, video.uuid);
return htmlToElement(`
<a id="${LINK_ID}" style="display: flex; align-items: center; margin: 2rem 0;" href=${url}>
<img src="${thumbnailURL(video.account.host, video.thumbnailPath)}">
<p style="font-size: 18px; margin-left: 1rem; color: var(--ytd-video-primary-info-renderer-title-color, var(--yt-primary-text-color));">
${video.account.host}
</p>:
</a>
`);
}
function removeVideoLink() {
const existingLink = document.getElementById(LINK_ID);
existingLink && existingLink.remove();
}
function ready(fn) {
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}

31
webpack.config.js Normal file
View File

@ -0,0 +1,31 @@
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
background: 'background.js',
youtube: 'youtube.js',
},
output: {
path: path.join(__dirname, 'extension', 'dist'),
filename: '[name].js',
},
resolve: {
// This allows you to import modules just like you would in a NodeJS app.
extensions: ['.js'],
modules: [
path.join(__dirname, 'src'),
'node_modules',
],
},
plugins: [
// Since some NodeJS modules expect to be running in Node, it is helpful
// to set this environment var to avoid reference errors.
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
],
// This will expose source map files so that errors will point to your
// original source files instead of the transpiled files.
devtool: 'sourcemap',
};

View File

@ -1,46 +0,0 @@
/* This file is part of PeerTubeify.
*
* PeerTubeify is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PeerTubeify is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerTubeify. If not, see <https://www.gnu.org/licenses/>.
*/
const watchURL = (host, uuid) => `https://${host}/videos/watch/${uuid}`;
const thumbnailURL = (host, path) => `https://${host}${path}`;
const title = document.title.slice(0, document.title.lastIndexOf(' -'));
if (title) {
browser.runtime.sendMessage({
query: title,
}).then(video => {
document.querySelector('.title').insertAdjacentElement('afterend', videoLink(video));
});
}
function htmlToElement(html) {
const template = document.createElement('template');
template.innerHTML = html.trim();
return template.content.firstChild;
}
function videoLink(video) {
const url = watchURL(video.account.host, video.uuid);
return htmlToElement(`
<a style="display: flex; align-items: center; margin: 2rem 0;" href=${url}>
<img src="${thumbnailURL(video.account.host, video.thumbnailPath)}">
<p style="font-size: 18px; margin-left: 1rem; color: var(--ytd-video-primary-info-renderer-title-color, var(--yt-primary-text-color));">
${video.account.host}
</p>:
</a>
`);
}