podflow 20250127__py3-none-any.whl → 20250130__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.
@@ -35,7 +35,7 @@ def download_video(
35
35
  pass
36
36
 
37
37
  def error(self, msg):
38
- msg = fail_message_initialize(msg, video_url)
38
+ msg = fail_message_initialize(msg, video_url).ljust(45)
39
39
  print(msg)
40
40
 
41
41
  outtmpl = f"channel_audiovisual/{output_dir}/{video_url}{sesuffix}.{output_format}"
@@ -68,15 +68,16 @@ def download_video(
68
68
  ydl.download([f"{video_website}"]) # 下载指定视频链接的视频
69
69
  return None, None
70
70
  except Exception as download_video_error:
71
- fail_info = fail_message_initialize(download_video_error, video_url)
71
+ fail_info = fail_message_initialize(download_video_error, video_url).replace("\n","")
72
72
  remove_info = ""
73
73
  if fail_info in [
74
+ "",
74
75
  "\033[31m请求拒绝\033[0m",
75
76
  "\033[31m数据不完整\033[0m",
76
77
  "\033[31m传输中断\033[0m",
77
78
  "\033[31m请求超时\033[0m",
78
79
  "\033[31m响应超时\033[0m",
79
- ]:
80
+ ] and "www.youtube.com" in video_website:
80
81
  if os.path.isfile(outtmpl):
81
82
  os.remove(outtmpl)
82
83
  remove_info = "|已删除失败文件"
@@ -29,10 +29,16 @@ def duration_and_formats(video_website, video_url, cookies):
29
29
  "logger": MyLogger(),
30
30
  }
31
31
  if cookies:
32
- ydl_opts["http_headers"] = {
33
- "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
34
- "Referer": "https://www.bilibili.com/",
35
- }
32
+ if "www.bilibili.com" in video_website:
33
+ ydl_opts["http_headers"] = {
34
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
35
+ "Referer": "https://www.bilibili.com/",
36
+ }
37
+ elif "www.youtube.com" in video_website:
38
+ ydl_opts["http_headers"] = {
39
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
40
+ "Referer": "https://www.youtube.com/",
41
+ }
36
42
  ydl_opts["cookiefile"] = cookies # cookies 是你的 cookies 文件名
37
43
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
38
44
  # 使用提供的 URL 提取视频信息
Podflow/youtube/build.py CHANGED
@@ -21,6 +21,7 @@ from Podflow.message.xml_original_item import xml_original_item
21
21
  def get_youtube_introduction():
22
22
  # 创建线程锁
23
23
  youtube_xml_get_lock = threading.Lock()
24
+
24
25
  # 使用http获取youtube频道简介和图标模块
25
26
  def youtube_xml_get(output_dir):
26
27
  if channel_about := http_client(
@@ -47,6 +48,7 @@ def get_youtube_introduction():
47
48
  ).group()
48
49
  with youtube_xml_get_lock:
49
50
  gVar.youtube_xml_get_tree[output_dir] = xml_tree
51
+
50
52
  # 创建线程列表
51
53
  youtube_xml_get_threads = []
52
54
  for output_dir in gVar.channelid_youtube_ids_update:
@@ -67,26 +69,43 @@ def get_youtube_playlist(url, channelid_title):
67
69
  0
68
70
  ]["tabRenderer"]["content"]["sectionListRenderer"]["contents"][0][
69
71
  "itemSectionRenderer"
70
- ][
71
- "contents"
72
- ][
73
- 0
74
- ][
75
- "playlistVideoListRenderer"
76
- ][
77
- "contents"
78
- ]
72
+ ]["contents"][0]["playlistVideoListRenderer"]["contents"]
79
73
  videoids.extend(
80
74
  content["playlistVideoRenderer"]["videoId"] for content in contents
81
75
  )
82
76
  return videoids
83
77
 
84
78
 
79
+ # 从HTML获取YouTube媒体信息模块
80
+ def youtube_html_guid_message(guid):
81
+ ytInitialPlayerResponse = get_html_dict(
82
+ f"https://www.youtube.com/watch?v={guid}",
83
+ f"{guid} HTML",
84
+ "ytInitialPlayerResponse",
85
+ )
86
+ try:
87
+ image = ytInitialPlayerResponse["microformat"]["playerMicroformatRenderer"][
88
+ "thumbnail"
89
+ ]["thumbnails"][0]["url"]
90
+ title = ytInitialPlayerResponse["microformat"]["playerMicroformatRenderer"][
91
+ "title"
92
+ ]["simpleText"]
93
+ description = ytInitialPlayerResponse["microformat"][
94
+ "playerMicroformatRenderer"
95
+ ]["description"]["simpleText"]
96
+ published = ytInitialPlayerResponse["microformat"]["playerMicroformatRenderer"][
97
+ "publishDate"
98
+ ]
99
+ return published, image, title, description
100
+ except KeyError:
101
+ return None
102
+
103
+
85
104
  # 生成YouTube的item模块
86
105
  def youtube_xml_item(entry, title_change=None):
87
106
  if title_change is None:
88
107
  title_change = {}
89
- # sourcery skip: avoid-builtin-shadow
108
+
90
109
  # 输入时间字符串和原始时区
91
110
  time_str = re.search(r"(?<=<published>).+(?=</published>)", entry).group()
92
111
  pubDate = format_time(time_str)
@@ -115,14 +134,21 @@ def get_xml_item(guid, item, channelid_title, title_change, output_dir):
115
134
  video_website = f"https://youtube.com/watch?v={guid}"
116
135
  if item["yt-dlp"]:
117
136
  guid_value = gVar.video_id_update_format[guid]
118
- title = html.escape(guid_value["title"])
119
- description = html.escape(re.sub(r"\n+", "\n", guid_value["description"]))
120
- timestamp = guid_value["timestamp"]
121
- published = datetime.fromtimestamp(timestamp, timezone.utc).strftime(
122
- "%Y-%m-%dT%H:%M:%S%z"
123
- )
137
+ if timestamp := guid_value["timestamp"]:
138
+ published = datetime.fromtimestamp(timestamp, timezone.utc).strftime(
139
+ "%Y-%m-%dT%H:%M:%S%z"
140
+ )
141
+ title = guid_value["title"]
142
+ description = guid_value["description"]
143
+ image = guid_value["image"]
144
+ elif guid_message := youtube_html_guid_message(guid):
145
+ published, image, title, description = guid_message
146
+ else:
147
+ return None
148
+ title = html.escape(title)
149
+ description = html.escape(re.sub(r"\n+", "\n", description))
150
+ image = re.sub(r"\?.*$", "", image)
124
151
  pubDate = format_time(published)
125
- image = re.sub(r"\?.*$", "", guid_value["image"])
126
152
  else:
127
153
  title = html.escape(item["title"])
128
154
  description = html.escape(re.sub(r"\n+", "\n", item["description"]))
@@ -164,16 +190,16 @@ def youtube_xml_items(output_dir):
164
190
  for guid in output_dir_value["content"]["list"]:
165
191
  if guid not in gVar.video_id_failed:
166
192
  item = output_dir_value["content"]["item"][guid]
