lyrpy 2024.0.4__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.
- SRC/LIB/__init__.py +21 -0
- SRC/LIB/lyrpy/LUConst.py +358 -0
- {lyrpy → SRC/LIB/lyrpy}/LUDateTime.py +2 -4
- {lyrpy → SRC/LIB/lyrpy}/LUDecotators.py +2 -3
- {lyrpy → SRC/LIB/lyrpy}/LUDict.py +0 -1
- {lyrpy → SRC/LIB/lyrpy}/LUDoc.py +4 -3
- {lyrpy → SRC/LIB/lyrpy}/LUErrors.py +0 -1
- {lyrpy → SRC/LIB/lyrpy}/LUFile.py +115 -61
- {lyrpy → SRC/LIB/lyrpy}/LUFileUtils.py +60 -45
- {lyrpy → SRC/LIB/lyrpy}/LULog.py +267 -191
- {lyrpy → SRC/LIB/lyrpy}/LUObjects.py +4 -4
- {lyrpy → SRC/LIB/lyrpy}/LUObjectsYT.py +39 -22
- {lyrpy → SRC/LIB/lyrpy}/LUParserARG.py +2 -3
- {lyrpy → SRC/LIB/lyrpy}/LUParserINI.py +8 -3
- {lyrpy → SRC/LIB/lyrpy}/LUParserREG.py +5 -1
- {lyrpy → SRC/LIB/lyrpy}/LUQThread.py +6 -4
- {lyrpy → SRC/LIB/lyrpy}/LUQTimer.py +5 -5
- {lyrpy → SRC/LIB/lyrpy}/LUSheduler.py +24 -23
- SRC/LIB/lyrpy/LUTelegram.py +428 -0
- {lyrpy → SRC/LIB/lyrpy}/LUThread.py +7 -6
- {lyrpy → SRC/LIB/lyrpy}/LUTimer.py +5 -3
- {lyrpy → SRC/LIB/lyrpy}/LUVersion.py +4 -1
- {lyrpy → SRC/LIB/lyrpy}/LUYouTube.py +6 -7
- {lyrpy → SRC/LIB/lyrpy}/LUos.py +13 -3
- SRC/LIB/lyrpy/__init__.py +21 -0
- {lyrpy → SRC/LIB/lyrpy}/__main__.py +20 -19
- SRC/__init__.py +0 -0
- SRC/lyrpy/LUConsole.py +402 -0
- SRC/lyrpy/LUConst.py +358 -0
- SRC/lyrpy/LUDateTime.py +205 -0
- SRC/lyrpy/LUDecotators.py +417 -0
- SRC/lyrpy/LUDict.py +116 -0
- SRC/lyrpy/LUDoc.py +62 -0
- SRC/lyrpy/LUErrors.py +79 -0
- SRC/lyrpy/LUFile.py +1228 -0
- SRC/lyrpy/LUFileUtils.py +501 -0
- SRC/lyrpy/LULog.py +2324 -0
- SRC/lyrpy/LUNetwork.py +277 -0
- SRC/lyrpy/LUNumUtils.py +305 -0
- SRC/lyrpy/LUObjects.py +208 -0
- SRC/lyrpy/LUObjectsYT.py +846 -0
- SRC/lyrpy/LUParserARG.py +364 -0
- SRC/lyrpy/LUParserINI.py +376 -0
- SRC/lyrpy/LUParserREG.py +514 -0
- SRC/lyrpy/LUProc.py +110 -0
- SRC/lyrpy/LUQThread.py +141 -0
- SRC/lyrpy/LUQTimer.py +197 -0
- SRC/lyrpy/LUSheduler.py +941 -0
- SRC/lyrpy/LUStrDecode.py +223 -0
- SRC/lyrpy/LUStrUtils.py +633 -0
- SRC/lyrpy/LUSupport.py +124 -0
- SRC/lyrpy/LUTelegram.py +428 -0
- SRC/lyrpy/LUThread.py +177 -0
- SRC/lyrpy/LUTimer.py +141 -0
- SRC/lyrpy/LUVersion.py +383 -0
- SRC/lyrpy/LUYouTube.py +203 -0
- SRC/lyrpy/LUos.py +807 -0
- lyrpy/LUConst.py → SRC/lyrpy/LUsys.py +12 -10
- SRC/lyrpy/__init__.py +21 -0
- lyrpy/__init__.py → SRC/lyrpy/__main__.py +2 -3
- TESTS/__init__.py +0 -0
- TESTS/test_lyrpy.py +4 -0
- TESTS/test_main.py +10 -0
- __SRC/LIB/__init__.py +0 -0
- __SRC/LIB/lyrpy/LUConsole.py +402 -0
- __SRC/LIB/lyrpy/LUConst.py +358 -0
- __SRC/LIB/lyrpy/LUDateTime.py +205 -0
- __SRC/LIB/lyrpy/LUDecotators.py +417 -0
- __SRC/LIB/lyrpy/LUDict.py +116 -0
- __SRC/LIB/lyrpy/LUDoc.py +62 -0
- __SRC/LIB/lyrpy/LUErrors.py +79 -0
- __SRC/LIB/lyrpy/LUFile.py +1228 -0
- __SRC/LIB/lyrpy/LUFileUtils.py +501 -0
- __SRC/LIB/lyrpy/LULog.py +2324 -0
- __SRC/LIB/lyrpy/LUNetwork.py +277 -0
- __SRC/LIB/lyrpy/LUNumUtils.py +305 -0
- __SRC/LIB/lyrpy/LUObjects.py +208 -0
- __SRC/LIB/lyrpy/LUObjectsYT.py +846 -0
- __SRC/LIB/lyrpy/LUParserARG.py +364 -0
- __SRC/LIB/lyrpy/LUParserINI.py +376 -0
- __SRC/LIB/lyrpy/LUParserREG.py +514 -0
- __SRC/LIB/lyrpy/LUProc.py +110 -0
- __SRC/LIB/lyrpy/LUQThread.py +141 -0
- __SRC/LIB/lyrpy/LUQTimer.py +197 -0
- __SRC/LIB/lyrpy/LUSheduler.py +941 -0
- __SRC/LIB/lyrpy/LUStrDecode.py +223 -0
- __SRC/LIB/lyrpy/LUStrUtils.py +633 -0
- __SRC/LIB/lyrpy/LUSupport.py +124 -0
- __SRC/LIB/lyrpy/LUTelegram.py +428 -0
- __SRC/LIB/lyrpy/LUThread.py +177 -0
- __SRC/LIB/lyrpy/LUTimer.py +141 -0
- __SRC/LIB/lyrpy/LUVersion.py +383 -0
- __SRC/LIB/lyrpy/LUYouTube.py +203 -0
- __SRC/LIB/lyrpy/LUos.py +807 -0
- __SRC/LIB/lyrpy/LUsys.py +47 -0
- __SRC/LIB/lyrpy/__init__.py +21 -0
- __SRC/LIB/lyrpy/__main__.py +20 -0
- __SRC/__init__.py +0 -0
- ____src/__init__.py +0 -0
- ____src/lyrpy/LUConsole.py +402 -0
- ____src/lyrpy/LUConst.py +358 -0
- ____src/lyrpy/LUDateTime.py +205 -0
- ____src/lyrpy/LUDecotators.py +417 -0
- ____src/lyrpy/LUDict.py +116 -0
- ____src/lyrpy/LUDoc.py +62 -0
- ____src/lyrpy/LUErrors.py +79 -0
- ____src/lyrpy/LUFile.py +1228 -0
- ____src/lyrpy/LUFileUtils.py +501 -0
- ____src/lyrpy/LULog.py +2324 -0
- ____src/lyrpy/LUNetwork.py +277 -0
- ____src/lyrpy/LUNumUtils.py +305 -0
- ____src/lyrpy/LUObjects.py +208 -0
- ____src/lyrpy/LUObjectsYT.py +846 -0
- ____src/lyrpy/LUParserARG.py +364 -0
- ____src/lyrpy/LUParserINI.py +376 -0
- ____src/lyrpy/LUParserREG.py +514 -0
- ____src/lyrpy/LUProc.py +110 -0
- ____src/lyrpy/LUQThread.py +141 -0
- ____src/lyrpy/LUQTimer.py +197 -0
- ____src/lyrpy/LUSheduler.py +941 -0
- ____src/lyrpy/LUStrDecode.py +223 -0
- ____src/lyrpy/LUStrUtils.py +633 -0
- ____src/lyrpy/LUSupport.py +124 -0
- ____src/lyrpy/LUTelegram.py +428 -0
- ____src/lyrpy/LUThread.py +177 -0
- ____src/lyrpy/LUTimer.py +141 -0
- ____src/lyrpy/LUVersion.py +383 -0
- ____src/lyrpy/LUYouTube.py +203 -0
- ____src/lyrpy/LUos.py +807 -0
- ____src/lyrpy/LUsys.py +47 -0
- ____src/lyrpy/__init__.py +21 -0
- ____src/lyrpy/__main__.py +20 -0
- lyrpy-2025.0.2.dist-info/METADATA +21 -0
- lyrpy-2025.0.2.dist-info/RECORD +145 -0
- {lyrpy-2024.0.4.dist-info → lyrpy-2025.0.2.dist-info}/WHEEL +1 -1
- lyrpy-2025.0.2.dist-info/top_level.txt +2 -0
- lyrpy-2024.0.4.data/data/data/text.txt +0 -1
- lyrpy-2024.0.4.dist-info/METADATA +0 -44
- lyrpy-2024.0.4.dist-info/RECORD +0 -38
- lyrpy-2024.0.4.dist-info/top_level.txt +0 -1
- {lyrpy → SRC/LIB/lyrpy}/LUConsole.py +0 -0
- {lyrpy → SRC/LIB/lyrpy}/LUNetwork.py +0 -0
- {lyrpy → SRC/LIB/lyrpy}/LUNumUtils.py +0 -0
- {lyrpy → SRC/LIB/lyrpy}/LUProc.py +0 -0
- {lyrpy → SRC/LIB/lyrpy}/LUStrDecode.py +0 -0
- {lyrpy → SRC/LIB/lyrpy}/LUStrUtils.py +0 -0
- {lyrpy → SRC/LIB/lyrpy}/LUSupport.py +0 -0
- {lyrpy → SRC/LIB/lyrpy}/LUsys.py +0 -0
- {lyrpy-2024.0.4.dist-info → lyrpy-2025.0.2.dist-info/licenses}/LICENSE +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
|