lyrpy 2025.0.1__py3-none-any.whl → 2025.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.

Potentially problematic release.


This version of lyrpy might be problematic. Click here for more details.

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