1+ import play from "../../../icons/play.svg" ;
2+
3+ export type video = {
4+ length : string ,
5+ thumbnail : string ,
6+ title : string ,
7+ creator : string ,
8+ } ;
9+
10+ const store : { [ key : string ] : video } = { } ;
11+ const queue : string [ ] = [ ] ;
12+ let queuepos = 0 ;
13+ let queueel : HTMLElement = null ;
14+
15+ export async function addToStore ( name : string , length : string , thumbnail : string , title : string , creator : string ) : Promise < void > ;
16+ export async function addToStore ( name : string ) : Promise < void > ;
17+ export async function addToStore ( name : string , ...args : any [ ] ) {
18+ if ( store [ name ] )
19+ return ; // already in
20+ const [ length , thumbnail , title , creator ] = args . length === 4 ? args : await requestData ( name ) ;
21+ store [ name ] = { length, thumbnail, title, creator } ;
22+ }
23+ export const enqueue = ( name : string , pos ?: number ) => {
24+ if ( ! store [ name ] )
25+ throw "Not in store!" ;
26+ if ( pos !== undefined )
27+ queue . splice ( pos , 0 , name ) ;
28+ else
29+ queue . splice ( queue . length , 0 , name ) ;
30+ console . log ( queue ) ;
31+ } ;
32+ export const enqueueNow = ( name : string ) => {
33+ if ( ! name )
34+ throw "Not in store!" ;
35+ queue . splice ( queuepos + 1 , 0 , name ) ;
36+ console . log ( queue ) ;
37+ }
38+ export const removeFromQueue = ( index : number ) => {
39+ queue . splice ( index , 1 ) ;
40+ console . log ( queue ) ;
41+ }
42+ export const gotoQueue = ( index : number ) => {
43+ queueel ?. children [ queuepos ] ?. classList . remove ( 'playing' ) ;
44+ queuepos = index ;
45+ const url = `/videos/${ queue [ index ] } ` ;
46+ // trick router into accepting my url without reloading page
47+ window . history . pushState ( null , null , url ) ;
48+ window . history . pushState ( null , null , url ) ;
49+ window . history . back ( ) ;
50+ queueel ?. children [ index ] ?. classList . add ( 'playing' ) ;
51+ console . log ( queuepos ) ;
52+ }
53+ export const gotoNextInQueue = ( ) => gotoQueue ( queuepos + 1 ) ;
54+
55+
56+ export const init = ( ) => {
57+ // remove existing elements from extension reload
58+ Array . from ( document . querySelectorAll ( '.enhancer-queue' ) ) . forEach ( e => e . remove ( ) ) ;
59+
60+ const q = document . createElement ( 'div' ) ;
61+ q . className = 'enhancer-queue' ;
62+ q . innerHTML = `
63+ <div class="top"></div>
64+ <div class="elements"></div>
65+ ` ;
66+ const e = q . querySelector ( '.elements' ) as HTMLElement ;
67+ queueel = e ;
68+ document . body . appendChild ( q ) ;
69+
70+ queue . splice = ( start : number , count : number , ...elements : string [ ] ) => {
71+ start = start < 0 ? queue . length - start : start ;
72+ start = start < 0 ? 0 : start > queue . length ? queue . length : start ;
73+ const end = start + count > queue . length ? queue . length : start + count ;
74+ let s = start > 0 ? e . children [ start - 1 ] : null ;
75+ for ( let i = start ; i < end ; i ++ )
76+ e . children [ i ] . remove ( ) ;
77+ for ( let el of elements ) {
78+ const node = insertChild ( el ) ;
79+ s = s === null ? e . appendChild ( node ) : ( s . after ( node ) , node ) ;
80+ }
81+ return Array . prototype . splice . call ( queue , start , count , ...elements ) ;
82+ } ;
83+ e . addEventListener ( 'click' , clickElements ) ;
84+ window . addEventListener ( 'message' , msg ) ;
85+ } ;
86+ const clickElements = ( e : MouseEvent ) => {
87+ const el = ( e . target as HTMLElement ) . closest ( '.element' ) ;
88+ if ( el === null )
89+ return ;
90+ e . preventDefault ( ) ;
91+ const i = Array . from ( el . parentElement . children ) . findIndex ( e => e . isSameNode ( el ) ) ;
92+ gotoQueue ( i ) ;
93+ } ;
94+ const msg = ( e : MessageEvent ) => {
95+ if ( e . origin !== "https://player.zype.com" && e . origin !== "http://player.zype.com" )
96+ return ;
97+ const m = JSON . parse ( e . data ) ;
98+ if ( m . event === "zype:complete" ) gotoNextInQueue ( ) ;
99+ }
100+
101+
102+ type thumb = {
103+ aspect_ratio : number ,
104+ height : number ,
105+ width : number ,
106+ url : string ,
107+ name : string ,
108+ } ;
109+ type cat = {
110+ _id : string ,
111+ category_id : string ,
112+ title : string ,
113+ value : string [ ] ,
114+ } ;
115+ const requestData = async ( name : string ) => {
116+ const data = await fetch ( `https://api.zype.com/videos?friendly_title=${ name } &per_page=1&api_key=JlSv9XTImxelHi-eAHUVDy_NUM3uAtEogEpEdFoWHEOl9SKf5gl9pCHB1AYbY3QF` , {
117+ "credentials" : "omit" ,
118+ "headers" : {
119+ "Accept" : "application/json, text/plain, */*" ,
120+ "Accept-Language" : "en-US,en;q=0.5" ,
121+ "Cache-Control" : "max-age=0"
122+ } ,
123+ "referrer" : `https://watchnebula.com/videos/${ name } ` ,
124+ "method" : "GET" ,
125+ "mode" : "cors"
126+ } ) . then ( res => res . json ( ) ) . catch ( console . error ) ;
127+ const vid = data . response [ 0 ] ;
128+ return [
129+ `${ Math . floor ( vid . duration / 60 ) } :${ vid . duration - Math . floor ( vid . duration / 60 ) * 60 } ` ,
130+ ( vid . thumbnails as thumb [ ] ) [ 0 ] . url ,
131+ vid . title ,
132+ ( vid . categories as cat [ ] ) . find ( c => c . value . length ) . value [ 0 ]
133+ ] as string [ ] ;
134+ } ;
135+ const insertChild = ( name : string ) : HTMLElement => {
136+ const n = document . createElement ( 'div' ) ;
137+ n . className = 'element' ;
138+ n . innerHTML = `
139+ <div class="thumb">
140+ <img src="${ store [ name ] . thumbnail } " />
141+ <div class="play">${ play } </div>
142+ </div>
143+ <div class="data">
144+ <span class="title">${ store [ name ] . title } </span>
145+ <span class="creator">${ store [ name ] . creator } • ${ store [ name ] . length } </span>
146+ </div>
147+ ` ;
148+ return n ;
149+ } ;
0 commit comments