Merge branch 'invidious' into 'master'

Add support for Invidious redirections

Closes #6

See merge request Ealhad/peertubeify!6
This commit is contained in:
Ealhad 2019-02-19 12:47:04 +00:00
commit 357a4a10ef
4 changed files with 51 additions and 36 deletions

View File

@ -20,7 +20,7 @@
"scripts": ["dist/background.js", "dist/vendors.js"] "scripts": ["dist/background.js", "dist/vendors.js"]
}, },
"content_scripts": [{ "content_scripts": [{
"matches": ["*://*.youtube.com/*"], "matches": ["*://*.youtube.com/*", "*://*.invidio.us/*"],
"js": ["dist/youtube.js", "dist/vendors.js"] "js": ["dist/youtube.js", "dist/vendors.js"]
}, { }, {
"matches": ["https://*/videos/watch/*"], "matches": ["https://*/videos/watch/*"],

View File

@ -18,7 +18,6 @@ import * as _ from 'lodash/fp';
import * as browser from 'webextension-polyfill'; import * as browser from 'webextension-polyfill';
import { MessageKind, RedirectType } from './types'; import { MessageKind, RedirectType } from './types';
import constants from './constants';
import Preferences from './preferences'; import Preferences from './preferences';
import * as InvidiousAPI from './invidious-api'; import * as InvidiousAPI from './invidious-api';
import * as PeertubeAPI from './peertube-api'; import * as PeertubeAPI from './peertube-api';
@ -33,25 +32,27 @@ const getTitle = async (id: string) => {
} }
/** /**
* Redirect Youtube without loading it if the video is found and preferences lAHhDKzReKBQKj3R * Redirect Youtube without loading it if the video is found and preferences
* set on automatic redirection. * set on automatic redirection.
*/ */
const redirectYoutube = async (r) => { const redirectYoutube = async (r) => {
const prefs = await Preferences.getPreferences(); const prefs = await Preferences.getPreferences();
if (prefs.redirectYoutube == RedirectType.Auto) { if (prefs.redirectYoutube == RedirectType.Auto) {
const query = new URLSearchParams(r.url.substring(r.url.indexOf('?') + 1)); const isEmbed = _.contains('embed', r.url);
const title = await getTitle(query.get('v')); const query = isEmbed
? r.url.substr(r.url.lastIndexOf('/') + 1, 11)
: r.url.substr(r.url.indexOf('?v=') + 3, 11);
const title = await getTitle(query);
const video = await searchByName(title); const video = await searchByName(title);
const url = getPeertubeVideoURL(video, prefs); const url = getPeertubeVideoURL(video, prefs, { isEmbed });
return { return {
redirectUrl: url redirectUrl: url
}; };
} }
throw new Error('No results.');
}; };
/** /**
@ -70,18 +71,18 @@ const redirectPeertube = async (r) => {
const id = _.last(_.split('/', r.url)); const id = _.last(_.split('/', r.url));
const video: any = await PeertubeAPI.getVideo(id); const video: any = await PeertubeAPI.getVideo(id);
const isEmbed = _.contains('embed', r.url);
if (prefs.openInOriginalInstance && video.account.host === hostname) { if (prefs.openInOriginalInstance && video.account.host === hostname) {
return {}; // Don't redirect if original instance return {}; // Don't redirect if original instance
} }
const url = getPeertubeVideoURL(video, prefs); const url = getPeertubeVideoURL(video, prefs, { isEmbed });
return { return {
redirectUrl: url redirectUrl: url
}; };
} }
throw new Error('No results.');
}; };
const searchByName = query => new Promise(async (resolve, reject) => { const searchByName = query => new Promise(async (resolve, reject) => {
@ -97,7 +98,7 @@ const searchByName = query => new Promise(async (resolve, reject) => {
}); });
}); });
browser.runtime.onMessage.addListener(function(message, sender) { browser.runtime.onMessage.addListener(function(message) {
switch (message.kind) { switch (message.kind) {
case MessageKind.SearchByName: case MessageKind.SearchByName:
return searchByName(message.query); return searchByName(message.query);
@ -108,12 +109,12 @@ browser.runtime.onMessage.addListener(function(message, sender) {
browser.webRequest.onBeforeRequest.addListener( browser.webRequest.onBeforeRequest.addListener(
redirectYoutube, redirectYoutube,
{ urls: ['*://*.youtube.com/watch?v=*'] }, { urls: ['*://*.youtube.com/watch?v=*', '*://*.youtube.com/embed/*', '*://*.invidio.us/watch?v=*', '*://*.invidio.us/embed/*'] },
['blocking'] ['blocking']
); );
browser.webRequest.onBeforeRequest.addListener( browser.webRequest.onBeforeRequest.addListener(
redirectPeertube, redirectPeertube,
{ urls: ['*://*/videos/watch/*'] }, { urls: ['*://*/videos/watch/*', '*://*/videos/embed/*'] },
['blocking'] ['blocking']
); );

View File

@ -4,8 +4,10 @@ export function htmlToElement(html: string): Element {
return template.content.firstElementChild; return template.content.firstElementChild;
} }
export function getPeertubeVideoURL(video, prefs) { export function getPeertubeVideoURL(video, prefs, { isEmbed = false } = {}) {
return `https://${getPeertubeHost(video.account.host, prefs)}/videos/watch/${video.uuid}` const endpoint = isEmbed ? 'embed' : 'watch';
return `https://${getPeertubeHost(video.account.host, prefs)}/videos/${endpoint}/${video.uuid}`;
} }
export function getPeertubeHost(host, prefs) { export function getPeertubeHost(host, prefs) {

View File

@ -22,7 +22,7 @@ import { MessageKind, RedirectType } from './types';
import Preferences from './preferences' import Preferences from './preferences'
const thumbnailURL = (host, path) => `https://${host}${path}`; const thumbnailURL = (host, path) => `https://${host}${path}`;
const isYouTube = _.contains('youtube.com', document.location.hostname);
const LINK_ID = 'peertube-link'; const LINK_ID = 'peertube-link';
function searchVideo(query) { function searchVideo(query) {
@ -43,7 +43,9 @@ async function peertubeify(query: String) {
const link = videoLink(url, video); const link = videoLink(url, video);
removeVideoLink(); removeVideoLink();
document.querySelector('ytd-app').appendChild(link);
const querySelector = isYouTube ? 'ytd-app' : 'body';
document.querySelector(querySelector).appendChild(link);
}).catch(removeVideoLink); }).catch(removeVideoLink);
break; break;
} }
@ -53,23 +55,32 @@ async function peertubeify(query: String) {
} }
} }
const throttledPeertubeify = _.throttle(1000, peertubeify); if (isYouTube) {
const observer = new MutationObserver(function(mutationsList) { const throttledPeertubeify = _.throttle(1000, peertubeify);
for (const mutation of mutationsList) { const observer = new MutationObserver(function(mutationsList) {
if ((mutation.target as Element).classList.contains('ytp-title-link')) { for (const mutation of mutationsList) {
for (const node of mutation.addedNodes) { if ((mutation.target as Element).classList.contains('ytp-title-link')) {
if (node.nodeType == Node.TEXT_NODE) { for (const node of mutation.addedNodes) {
throttledPeertubeify(node.textContent); if (node.nodeType == Node.TEXT_NODE) {
throttledPeertubeify(node.textContent);
}
} }
} }
} }
} });
});
observer.observe(document.body, { observer.observe(document.body, {
childList: true, childList: true,
subtree: true, subtree: true,
}) })
} else {
peertubeify(document.title.substring(0, document.title.indexOf(' - Invidious')));
}
const backgroundColor = isYouTube ? 'var(--yt-swatch-primary)' : '#fff';
const buttonColor = isYouTube ? 'var(--yt-swatch-text)' : '#000';
const textColor = isYouTube ? 'var(--yt-primary-text-color)' : '#000';
const hostSize = isYouTube ? '1.4rem' : '0.9rem';
const videoLink = (url, video) => htmlToElement(` const videoLink = (url, video) => htmlToElement(`
<div id="${LINK_ID}" <div id="${LINK_ID}"
@ -80,16 +91,17 @@ const videoLink = (url, video) => htmlToElement(`
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
padding: 1rem; padding: 1rem;
z-index: 10; z-index: 101;
box-shadow: inset 0px 4px 8px -3px rgba(17, 17, 17, .06); box-shadow: inset 0px 4px 8px -3px rgba(17, 17, 17, .06);
background-color: var(--yt-swatch-primary); background-color: ${backgroundColor};
letter-spacing: normal;
"> ">
<button <button
onclick="document.getElementById('${LINK_ID}').remove()" onclick="document.getElementById('${LINK_ID}').remove()"
style=" style="
all: unset; all: unset;
color: var(--yt-swatch-text); color: ${buttonColor};
cursor: pointer; cursor: pointer;
font-size: 24px; font-size: 24px;
position: absolute; position: absolute;
@ -111,7 +123,7 @@ const videoLink = (url, video) => htmlToElement(`
<div style=" <div style="
font-size: 18px; font-size: 18px;
margin-left: 1rem; margin-left: 1rem;
color: var(--yt-primary-text-color); color: ${textColor};
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-around; justify-content: space-around;
@ -120,7 +132,7 @@ const videoLink = (url, video) => htmlToElement(`
${video.name} ${video.name}
</p> </p>
<p style="font-size: 1.4rem; margin: 0;"> <p style="font-size: ${hostSize}; margin: 0;">
${video.account.host} ${video.account.host}
</p> </p>
</div> </div>