v0.2: use webpack, and DOM mutations to properly handle YT navigation
This commit is contained in:
parent
c54f8260fe
commit
7d97eb5885
|
@ -0,0 +1,2 @@
|
||||||
|
extension/dist
|
||||||
|
node_modules
|
|
@ -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)
|
|
||||||
});
|
|
|
@ -1,19 +1,18 @@
|
||||||
{
|
{
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "PeerTubeify",
|
"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.",
|
"description": "On YouTube, displays a link to the same video on PeerTube, if it exists.",
|
||||||
"homepage_url": "https://gitlab.com/Ealhad/peertubeify",
|
"homepage_url": "https://gitlab.com/Ealhad/peertubeify",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"activeTab",
|
"activeTab",
|
||||||
"notifications",
|
|
||||||
"<all_urls>"
|
"<all_urls>"
|
||||||
],
|
],
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": ["background.js"]
|
"scripts": ["dist/background.js"]
|
||||||
},
|
},
|
||||||
"content_scripts": [{
|
"content_scripts": [{
|
||||||
"matches": ["*://*.youtube.com/watch*"],
|
"matches": ["*://*.youtube.com/*"],
|
||||||
"js": ["youtube.js"]
|
"js": ["dist/youtube.js"]
|
||||||
}]
|
}]
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||||
|
}
|
|
@ -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)
|
||||||
|
});
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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',
|
||||||
|
};
|
46
youtube.js
46
youtube.js
|
@ -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>
|
|
||||||
`);
|
|
||||||
}
|
|
Loading…
Reference in New Issue