🔥 Modified for Watch on Odysee

This commit is contained in:
Shiba 2022-07-01 20:46:51 +00:00
parent f072c95051
commit 3a44267fdf
10 changed files with 50 additions and 250 deletions

View file

@ -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

View file

@ -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%);

View file

@ -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) {

View file

@ -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()

View file

@ -8,6 +8,10 @@ header {
justify-items: center;
}
#logo {
width: 5em;
}
main {
display: grid;
gap: 2em;

View file

@ -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

View file

@ -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
}) */
})
}