lyrpy 0.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
lyr/LUObjectsYT.py ADDED
@@ -0,0 +1,829 @@
1
+ """LUObjectsYT.py"""
2
+ # -*- coding: UTF-8 -*-
3
+ __annotations__ ="""
4
+ =======================================================
5
+ Copyright (c) 2023-2024
6
+ Author:
7
+ Lisitsin Y.R.
8
+ Project:
9
+ LU_PY
10
+ Python (LU)
11
+ Module:
12
+ LUObjectsYT.py
13
+
14
+ =======================================================
15
+ """
16
+
17
+ #------------------------------------------
18
+ # БИБЛИОТЕКИ python
19
+ #------------------------------------------
20
+ import os
21
+ import io
22
+ import datetime
23
+ import logging
24
+ import string
25
+ import time
26
+ from typing import BinaryIO
27
+
28
+ #------------------------------------------
29
+ # БИБЛИОТЕКИ сторонние
30
+ #------------------------------------------
31
+ from urllib.parse import urlparse
32
+
33
+ from pytube import YouTube, request
34
+ from pytube import Playlist
35
+ import pytube
36
+ import pytube.exceptions
37
+
38
+ #------------------------------------------
39
+ # БИБЛИОТЕКИ LU
40
+ #------------------------------------------
41
+ import lyr.LULog as LULog
42
+ import lyr.LUObjects as LUObjects
43
+ import lyr.LUFile as LUFile
44
+ import lyr.LUStrUtils as LUStrUtils
45
+ import lyr.LUThread as LUThread
46
+ import lyr.LUDateTime as LUDateTime
47
+
48
+ CYOUTUBE_COM = 'WWW.YOUTUBE.COM'
49
+ CYOUTUBE_BE = 'YOUTU.BE'
50
+ CYOUTU = 'YOUTU'
51
+ CYOUTUBE_PLAYLISTS = 'PLAYLISTS'
52
+ CYOUTUBE_PLAYLIST = 'PLAYLIST'
53
+ cMaxRes1080p = ('1080p','720p','480p','360p','240p','144p')
54
+ cMaxRes720p = ('720p','480p','360p','240p','144p')
55
+ cMaxRes480p = ('480p','360p','240p','144p')
56
+ cMaxRes360p = ('360p','240p','144p')
57
+ cMaxRes240p = ('240p','144p')
58
+ cMaxRes144p = ('144p','')
59
+
60
+ def ONfunction(*args):
61
+ #beginfunction
62
+ print('def ONfunction():')
63
+ ...
64
+ #endfunction
65
+ TONfunction = ONfunction
66
+
67
+ def progress_func (AStream, AChunk: bytes, Abytes_remaining: int):
68
+ #beginfunction
69
+ s = 'progress_func...'
70
+ LULog.LoggerTOOLS_AddDebug (s)
71
+ # if not AStream is None:
72
+ # LProgressMax = AStream.filesize
73
+ # LProgressLeft = Abytes_remaining
74
+ # LProgressValue = LProgressMax - LProgressLeft
75
+ # if not AChunk is None:
76
+ # ...
77
+ # #endif
78
+ # ...
79
+ # #endif
80
+ #endfunction
81
+
82
+ def complete_func (AStream, AFilePath: str):
83
+ #beginfunction
84
+ s = 'complete_func...'
85
+ LULog.LoggerTOOLS_AddDebug (s)
86
+ if not AStream is None:
87
+ LProgressMax = AStream.filesize
88
+ LProgressLeft = 0
89
+ LProgressValue = LProgressMax - LProgressLeft
90
+ # LULog.LoggerTOOLS_AddDebug (f'{LProgressMax}-{LProgressLeft}-{LProgressValue}')
91
+
92
+ if not AFilePath is None:
93
+ LFileName = LUStrUtils.PrintableStr (AFilePath)
94
+ LULog.LoggerTOOLS_AddDebug ('Файл ' + LFileName + ' загружен')
95
+ #endif
96
+ #endif
97
+ #endfunction
98
+
99
+ class TYouTubeObject (LUObjects.TObjects):
100
+ """TYouTubeObject"""
101
+ luClassName = "TYouTubeObject"
102
+
103
+ #--------------------------------------------------
104
+ # constructor
105
+ #--------------------------------------------------
106
+ def __init__ (self, APathDownload: str):
107
+ """Constructor"""
108
+ #beginfunction
109
+ super ().__init__ ()
110
+ self.__FObjectType: TObjectTypeClass = TObjectTypeClass.otYouTubeObject
111
+ #----------------------------------------------
112
+ self.__FYouTube: YouTube = None
113
+ self.__FStream: pytube.Stream = None
114
+ self.__FURL: str = ''
115
+ self.__FID: datetime = 0
116
+ #----------------------------------------------
117
+ self.__FURLInfo = dict ()
118
+ self.__FStreamInfo = dict ()
119
+ self.__FPlayList: str = ''
120
+ self.__FNumber: int = 0
121
+ self.__FCount: int = 0
122
+ #----------------------------------------------
123
+ self.__FONprogress: TONfunction = self.ONprogressObject
124
+ self.__FONcomplete: TONfunction = self.ONcompleteObject
125
+ #----------------------------------------------
126
+ self.__FYouTubeThread: LUThread.TThread = None
127
+ # self.__FStopYouTubeBoolean: bool = False
128
+ # self.__FStopYouTubeBooleanThread: bool = False
129
+ #----------------------------------------------
130
+ self.FProgressMax: int = 0
131
+ self.FProgressMin: int = 0
132
+ self.FProgressValue: int = 0
133
+ self.FProgressLeft: int = 0
134
+ #----------------------------------------------
135
+ self.FFilechunk: io.BufferedWriter = None
136
+ self.FFileNamechunk = ''
137
+ self.FChunk: bool = True
138
+ self.Fis_paused = False
139
+ self.Fis_cancelled = False
140
+ self.Fskip_existing = False
141
+ #----------------------------------------------
142
+ self.__FPathDownload = APathDownload
143
+ self.__FFilePathDownload = APathDownload
144
+ self.__FFileNamePrefixDownload = ''
145
+ self.__FFileNameDownload = ''
146
+ self.__FFileSizeDownload = 0
147
+ #----------------------------------------------
148
+ self.Clear()
149
+ #endfunction
150
+
151
+ #--------------------------------------------------
152
+ # destructor
153
+ #--------------------------------------------------
154
+ def __del__(self):
155
+ """destructor"""
156
+ #beginfunction
157
+ super ().__del__()
158
+ LClassName = self.__class__.__name__
159
+ s = '{} уничтожен'.format (LClassName)
160
+ # LULog.LoggerTOOLS_AddLevel (LULog.DEBUGTEXT, s)
161
+ #print (s)
162
+ #endfunction
163
+
164
+ #--------------------------------------------------
165
+ # @property ONprogress
166
+ #--------------------------------------------------
167
+ # getter
168
+ @property
169
+ def ONprogress (self):
170
+ #beginfunction
171
+ return self.__FONprogress
172
+ #endfunction
173
+ @ONprogress.setter
174
+ def ONprogress(self, Value):
175
+ #beginfunction
176
+ self.__FONprogress = Value
177
+ #endfunction
178
+
179
+ #--------------------------------------------------
180
+ # @property ONcomplete
181
+ #--------------------------------------------------
182
+ # getter
183
+ @property
184
+ def ONcomplete (self):
185
+ #beginfunction
186
+ return self.__FONcomplete
187
+ #endfunction
188
+ @ONcomplete.setter
189
+ def ONcomplete(self, Value):
190
+ #beginfunction
191
+ self.__FONcomplete = Value
192
+ #endfunction
193
+
194
+ #--------------------------------------------------
195
+ # ONprogressObject
196
+ #--------------------------------------------------
197
+ # def show_progress_bar (stream, chunk, bytes_remaining):
198
+ # prog.update (task, completed = stream.filesize - bytes_remaining)
199
+ # #this show the bytes_remaining, use rich to display a progress bar
200
+ #--------------------------------------------------
201
+ def ONprogressObject (self, AStream: pytube.Stream, AChunk: bytes, Abytes_remaining: int):
202
+ #beginfunction
203
+ s = 'TYouTubeObject.ONprogressObject...'
204
+ LULog.LoggerTOOLS_AddDebug (s)
205
+ if not AStream is None:
206
+ self.FProgressMax = AStream.filesize
207
+ self.FProgressLeft = Abytes_remaining
208
+ self.FProgressValue = self.FProgressMax - self.FProgressLeft
209
+ if not AChunk is None:
210
+ if not self.FFilechunk is None:
211
+ self.FFilechunk.write (AChunk)
212
+ #endif
213
+ #endif
214
+ #endif
215
+ #endfunction
216
+
217
+ #--------------------------------------------------
218
+ # ONcompleteObject
219
+ #--------------------------------------------------
220
+ # def on_complete (stream, file_path):
221
+ # prog.remove_task (task)
222
+ # prog.stop ()
223
+ # print ('[green] Downloaded ', file_path.split ('/') [-1], '\n')
224
+ #--------------------------------------------------
225
+ def ONcompleteObject (self, AStream: pytube.Stream, AFilePath: str):
226
+ #beginfunction
227
+ s = 'TYouTubeObject.ONcompleteObject...'
228
+ LULog.LoggerTOOLS_AddDebug (s)
229
+
230
+ if not AStream is None:
231
+ self.FProgressMax = AStream.filesize
232
+ self.FProgressLeft = 0
233
+ self.FProgressValue = self.FProgressMax - self.FProgressLeft
234
+ if not AFilePath is None:
235
+ LFileName = LUStrUtils.PrintableStr (AFilePath)
236
+ LULog.LoggerTOOLS_AddDebug ('Файл ' + LFileName + ' загружен')
237
+ #endif
238
+ if not self.__FYouTubeThread is None:
239
+ self.__FYouTubeThread.StopThread()
240
+ #endif
241
+ #endif
242
+ #endfunction
243
+
244
+ @staticmethod
245
+ def GetURLInfo (AYouTube: YouTube) -> {}:
246
+ """__GetURLInfo"""
247
+ #beginfunction
248
+ LURLInfo = dict ()
249
+ #Get the video author.
250
+ LURLInfo['author'] = AYouTube.author
251
+ #Get the video description.
252
+ LURLInfo['description'] = AYouTube.description
253
+ #Get the thumbnail url image.
254
+ LURLInfo['thumbnail_url'] = AYouTube.thumbnail_url
255
+ # Заголовок [Get the video title]
256
+ s = AYouTube.title
257
+ LURLInfo['title'] = LUStrUtils.PrintableStr(s)
258
+ # продолжительность видео [Get the video length in seconds]
259
+ LURLInfo['length'] = AYouTube.length
260
+
261
+ # #Get a list of Caption.
262
+ # LURLInfo['caption_tracks'] = AYouTube.caption_tracks
263
+ # #Interface to query caption tracks.
264
+ # LURLInfo['captions'] = AYouTube.captions
265
+ # #Get the video poster’s channel id.
266
+ # LURLInfo['channel_id'] = AYouTube.channel_id
267
+ # #Construct the channel url for the video’s poster from the channel id.
268
+ # LURLInfo['channel_url'] = AYouTube.channel_url
269
+ # #Returns a list of streams if they have been initialized.
270
+ # LURLInfo['fmt_streams'] = AYouTube.fmt_streams
271
+ # #Get the video keywords.
272
+ # LURLInfo['keywords'] = AYouTube.keywords
273
+ # #Get the metadata for the video.
274
+ # LURLInfo['metadata'] = AYouTube.metadata
275
+ # #Get the publish date.
276
+ # LURLInfo['publish_date'] = AYouTube.publish_date
277
+ # #Get the video average rating.
278
+ # LURLInfo['rating'] = AYouTube.rating
279
+ # #Return streamingData from video info.
280
+ # LURLInfo['streaming_data'] = AYouTube.streaming_data
281
+ # #Interface to query both adaptive (DASH) and progressive streams.
282
+ # LURLInfo['streams'] = AYouTube.streams
283
+ # #Parse the raw vid info and return the parsed result.
284
+ # LURLInfo['vid_info'] = AYouTube.vid_info
285
+ # # Количество просмотров [Get the number of the times the video has been viewed]
286
+ # LURLInfo['views'] = AYouTube.views
287
+ return LURLInfo
288
+ #endfunction
289
+
290
+ def __SetURLInfo (self):
291
+ """__SetURLInfo"""
292
+ #beginfunction
293
+ self.__FURLInfo = self.GetURLInfo (self.__FYouTube)
294
+ #endfunction
295
+
296
+ @staticmethod
297
+ def GetStreamInfo (AStream: pytube.Stream) -> {}:
298
+ """GetStreamInfo"""
299
+ #beginfunction
300
+ LStreamInfo = dict ()
301
+ LFileName = LUStrUtils.PrintableStr(AStream.default_filename)
302
+ LStreamInfo['default_filename'] = LFileName
303
+ # LStreamInfo['title'] = AStream.title
304
+ i = AStream.filesize
305
+ LStreamInfo['filesize'] = i
306
+ # ('1080p', '720p', '480p', '360p', '240p', '144p')
307
+ # LStreamInfo['resolution'] = AStream.resolution
308
+ # 'video'|'audio'
309
+ # LStreamInfo['type'] = AStream.type
310
+ # video/mp4
311
+ # LStreamInfo['mime_type'] = AStream.mime_type
312
+ # itag
313
+ # LStreamInfo['itag'] = AStream.itag
314
+ LStreamInfo['itag'] = 'itag'
315
+ # subtype
316
+ # LStreamInfo['subtype'] = AStream.subtype
317
+
318
+ # размер приблизительно
319
+ # LStreamInfo['filesize_approx'] = AStream.filesize_approx
320
+ # размер в Гб
321
+ # LStreamInfo['filesize_gb'] = AStream.filesize_gb
322
+ # размер в Кб
323
+ # LStreamInfo['filesize_kb'] = AStream.filesize_kb
324
+ # размер в Мб
325
+ # LStreamInfo['filesize_mb'] = AStream.filesize_mb
326
+ # url видео плейера
327
+ # LStreamInfo['url'] = AStream.url
328
+ # Get the video/audio codecs from list of codecs.
329
+ # LStreamInfo['parse_codecs'] = AStream.parse_codecs ()
330
+ # True/False - Whether the stream only contains audio.
331
+ # LStreamInfo['includes_audio_track'] = AStream.includes_audio_track
332
+ # True/False - Whether the stream only contains video.
333
+ # LStreamInfo['includes_video_track'] = AStream.includes_video_track
334
+ # #Whether the stream is DASH.
335
+ # LStreamInfo['is_adaptive'] = AStream.is_adaptive
336
+ # #Whether the stream is progressive.
337
+ # LStreamInfo['is_progressive'] = AStream.is_progressive
338
+ # AStream.exists_at_path()
339
+ return LStreamInfo
340
+ #endfunction
341
+
342
+ def __SetStreamInfo (self, AStream: pytube.Stream):
343
+ """SetStreamInfo"""
344
+ #beginfunction
345
+ self.__FStreamInfo = self.GetStreamInfo(AStream)
346
+ if len (self.PlayList) > 0:
347
+ self.__FFilePathDownload = os.path.join (self.PathDownload, self.PlayList)
348
+ # if not LUFile.DirectoryExists (self.FilePathDownload):
349
+ # LUFile.ForceDirectories (self.FilePathDownload)
350
+ # #endif
351
+ self.__FFileNamePrefixDownload = LUStrUtils.AddChar ('0', str (self.Number), 3) + '. '
352
+ else:
353
+ self.__FFilePathDownload = self.PathDownload
354
+ self.__FFileNamePrefixDownload = ''
355
+ #endif
356
+ self.__FFileNameDownload = os.path.join (self.FilePathDownload,
357
+ self.__FFileNamePrefixDownload+self.__FStreamInfo ['default_filename'])
358
+ self.__FFileSizeDownload = self.__FStreamInfo ['filesize']
359
+ #endfunction
360
+
361
+ #--------------------------------------------------
362
+ #
363
+ #--------------------------------------------------
364
+ def SetStream(self, AMaxRes: ()):
365
+ #beginfunction
366
+ self.__FStream = None
367
+ for res in AMaxRes:
368
+ LStreams = list ()
369
+ try:
370
+ LStreams = self.__FYouTube.streams.filter (res=res, type='video', file_extension='mp4')
371
+ except BaseException as ERROR:
372
+ s = f'__FYouTube.streams.filter={ERROR} res={res} URL={self.URL}'
373
+ LULog.LoggerTOOLS_AddError(s)
374
+ #endtry
375
+ if len (LStreams) > 0:
376
+ for LStream in LStreams:
377
+ try:
378
+ self.__SetStreamInfo (LStream)
379
+ self.__FStream = LStream
380
+ break
381
+ except BaseException as ERROR:
382
+ s = f'__SetStreamInfo={ERROR} res={res} URL={self.URL}'
383
+ LULog.LoggerTOOLS_AddError (s)
384
+ #endtry
385
+ #endfor
386
+ break
387
+ #endif
388
+ #endfor
389
+ #endfunction
390
+
391
+ #--------------------------------------------------
392
+ # @property URL
393
+ #--------------------------------------------------
394
+ def SetURL(self, AURL: str, AMaxRes: (), APlayList: str, ANumber: int, ACount: int):
395
+ #beginfunction
396
+ self.__FURL = AURL
397
+ self.__FYouTube: YouTube = YouTube(AURL)
398
+ # self.SetStream(AMaxRes)
399
+ self.__SetURLInfo()
400
+ self.PlayList = APlayList
401
+ self.Number = ANumber
402
+ self.Count = ACount
403
+ #endfunction
404
+
405
+ # getter
406
+ @property
407
+ def URL(self) -> str:
408
+ #beginfunction
409
+ return self.__FURL
410
+ #endfunction
411
+
412
+ #--------------------------------------------------
413
+ # @property ID
414
+ #--------------------------------------------------
415
+ # getter
416
+ @property
417
+ def ID(self) -> datetime:
418
+ #beginfunction
419
+ return self.__FID
420
+ #endfunction
421
+ @ID.setter
422
+ def ID(self, Value: datetime):
423
+ #beginfunction
424
+ self.__FID = Value
425
+ #endfunction
426
+
427
+ #--------------------------------------------------
428
+ # @property URLInfo
429
+ #--------------------------------------------------
430
+ # getter
431
+ @property
432
+ def URLInfo(self) -> dict:
433
+ #beginfunction
434
+ return self.__FURLInfo
435
+ #endfunction
436
+
437
+ #--------------------------------------------------
438
+ # @property StreamInfo
439
+ #--------------------------------------------------
440
+ # getter
441
+ @property
442
+ def StreamInfo(self) -> dict:
443
+ #beginfunction
444
+ return self.__FStreamInfo
445
+ #endfunction
446
+
447
+ #--------------------------------------------------
448
+ # @property YOUTUBE
449
+ #--------------------------------------------------
450
+ # getter
451
+ @property
452
+ def YOUTUBE(self) -> YouTube:
453
+ #beginfunction
454
+ return self.__FYouTube
455
+ #endfunction
456
+
457
+ #--------------------------------------------------
458
+ # @property PlayList
459
+ #--------------------------------------------------
460
+ # getter
461
+ @property
462
+ def PlayList(self) -> str:
463
+ #beginfunction
464
+ return self.__FPlayList
465
+ #endfunction
466
+ @PlayList.setter
467
+ def PlayList(self, Value: str):
468
+ #beginfunction
469
+ self.__FPlayList = Value
470
+ #endfunction
471
+
472
+ #--------------------------------------------------
473
+ # @property FileNameDownload
474
+ #--------------------------------------------------
475
+ # getter
476
+ @property
477
+ def FileNameDownload(self) -> str:
478
+ #beginfunction
479
+ return self.__FFileNameDownload
480
+ #endfunction
481
+ #--------------------------------------------------
482
+ # @property FilePathDownload
483
+ #--------------------------------------------------
484
+ # getter
485
+ @property
486
+ def FilePathDownload(self) -> str:
487
+ #beginfunction
488
+ return self.__FFilePathDownload
489
+ #endfunction
490
+ #--------------------------------------------------
491
+ # @property FileNamePrefixDownload
492
+ #--------------------------------------------------
493
+ # getter
494
+ @property
495
+ def FileNamePrefixDownload(self) -> str:
496
+ #beginfunction
497
+ return self.__FFileNamePrefixDownload
498
+ #endfunction
499
+ #--------------------------------------------------
500
+ # @property FileSizeDownload
501
+ #--------------------------------------------------
502
+ # getter
503
+ @property
504
+ def FileSizeDownload (self) -> int:
505
+ #beginfunction
506
+ return self.__FFileSizeDownload
507
+ #endfunction
508
+ #--------------------------------------------------
509
+ # @property PathDownload
510
+ #--------------------------------------------------
511
+ # getter
512
+ @property
513
+ def PathDownload (self) -> str:
514
+ #beginfunction
515
+ return self.__FPathDownload
516
+ #endfunction
517
+ @PathDownload.setter
518
+ def PathDownload(self, Value: str):
519
+ #beginfunction
520
+ self.__FPathDownload = Value
521
+ #endfunction
522
+
523
+ #--------------------------------------------------
524
+ # @property Number
525
+ #--------------------------------------------------
526
+ # getter
527
+ @property
528
+ def Number(self) -> int:
529
+ #beginfunction
530
+ return self.__FNumber
531
+ #endfunction
532
+ @Number.setter
533
+ def Number(self, Value: int):
534
+ #beginfunction
535
+ self.__FNumber = Value
536
+ #endfunction
537
+
538
+ #--------------------------------------------------
539
+ # @property Count
540
+ #--------------------------------------------------
541
+ # getter
542
+ @property
543
+ def Count(self) -> int:
544
+ #beginfunction
545
+ return self.__FCount
546
+ #endfunction
547
+ @Count.setter
548
+ def Count(self, Value: int):
549
+ #beginfunction
550
+ self.__FCount = Value
551
+ #endfunction
552
+
553
+ #--------------------------------------------------
554
+ # @property ProgressMax
555
+ #--------------------------------------------------
556
+ # getter
557
+ @property
558
+ def ProgressMax(self) -> int:
559
+ #beginfunction
560
+ return self._FProgressMax
561
+ #endfunction
562
+ @ProgressMax.setter
563
+ def ProgressMax(self, Value: int):
564
+ #beginfunction
565
+ self._FProgressMax = Value
566
+ #endfunction
567
+
568
+ # #--------------------------------------------------
569
+ # # @property StopYouTubeBoolean
570
+ # #--------------------------------------------------
571
+ # # getter
572
+ # @property
573
+ # def StopYouTubeBoolean(self) -> bool:
574
+ # #beginfunction
575
+ # return self.__FStopYouTubeBoolean
576
+ # #endfunction
577
+ # @StopYouTubeBoolean.setter
578
+ # def StopYouTubeBoolean(self, Value: bool):
579
+ # #beginfunction
580
+ # self.__FStopYouTubeBoolean = Value
581
+ # #endfunction
582
+
583
+ #--------------------------------------------------
584
+ # @property YouTubeThread
585
+ #--------------------------------------------------
586
+ # getter
587
+ @property
588
+ def YouTubeThread(self):
589
+ #beginfunction
590
+ return self.__FYouTubeThread
591
+ #endfunction
592
+ @YouTubeThread.setter
593
+ def YouTubeThread(self, Value):
594
+ #beginfunction
595
+ self.__FYouTubeThread = Value
596
+ #endfunction
597
+
598
+ def Clear (self):
599
+ """Clear"""
600
+ #beginfunction
601
+ # self.__FURL = ''
602
+ # self.ID = 0
603
+ # self.StopYouTubeBoolean = False
604
+ # self.ProgressMax = 0
605
+ # self.YouTubeThread = None
606
+ # self.PlayList = ''
607
+ # self.Number = 0
608
+ ...
609
+ #endfunction
610
+
611
+ def __DownloadURL_chunk (self, APATH: str, AFileName:str, AFileSize: int):
612
+ """DownloadURL_chunk"""
613
+ #beginfunction
614
+ self.FFileNamechunk = AFileName
615
+ LFileSize = AFileSize
616
+ with open(self.FFileNamechunk, 'wb') as self.FFilechunk:
617
+ stream = request.stream(self.__FStream.url) # get an iterable stream
618
+ Ldownloaded = 0
619
+ while True:
620
+ if self.Fis_cancelled:
621
+ # print('Fis_cancelled...')
622
+ break
623
+ #endif
624
+ if self.Fis_paused:
625
+ # print('Fis_paused...')
626
+ continue
627
+ #endif
628
+ Lchunk = next(stream, None) # get next chunk of video
629
+ if Lchunk:
630
+ self.__FONprogress (self.__FStream, Lchunk, LFileSize-Ldownloaded)
631
+ # print(len(Lchunk))
632
+ Ldownloaded += len(Lchunk)
633
+ else:
634
+ # no more data
635
+ self.__FONcomplete (self.__FStream, self.FFileNamechunk)
636
+ break
637
+ #endif
638
+ #endwhile
639
+ #endwith
640
+ #endfunction
641
+
642
+ def DownloadURL (self, ADownload=False, skip_existing = False):
643
+ """DownloadURL"""
644
+ #beginfunction
645
+ if not self.__FONprogress is None:
646
+ self.__FYouTube.register_on_progress_callback(self.__FONprogress)
647
+ if not self.__FONcomplete is None:
648
+ self.__FYouTube.register_on_complete_callback(self.__FONcomplete)
649
+
650
+ LPATH = self.FilePathDownload
651
+ if not LUFile.DirectoryExists (LPATH):
652
+ LUFile.ForceDirectories (LPATH)
653
+ #endif
654
+ LFileName = self.FileNameDownload
655
+ LFileSize = self.FileSizeDownload
656
+ if not LUFile.FileExists (LFileName):
657
+ LUFile.FileDelete (LFileName)
658
+ #endif
659
+
660
+ if ADownload and len (LFileName) > 0:
661
+ if not self.FChunk:
662
+ try:
663
+ LFileName = self.__FStream.download (LPATH,
664
+ skip_existing = skip_existing,
665
+ filename_prefix = self.FileNamePrefixDownload)
666
+ # except BaseException as ERROR:
667
+ except Exception as ERROR:
668
+ s = f'DownloadURL={ERROR}'
669
+ LULog.LoggerTOOLS_AddError (s)
670
+ #endtry
671
+ else:
672
+ self.__DownloadURL_chunk (LPATH, LFileName, LFileSize)
673
+ if self.Fis_cancelled:
674
+ if LUFile.FileExists (LFileName):
675
+ LUFile.FileDelete (LFileName)
676
+ #endif
677
+ #endif
678
+ #endif
679
+ else:
680
+ N = LFileSize // 4
681
+ i = N
682
+ while i < LFileSize:
683
+ self.__FONprogress(self.__FStream, None, N-i)
684
+ i = i + N
685
+ #endwhile
686
+ self.__FONcomplete (self.__FStream, None)
687
+ #endif
688
+ #endfunction
689
+
690
+ def StartYouTubeThread (self, *args, **kwargs):
691
+ """StartYouTubeThread"""
692
+ #beginfunction
693
+ self.__FYouTubeThread = LUThread.TThread(kwargs=kwargs)
694
+ self.__FYouTubeThread.StartThread()
695
+ #endfunction
696
+ #endclass
697
+
698
+ def CheckURLs (AURL: str, AURLs: dict):
699
+
700
+ def _CheckPlaylists ():
701
+ #beginfunction
702
+ """
703
+ # ЦИКЛ ОТ i=0 ДО AURLPlaylists.count-1
704
+ """
705
+ ...
706
+ #endfunction
707
+
708
+ def _CheckYOUTUBEPlaylist ():
709
+ #beginfunction
710
+ LPlaylist = Playlist (AURL)
711
+ Lvideo_urls = LPlaylist.video_urls
712
+ j = len(LPlaylist.video_urls)
713
+ i = 0
714
+ for url in Lvideo_urls:
715
+ i = i + 1
716
+ LPlaylistTitle = LUStrUtils.DelChars(LPlaylist.title, '/')
717
+ AURLs[url] = {'PlayListName': LPlaylistTitle, 'N': j, 'NN': i}
718
+ #endfor
719
+ #endfunction
720
+
721
+ #beginfunction
722
+ LURI = urlparse (AURL)
723
+ if LURI.hostname.upper() == CYOUTUBE_COM or LURI.hostname.upper() == CYOUTUBE_BE:
724
+ if CYOUTUBE_PLAYLISTS in LURI.path.upper():
725
+ _CheckPlaylists ()
726
+ else:
727
+ if CYOUTUBE_PLAYLIST in LURI.path.upper():
728
+ _CheckYOUTUBEPlaylist ()
729
+ else:
730
+ if len(LURI.query) > 0:
731
+ # https: // www.youtube.com / @ nativecode / videos
732
+ AURLs [AURL] = {'PlayListName': '', 'N': 1, 'NN': 1}
733
+ #endif
734
+ #endif
735
+ #endif
736
+ #endif
737
+ #endfunction
738
+
739
+ #------------------------------------------
740
+ #
741
+ #------------------------------------------
742
+ def DownloadURL (AURL: str, APATH: str, AMaxRes: (), ADownload=False,
743
+ type='video', file_extension = 'mp4',
744
+ skip_existing = False, filename_prefix=''):
745
+ """DownloadURL"""
746
+ #beginfunction
747
+ LYouTube: YouTube = YouTube (AURL,
748
+ on_progress_callback=progress_func,
749
+ on_complete_callback=complete_func)
750
+ LURLInfo = TYouTubeObject.GetURLInfo(LYouTube)
751
+
752
+ LPATH = APATH
753
+
754
+ # все потоки
755
+ LStreams = LYouTube.streams
756
+ # все потоки progressive
757
+ LStreams = LYouTube.streams.filter (progressive = True)
758
+ # все потоки video, mp4, LMaxRes
759
+ LMaxRes = cMaxRes480p
760
+ LMaxRes = cMaxRes1080p
761
+ LMaxRes = AMaxRes
762
+
763
+ for res in LMaxRes:
764
+ try:
765
+ LStreams = LYouTube.streams.filter (type=type, file_extension=file_extension, res=res)
766
+ except BaseException as ERROR:
767
+ LStreams = None
768
+ s = f'filter={ERROR}'
769
+ LULog.LoggerTOOLS_AddError (s)
770
+ #endtry
771
+
772
+ if not LStreams is None:
773
+ for LStream in LStreams:
774
+ LStreamInfo = TYouTubeObject.GetStreamInfo (LStream)
775
+ LTag = LStreamInfo ['itag']
776
+ # Lresolution = LStreamInfo ['resolution']
777
+ # LULog.LoggerTOOLS_AddDebug (Lresolution)
778
+
779
+ Lfilename_prefix = filename_prefix
780
+ LFileName = os.path.join (LPATH, Lfilename_prefix + LStreamInfo ['default_filename'])
781
+
782
+ try:
783
+ if ADownload:
784
+ if not LStream.exists_at_path (LFileName):
785
+ s = LStream.download (APATH, skip_existing=skip_existing, filename_prefix=filename_prefix)
786
+ else:
787
+ LULog.LoggerTOOLS_AddDebug ('Файл ' + LFileName + ' существует...')
788
+ complete_func (LStream, None)
789
+ #endif
790
+ else:
791
+ LFileName = LStreamInfo ['default_filename']
792
+ AFileSize = int (LStreamInfo ['filesize'])
793
+ N = AFileSize // 4
794
+ i = N
795
+ while i < AFileSize:
796
+ progress_func (LStream, None, i)
797
+ i = i + N
798
+ #endwhile
799
+ s = f'Видео не загружалось: {res}/{LTag}={LFileName}'
800
+ LULog.LoggerTOOLS_AddDebug (s)
801
+ complete_func (LStream, None)
802
+ #endif
803
+ except BaseException as ERROR:
804
+ s = f'DownloadURL={ERROR}'
805
+ LULog.LoggerTOOLS_AddError (s)
806
+ LULog.LoggerTOOLS_AddError (LFileName)
807
+ #endtry
808
+ #endfor
809
+ # если по фильтру есть хотя бы один поток
810
+ break
811
+ #endif
812
+ #endfor
813
+ #endfunction
814
+
815
+ #------------------------------------------
816
+ def main ():
817
+ #beginfunction
818
+ ...
819
+ #endfunction
820
+
821
+ #------------------------------------------
822
+ #
823
+ #------------------------------------------
824
+ #beginmodule
825
+ if __name__ == "__main__":
826
+ main()
827
+ #endif
828
+
829
+ #endmodule