From bf87557b843eae884eb9fd906748ea77a035d6d5 Mon Sep 17 00:00:00 2001 From: Booteille Date: Mon, 12 Nov 2018 20:15:06 +0100 Subject: [PATCH 1/8] Rename method preventYoutube to redirectYoutube --- src/background.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/background.ts b/src/background.ts index 2fc52e0..62fe611 100644 --- a/src/background.ts +++ b/src/background.ts @@ -32,10 +32,10 @@ const getTitle = async (id: string) => { } /** - * Prevent Youtube from loading if the video is found and preferences set on - * automatic redirection. + * Redirect Youtube without loading it if the video is found and preferences lAHhDKzReKBQKj3R + * set on automatic redirection. */ -const preventYoutube = async (r) => { +const redirectYoutube = async (r) => { const prefs = await Preferences.getPreferences(); if (prefs.redirectYoutube == RedirectType.Auto) { @@ -93,7 +93,7 @@ browser.runtime.onMessage.addListener(function(message, sender) { }); browser.webRequest.onBeforeRequest.addListener( - preventYoutube, + redirectYoutube, { urls: ['*://*.youtube.com/watch?v=*'] }, ['blocking'] ); From 5c35ce031d5b6c7754e5661f374d6c1b552a1f5f Mon Sep 17 00:00:00 2001 From: Booteille Date: Mon, 12 Nov 2018 21:34:43 +0100 Subject: [PATCH 2/8] Refactor PeertubeAPI usage --- src/background.ts | 17 +++++------------ src/constants.ts | 5 ++++- src/invidious-api.ts | 2 +- src/peertube-api.ts | 29 +++++++++++++++++++++++++++++ src/preferences.ts | 4 ++-- 5 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 src/peertube-api.ts diff --git a/src/background.ts b/src/background.ts index 62fe611..04e07c8 100644 --- a/src/background.ts +++ b/src/background.ts @@ -21,6 +21,7 @@ import { MessageKind, RedirectType } from './types'; import constants from './constants'; import Preferences from './preferences'; import InvidiousAPI from './invidious-api'; +import PeertubeAPI from './peertube-api'; import { getPeertubeVideoURL } from './util'; /** @@ -53,13 +54,8 @@ const redirectYoutube = async (r) => { throw new Error('No results.'); }; -const buildSearchByNameURL = (instance: string, query: string): string => `https://${instance}/api/v1/search/videos?search=${encodeURIComponent(query)}`; - const searchByName = query => new Promise(async (resolve, reject) => { - const instance = _.getOr(constants.defaultInstance, 'searchInstance', await browser.storage.local.get()).toString(); - - fetch(buildSearchByNameURL(instance, query)) - .then(res => res.json()) + PeertubeAPI.searchVideo({ search: query }) .then(function(data) { if (data.total > 0) { const video = data.data[0] @@ -71,15 +67,12 @@ 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(); + const prefs = await Preferences.getPreferences(); - fetch(buildSearchByIDURL(instance, id)) - .then(res => res.json()) + PeertubeAPI.getVideo(id) .then(function(video) { - resolve({ url: `https://${instance}/videos/watch/${id}`, video }); + resolve({ url: getPeertubeVideoURL(video, prefs), video }); }) }) diff --git a/src/constants.ts b/src/constants.ts index 7614a01..ab040e2 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,5 +1,8 @@ export default { - defaultInstance: 'peertube.social', + peertubeAPI: { + defaultInstance: 'peertube.social', + endpoint: 'api/v1', + }, invidiousAPI: { url: 'https://invidio.us/api/v1', videos: 'videos', diff --git a/src/invidious-api.ts b/src/invidious-api.ts index d44863f..77637d3 100644 --- a/src/invidious-api.ts +++ b/src/invidious-api.ts @@ -12,7 +12,7 @@ export default class InvidiousAPI { return fetch(`${constants.invidiousAPI.url}/${action}/${paramString}`) .then(res => res.json()) .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 )); } diff --git a/src/peertube-api.ts b/src/peertube-api.ts new file mode 100644 index 0000000..412abcd --- /dev/null +++ b/src/peertube-api.ts @@ -0,0 +1,29 @@ +import * as _ from 'lodash/fp'; +import constants from './constants'; + +export default class PeertubeAPI { + private static async fetchAPI(path: string, query?: Object) { + const instance = _.getOr(constants.peertubeAPI.defaultInstance, 'searchInstance', await browser.storage.local.get()).toString(); + + let url = `https://${constants.peertubeAPI.defaultInstance}/${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 + )); + } + + static async getVideo(id: string) { + return this.fetchAPI('videos/' + id); + } + + static async searchVideo(query: Object) { + return this.fetchAPI('search/videos', query); + } +} diff --git a/src/preferences.ts b/src/preferences.ts index fd41297..ada960a 100644 --- a/src/preferences.ts +++ b/src/preferences.ts @@ -28,7 +28,7 @@ export default class Preferences { redirectPeertube: RedirectType; 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.redirectYoutube = _.defaultTo(RedirectType.Show, localStorage.redirectYoutube) this.redirectPeertube = _.defaultTo(RedirectType.None, localStorage.redirectPeertube) @@ -54,6 +54,6 @@ export default class Preferences { } set searchInstance(instance) { - this._searchInstance = _.isEmpty(instance) ? constants.defaultInstance : stripProtocol(instance) + this._searchInstance = _.isEmpty(instance) ? constants.peertubeAPI.defaultInstance : stripProtocol(instance) } } From 2614a3fc11a30ccaa0bf433e38234f6668544632 Mon Sep 17 00:00:00 2001 From: Booteille Date: Mon, 12 Nov 2018 23:05:06 +0100 Subject: [PATCH 3/8] Refactor Automatic Peertube redirection to redirect before loading the page --- src/background.ts | 47 +++++++++++++++++++++++++++++++++++++++------ src/peertube-api.ts | 2 +- src/peertube.ts | 13 +++---------- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/background.ts b/src/background.ts index 04e07c8..c8f5bbd 100644 --- a/src/background.ts +++ b/src/background.ts @@ -54,6 +54,39 @@ const redirectYoutube = async (r) => { throw new Error('No results.'); }; +/** + * 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 = await searchByID(id); + const getHost = video => new Promise(async (resolve, reject) => { + resolve(video.account.host); + }); + + if (prefs.openInOriginalInstance && await getHost(video) === 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) => { PeertubeAPI.searchVideo({ search: query }) .then(function(data) { @@ -68,13 +101,9 @@ const searchByName = query => new Promise(async (resolve, reject) => { }); const searchByID = id => new Promise(async (resolve, reject) => { - const prefs = await Preferences.getPreferences(); - PeertubeAPI.getVideo(id) - .then(function(video) { - resolve({ url: getPeertubeVideoURL(video, prefs), video }); - }) -}) + .then(video => resolve(video)); +}); browser.runtime.onMessage.addListener(function(message, sender) { switch (message.kind) { @@ -90,3 +119,9 @@ browser.webRequest.onBeforeRequest.addListener( { urls: ['*://*.youtube.com/watch?v=*'] }, ['blocking'] ); + +browser.webRequest.onBeforeRequest.addListener( + redirectPeertube, + { urls: ['*://*/videos/watch/*'] }, + ['blocking'] +); diff --git a/src/peertube-api.ts b/src/peertube-api.ts index 412abcd..2666e60 100644 --- a/src/peertube-api.ts +++ b/src/peertube-api.ts @@ -5,7 +5,7 @@ export default class PeertubeAPI { private static async fetchAPI(path: string, query?: Object) { const instance = _.getOr(constants.peertubeAPI.defaultInstance, 'searchInstance', await browser.storage.local.get()).toString(); - let url = `https://${constants.peertubeAPI.defaultInstance}/${constants.peertubeAPI.endpoint}/${path}`; + let url = `https://${instance}/${constants.peertubeAPI.endpoint}/${path}`; if (query) { url = url + '?' + Object.keys(query).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(query[key])).join('&'); diff --git a/src/peertube.ts b/src/peertube.ts index f275fcc..76db0d9 100644 --- a/src/peertube.ts +++ b/src/peertube.ts @@ -17,7 +17,7 @@ import * as _ from 'lodash/fp'; import * as browser from 'webextension-polyfill'; -import { htmlToElement } from './util'; +import { htmlToElement, getPeertubeVideoURL } from './util'; import { MessageKind, RedirectType } from './types'; import Preferences from './preferences'; @@ -46,20 +46,13 @@ async function peertubeify() { switch (prefs.redirectPeertube) { case RedirectType.Show: { searchVideo() - .then(async ({ video, url }) => { - const link = videoLink(url, video); + .then(async video => { + const link = videoLink(getPeertubeVideoURL(video, prefs), video); removeVideoLink(); document.querySelector('body').appendChild(link); }).catch(removeVideoLink); break; } - case RedirectType.Auto: { - searchVideo() - .then(async ({ video, url }) => { - location.replace(url); - }); - break; - } case RedirectType.None: { break; } From 2385b5f5c869308ee7cf1f64eca3f9a4fb1e9d33 Mon Sep 17 00:00:00 2001 From: Booteille Date: Tue, 13 Nov 2018 23:49:40 +0100 Subject: [PATCH 4/8] Use type casting instead of Promise --- src/background.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/background.ts b/src/background.ts index c8f5bbd..76b5b10 100644 --- a/src/background.ts +++ b/src/background.ts @@ -68,12 +68,9 @@ const redirectPeertube = async (r) => { if (prefs.redirectPeertube == RedirectType.Auto) { const id = _.last(_.split('/', r.url)); - const video = await searchByID(id); - const getHost = video => new Promise(async (resolve, reject) => { - resolve(video.account.host); - }); + const video: any = await searchByID(id); - if (prefs.openInOriginalInstance && await getHost(video) === hostname) { + if (prefs.openInOriginalInstance && video.account.host === hostname) { return {}; // Don't redirect if original instance } From 3c4317504eb04fd5151ab138cceda58234e417f4 Mon Sep 17 00:00:00 2001 From: Ealhad Date: Wed, 14 Nov 2018 23:54:16 +0100 Subject: [PATCH 5/8] Export functions instead of using class with only static members MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Theres's no need to use a class all members are static and we never instantiate it — it's not Java :D --- src/background.ts | 4 ++-- src/invidious-api.ts | 43 +++++++++++++++++++++---------------------- src/peertube-api.ts | 40 +++++++++++++++++++--------------------- 3 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/background.ts b/src/background.ts index 76b5b10..2b8d99e 100644 --- a/src/background.ts +++ b/src/background.ts @@ -20,8 +20,8 @@ import * as browser from 'webextension-polyfill'; import { MessageKind, RedirectType } from './types'; import constants from './constants'; import Preferences from './preferences'; -import InvidiousAPI from './invidious-api'; -import PeertubeAPI from './peertube-api'; +import * as InvidiousAPI from './invidious-api'; +import * as PeertubeAPI from './peertube-api'; import { getPeertubeVideoURL } from './util'; /** diff --git a/src/invidious-api.ts b/src/invidious-api.ts index 77637d3..266be82 100644 --- a/src/invidious-api.ts +++ b/src/invidious-api.ts @@ -1,27 +1,26 @@ import * as _ from 'lodash/fp'; import constants from './constants'; -export default class InvidiousAPI { - private static async fetchAPI(action: string, params: any) { - const paramString = typeof params == 'string' - ? params - : Object.keys(params).map(function(key) { - return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]); - }).join('&'); +async function fetchAPI(action: string, params: any) { + const paramString = typeof params == 'string' + ? params + : Object.keys(params).map(function(key) { + return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]); + }).join('&'); - return fetch(`${constants.invidiousAPI.url}/${action}/${paramString}`) - .then(res => res.json()) - .catch(e => console.error( - 'An error occured while trying to fetch Invidious API used by PeerTubeify: ' - + e.message - )); - } - - static async getVideo(id: string) { - return this.fetchAPI(constants.invidiousAPI.videos, id); - } - - static async getChannel(ucid: string) { - return this.fetchAPI(constants.invidiousAPI.channels, ucid); - } + return fetch(`${constants.invidiousAPI.url}/${action}/${paramString}`) + .then(res => res.json()) + .catch(e => console.error( + 'An error occured while trying to fetch Invidious API used by PeerTubeify: ' + + e.message + )); +} + + +export async function getVideo(id: string) { + return fetchAPI(constants.invidiousAPI.videos, id); +} + +export async function getChannel(ucid: string) { + return fetchAPI(constants.invidiousAPI.channels, ucid); } diff --git a/src/peertube-api.ts b/src/peertube-api.ts index 2666e60..5e3f457 100644 --- a/src/peertube-api.ts +++ b/src/peertube-api.ts @@ -1,29 +1,27 @@ import * as _ from 'lodash/fp'; import constants from './constants'; -export default class PeertubeAPI { - private static async fetchAPI(path: string, query?: Object) { - const instance = _.getOr(constants.peertubeAPI.defaultInstance, 'searchInstance', await browser.storage.local.get()).toString(); +async function fetchAPI(path: string, query?: Object) { + const instance = _.getOr(constants.peertubeAPI.defaultInstance, 'searchInstance', await browser.storage.local.get()).toString(); - let url = `https://${instance}/${constants.peertubeAPI.endpoint}/${path}`; + 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 - )); + if (query) { + url = url + '?' + Object.keys(query).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(query[key])).join('&'); } - static async getVideo(id: string) { - return this.fetchAPI('videos/' + id); - } - - static async searchVideo(query: Object) { - return this.fetchAPI('search/videos', query); - } + 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); } From 66893b5015d3ce31e19d5f16f7aeec3592ef24b5 Mon Sep 17 00:00:00 2001 From: Ealhad Date: Thu, 15 Nov 2018 00:29:55 +0100 Subject: [PATCH 6/8] Remove superfluous function --- src/background.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/background.ts b/src/background.ts index 2b8d99e..fd414b2 100644 --- a/src/background.ts +++ b/src/background.ts @@ -68,7 +68,7 @@ const redirectPeertube = async (r) => { if (prefs.redirectPeertube == RedirectType.Auto) { const id = _.last(_.split('/', r.url)); - const video: any = await searchByID(id); + const video: any = await PeertubeAPI.getVideo(id); if (prefs.openInOriginalInstance && video.account.host === hostname) { return {}; // Don't redirect if original instance @@ -97,17 +97,12 @@ const searchByName = query => new Promise(async (resolve, reject) => { }); }); -const searchByID = id => new Promise(async (resolve, reject) => { - PeertubeAPI.getVideo(id) - .then(video => resolve(video)); -}); - browser.runtime.onMessage.addListener(function(message, sender) { switch (message.kind) { case MessageKind.SearchByName: return searchByName(message.query); case MessageKind.SearchByID: - return searchByID(message.id); + return PeertubeAPI.getVideo(message.id); } }); From 8049d4671e27731a64af10f668e8882379442327 Mon Sep 17 00:00:00 2001 From: Ealhad Date: Thu, 15 Nov 2018 00:32:56 +0100 Subject: [PATCH 7/8] Add license header to new files --- src/invidious-api.ts | 16 ++++++++++++++++ src/peertube-api.ts | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/invidious-api.ts b/src/invidious-api.ts index 266be82..69f7154 100644 --- a/src/invidious-api.ts +++ b/src/invidious-api.ts @@ -1,3 +1,19 @@ +/* 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 . + */ + import * as _ from 'lodash/fp'; import constants from './constants'; diff --git a/src/peertube-api.ts b/src/peertube-api.ts index 5e3f457..5515759 100644 --- a/src/peertube-api.ts +++ b/src/peertube-api.ts @@ -1,3 +1,19 @@ +/* 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 . + */ + import * as _ from 'lodash/fp'; import constants from './constants'; From 25b6e7949a9f1e2d2b502c51da4340ad82ca88ac Mon Sep 17 00:00:00 2001 From: Ealhad Date: Thu, 15 Nov 2018 00:38:41 +0100 Subject: [PATCH 8/8] Use Preferences abstraction instead of manual localStorage interaction Default values and localStorage manipulation should be implemented in the Prefereces class. --- src/peertube-api.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/peertube-api.ts b/src/peertube-api.ts index 5515759..2f353a4 100644 --- a/src/peertube-api.ts +++ b/src/peertube-api.ts @@ -16,9 +16,10 @@ import * as _ from 'lodash/fp'; import constants from './constants'; +import Preferences from './preferences'; async function fetchAPI(path: string, query?: Object) { - const instance = _.getOr(constants.peertubeAPI.defaultInstance, 'searchInstance', await browser.storage.local.get()).toString(); + const instance = (await Preferences.getPreferences()).searchInstance; let url = `https://${instance}/${constants.peertubeAPI.endpoint}/${path}`;