167
- xml_item_text = get_xml_item(
193
+ if xml_item_text := get_xml_item(
168
194
  guid, item, channelid_title, title_change, output_dir
169
- )
170
- items_list.append(f"{xml_item_text}<!-- {output_dir} -->")
171
- entry_num += 1
172
- if (
173
- gVar.video_id_update_format[guid]["description"]
174
- and gVar.video_id_update_format[guid]["description"][0] == "『"
175
195
  ):
176
- original_judgment = False
196
+ items_list.append(f"{xml_item_text}<!-- {output_dir} -->")
197
+ entry_num += 1
198
+ if (
199
+ gVar.video_id_update_format[guid]["description"]
200
+ and gVar.video_id_update_format[guid]["description"][0] == "『"
201
+ ):
202
+ original_judgment = False
177
203
  else:
178
204
  if output_dir_value["type"] == "html": # 获取最新的rss信息
179
205
  file_xml = output_dir_value["content"].text
@@ -217,14 +243,14 @@ def youtube_xml_items(output_dir):
217
243
  for backward_guid in backward["list"]:
218
244
  if backward_guid not in gVar.video_id_failed:
219
245
  backward_item = backward["item"][backward_guid]
220
- backward_xml_item_text = get_xml_item(
246
+ if backward_xml_item_text := get_xml_item(
221
247
  backward_guid,
222
248
  backward_item,
223
249
  channelid_title,
224
250
  title_change,
225
251
  output_dir,
226
- )
227
- items_list.append(f"{backward_xml_item_text}<!-- {output_dir} -->")
252
+ ):
253
+ items_list.append(f"{backward_xml_item_text}<!-- {output_dir} -->")
228
254
  # 生成对应xml
229
255
  try:
230
256
  with open(
Podflow/youtube/get.py CHANGED
@@ -15,61 +15,73 @@ from Podflow.basic.list_merge_tidy import list_merge_tidy
15
15
 
16
16
  # 从YouTube播放列表获取更新模块
17
17
  def get_youtube_html_playlists(
18
- youtube_key,
19
- youtube_value,
20
- guids=[""],
21
- direction_forward=True,
22
- update_size=20,
23
- youtube_content_ytid_original=[],
18
+ youtube_key, # YouTube 频道的唯一标识
19
+ youtube_value, # YouTube 账户或其他标识信息
20
+ guids=None, # 视频 ID 列表(用于比较已有视频)
21
+ direction_forward=True, # 控制获取方向,默认向前获取新的视频
22
+ update_size=20, # 更新数量限制,最多获取 20 个新视频
23
+ youtube_content_ytid_original=None, # 原始 YouTube 视频 ID 列表
24
24
  ):
25
- idlist = []
26
- item = {}
27
- threads = []
28
- fail = []
25
+ idlist = [] # 存储新获取的 YouTube 视频 ID
26
+ item = {} # 存储视频信息(标题、描述、封面等)
27
+ threads = [] # 线程列表,用于并发获取视频详细信息
28
+ fail = [] # 存储获取失败的视频 ID
29
+
30
+ if guids is None:
31
+ guids = [""]
32
+ if youtube_content_ytid_original is None:
33
+ youtube_content_ytid_original = []
34
+
29
35
  try:
30
- videoid_start = guids[0] if direction_forward else guids[-1]
36
+ videoid_start = guids[0] if direction_forward else guids[-1] # 获取起始视频 ID
31
37
  except IndexError:
32
- videoid_start = ""
38
+ videoid_start = "" # 处理空列表情况,避免 IndexError
33
39
 
34
- # 获取媒体相关信息模块
40
+ # 获取视频详细信息的内部函数
35
41
  def get_video_item(videoid, youtube_value):
36
42
  yt_Initial_Player_Response = get_html_dict(
37
43
  f"https://www.youtube.com/watch?v={videoid}",
38
44
  f"{youtube_value}|{videoid}",
39
45
  "ytInitialPlayerResponse",
40
- )
46
+ ) # 解析 YouTube 页面,获取视频信息
41
47
  if not yt_Initial_Player_Response:
42
- return None
48
+ return None # 若获取失败,则返回 None
49
+
43
50
  try:
44
51
  player_Microformat_Renderer = yt_Initial_Player_Response["microformat"][
45
52
  "playerMicroformatRenderer"
46
53
  ]
47
54
  except (KeyError, TypeError, IndexError, ValueError):
48
- player_Microformat_Renderer = {}
49
- fail.append(videoid)
55
+ player_Microformat_Renderer = {} # 解析失败时,返回空字典
56
+ fail.append(videoid) # 记录失败的视频 ID
57
+
50
58
  if player_Microformat_Renderer:
51
59
  try:
52
60
  item[videoid]["description"] = player_Microformat_Renderer[
53
61
  "description"
54
62
  ]["simpleText"]
55
63
  except (KeyError, TypeError, IndexError, ValueError):
56
- item[videoid]["description"] = ""
57
- item[videoid]["pubDate"] = player_Microformat_Renderer["publishDate"]
64
+ item[videoid]["description"] = "" # 若没有描述,则置为空
65
+ item[videoid]["pubDate"] = player_Microformat_Renderer[
66
+ "publishDate"
67
+ ] # 获取发布时间
58
68
  item[videoid]["image"] = player_Microformat_Renderer["thumbnail"][
59
69
  "thumbnails"
60
- ][0]["url"]
70
+ ][0]["url"] # 获取封面图
61
71
  with contextlib.suppress(KeyError, TypeError, IndexError, ValueError):
62
- fail.remove(videoid)
72
+ fail.remove(videoid) # 若成功获取,则从失败列表中移除
63
73
  else:
64
- return None
74
+ return None # 若无有效数据,返回 None
65
75
 
76
+ # 获取播放列表数据
66
77
  yt_initial_data = get_html_dict(
67
- f"https://www.youtube.com/watch?v={videoid_start}&list=UULF{youtube_key[-22:]}",
78
+ f"https://www.youtube.com/watch?v={videoid_start}&list=UU{youtube_key[-22:]}",
68
79
  f"{youtube_value} HTML",
69
80
  "ytInitialData",
70
- )
81
+ ) # 解析 YouTube 播放列表页面,获取数据
71
82
  if not yt_initial_data:
72
- return None
83
+ return None # 若获取失败,则返回 None
84
+
73
85
  try:
74
86
  playlists = yt_initial_data["contents"]["twoColumnWatchNextResults"][
75
87
  "playlist"
@@ -78,74 +90,70 @@ def get_youtube_html_playlists(
78
90
  "playlist"
79
91
  ]["playlist"]["ownerName"]["simpleText"]
80
92
  except (KeyError, TypeError, IndexError, ValueError):
81
- return None
93
+ return None # 若解析失败,返回 None
94
+
95
+ # 若方向是向前获取(最新视频)或没有起始视频 ID
82
96
  if direction_forward or not videoid_start:
83
97
  for playlist in playlists:
84
- videoid = playlist["playlistPanelVideoRenderer"]["videoId"]
98
+ videoid = playlist["playlistPanelVideoRenderer"]["videoId"] # 提取视频 ID
85
99
  if (
86
100
  playlist["playlistPanelVideoRenderer"]["navigationEndpoint"][
87
101
  "watchEndpoint"
88
102
  ]["index"]
89
103
  == update_size
90
104
  ):
91
- break
92
- if videoid not in guids:
93
- title = playlist["playlistPanelVideoRenderer"]["title"]["simpleText"]
94
- idlist.append(videoid)
95
- item[videoid] = {
96
- "title": title,
97
- "yt-dlp": True,
98
- }
99
- if videoid in youtube_content_ytid_original:
100
- item[videoid]["yt-dlp"] = False
105
+ break # 如果达到更新上限,则停止
106
+ if videoid not in guids: # 确保视频 ID 不是已存在的
107
+ title = playlist["playlistPanelVideoRenderer"]["title"][
108
+ "simpleText"
109
+ ] # 获取视频标题
110
+ idlist.append(videoid) # 添加到 ID 列表
111
+ item[videoid] = {"title": title, "yt-dlp": True} # 记录视频信息
112
+ if videoid in youtube_content_ytid_original: # 若视频已在原始列表中
113
+ item[videoid]["yt-dlp"] = False # 标记为已存在
101
114
  item_thread = threading.Thread(
102
- target=get_video_item,
103
- args=(
104
- videoid,
105
- youtube_value,
106
- ),
107
- )
115
+ target=get_video_item, args=(videoid, youtube_value)
116
+ ) # 启动线程获取详细信息
108
117
  item_thread.start()
109
118
  threads.append(item_thread)
110
- else:
119
+ else: # 处理向后获取(获取较旧的视频)
111
120
  reversed_playlists = []
112
121
  for playlist in reversed(playlists):
113
122
  videoid = playlist["playlistPanelVideoRenderer"]["videoId"]
114
123
  if videoid not in guids:
115
- reversed_playlists.append(playlist)
124
+ reversed_playlists.append(playlist) # 收集未存在的旧视频
116
125
  else:
117
- break
126
+ break # 如果找到已存在的视频 ID,则停止
127
+
118
128
  for playlist in reversed(reversed_playlists[-update_size:]):
119
129
  videoid = playlist["playlistPanelVideoRenderer"]["videoId"]
120
130
  title = playlist["playlistPanelVideoRenderer"]["title"]["simpleText"]
121
131
  idlist.append(videoid)
122
- item[videoid] = {
123
- "title": title,
124
- "yt-dlp": True,
125
- }
132
+ item[videoid] = {"title": title, "yt-dlp": True}
126
133
  if videoid in youtube_content_ytid_original:
127
134
  item[videoid]["yt-dlp"] = False
128
135
  item_thread = threading.Thread(
129
- target=get_video_item,
130
- args=(
131
- videoid,
132
- youtube_value,
133
- ),
136
+ target=get_video_item, args=(videoid, youtube_value)
134
137
  )
135
138
  item_thread.start()
136
139
  threads.append(item_thread)
140
+
137
141
  for thread in threads:
138
- thread.join()
142
+ thread.join() # 等待所有线程完成
143
+
144
+ # 处理获取失败的视频
139
145
  for videoid in fail:
140
- get_video_item(videoid, youtube_value)
141
- if fail:
146
+ get_video_item(videoid, youtube_value) # 重新尝试获取失败的视频
147
+
148
+ if fail: # 如果仍然有失败的视频
142
149
  if direction_forward or not videoid_start:
143
150
  for videoid in fail:
144
151
  print(
145
152
  f"{datetime.now().strftime('%H:%M:%S')}|{youtube_value}|{videoid} HTML无法更新, 将不获取"
146
153
  )
147
- idlist.remove(videoid)
148
- del item[videoid]
154
+ if videoid in idlist:
155
+ idlist.remove(videoid) # 安全地移除视频 ID,避免 `ValueError`
156
+ del item[videoid] # 删除对应的字典项
149
157
  else:
150
158
  print(
151
159
  f"{datetime.now().strftime('%H:%M:%S')}|{youtube_value} HTML有失败只更新部分"
@@ -153,12 +161,14 @@ def get_youtube_html_playlists(
153
161
  index = len(idlist)
154
162
  for videoid in fail:
155
163
  if videoid in idlist:
156
- index = min(idlist.index(videoid), index)
157
- idlist_fail = idlist[index:]
158
- idlist = idlist[:index]
164
+ index = min(idlist.index(videoid), index) # 计算最早失败视频的索引
165
+ idlist_fail = idlist[index:] # 截取失败的视频 ID 列表
166
+ idlist = idlist[:index] # 只保留成功的视频 ID
159
167
  for videoid in idlist_fail:
160
- idlist.remove(videoid)
161
- return {"list": idlist, "item": item, "title": main_title}
168
+ if videoid in idlist:
169
+ idlist.remove(videoid) # 安全删除失败视频 ID
170
+
171
+ return {"list": idlist, "item": item, "title": main_title} # 返回最终结果
162
172
 
163
173
 
164
174
  def get_youtube_shorts_id(youtube_key, youtube_value):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: podflow
3
- Version: 20250127
3
+ Version: 20250130
4
4
  Summary: A podcast server that includes YouTube and BiliBili
5
5
  Home-page: https://github.com/gruel-zxz/podflow
6
6
  Author: gruel_zxz
@@ -15,7 +15,7 @@ Description-Content-Type: text/markdown
15
15
  Requires-Dist: astral>=3.2
16
16
  Requires-Dist: bottle>=0.13.2
17
17
  Requires-Dist: qrcode>=8.0
18
- Requires-Dist: yt-dlp>=2025.1.15
18
+ Requires-Dist: yt-dlp>=2025.1.26
19
19
  Requires-Dist: chardet>=5.2.0
20
20
  Requires-Dist: cherrypy>=18.10.0
21
21
  Requires-Dist: requests>=2.32.3
@@ -31,7 +31,7 @@ Podflow/config/get_config.py,sha256=xM_C1Vk5EUAdPKwR7guPSo2IVR_QOZ-EFHfbmtMtm30,
31
31
  Podflow/download/__init__.py,sha256=1TgjbOdcnnPTBMXpzqaazcN50EUomBW0zHN0wXAa3cM,47
32
32
  Podflow/download/convert_bytes.py,sha256=33Fgeyt-yEmysFZaj23tGtjUkUtHuKZohRKR4TxOxyg,543
33
33
  Podflow/download/delete_part.py,sha256=G9lK8G8tOOmnEBmAHJKPdqPeLhJ61S5m8o6iL5g9SyE,679
34
- Podflow/download/dl_aideo_video.py,sha256=6PpzQF1sdGU24ruq0g3olLAWM_nVyPQ2dFp05wvJCUA,9916
34
+ Podflow/download/dl_aideo_video.py,sha256=DDB03WfBzqHW9NOozGN6gj4BwG4jyiW79-_fbfVBX9c,9998
35
35
  Podflow/download/show_progress.py,sha256=7oGzhj_frO2A1o5JeGuHn7bHtma5oPpD_IWcctIO2rs,1595
36
36
  Podflow/download/wait_animation.py,sha256=E2V3cm-10e5Iif40oU722OfzDe7YiLMbDqsjZ6dshBE,1056
37
37
  Podflow/download/youtube_and_bilibili_download.py,sha256=jt6CWb8ZJ-dyIom7fJ_K1qve9pSzoW0hNwfWnZiju7w,1228
@@ -53,7 +53,7 @@ Podflow/message/get_original_rss.py,sha256=CK_Q5enOzUafgL2l5OlXBpC08Nj_B7AKPzw5D
53
53
  Podflow/message/get_video_format.py,sha256=RIX0fxuPYkoQPRWt-ulJPhfEWtMkyxwOEVqcuRsp4v8,4770
54
54
  Podflow/message/get_video_format_multithread.py,sha256=ZXzY9RwT59eOvP6Lmx-I07P3C1CWCl-4l_uw_pkozqE,1406
55
55
  Podflow/message/get_youtube_and_bilibili_video_format.py,sha256=RuaxL3JwZs3_Bqm77g9SIcyV8o-WJu_qOCWhEnD15WE,4321
56
- Podflow/message/media_format.py,sha256=zCiUixdk5ZvZz9J0OS3BFw8sHPgR3Jdb1tu7aLLg9uU,6948
56
+ Podflow/message/media_format.py,sha256=WH0NnjWPLigU8Wy2kbqDIhj_RISnaCCXtsR5qIjLFdU,7346
57
57
  Podflow/message/original_rss_fail_print.py,sha256=pVVb_BGM1HofHDh9pCX5GS03gOnNAssfHDjj5Ytz_mw,502
58
58
  Podflow/message/rss_create_hash.py,sha256=NODhtprDPkpiuiezupARKm5Xr4Zt2Io_lcxmHedPAQc,638
59
59
  Podflow/message/title_correction.py,sha256=JR2q3PubOUUAfQEPjIzeRzUe4Jy86opGIO1st51qt2g,915
@@ -70,11 +70,11 @@ Podflow/remove/__init__.py,sha256=kns-jfTXH8lXh9OQ5E5-llsrAPlET5rl6RYpjoZKav8,45
70
70
  Podflow/remove/remove_dir.py,sha256=tah3LCD0bCcf5dDg3NrHuseaje3-31C5NLNupMg15TU,1099
71
71
  Podflow/remove/remove_file.py,sha256=R8Gr0d6bIAYKQ7YEfFl5_QJ_CcumTu_8XejP7xuRm2k,981
72
72
  Podflow/youtube/__init__.py,sha256=-bdMyuw-wxoz2miVkp284amS4Qg0k7VN0JPuGF-cXlM,46
73
- Podflow/youtube/build.py,sha256=PnRr_nI_DIMDF0IPZUIuO8mJBB57FS-VZNTYHVzRQKI,10143
74
- Podflow/youtube/get.py,sha256=Frk7NMAUpqyeoCHBplTu6P3C9lHXyMmnyUg3XxSuUnw,15171
73
+ Podflow/youtube/build.py,sha256=y1R5KI_R8ydYjjxZKvMtNaHUiyMm4iBa-MIEMbA92FY,11210
74
+ Podflow/youtube/get.py,sha256=dFLyiHttygqdJltwC29jD_v8wwoLynE5NUdow_0wERI,16970
75
75
  Podflow/youtube/login.py,sha256=DlS_ZG4g6CKWqS5ojE4UwFJSCSZDsXbeuDVgHtQAa4A,1380
76
- podflow-20250127.dist-info/METADATA,sha256=rVgZbUHkV4olDbi-mvMDHtiPl8tYTaw5yXppBNqDJuk,13801
77
- podflow-20250127.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
78
- podflow-20250127.dist-info/entry_points.txt,sha256=44nj8jJB7bo1JLNrKQZmwMGEA1OalrALJ0tF_G0yXLY,131
79
- podflow-20250127.dist-info/top_level.txt,sha256=KcvRCiz_DRWWc9i-PgpARvFB0J4CKmpZOZgPqOdG-Lk,8
80
- podflow-20250127.dist-info/RECORD,,
76
+ podflow-20250130.dist-info/METADATA,sha256=iGZO9mepzFymSkKGPRHulbz4avh3uzGaqXijdh6vUbo,13801
77
+ podflow-20250130.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
78
+ podflow-20250130.dist-info/entry_points.txt,sha256=44nj8jJB7bo1JLNrKQZmwMGEA1OalrALJ0tF_G0yXLY,131
79
+ podflow-20250130.dist-info/top_level.txt,sha256=KcvRCiz_DRWWc9i-PgpARvFB0J4CKmpZOZgPqOdG-Lk,8
80
+ podflow-20250130.dist-info/RECORD,,