mirror of
https://github.com/LBRYFoundation/Watch-on-LBRY.git
synced 2025-08-23 17:47:26 +00:00
🔥 Modified for Watch on Odysee
This commit is contained in:
parent
f072c95051
commit
3a44267fdf
10 changed files with 50 additions and 250 deletions
23
.github/workflows/contributors.yml
vendored
23
.github/workflows/contributors.yml
vendored
|
@ -1,23 +0,0 @@
|
|||
name: Add contributors
|
||||
on:
|
||||
schedule:
|
||||
- cron: '20 20 * * *'
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
add-contributors:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: BobAnkh/add-contributors@master
|
||||
with:
|
||||
CONTRIBUTOR: '## Contributors'
|
||||
COLUMN_PER_ROW: '6'
|
||||
ACCESS_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
IMG_WIDTH: '100'
|
||||
FONT_SIZE: '14'
|
||||
PATH: '/README.md'
|
||||
COMMIT_MESSAGE: 'docs(README): update contributors'
|
||||
AVATAR_SHAPE: 'round'
|
Binary file not shown.
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 22 KiB |
Binary file not shown.
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 4 KiB |
|
@ -1,6 +1,6 @@
|
|||
:root {
|
||||
--color-master: #499375;
|
||||
--color-slave: #43889d;
|
||||
--color-master: #cf3352;
|
||||
--color-slave: #f77937;
|
||||
--color-error: rgb(245, 81, 69);
|
||||
--color-gradient-0: linear-gradient(130deg, var(--color-master), var(--color-slave));
|
||||
--color-gradient-1: linear-gradient(130deg, #ff7a18, #af002d 41.07%, #319197 76.05%);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { chunk } from "lodash"
|
||||
import path from "path"
|
||||
import { getExtensionSettingsAsync, ytUrlResolversSettings } from "../../settings"
|
||||
import { sign } from "../crypto"
|
||||
import { lbryUrlCache } from "./urlCache"
|
||||
|
||||
const QUERY_CHUNK_SIZE = 100
|
||||
|
@ -18,7 +17,7 @@ interface ApiResponse {
|
|||
}
|
||||
|
||||
export async function resolveById(params: Paramaters, progressCallback?: (progress: number) => void): Promise<Results> {
|
||||
const { urlResolver: urlResolverSettingName, privateKey, publicKey } = await getExtensionSettingsAsync()
|
||||
const { urlResolver: urlResolverSettingName } = await getExtensionSettingsAsync()
|
||||
const urlResolverSetting = ytUrlResolversSettings[urlResolverSettingName]
|
||||
|
||||
async function requestChunk(params: Paramaters) {
|
||||
|
@ -46,11 +45,6 @@ export async function resolveById(params: Paramaters, progressCallback?: (progre
|
|||
url.pathname = path.join(url.pathname, '/resolve')
|
||||
url.searchParams.set('video_ids', params.filter((item) => item.type === 'video').map((item) => item.id).join(','))
|
||||
url.searchParams.set('channel_ids', params.filter((item) => item.type === 'channel').map((item) => item.id).join(','))
|
||||
if (urlResolverSetting.signRequest && publicKey && privateKey)
|
||||
url.searchParams.set('keys', JSON.stringify({
|
||||
signature: await sign(url.searchParams.toString(), privateKey),
|
||||
publicKey
|
||||
}))
|
||||
|
||||
const apiResponse = await fetch(url.toString(), { cache: 'no-store' })
|
||||
if (apiResponse.ok) {
|
||||
|
|
|
@ -1,23 +1,14 @@
|
|||
import { h, render } from 'preact'
|
||||
import { useState } from 'preact/hooks'
|
||||
import { createDialogManager, Dialogs } from '../../components/dialogs'
|
||||
import { exportProfileKeysAsFile, friendlyPublicKey, generateProfileAndSetNickname, getProfile, purgeProfile, resetProfileSettings } from '../../modules/crypto'
|
||||
import { lbryUrlCache } from '../../modules/yt/urlCache'
|
||||
import { getTargetPlatfromSettingsEntiries, getYtUrlResolversSettingsEntiries, setExtensionSetting, useExtensionSettings } from '../../settings'
|
||||
import { openImportPopup } from '../import/main'
|
||||
import { setExtensionSetting, targetPlatformSettings, useExtensionSettings } from '../../settings'
|
||||
|
||||
|
||||
/** Gets all the options for redirect destinations as selection options */
|
||||
const targetPlatforms = getTargetPlatfromSettingsEntiries()
|
||||
const ytUrlResolverOptions = getYtUrlResolversSettingsEntiries()
|
||||
|
||||
function WatchOnLbryPopup(params: { profile: Awaited<ReturnType<typeof getProfile>> | null }) {
|
||||
const { redirect, targetPlatform, urlResolver, privateKey, publicKey } = useExtensionSettings()
|
||||
function WatchOnLbryPopup(params: {}) {
|
||||
const { redirect } = useExtensionSettings()
|
||||
let [loading, updateLoading] = useState(() => false)
|
||||
let [route, updateRoute] = useState<string | null>(() => null)
|
||||
|
||||
const dialogManager = createDialogManager()
|
||||
const nickname = params.profile ? params.profile.nickname ?? 'No Nickname' : '...'
|
||||
|
||||
|
||||
async function loads<T>(operation: Promise<T>) {
|
||||
|
@ -35,151 +26,38 @@ function WatchOnLbryPopup(params: { profile: Awaited<ReturnType<typeof getProfil
|
|||
return <div id='popup'>
|
||||
<Dialogs manager={dialogManager} />
|
||||
{
|
||||
publicKey
|
||||
? <header>
|
||||
<section>
|
||||
<label>{nickname}</label>
|
||||
<p>{friendlyPublicKey(publicKey)}</p>
|
||||
<span><b>Score: {params.profile?.score ?? '...'}</b> - <a target='_blank' href="https://finder.madiator.com/leaderboard" class="filled">🔗Leaderboard</a></span>
|
||||
{urlResolver !== 'madiatorFinder' && <span class="error">You need to use Madiator Finder API for scoring to work</span>}
|
||||
</section>
|
||||
<section>
|
||||
{
|
||||
route === 'profile'
|
||||
? <a onClick={() => updateRoute('')} className="filled">⇐ Back</a>
|
||||
: <a className='filled' onClick={() => updateRoute('profile')} href="#profile">Profile Settings</a>
|
||||
}
|
||||
</section>
|
||||
</header>
|
||||
: <header>
|
||||
{
|
||||
route === 'profile'
|
||||
? <a onClick={() => updateRoute('')} className="filled">⇐ Back</a>
|
||||
: <a className='filled' onClick={() => updateRoute('profile')} href="#profile">Profile Settings</a>
|
||||
}
|
||||
</header>
|
||||
<header>
|
||||
<section>
|
||||
<img id="logo" src={targetPlatformSettings.odysee.button.icon}></img>
|
||||
<label>Watch on Odysee</label>
|
||||
</section>
|
||||
</header>
|
||||
}
|
||||
{
|
||||
route === 'profile' ?
|
||||
publicKey ?
|
||||
<main>
|
||||
<section>
|
||||
<div className='options'>
|
||||
<a onClick={() => loads(generateProfileAndSetNickname(dialogManager)).then(() => renderPopup())} className={`button active`}>
|
||||
Change Nickname
|
||||
</a>
|
||||
<a onClick={async () => {
|
||||
if (!await dialogManager.confirm("This will delete your keypair from this device."
|
||||
+ "\nStill wanna continue?"
|
||||
+ "\n\nNOTE: Without keypair you can't purge your data online."
|
||||
+ "\nSo if you wish to purge, please use purging instead.")) return
|
||||
resetProfileSettings()
|
||||
renderPopup()
|
||||
}}
|
||||
className={`button`}
|
||||
>
|
||||
Forget/Logout
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<label>Backup your account</label>
|
||||
<p>Import and export your unique keypair.</p>
|
||||
<div className='options'>
|
||||
<a onClick={() => exportProfileKeysAsFile()} className={`button active`}>
|
||||
Export
|
||||
</a>
|
||||
<a onClick={() => openImportPopup()}
|
||||
className={`button`}
|
||||
>
|
||||
Import
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<label>Purge your profile and data!</label>
|
||||
<p>Purge your profile data online and offline.</p>
|
||||
<div className='options'>
|
||||
<div className="purge-aaaaaaa">
|
||||
<span className='filled'>(╯°□°)╯︵ ┻━┻</span>
|
||||
</div>
|
||||
<a onClick={() => loads(purgeProfile(dialogManager)).then(() => renderPopup())} className={`button`}>
|
||||
Purge Everything!!
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<label>Generate new profile</label>
|
||||
<p>Generate a new keypair.</p>
|
||||
<div className='options'>
|
||||
<a onClick={async () => await dialogManager.confirm("This will overwrite your old keypair.\nStill wanna continue?\n\nNOTE: Without keypair you can't purge your data online.\nSo if you wish to purge, please use purging instead.")
|
||||
&& loads(generateProfileAndSetNickname(dialogManager, true)).then(() => renderPopup())
|
||||
}
|
||||
className={`button`}
|
||||
>
|
||||
Generate New Account
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
:
|
||||
<main>
|
||||
<section>
|
||||
<label>You don't have a profile.</label>
|
||||
<p>You can either import keypair for an existing profile or generate a new profile keypair.</p>
|
||||
<div className='options'>
|
||||
<a onClick={() => openImportPopup()} className={`button`}>
|
||||
Import
|
||||
</a>
|
||||
<a onClick={() => loads(generateProfileAndSetNickname(dialogManager)).then(() => renderPopup())} className={`button active`}>
|
||||
Generate
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
:
|
||||
<main>
|
||||
<section>
|
||||
<label>Pick a mode:</label>
|
||||
<div className='options'>
|
||||
<a onClick={() => setExtensionSetting('redirect', true)} className={`button ${redirect ? 'active' : ''}`}>
|
||||
Redirect
|
||||
</a>
|
||||
<a onClick={() => setExtensionSetting('redirect', false)} className={`button ${redirect ? '' : 'active'}`}>
|
||||
Show a button
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<label>Which platform you would like to redirect?</label>
|
||||
<div className='options'>
|
||||
{targetPlatforms.map(([name, value]) =>
|
||||
<a onClick={() => setExtensionSetting('targetPlatform', name)} className={`button ${targetPlatform === name ? 'active' : ''}`}>
|
||||
{value.displayName}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<label>Which resolver API you want to use?</label>
|
||||
<div className='options'>
|
||||
{ytUrlResolverOptions.map(([name, value]) =>
|
||||
<a onClick={() => setExtensionSetting('urlResolver', name)} className={`button ${urlResolver === name ? 'active' : ''}`}>
|
||||
{value.name}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<a onClick={() => loads(lbryUrlCache.clearAll().then(() => dialogManager.alert("Cleared Cache!")))} className={`button active`}>
|
||||
Clear Resolver Cache
|
||||
<main>
|
||||
<section>
|
||||
<label>Pick a mode:</label>
|
||||
<div className='options'>
|
||||
<a onClick={() => setExtensionSetting('redirect', true)} className={`button ${redirect ? 'active' : ''}`}>
|
||||
Redirect
|
||||
</a>
|
||||
</section>
|
||||
<section>
|
||||
<label>Tools</label>
|
||||
<a target='_blank' href='/pages/YTtoLBRY/index.html' className={`filled`}>
|
||||
Subscription Converter
|
||||
<a onClick={() => setExtensionSetting('redirect', false)} className={`button ${redirect ? '' : 'active'}`}>
|
||||
Show a button
|
||||
</a>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<a onClick={() => loads(lbryUrlCache.clearAll().then(() => dialogManager.alert("Cleared Cache!")))} className={`button active`}>
|
||||
Clear Resolver Cache
|
||||
</a>
|
||||
</section>
|
||||
<section>
|
||||
<label>Tools</label>
|
||||
<a target='_blank' href='/pages/YTtoLBRY/index.html' className={`filled`}>
|
||||
Subscription Converter
|
||||
</a>
|
||||
</section>
|
||||
</main>
|
||||
}
|
||||
{loading && <div class="overlay">
|
||||
<span>Loading...</span>
|
||||
|
@ -188,8 +66,7 @@ function WatchOnLbryPopup(params: { profile: Awaited<ReturnType<typeof getProfil
|
|||
}
|
||||
|
||||
function renderPopup() {
|
||||
render(<WatchOnLbryPopup profile={null} />, document.getElementById('root')!)
|
||||
getProfile().then((profile) => render(<WatchOnLbryPopup profile={profile} />, document.getElementById('root')!))
|
||||
render(<WatchOnLbryPopup />, document.getElementById('root')!)
|
||||
}
|
||||
|
||||
renderPopup()
|
||||
|
|
|
@ -8,6 +8,10 @@ header {
|
|||
justify-items: center;
|
||||
}
|
||||
|
||||
#logo {
|
||||
width: 5em;
|
||||
}
|
||||
|
||||
main {
|
||||
display: grid;
|
||||
gap: 2em;
|
||||
|
|
|
@ -143,23 +143,7 @@ async function requestResolveById(...params: Parameters<typeof resolveById>): Re
|
|||
videoElement.pause()
|
||||
})
|
||||
|
||||
if (platfrom === targetPlatformSettings.app) {
|
||||
if (document.hidden) await new Promise((resolve) => document.addEventListener('visibilitychange', resolve, { once: true }))
|
||||
|
||||
// On redirect with app, people might choose to cancel browser's dialog
|
||||
// So we dont destroy the current window automatically for them
|
||||
// And also we are keeping the same window for less distiraction
|
||||
if (settings.redirect) {
|
||||
location.replace(url.toString())
|
||||
}
|
||||
else {
|
||||
open(url.toString(), '_blank')
|
||||
if (window.history.length === 1) window.close()
|
||||
else window.history.back()
|
||||
}
|
||||
}
|
||||
else
|
||||
location.replace(url.toString())
|
||||
location.replace(url.toString())
|
||||
}
|
||||
|
||||
let removeVideoTimeUpdateListener: (() => void) | null = null
|
||||
|
|
|
@ -5,16 +5,12 @@ export interface ExtensionSettings {
|
|||
redirect: boolean
|
||||
targetPlatform: TargetPlatformName
|
||||
urlResolver: YTUrlResolverName
|
||||
publicKey: string | null,
|
||||
privateKey: string | null
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: ExtensionSettings = {
|
||||
redirect: true,
|
||||
targetPlatform: 'odysee',
|
||||
urlResolver: 'odyseeApi',
|
||||
privateKey: null,
|
||||
publicKey: null
|
||||
urlResolver: 'odyseeApi'
|
||||
}
|
||||
|
||||
export function getExtensionSettingsAsync(): Promise<ExtensionSettings> {
|
||||
|
@ -74,19 +70,6 @@ export const getTargetPlatfromSettingsEntiries = () => {
|
|||
return Object.entries(targetPlatformSettings) as any as [Extract<keyof typeof targetPlatformSettings, string>, TargetPlatform][]
|
||||
}
|
||||
export const targetPlatformSettings = {
|
||||
'madiator.com': targetPlatform({
|
||||
domainPrefix: 'https://madiator.com/',
|
||||
displayName: 'Madiator.com',
|
||||
theme: 'linear-gradient(130deg, #499375, #43889d)',
|
||||
button: {
|
||||
text: 'Watch on',
|
||||
icon: chrome.runtime.getURL('assets/icons/lbry/madiator-logo.svg'),
|
||||
style: {
|
||||
button: { flexDirection: 'row-reverse' },
|
||||
icon: { transform: 'scale(1.2)' }
|
||||
}
|
||||
}
|
||||
}),
|
||||
odysee: targetPlatform({
|
||||
domainPrefix: 'https://odysee.com/',
|
||||
displayName: 'Odysee',
|
||||
|
@ -95,16 +78,7 @@ export const targetPlatformSettings = {
|
|||
text: 'Watch on Odysee',
|
||||
icon: chrome.runtime.getURL('assets/icons/lbry/odysee-logo.svg')
|
||||
}
|
||||
}),
|
||||
app: targetPlatform({
|
||||
domainPrefix: 'lbry://',
|
||||
displayName: 'LBRY App',
|
||||
theme: 'linear-gradient(130deg, #499375, #43889d)',
|
||||
button: {
|
||||
text: 'Watch on LBRY',
|
||||
icon: chrome.runtime.getURL('assets/icons/lbry/lbry-logo.svg')
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
@ -125,19 +99,19 @@ export function getSourcePlatfromSettingsFromHostname(hostname: string) {
|
|||
return null
|
||||
}
|
||||
export const sourcePlatfromSettings = {
|
||||
"yewtu.be": sourcePlatform({
|
||||
hostnames: ['yewtu.be', 'vid.puffyan.us', 'invidio.xamh.de', 'invidious.kavin.rocks'],
|
||||
htmlQueries: {
|
||||
mountButtonBefore: '#watch-on-youtube',
|
||||
videoPlayer: '#player-container video'
|
||||
}
|
||||
}),
|
||||
"youtube.com": sourcePlatform({
|
||||
hostnames: ['www.youtube.com'],
|
||||
htmlQueries: {
|
||||
mountButtonBefore: 'ytd-video-owner-renderer~#subscribe-button',
|
||||
videoPlayer: '#ytd-player video'
|
||||
}
|
||||
}),
|
||||
"yewtu.be": sourcePlatform({
|
||||
hostnames: ['yewtu.be', 'vid.puffyan.us', 'invidio.xamh.de', 'invidious.kavin.rocks'],
|
||||
htmlQueries: {
|
||||
mountButtonBefore: '#watch-on-youtube',
|
||||
videoPlayer: '#player-container video'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -154,15 +128,5 @@ export const ytUrlResolversSettings = {
|
|||
name: "Odysee",
|
||||
href: "https://api.odysee.com/yt",
|
||||
signRequest: false
|
||||
}),
|
||||
madiatorFinder: ytUrlResolver({
|
||||
name: "Madiator Finder",
|
||||
href: "https://finder.madiator.com/api/v1",
|
||||
signRequest: true
|
||||
}),
|
||||
/* madiatorFinderLocal: ytUrlResolver({
|
||||
name: "Madiator Finder Local",
|
||||
href: "http://127.0.0.1:3001/api/v1",
|
||||
signRequest: true
|
||||
}) */
|
||||
})
|
||||
}
|
Loading…
Add table
Reference in a new issue