Merge branch 'invidious' into 'master'
Add support for Invidious redirections Closes #6 See merge request Ealhad/peertubeify!6
This commit is contained in:
commit
357a4a10ef
|
@ -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/*"],
|
||||||
|
|
|
@ -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']
|
||||||
);
|
);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue