Refactor Peertube Automatic Redirection
See merge request Ealhad/peertubeify!3
This commit is contained in:
commit
f827e9b848
|
@ -20,7 +20,8 @@ import * as browser from 'webextension-polyfill';
|
||||||
import { MessageKind, RedirectType } from './types';
|
import { MessageKind, RedirectType } from './types';
|
||||||
import constants from './constants';
|
import constants from './constants';
|
||||||
import Preferences from './preferences';
|
import Preferences from './preferences';
|
||||||
import InvidiousAPI from './invidious-api';
|
import * as InvidiousAPI from './invidious-api';
|
||||||
|
import * as PeertubeAPI from './peertube-api';
|
||||||
import { getPeertubeVideoURL } from './util';
|
import { getPeertubeVideoURL } from './util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,10 +33,10 @@ const getTitle = async (id: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent Youtube from loading if the video is found and preferences set on
|
* Redirect Youtube without loading it if the video is found and preferences lAHhDKzReKBQKj3R
|
||||||
* automatic redirection.
|
* set on automatic redirection.
|
||||||
*/
|
*/
|
||||||
const preventYoutube = 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) {
|
||||||
|
@ -53,13 +54,38 @@ const preventYoutube = async (r) => {
|
||||||
throw new Error('No results.');
|
throw new Error('No results.');
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildSearchByNameURL = (instance: string, query: string): string => `https://${instance}/api/v1/search/videos?search=${encodeURIComponent(query)}`;
|
/**
|
||||||
|
* Redirect to preferred PeerTube Instance when trying to watch a PeerTube
|
||||||
|
* video.
|
||||||
|
*/
|
||||||
|
const redirectPeertube = async (r) => {
|
||||||
|
const prefs = await Preferences.getPreferences();
|
||||||
|
const hostname = new URL(r.url).hostname;
|
||||||
|
|
||||||
|
if (prefs.openInOriginalInstance === false && prefs.searchInstance === hostname) {
|
||||||
|
return {}; // Don't redirect if good instance
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefs.redirectPeertube == RedirectType.Auto) {
|
||||||
|
const id = _.last(_.split('/', r.url));
|
||||||
|
const video: any = await PeertubeAPI.getVideo(id);
|
||||||
|
|
||||||
|
if (prefs.openInOriginalInstance && video.account.host === hostname) {
|
||||||
|
return {}; // Don't redirect if original instance
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = getPeertubeVideoURL(video, prefs);
|
||||||
|
|
||||||
|
return {
|
||||||
|
redirectUrl: url
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('No results.');
|
||||||
|
};
|
||||||
|
|
||||||
const searchByName = 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();
|
PeertubeAPI.searchVideo({ search: query })
|
||||||
|
|
||||||
fetch(buildSearchByNameURL(instance, query))
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
if (data.total > 0) {
|
if (data.total > 0) {
|
||||||
const video = data.data[0]
|
const video = data.data[0]
|
||||||
|
@ -71,29 +97,23 @@ const searchByName = 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) {
|
||||||
switch (message.kind) {
|
switch (message.kind) {
|
||||||
case MessageKind.SearchByName:
|
case MessageKind.SearchByName:
|
||||||
return searchByName(message.query);
|
return searchByName(message.query);
|
||||||
case MessageKind.SearchByID:
|
case MessageKind.SearchByID:
|
||||||
return searchByID(message.id);
|
return PeertubeAPI.getVideo(message.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
browser.webRequest.onBeforeRequest.addListener(
|
browser.webRequest.onBeforeRequest.addListener(
|
||||||
preventYoutube,
|
redirectYoutube,
|
||||||
{ urls: ['*://*.youtube.com/watch?v=*'] },
|
{ urls: ['*://*.youtube.com/watch?v=*'] },
|
||||||
['blocking']
|
['blocking']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
browser.webRequest.onBeforeRequest.addListener(
|
||||||
|
redirectPeertube,
|
||||||
|
{ urls: ['*://*/videos/watch/*'] },
|
||||||
|
['blocking']
|
||||||
|
);
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
export default {
|
export default {
|
||||||
|
peertubeAPI: {
|
||||||
defaultInstance: 'peertube.social',
|
defaultInstance: 'peertube.social',
|
||||||
|
endpoint: 'api/v1',
|
||||||
|
},
|
||||||
invidiousAPI: {
|
invidiousAPI: {
|
||||||
url: 'https://invidio.us/api/v1',
|
url: 'https://invidio.us/api/v1',
|
||||||
videos: 'videos',
|
videos: 'videos',
|
||||||
|
|
|
@ -1,8 +1,23 @@
|
||||||
|
/* 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 _ from 'lodash/fp';
|
||||||
import constants from './constants';
|
import constants from './constants';
|
||||||
|
|
||||||
export default class InvidiousAPI {
|
async function fetchAPI(action: string, params: any) {
|
||||||
private static async fetchAPI(action: string, params: any) {
|
|
||||||
const paramString = typeof params == 'string'
|
const paramString = typeof params == 'string'
|
||||||
? params
|
? params
|
||||||
: Object.keys(params).map(function(key) {
|
: Object.keys(params).map(function(key) {
|
||||||
|
@ -12,16 +27,16 @@ export default class InvidiousAPI {
|
||||||
return fetch(`${constants.invidiousAPI.url}/${action}/${paramString}`)
|
return fetch(`${constants.invidiousAPI.url}/${action}/${paramString}`)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.catch(e => console.error(
|
.catch(e => console.error(
|
||||||
'An error occured while trying to fetch API used by PeerTubeify: '
|
'An error occured while trying to fetch Invidious API used by PeerTubeify: '
|
||||||
+ e.message
|
+ e.message
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getVideo(id: string) {
|
|
||||||
return this.fetchAPI(constants.invidiousAPI.videos, id);
|
export async function getVideo(id: string) {
|
||||||
|
return fetchAPI(constants.invidiousAPI.videos, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getChannel(ucid: string) {
|
export async function getChannel(ucid: string) {
|
||||||
return this.fetchAPI(constants.invidiousAPI.channels, ucid);
|
return fetchAPI(constants.invidiousAPI.channels, ucid);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* 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 constants from './constants';
|
||||||
|
import Preferences from './preferences';
|
||||||
|
|
||||||
|
async function fetchAPI(path: string, query?: Object) {
|
||||||
|
const instance = (await Preferences.getPreferences()).searchInstance;
|
||||||
|
|
||||||
|
let url = `https://${instance}/${constants.peertubeAPI.endpoint}/${path}`;
|
||||||
|
|
||||||
|
if (query) {
|
||||||
|
url = url + '?' + Object.keys(query).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(query[key])).join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(url)
|
||||||
|
.then(res => res.json())
|
||||||
|
.catch(e => console.error(
|
||||||
|
`An error occured while trying to fetch ${instance} API used by PeerTubeify: `
|
||||||
|
+ e.message
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getVideo(id: string) {
|
||||||
|
return fetchAPI('videos/' + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function searchVideo(query: Object) {
|
||||||
|
return fetchAPI('search/videos', query);
|
||||||
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
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 { htmlToElement, getPeertubeVideoURL } from './util';
|
||||||
import { MessageKind, RedirectType } from './types';
|
import { MessageKind, RedirectType } from './types';
|
||||||
import Preferences from './preferences';
|
import Preferences from './preferences';
|
||||||
|
|
||||||
|
@ -46,20 +46,13 @@ async function peertubeify() {
|
||||||
switch (prefs.redirectPeertube) {
|
switch (prefs.redirectPeertube) {
|
||||||
case RedirectType.Show: {
|
case RedirectType.Show: {
|
||||||
searchVideo()
|
searchVideo()
|
||||||
.then(async ({ video, url }) => {
|
.then(async video => {
|
||||||
const link = videoLink(url, video);
|
const link = videoLink(getPeertubeVideoURL(video, prefs), video);
|
||||||
removeVideoLink();
|
removeVideoLink();
|
||||||
document.querySelector('body').appendChild(link);
|
document.querySelector('body').appendChild(link);
|
||||||
}).catch(removeVideoLink);
|
}).catch(removeVideoLink);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RedirectType.Auto: {
|
|
||||||
searchVideo()
|
|
||||||
.then(async ({ video, url }) => {
|
|
||||||
location.replace(url);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RedirectType.None: {
|
case RedirectType.None: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ export default class Preferences {
|
||||||
redirectPeertube: RedirectType;
|
redirectPeertube: RedirectType;
|
||||||
|
|
||||||
constructor(localStorage) {
|
constructor(localStorage) {
|
||||||
this.searchInstance = _.defaultTo(constants.defaultInstance, localStorage.searchInstance as string);
|
this.searchInstance = _.defaultTo(constants.peertubeAPI.defaultInstance, localStorage.searchInstance as string);
|
||||||
this.openInOriginalInstance = _.defaultTo(true, localStorage.openInOriginalInstance as boolean);
|
this.openInOriginalInstance = _.defaultTo(true, localStorage.openInOriginalInstance as boolean);
|
||||||
this.redirectYoutube = _.defaultTo(RedirectType.Show, localStorage.redirectYoutube)
|
this.redirectYoutube = _.defaultTo(RedirectType.Show, localStorage.redirectYoutube)
|
||||||
this.redirectPeertube = _.defaultTo(RedirectType.None, localStorage.redirectPeertube)
|
this.redirectPeertube = _.defaultTo(RedirectType.None, localStorage.redirectPeertube)
|
||||||
|
@ -54,6 +54,6 @@ export default class Preferences {
|
||||||
}
|
}
|
||||||
|
|
||||||
set searchInstance(instance) {
|
set searchInstance(instance) {
|
||||||
this._searchInstance = _.isEmpty(instance) ? constants.defaultInstance : stripProtocol(instance)
|
this._searchInstance = _.isEmpty(instance) ? constants.peertubeAPI.defaultInstance : stripProtocol(instance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue