Merge pull request #132 from DeepDoge/master

Opening new tabs handled by the background now
This commit is contained in:
kodxana 2022-08-09 18:58:29 +02:00 committed by GitHub
commit 64570b83bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 126 additions and 99 deletions

View file

@ -18,6 +18,7 @@
"https://odysee.com/", "https://odysee.com/",
"https://madiator.com/", "https://madiator.com/",
"https://finder.madiator.com/", "https://finder.madiator.com/",
"tabs",
"storage" "storage"
], ],
"web_accessible_resources": [ "web_accessible_resources": [

View file

@ -8,7 +8,8 @@
"128": "assets/icons/wol/icon128.png" "128": "assets/icons/wol/icon128.png"
}, },
"permissions": [ "permissions": [
"storage" "storage",
"tabs"
], ],
"host_permissions": [ "host_permissions": [
"https://www.youtube.com/", "https://www.youtube.com/",

View file

@ -2,23 +2,34 @@ import { resolveById } from "../modules/yt/urlResolve"
const onGoingLbryPathnameRequest: Record<string, ReturnType<typeof resolveById>> = {} const onGoingLbryPathnameRequest: Record<string, ReturnType<typeof resolveById>> = {}
chrome.runtime.onMessage.addListener(({ json }, sender, sendResponse) => { chrome.runtime.onMessage.addListener(({ method, data }, sender, sendResponse) => {
function resolve(result: Awaited<ReturnType<typeof resolveById>>) { function resolve(result: Awaited<ReturnType<typeof resolveById>>) {
sendResponse(JSON.stringify(result)) sendResponse(JSON.stringify(result))
} }
(async () => { (async () => {
try {
const params: Parameters<typeof resolveById> = JSON.parse(json) switch (method) {
// Don't create a new Promise for same ID until on going one is over. case 'openTab':
const promise = onGoingLbryPathnameRequest[json] ?? (onGoingLbryPathnameRequest[json] = resolveById(...params)) {
console.log('lbrypathname request', params, await promise) const { href, active }: { href: string, active: boolean } = JSON.parse(data)
resolve(await promise) chrome.tabs.create({ url: href, active })
} catch (error) { }
sendResponse('error') break
console.error(error) case 'resolveUrl':
} try {
finally { const params: Parameters<typeof resolveById> = JSON.parse(data)
delete onGoingLbryPathnameRequest[json] // Don't create a new Promise for same ID until on going one is over.
const promise = onGoingLbryPathnameRequest[data] ?? (onGoingLbryPathnameRequest[data] = resolveById(...params))
console.log('lbrypathname request', params, await promise)
resolve(await promise)
} catch (error) {
sendResponse(`error:${(error as any).toString()}`)
console.error(error)
}
finally {
delete onGoingLbryPathnameRequest[data]
}
break
} }
})() })()

View file

@ -26,6 +26,7 @@ import { getExtensionSettingsAsync, getSourcePlatfromSettingsFromHostname, getTa
chrome.storage.onChanged.addListener(async (changes, areaName) => { chrome.storage.onChanged.addListener(async (changes, areaName) => {
if (areaName !== 'local') return if (areaName !== 'local') return
Object.assign(settings, Object.fromEntries(Object.entries(changes).map(([key, change]) => [key, change.newValue]))) Object.assign(settings, Object.fromEntries(Object.entries(changes).map(([key, change]) => [key, change.newValue])))
if (settings.redirect) updateButton(null)
}) })
const buttonMountPoint = document.createElement('div') const buttonMountPoint = document.createElement('div')
@ -222,12 +223,17 @@ import { getExtensionSettingsAsync, getSourcePlatfromSettingsFromHostname, getTa
} }
// We should get this from background, so the caching works and we don't get errors in the future if yt decides to impliment CORS // We should get this from background, so the caching works and we don't get errors in the future if yt decides to impliment CORS
async function requestResolveById(...params: Parameters<typeof resolveById>): ReturnType<typeof resolveById> { async function requestResolveById(...params: Parameters<typeof resolveById>): ReturnType<typeof resolveById> {
const json = await new Promise<string | null | 'error'>((resolve) => chrome.runtime.sendMessage({ json: JSON.stringify(params) }, resolve)) const response = await new Promise<string | null | 'error'>((resolve) => chrome.runtime.sendMessage({ method: 'resolveUrl', data: JSON.stringify(params) }, resolve))
if (json === 'error') { if (response?.startsWith('error:')) {
console.error("Background error on:", params) console.error("Background error on:", params)
throw new Error("Background error.") throw new Error(`Background error.${response ?? ''}`)
} }
return json ? JSON.parse(json) : null return response ? JSON.parse(response) : null
}
// Request new tab
async function openNewTab(url: URL, active: boolean) {
chrome.runtime.sendMessage({ method: 'openTab', data: JSON.stringify({ href: url.href, active }) })
} }
function getLbryUrlByTarget(target: Target) { function getLbryUrlByTarget(target: Target) {
@ -237,98 +243,106 @@ import { getExtensionSettingsAsync, getSourcePlatfromSettingsFromHostname, getTa
return url return url
} }
let urlCache: URL | null = null let urlHrefCache: string | null = null
while (true) { while (true) {
await sleep(500) await sleep(500)
const url: URL = new URL(location.href);
const url: URL = (urlCache?.href === location.href) ? urlCache : new URL(location.href)
const source = await getSourceByUrl(new URL(location.href)) await (async () => {
if (!source) continue const source = await getSourceByUrl(new URL(location.href))
if (!source) return
try {
if (settings.redirect) { try {
const target = (await getTargetsBySources(source))[source.id] if (settings.redirect) {
if (!target) continue const target = (await getTargetsBySources(source))[source.id]
if (url === urlCache) continue if (!target) return
console.log(url.href, urlHrefCache)
const lbryURL = getLbryUrlByTarget(target) if (url.href === urlHrefCache) return
// As soon as video play is ready and start playing, pause it. const lbryURL = getLbryUrlByTarget(target)
findVideoElementAwait(source).then((videoElement) => {
videoElement.addEventListener('play', () => videoElement.pause(), { once: true }) if (source.type === 'video') {
videoElement.pause() // As soon as video play is ready and start playing, pause it.
}) findVideoElementAwait(source).then((videoElement) => {
videoElement.addEventListener('play', () => videoElement.pause(), { once: true })
if (target.platform === targetPlatformSettings.app) { videoElement.pause()
if (document.hidden) await new Promise((resolve) => document.addEventListener('visibilitychange', resolve, { once: true })) })
// Replace is being used so browser doesnt start an empty window }
// Its not gonna be able to replace anyway, since its a LBRY Uri
location.replace(lbryURL) if (target.platform === targetPlatformSettings.app) {
if (document.hidden) await new Promise((resolve) => document.addEventListener('visibilitychange', resolve, { once: true }))
// Replace is being used so browser doesnt start an empty window
// Its not gonna be able to replace anyway, since its a LBRY Uri
location.replace(lbryURL)
}
else {
console.log('open', lbryURL.href)
openNewTab(lbryURL, document.hasFocus())
if (window.history.length === 1) window.close()
else window.history.back()
}
} }
else { else {
open(lbryURL, '_blank') if (urlHrefCache !== url.href) updateButton(null)
if (window.history.length === 1) window.close() let target = (await getTargetsBySources(source))[source.id]
else window.history.back()
} // There is no target found via API try to check Video Description for LBRY links.
} if (!target) {
else { const linksContainer =
if (urlCache !== url) updateButton(null) source.type === 'video' ?
let target = (await getTargetsBySources(source))[source.id] document.querySelector(source.platform.htmlQueries.videoDescription) :
source.platform.htmlQueries.channelLinks ? document.querySelector(source.platform.htmlQueries.channelLinks) : null
// There is no target found via API try to check Video Description for LBRY links.
if (!target) { if (linksContainer) {
const linksContainer = const anchors = Array.from(linksContainer.querySelectorAll<HTMLAnchorElement>('a'))
source.type === 'video' ?
document.querySelector(source.platform.htmlQueries.videoDescription) : for (const anchor of anchors) {
source.platform.htmlQueries.channelLinks ? document.querySelector(source.platform.htmlQueries.channelLinks) : null if (!anchor.href) continue
const url = new URL(anchor.href)
if (linksContainer) { let lbryURL: URL | null = null
const anchors = Array.from(linksContainer.querySelectorAll<HTMLAnchorElement>('a'))
// Extract real link from youtube's redirect link
for (const anchor of anchors) { if (source.platform === sourcePlatfromSettings['youtube.com']) {
if (!anchor.href) continue if (!targetPlatforms.some(([key, platform]) => url.searchParams.get('q')?.startsWith(platform.domainPrefix))) continue
const url = new URL(anchor.href) lbryURL = new URL(url.searchParams.get('q')!)
let lbryURL: URL | null = null }
// Just directly use the link itself on other platforms
// Extract real link from youtube's redirect link else {
if (source.platform === sourcePlatfromSettings['youtube.com']) { if (!targetPlatforms.some(([key, platform]) => url.href.startsWith(platform.domainPrefix))) continue
if (!targetPlatforms.some(([key, platform]) => url.searchParams.get('q')?.startsWith(platform.domainPrefix))) continue lbryURL = new URL(url.href)
lbryURL = new URL(url.searchParams.get('q')!) }
}
// Just directly use the link itself on other platforms if (lbryURL) {
else { target = {
if (!targetPlatforms.some(([key, platform]) => url.href.startsWith(platform.domainPrefix))) continue lbryPathname: lbryURL.pathname.substring(1),
lbryURL = new URL(url.href) time: null,
} type: lbryURL.pathname.substring(1).includes('/') ? 'video' : 'channel',
platform: targetPlatformSettings[settings.targetPlatform]
if (lbryURL) { }
target = { break
lbryPathname: lbryURL.pathname.substring(1),
time: null,
type: lbryURL.pathname.substring(1).includes('/') ? 'video' : 'channel',
platform: targetPlatformSettings[settings.targetPlatform]
} }
break
} }
} }
} }
}
if (!target) updateButton(null)
if (!target) updateButton(null) else {
else { // If target is a video target add timestampt to it
// If target is a video target add timestampt to it if (target.type === 'video') {
if (target.type === 'video') { const videoElement = document.querySelector<HTMLVideoElement>(source.platform.htmlQueries.videoPlayer)
const videoElement = document.querySelector<HTMLVideoElement>(source.platform.htmlQueries.videoPlayer) if (videoElement) target.time = videoElement.currentTime > 3 && videoElement.currentTime < videoElement.duration - 1 ? videoElement.currentTime : null
if (videoElement) target.time = videoElement.currentTime > 3 && videoElement.currentTime < videoElement.duration - 1 ? videoElement.currentTime : null }
updateButton({ target, source })
} }
updateButton({ target, source })
} }
} catch (error) {
console.error(error)
} }
} catch (error) { })()
console.error(error)
} urlHrefCache = url.href
urlCache = url
} }
})() })()