11const puppeteer = require ( 'puppeteer-extra' )
22const StealthPlugin = require ( 'puppeteer-extra-plugin-stealth' )
33
4- const { csv_map : index , blacklisted_creator, get_row_video_ids, check_includes , get_archive_csv, log, logErr, delay, getInput } = require ( './utils.js' )
4+ const { csv_map : index , blacklisted_creator, get_row_video_ids, get_archive_csv, log, logErr, delay, getInput } = require ( './utils.js' )
55
66puppeteer . use ( StealthPlugin ( ) )
77
8- function update_playlist ( use_cookie , headless , queue_delay , playlist_url , check_blacklisted ) {
8+ let
9+ has_edit_pemissions = true ,
10+ ask_before_adding = false
11+
12+ function update_playlist ( use_cookie , headless , queue_delay , playlist_url , check_blacklisted , add_if_missing , report_contradictory ) {
13+ if ( add_if_missing === 0 )
14+ has_edit_pemissions = false
15+ else if ( add_if_missing === 1 )
16+ ask_before_adding = true
17+
918 puppeteer . launch ( { headless : headless } ) . then ( async browser => {
1019 const page = await browser . newPage ( )
1120 if ( use_cookie )
1221 await login_with_cookie ( page , playlist_url )
1322 else
1423 await normal_login ( page , playlist_url )
15-
16- // Give the page a bit to load the playlist with all the videos
17- await delay ( 3000 )
18-
19- let can_add = true
24+
2025 try {
2126 // This is the + button which is needed to reveal the playlist adding video options
2227 await page . click ( '#showmediaurl' )
@@ -25,36 +30,50 @@ function update_playlist(use_cookie, headless, queue_delay, playlist_url, check_
2530 await page . waitForSelector ( "#addfromurl .checkbox .add-temp" ) . then ( button => button . click ( ) ) ;
2631 } catch {
2732 await logErr ( "Can't add videos to this playlist" )
28- can_add = false
33+ has_edit_pemissions = false
2934 }
3035
3136 // return a 2d array of all video identifiers currently in the playlist
32- let playlistSnapshot = await page . evaluate ( ( ) => {
33- const elements = Array . from ( document . getElementsByClassName ( 'qe_title' ) ) ;
34- let id , ids_links = { }
35- elements . shift ( )
37+ let playlistSnapshot
38+
39+ do {
40+ // Give the page a bit to load the playlist with all the videos
41+ await delay ( 2000 )
42+
43+ playlistSnapshot = await page . evaluate ( ( ) => {
44+ const elements = Array . from ( document . getElementsByClassName ( 'qe_title' ) ) ;
45+ let id , ids_links = { }
46+ elements . shift ( )
3647
37- // can't use vid_identifier() here since this runs in the page context
48+ // can't use vid_identifier() here since this runs in the page context
3849
39- for ( var e of elements ) {
40- id = e . href . split ( '/' )
50+ for ( var e of elements ) {
51+ id = e . href . split ( '/' )
4152
42- if ( ! id . at ( - 1 ) ) {
43- id = id . at ( - 2 ) + "/"
44- }
53+ if ( ! id . at ( - 1 ) ) {
54+ id = id . at ( - 2 ) + "/"
55+ }
4556
46- id = id . at ( - 1 )
47- ids_links [ id ] = e . href
48- }
49-
50- return ids_links
51- } )
57+ id = id . at ( - 1 )
58+ ids_links [ id ] = e . href
59+ }
60+
61+ return ids_links
62+ } )
63+ } while ( ! Object . keys ( playlistSnapshot ) . length )
5264
53- let row_is_blacklisted
54- let csv_row = 1 , add_vid_attempts = 0
55- let row_video_ids
56- let includes
57- const blacklist_included = [ ]
65+ let
66+ row_is_blacklisted ,
67+ csv_row = 1 ,
68+ add_vid_attempts = 0 ,
69+ row_video_ids ,
70+ included ,
71+ should_queue = true ,
72+ is_contradictory = false
73+
74+ const
75+ blacklist_included = [ ] ,
76+ contradictory_included = [ ]
5877
5978 const archive_data = await get_archive_csv ( 'https://docs.google.com/spreadsheets/d/1rEofPkliKppvttd8pEX8H6DtSljlfmQLdFR-SlyyX7E/export?format=csv' )
6079
@@ -64,81 +83,91 @@ function update_playlist(use_cookie, headless, queue_delay, playlist_url, check_
6483 ++ csv_row
6584 row_is_blacklisted = check_blacklisted && blacklisted_creator ( archive_row )
6685 row_video_ids = await get_row_video_ids ( archive_row )
86+ included = check_includes ( playlistSnapshot , row_video_ids )
6787
6888 if ( row_is_blacklisted ) {
69- var present_url
70-
71- for ( const id of row_video_ids ) {
72- includes = check_includes ( playlistSnapshot , id )
73-
74- if ( includes . in_snapshot ) {
75- present_url = playlistSnapshot [ includes . id ]
76- delete playlistSnapshot [ includes . id ]
77- break
78- }
79- }
80-
81- if ( present_url ) {
89+ if ( included . video_id ) {
8290 await logErr ( `${ csv_row } : blacklisted video found in playlist - ${ archive_row [ index . TITLE ] } ` )
83- blacklist_included . push ( `${ archive_row [ index . TITLE ] } - ${ present_url } ` )
91+ blacklist_included . push ( `${ archive_row [ index . TITLE ] } - ${ playlistSnapshot [ included . video_id ] } ` )
92+ delete playlistSnapshot [ included . video_id ]
8493 continue
8594 }
8695
8796 log ( `${ csv_row } : skipping blacklisted video` )
8897 continue
8998 }
9099
91- if ( archive_row [ index . NOTES ] . includes ( "age restriction bypass" ) || archive_row [ index . NOTES ] . includes ( "bypass age restriction" ) ) {
92- includes = check_includes ( playlistSnapshot , row_video_ids [ 2 ] )
100+ if ( included . video_id ) {
101+ switch ( included . archive_index ) {
102+ case index . LINK :
103+ if ( ! archive_row [ index . STATE ] )
104+ log ( `${ csv_row } : present` )
105+ else
106+ is_contradictory = true
107+ break
93108
94- if ( includes . in_snapshot ) {
95- delete playlistSnapshot [ includes . id ]
96- log ( `${ csv_row } : age-restriction bypassing link present` )
97- continue
109+ case index . ALT_LINK :
110+ if ( archive_row [ index . FOUND ] !== "needed" )
111+ log ( `${ csv_row } : alt present` )
112+ else
113+ is_contradictory = true
114+ break
115+
116+ default :
117+ log ( `${ csv_row } : age-restriction bypassing link present` )
98118 }
99119
100- log ( `${ csv_row } : not present - Title: ${ archive_row [ index . TITLE ] } ` )
101- if ( can_add ) {
120+ if ( is_contradictory && report_contradictory ) {
121+ contradictory_included . push (
122+ `${ playlistSnapshot [ included . video_id ] } - ${ archive_row [ index . TITLE ] } `
123+ )
124+
125+ is_contradictory = false
126+ }
127+
128+ delete playlistSnapshot [ included . video_id ]
129+ continue
130+ }
131+
132+ // Add the first available url
133+
134+ if ( archive_row [ index . NOTES ] . includes ( "age restriction" ) ) {
135+ log ( `${ csv_row } : not present - ${ archive_row [ index . TITLE ] } ` )
136+
137+ if ( should_queue = can_add ( ) ) {
102138 log ( "adding using age-restriction bypassing link...\n" )
103139 await page . type ( '#mediaurl' , archive_row [ index . NOTES ] . split ( " " ) . at ( - 1 ) )
104140 }
105141 }
142+ else if ( ! archive_row [ index . STATE ] ) {
143+ log ( `${ csv_row } : not present - ${ archive_row [ index . TITLE ] } ` )
106144
107- else if ( archive_row [ index . FOUND ] === "found" ) {
108- includes = check_includes ( playlistSnapshot , row_video_ids [ 1 ] )
109-
110- if ( includes . in_snapshot ) {
111- log ( `${ csv_row } : alt present` )
112- delete playlistSnapshot [ includes . id ]
113- continue
145+ if ( should_queue = can_add ( ) ) {
146+ log ( "adding...\n" )
147+ await page . type ( '#mediaurl' , archive_row [ index . LINK ] )
114148 }
149+ }
150+ else if ( archive_row [ index . FOUND ] === "found" ) {
151+ log ( `${ csv_row } : not present - ${ archive_row [ index . TITLE ] } ` )
115152
116- log ( `${ csv_row } : not present - Title: ${ archive_row [ index . TITLE ] } ` )
117- if ( can_add ) {
153+ if ( should_queue = can_add ( ) ) {
118154 log ( "adding using alt link...\n" )
119155 await page . type ( '#mediaurl' , archive_row [ index . ALT_LINK ] )
120156 }
121157 }
122-
123- else if ( archive_row [ index . FOUND ] === "needed" ) {
124- await logErr ( `${ csv_row } : no useable alt link - Title: ${ archive_row [ index . TITLE ] } ` )
125- continue
126- }
158+ else if ( row_video_ids . length === 3 ) {
159+ log ( `${ csv_row } : not present - ${ archive_row [ index . TITLE ] } ` )
127160
128- else {
129- includes = check_includes ( playlistSnapshot , row_video_ids [ 0 ] )
130- if ( includes . in_snapshot ) {
131- log ( `${ csv_row } : present` )
132- delete playlistSnapshot [ includes . id ]
133- continue
134- }
135-
136- log ( `${ csv_row } : not present - Title: ${ archive_row [ index . TITLE ] } ` )
137- if ( can_add ) {
138- log ( "adding...\n" )
139- await page . type ( '#mediaurl' , archive_row [ index . LINK ] )
161+ if ( should_queue = can_add ( ) ) {
162+ log ( "adding using link in notes...\n" )
163+ await page . type ( '#mediaurl' , archive_row [ index . NOTES ] . split ( " " ) . at ( - 1 ) )
140164 }
141165 }
166+ else {
167+ await logErr ( `${ csv_row } : no useable links for: ${ archive_row [ index . TITLE ] } ` )
168+ continue
169+ }
170+
142171
143172 if ( await page . $ ( '.server-msg-disconnect' ) ) {
144173 logErr ( 'Disconnected from server because of duplicate login' )
@@ -151,7 +180,7 @@ function update_playlist(use_cookie, headless, queue_delay, playlist_url, check_
151180 but the default value is 2000 just to be safe since sometimes queing
152181 can take a bit longer before clearing the url entry box, which may cause errors
153182 */
154- if ( can_add ) {
183+ if ( should_queue ) {
155184 await page . click ( '#queue_end' )
156185 await delay ( queue_delay + ( ! headless * 1000 ) )
157186
@@ -190,25 +219,35 @@ function update_playlist(use_cookie, headless, queue_delay, playlist_url, check_
190219
191220 if ( blacklist_included . length ) {
192221 log ( "Blacklisted videos found in Cytube playlist" )
193- for ( let video_identifiers of blacklist_included )
222+
223+ for ( const video_identifiers of blacklist_included )
194224 logErr ( video_identifiers , false )
195225 log ( )
196226 }
197227
198228 if ( Object . keys ( playlistSnapshot ) . length !== 0 ) {
199- log ( "Videos found in Cytube playlist that shouldn't be according to the pony archive" )
200- for ( var url of Object . values ( playlistSnapshot ) )
229+ log ( "Videos found in Cytube playlist that are duplicates or aren't in the archive" )
230+
231+ for ( const url of Object . values ( playlistSnapshot ) )
201232 logErr ( url , false )
202233 log ( )
203234 }
204235
205- if ( ! headless ) await getInput ( '' , false )
236+ if ( contradictory_included . length ) {
237+ log ( "Videos found in playlist that shouldn't be according to archive labels" )
238+
239+ for ( const video_identifier of contradictory_included )
240+ logErr ( video_identifier , false )
241+ log ( )
242+ }
243+
244+ if ( ! headless ) getInput ( '' )
206245 await browser . close ( )
207246 } )
208247}
209248
210249async function login_with_cookie ( page ) {
211- let input = await getInput ( 'Authentication Cookie: ' , true )
250+ let input = getInput ( 'Authentication Cookie: ' , true )
212251 let cookie = {
213252 'name' : 'auth' ,
214253 'value' : input ,
@@ -227,7 +266,7 @@ async function login_with_cookie(page) {
227266 logErr ( "Invalid Authentication Cookie Provided" )
228267 log ( )
229268
230- cookie . value = await getInput ( 'Authentication Cookie: ' , true )
269+ cookie . value = getInput ( 'Authentication Cookie: ' , true )
231270 }
232271}
233272
@@ -247,4 +286,47 @@ async function normal_login(page, url) {
247286 await page . goto ( url )
248287}
249288
289+
290+ id_indices = [ index . LINK , index . ALT_LINK , index . NOTES ]
291+
292+ function check_includes ( playlist_snapshot , video_ids ) {
293+ const ret = { archive_index : null , video_id : null }
294+ let id , i = 0
295+
296+ for ( ; i < video_ids . length ; ++ i ) {
297+ id = video_ids [ i ]
298+
299+ if ( typeof id === "string" ) {
300+ if ( id in playlist_snapshot ) {
301+ ret . video_id = id
302+ break
303+ }
304+ }
305+ // For Ponytube videos with two ids
306+ else if ( id [ 0 ] in playlist_snapshot ) {
307+ ret . video_id = id [ 0 ]
308+ break
309+ }
310+ else if ( id [ 1 ] in playlist_snapshot ) {
311+ ret . video_id = id [ 1 ]
312+ break
313+ }
314+ }
315+
316+ if ( ret . video_id !== null )
317+ ret . archive_index = id_indices [ i ]
318+
319+ return ret
320+ }
321+
322+ function can_add ( ) {
323+ return (
324+ has_edit_pemissions &&
325+ (
326+ ! ask_before_adding ||
327+ getInput ( "Add this video to the playlist? (y/n)\n" ) . toLowerCase ( ) === "y"
328+ )
329+ )
330+ }
331+
250332module . exports = { update_playlist }
0 commit comments