Add the possibility to display a link when on another PeerTube instance

This commit is contained in:
Ealhad 2018-09-15 18:31:00 +02:00
parent 59027cb927
commit f197253e52
11 changed files with 177 additions and 19 deletions

View File

@ -4,6 +4,10 @@ PeerTubeify is a browser extension to help discovering which YouTube videos are
also available on [[https://joinpeertube.org/][PeerTube]], by displaying a link and a thumbnail below the video also available on [[https://joinpeertube.org/][PeerTube]], by displaying a link and a thumbnail below the video
title, when watching a video on YouTube. title, when watching a video on YouTube.
It also allows you to choose a preferred PeerTube instance; when you watch a
video on another instance, a link to the same video in your preferred instance
is displayed.
PeerTube is a federated video streaming platform. PeerTube is a federated video streaming platform.
PeerTubeify is not affiliated with PeerTube. PeerTubeify is not affiliated with PeerTube.

View File

@ -1,7 +1,7 @@
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "PeerTubeify", "name": "PeerTubeify",
"version": "0.2.5", "version": "0.3.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",
"icons": { "icons": {
@ -20,6 +20,9 @@
"content_scripts": [{ "content_scripts": [{
"matches": ["*://*.youtube.com/*"], "matches": ["*://*.youtube.com/*"],
"js": ["dist/youtube.js"] "js": ["dist/youtube.js"]
}, {
"matches": ["https://*/videos/watch/*"],
"js": ["dist/peertube.js"]
}], }],
"options_ui": { "options_ui": {
"page": "dist/options.html" "page": "dist/options.html"

View File

@ -1,6 +1,6 @@
{ {
"name": "peertubeify", "name": "peertubeify",
"version": "0.2.5", "version": "0.3.0",
"description": "PeerTubeify is a browser extension to help discovering which YouTube videos are also available on PeerTube.", "description": "PeerTubeify is a browser extension to help discovering which YouTube videos are also available on PeerTube.",
"main": "webpack.config.js", "main": "webpack.config.js",
"dependencies": {}, "dependencies": {},

View File

@ -17,14 +17,15 @@
import * as _ from 'lodash/fp'; import * as _ from 'lodash/fp';
import * as browser from 'webextension-polyfill'; import * as browser from 'webextension-polyfill';
import { MessageKind } from './types';
import { constants } from './constants'; import { constants } from './constants';
const buildSearchURL = (instance: string, query: string): string => `https://${instance}/api/v1/search/videos?search=${encodeURIComponent(query)}`; const buildSearchByNameURL = (instance: string, query: string): string => `https://${instance}/api/v1/search/videos?search=${encodeURIComponent(query)}`;
const search = query => new Promise(async (resolve, reject) => { const searchByName = query => new Promise(async (resolve, reject) => {
const instance = _.getOr(constants.defaultInstance, 'searchInstance', await browser.storage.local.get()).toString(); const instance = _.getOr(constants.defaultInstance, 'searchInstance', await browser.storage.local.get()).toString();
fetch(buildSearchURL(instance, query)) fetch(buildSearchByNameURL(instance, query))
.then(res => res.json()) .then(res => res.json())
.then(function(data) { .then(function(data) {
if (data.total > 0) { if (data.total > 0) {
@ -37,7 +38,23 @@ const search = query => new Promise(async (resolve, reject) => {
}); });
}); });
const buildSearchByIDURL = (instance: string, id: string): string => `https://${instance}/api/v1/videos/${id}`;
const searchByID = id => new Promise(async (resolve, reject) => {
const instance = _.getOr(constants.defaultInstance, 'searchInstance', await browser.storage.local.get()).toString();
fetch(buildSearchByIDURL(instance, id))
.then(res => res.json())
.then(function (video) {
resolve({ url: `https://${instance}/videos/watch/${id}`, video });
})
})
browser.runtime.onMessage.addListener(function(message, sender) { browser.runtime.onMessage.addListener(function(message, sender) {
return search(message.query) switch (message.kind) {
case MessageKind.SearchByName:
return searchByName(message.query);
case MessageKind.SearchByID:
return searchByID(message.id);
}
}); });

View File

@ -22,6 +22,13 @@
<input type="checkbox" id="open-in-original-instance"> <input type="checkbox" id="open-in-original-instance">
</label> </label>
<label style="margin-bottom: 1rem; display: flex; align-items: center;">
<p style="margin-right: 1rem">
Show a message on other PeerTube instances to redirect to your preferred one?
</p>
<input type="checkbox" id="show-on-peertube">
</label>
<button style="display: block; margin-left: auto" type="submit">Save</button> <button style="display: block; margin-left: auto" type="submit">Save</button>
</form> </form>

View File

@ -21,14 +21,16 @@ import { constants } from './constants';
function id(id: string): Element { return document.getElementById(id); } function id(id: string): Element { return document.getElementById(id); }
const searchInstanceInput = () => id('search-instance') as HTMLInputElement; const searchInstance = () => id('search-instance') as HTMLInputElement;
const openInOriginalInstanceInput = () => id('open-in-original-instance') as HTMLInputElement; const openInOriginalInstance = () => id('open-in-original-instance') as HTMLInputElement;
const showOnPeertube = () => id('show-on-peertube') as HTMLInputElement;
function saveOptions(e) { function saveOptions(e) {
e.preventDefault(); e.preventDefault();
browser.storage.local.set({ browser.storage.local.set({
searchInstance: _.defaultTo(constants.defaultInstance, stripProtocol(searchInstanceInput().value)), searchInstance: _.defaultTo(constants.defaultInstance, stripProtocol(searchInstance().value)),
openInOriginalInstance: _.defaultTo(true, openInOriginalInstanceInput().checked), openInOriginalInstance: _.defaultTo(true, openInOriginalInstance().checked),
showOnPeertube: _.defaultTo(false, showOnPeertube().checked),
}); });
} }
@ -36,8 +38,9 @@ const stripProtocol = _.replace(/^https?:\/\//, '');
function restoreOptions() { function restoreOptions() {
browser.storage.local.get().then(result => { browser.storage.local.get().then(result => {
searchInstanceInput().value = _.defaultTo(constants.defaultInstance, result.searchInstance as string); searchInstance().value = _.defaultTo(constants.defaultInstance, result.searchInstance as string);
openInOriginalInstanceInput().checked = _.defaultTo(true, result.openInOriginalInstance as boolean); openInOriginalInstance().checked = _.defaultTo(true, result.openInOriginalInstance as boolean);
showOnPeertube().checked = _.defaultTo(false, result.showOnPeertube as boolean);
}) })
} }

117
src/peertube.ts Normal file
View File

@ -0,0 +1,117 @@
/* 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 * as _ from 'lodash/fp';
import * as browser from 'webextension-polyfill';
import { htmlToElement } from './util';
import { MessageKind } from './types';
import { constants } from './constants';
const watchURL = (host, uuid) => `https://${host}/videos/watch/${uuid}`;
const thumbnailURL = (host, path) => `https://${host}${path}`;
const LINK_ID = 'peertube-link';
async function peertubeify() {
const options = await browser.storage.local.get();
const showOnPeertube = _.getOr(false, 'showOnPeertube', options);
const preferredInstance = _.getOr(constants.defaultInstance, 'searchInstance', options);
const isPreferredInstance = _.equals(preferredInstance, location.hostname)
if (showOnPeertube && !isPreferredInstance) {
const id = _.last(_.split('/', location.href));
browser.runtime.sendMessage({
kind: MessageKind.SearchByID,
id
}).then(async ({video, url}) => {
const link = videoLink(url, video);
removeVideoLink();
document.querySelector('body').appendChild(link);
}).catch(removeVideoLink);
}
}
const throttledPeertubeify = _.throttle(1000, peertubeify);
const observer = new MutationObserver(function(mutationsList) {
for (const mutation of mutationsList) {
if ((mutation.target as Element).id =='video-element-wrapper') {
throttledPeertubeify();
}
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
})
const videoLink = (url, video) => htmlToElement(`
<div id="${LINK_ID}"
style="
position: fixed;
bottom: 0;
left: 0;
box-sizing: border-box;
width: 100%;
padding: 1rem;
z-index: 10000;
box-shadow: inset 0px 4px 8px -3px rgba(17, 17, 17, .06);
background-color: #000;
">
<button
onclick="document.getElementById('${LINK_ID}').remove()"
style="
all: unset;
color: #fff;
cursor: pointer;
font-size: 24px;
position: absolute;
line-height: .8;
top: 1rem;
right: 1rem;">
</button>
<a
style="
display: flex;
align-items: center;
text-decoration: none;"
href=${url}>
<img src="${thumbnailURL(video.account.host, video.thumbnailPath)}">
<div style="
font-size: 18px;
margin-left: 1rem;
color: #fff;
display: flex;
flex-direction: column;
justify-content: space-around;
">
<p style="margin: 0 0 1rem;">
${video.name}
</p>
</div>
</a>
</div>
`);
function removeVideoLink() {
const existingLink = document.getElementById(LINK_ID);
existingLink && existingLink.remove();
}

4
src/types.ts Normal file
View File

@ -0,0 +1,4 @@
export enum MessageKind {
SearchByName,
SearchByID,
}

5
src/util.ts Normal file
View File

@ -0,0 +1,5 @@
export function htmlToElement(html: string): Element {
const template = document.createElement('template');
template.innerHTML = html.trim();
return template.content.firstElementChild;
}

View File

@ -17,6 +17,8 @@
import * as _ from 'lodash/fp'; import * as _ from 'lodash/fp';
import * as browser from 'webextension-polyfill'; import * as browser from 'webextension-polyfill';
import { htmlToElement } from './util';
import { MessageKind } from './types';
import { constants } from './constants'; import { constants } from './constants';
const watchURL = (host, uuid) => `https://${host}/videos/watch/${uuid}`; const watchURL = (host, uuid) => `https://${host}/videos/watch/${uuid}`;
@ -26,7 +28,8 @@ const LINK_ID = 'peertube-link';
function peertubeify(query: string) { function peertubeify(query: string) {
browser.runtime.sendMessage({ browser.runtime.sendMessage({
query kind: MessageKind.SearchByName,
query,
}).then(async video => { }).then(async video => {
const options = await browser.storage.local.get(); const options = await browser.storage.local.get();
const openInOriginalInstance = _.getOr(true, 'openInOriginalInstance', options); const openInOriginalInstance = _.getOr(true, 'openInOriginalInstance', options);
@ -58,12 +61,6 @@ observer.observe(document.body, {
subtree: true, subtree: true,
}) })
function htmlToElement(html: string): Element {
const template = document.createElement('template');
template.innerHTML = html.trim();
return template.content.firstElementChild;
}
const videoLink = (url, video) => htmlToElement(` const videoLink = (url, video) => htmlToElement(`
<div id="${LINK_ID}" <div id="${LINK_ID}"
style=" style="

View File

@ -5,6 +5,7 @@ module.exports = {
entry: { entry: {
background: 'background.ts', background: 'background.ts',
youtube: 'youtube.ts', youtube: 'youtube.ts',
peertube: 'peertube.ts',
options: ['options.ts', 'options.html'], options: ['options.ts', 'options.html'],
}, },
output: { output: {