1+ import { BrowserMessage , debounce , getBrowserInstance , getFromStorage , nebulavideo } from '../../helpers/sharedExt' ;
2+ import { constructButton } from './html' ;
3+
4+ const optionsDefaults = {
5+ ytOpenTab : false ,
6+ ytMuteOnly : false ,
7+ ytReplaceTab : false ,
8+ } ;
9+ let options = { ...optionsDefaults } ;
10+
11+ export const invidious = async ( ) => {
12+ options = await getFromStorage ( optionsDefaults ) ;
13+ console . debug ( 'Invidious loaded on' , location . hostname ) ;
14+ getBrowserInstance ( ) . storage . onChanged . addListener ( changed => {
15+ Object . keys ( options ) . forEach ( prop => {
16+ if ( prop in changed && 'newValue' in changed [ prop ] ) {
17+ options [ prop ] = changed [ prop ] . newValue as typeof options [ typeof prop ] ;
18+ }
19+ } ) ;
20+ console . dev . debug ( 'Reload information' , changed ) ;
21+ setTimeout ( run , 100 ) ;
22+ } ) ;
23+
24+ Array . from ( document . querySelectorAll < HTMLElement > ( '.watch-on-nebula' ) ) . forEach ( n => n . remove ( ) ) ;
25+ setTimeout ( run , 0 ) ;
26+ } ;
27+
28+ const remove = ( ) => Array . from ( document . querySelectorAll < HTMLElement > ( '.watch-on-nebula' ) ) . forEach ( n => n . style . display = 'none' ) ;
29+ const findParentLink = ( el : HTMLElement ) => {
30+ while ( el ) {
31+ if ( el . tagName === 'A' ) return el as HTMLAnchorElement ;
32+ el = el . parentElement ;
33+ }
34+ } ;
35+ const run = debounce ( async ( ) => {
36+ if ( ! location . pathname . startsWith ( '/watch' ) ) {
37+ console . dev . log ( 'not a video' ) ;
38+ remove ( ) ;
39+ return ;
40+ }
41+
42+ const channelEl = document . getElementById ( 'channel-name' ) ;
43+ const channelNice = channelEl ?. textContent . trim ( ) ;
44+ const channelLink = findParentLink ( channelEl ) ;
45+ const channelID = channelLink ?. href . match ( / \/ c h a n n e l \/ ( [ ^ \/ ] + ) / ) ?. [ 1 ] ;
46+ const titleEl = document . querySelector ( '#player-container ~ * h1' ) ;
47+ const videoTitle = titleEl ?. textContent . trim ( ) ;
48+ console . dev . debug ( 'Elements' , ! ! channelEl , ! ! titleEl , ! ! channelLink ) ;
49+ if ( ! channelEl || ! titleEl || ! channelLink ) return ;
50+ const vidID = location . search . match ( / [ ? & ] v = ( [ ^ & ] + ) / ) ?. [ 1 ] ;
51+
52+ const { res : vid , err } : { res ?: nebulavideo , err ?: any ; } = await getBrowserInstance ( ) . runtime . sendMessage ( { type : BrowserMessage . GET_VID , channelID, channelName : channelNice , channelNice, videoTitle } ) ;
53+ console . dev . log ( 'got:' , vid , err ) ;
54+ if ( ! vid ) throw new Error ( err ) ;
55+ console . debug ( 'got video information' ,
56+ '\nchannelID:' , channelID , 'channelName:' , channelNice , 'videoTitle:' , videoTitle , 'vidID:' , vidID ,
57+ '\non nebula?' , ! ! vid ) ;
58+
59+ if ( ! vid ) return remove ( ) ;
60+ console . dev . log ( 'Found video:' , vid ) ;
61+
62+ const watchOnYtEl = document . querySelector < HTMLElement > ( '#watch-on-youtube' ) ;
63+ if ( ! watchOnYtEl ) return ;
64+ constructButton ( vid , watchOnYtEl ) ;
65+
66+ if ( ( window . history . state || { } ) [ '_enhancer_checked' ] === true ) return console . debug ( 'Ignoring video since already processed' ) ;
67+
68+ const { ytOpenTab : doOpenTab , ytReplaceTab : replaceTab } = options ;
69+ console . dev . debug ( 'Referer:' , document . referrer ) ;
70+ if ( document . referrer . match ( / h t t p s ? : \/ \/ ( .+ \. ) ? n e b u l a \. ( a p p | t v ) \/ ? / ) && window . history . length <= 1 ) return ; // prevent open link if via nebula link (any link)
71+ if ( vid . is === 'channel' || ! doOpenTab ) return ;
72+
73+ /* eslint-disable-next-line camelcase */
74+ window . history . replaceState ( { ...window . history . state , _enhancer_checked : true } , '' ) ;
75+
76+ if ( replaceTab ) {
77+ window . location . href = vid . link ;
78+ return ;
79+ }
80+
81+ window . open ( vid . link , vidID ) ;
82+ } , 5 ) ;
0 commit comments