warp-beacon 2.3.38__py3-none-any.whl → 2.3.40__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.
@@ -1,2 +1,2 @@
1
- __version__ = "2.3.38"
1
+ __version__ = "2.3.40"
2
2
 
@@ -80,6 +80,7 @@ class InstagramHuman(object):
80
80
  if random.random() > 0.6:
81
81
  logging.info("Simulation profile view ...")
82
82
  self.profile_view()
83
+ self.random_pause()
83
84
  except Exception as e:
84
85
  logging.warning("Error in evening_routine")
85
86
  logging.exception(e)
@@ -101,7 +102,9 @@ class InstagramHuman(object):
101
102
 
102
103
  def profile_view(self) -> None:
103
104
  try:
105
+ logging.info("profile_view ...")
104
106
  my_user_id = self.scrapler.cl.user_id
107
+ logging.info("user_following ...")
105
108
  friends = list(self.scrapler.download_hndlr(self.scrapler.cl.user_following, my_user_id, amount=random.randint(5, 50)).values())
106
109
  time.sleep(random.uniform(2, 5))
107
110
  if not friends:
@@ -111,15 +114,18 @@ class InstagramHuman(object):
111
114
  target_user_id = ""
112
115
  if isinstance(random_friend, UserShort):
113
116
  target_user_id = random_friend.pk
117
+ logging.info("user_info with target_user_id = '%s' ...", target_user_id)
114
118
  self.scrapler.download_hndlr(self.scrapler.cl.user_info, target_user_id)
115
119
  time.sleep(random.uniform(2, 5))
116
120
  elif isinstance(random_friend, str):
117
121
  target_user_id = self.scrapler.download_hndlr(self.scrapler.cl.user_id_from_username, random_friend)
122
+ logging.info("user_info with target_user_id = '%s' ...", target_user_id)
118
123
  self.scrapler.download_hndlr(self.scrapler.cl.user_info, target_user_id)
119
124
 
120
125
  time.sleep(random.uniform(2, 5))
121
126
 
122
127
  if random.random() > 0.7:
128
+ logging.info("user_medias with target_user_id = '%s' ...", target_user_id)
123
129
  self.scrapler.download_hndlr(self.scrapler.cl.user_medias, target_user_id, amount=random.randint(1, 5))
124
130
 
125
131
  self.random_pause()
@@ -38,6 +38,8 @@ class IGScheduler(object):
38
38
  if os.path.exists(self.state_file):
39
39
  with open(self.state_file, 'r', encoding="utf-8") as f:
40
40
  self.state = json.loads(f.read())
41
+ if "remaining" in self.state:
42
+ logging.info("Next scheduler activity in '%s' seconds", self.state["remaining"])
41
43
  except Exception as e:
42
44
  logging.error("Failed to load Scheduler state!")
43
45
  logging.exception(e)
@@ -89,7 +91,7 @@ class IGScheduler(object):
89
91
  self.save_state()
90
92
 
91
93
  if self.state["remaining"] <= 0:
92
- self.state["remaining"] = randrange(4100, 22300)
94
+ self.state["remaining"] = randrange(4292, 8623)
93
95
  logging.info("Next scheduler activity in '%s' seconds", self.state["remaining"])
94
96
 
95
97
  start_time = time.time()
@@ -54,6 +54,8 @@ def extract_exception_message(e: Exception) -> str:
54
54
  msg = e.message
55
55
  elif hasattr(e, "reason"):
56
56
  msg = e.reason
57
+ elif hasattr(e, "msg"):
58
+ msg = e.msg
57
59
  elif hasattr(e, "args"):
58
60
  msg = str(e.args)
59
61
 
@@ -7,26 +7,29 @@ import socket
7
7
  import ssl
8
8
  #from abc import abstractmethod
9
9
  from typing import Callable, Union, Optional
10
+ import logging
10
11
  import json
11
12
  import urllib
12
13
  import http.client
14
+ import pytubefix.exceptions
13
15
  import requests
14
16
  from PIL import Image
15
17
  import numpy as np
18
+ from urllib.parse import urlparse, parse_qs
16
19
 
17
- from warp_beacon.jobs.download_job import DownloadJob
18
- from warp_beacon.scraper.abstract import ScraperAbstract
19
- #from warp_beacon.mediainfo.abstract import MediaInfoAbstract
20
- from warp_beacon.scraper.exceptions import TimeOut, Unavailable, extract_exception_message
21
-
20
+ import pytubefix
22
21
  from pytubefix import YouTube
23
22
  from pytubefix.innertube import _default_clients
24
23
  from pytubefix.streams import Stream
25
24
  from pytubefix.innertube import InnerTube, _client_id, _client_secret
26
- from pytubefix.exceptions import VideoUnavailable, VideoPrivate, MaxRetriesExceeded
25
+ #from pytubefix.exceptions import VideoUnavailable, VideoPrivate, MaxRetriesExceeded
27
26
  from pytubefix import request
27
+ import yt_dlp
28
28
 
29
- import logging
29
+ from warp_beacon.jobs.download_job import DownloadJob
30
+ from warp_beacon.scraper.abstract import ScraperAbstract
31
+ #from warp_beacon.mediainfo.abstract import MediaInfoAbstract
32
+ from warp_beacon.scraper.exceptions import TimeOut, Unavailable, extract_exception_message
30
33
 
31
34
  def patched_fetch_bearer_token(self) -> None:
32
35
  """Fetch an OAuth token."""
@@ -101,13 +104,24 @@ class YoutubeAbstract(ScraperAbstract):
101
104
  os.rename(filename, new_filepath)
102
105
 
103
106
  return new_filepath
107
+
108
+ def get_video_id(self, url: str) -> Optional[str]:
109
+ parsed_url = urlparse(url)
110
+ query = parse_qs(parsed_url.query)
111
+ return query.get('v', [None])[0]
104
112
 
105
113
  def remove_tmp_files(self) -> None:
106
114
  for i in os.listdir(self.DOWNLOAD_DIR):
107
115
  if "yt_download_" in i:
108
116
  os.unlink("%s/%s" % (self.DOWNLOAD_DIR, i))
109
117
 
110
- def calculate_size_with_padding(self, image: Image, aspect_ratio_width: int, aspect_ratio_height: int, target_size: tuple=(320, 320), background_color: tuple=(0, 0, 0)) -> Image:
118
+ def calculate_size_with_padding(self,
119
+ image: Image,
120
+ aspect_ratio_width: int,
121
+ aspect_ratio_height: int,
122
+ target_size: tuple=(320, 320),
123
+ background_color: tuple=(0, 0, 0)
124
+ ) -> Image:
111
125
  aspect_ratio = aspect_ratio_width / aspect_ratio_height
112
126
  target_width, target_height = target_size
113
127
 
@@ -194,7 +208,7 @@ class YoutubeAbstract(ScraperAbstract):
194
208
  kwargs["timeout"] = timeout
195
209
  ret_val = func(*args, **kwargs)
196
210
  break
197
- except MaxRetriesExceeded:
211
+ except pytubefix.exceptions.MaxRetriesExceeded:
198
212
  # do noting, not interested
199
213
  pass
200
214
  #except http.client.IncompleteRead as e:
@@ -216,7 +230,21 @@ class YoutubeAbstract(ScraperAbstract):
216
230
  retries += 1
217
231
  timeout += timeout_increment
218
232
  time.sleep(pause_secs)
219
- except (VideoUnavailable, VideoPrivate) as e:
233
+ except (pytubefix.exceptions.VideoUnavailable, pytubefix.exceptions.VideoPrivate) as e:
234
+ raise Unavailable(extract_exception_message(e))
235
+ except yt_dlp.utils.DownloadError as e:
236
+ raise Unavailable(extract_exception_message(e))
237
+ except yt_dlp.utils.GeoRestrictedError:
238
+ raise Unavailable(extract_exception_message(e))
239
+ except yt_dlp.utils.PostProcessingError as e:
240
+ raise Unavailable(extract_exception_message(e))
241
+ except yt_dlp.utils.ExtractorError as e:
242
+ raise Unavailable(extract_exception_message(e))
243
+ except yt_dlp.utils.MaxDownloadsReached as e:
244
+ raise Unavailable(extract_exception_message(e))
245
+ except yt_dlp.utils.UnavailableVideoError as e:
246
+ raise Unavailable(extract_exception_message(e))
247
+ except yt_dlp.utils.ThrottledDownload as e:
220
248
  raise Unavailable(extract_exception_message(e))
221
249
 
222
250
  return ret_val
@@ -241,8 +269,8 @@ class YoutubeAbstract(ScraperAbstract):
241
269
  yt_opts["token_file"] = self.YT_SESSION_FILE % self.account_index
242
270
  if self.proxy:
243
271
  proxy_dsn = self.proxy.get("dsn", "")
272
+ logging.info("Using proxy DSN '%s'", proxy_dsn)
244
273
  if proxy_dsn:
245
- logging.info("Using proxy DSN '%s'", proxy_dsn)
246
274
  if "https://" in proxy_dsn:
247
275
  yt_opts["proxies"] = {"https": proxy_dsn}
248
276
  elif "http://" in proxy_dsn:
@@ -251,14 +279,44 @@ class YoutubeAbstract(ScraperAbstract):
251
279
  logging.warning("Proxy DSN malformed!")
252
280
  return YouTube(**yt_opts)
253
281
 
282
+ def build_yt_dlp(self) -> yt_dlp.YoutubeDL:
283
+ auth_data = {}
284
+ with open(self.YT_SESSION_FILE % self.account_index, 'r', encoding="utf-8") as f:
285
+ auth_data = json.loads(f.read())
286
+ time_name = str(time.time()).replace('.', '_')
287
+ ydl_opts = {
288
+ 'outtmpl': f'{self.DOWNLOAD_DIR}/{time_name}.%(ext)s',
289
+ 'format': 'bestvideo+bestaudio/best',
290
+ 'merge_output_format': 'mp4',
291
+ 'noplaylist': True,
292
+ 'tv_auth': auth_data
293
+ }
294
+
295
+ if self.proxy:
296
+ proxy_dsn = self.proxy.get("dsn", "")
297
+ logging.info("Using proxy DSN '%s'", proxy_dsn)
298
+ if proxy_dsn:
299
+ ydl_opts["proxy"] = proxy_dsn
300
+
301
+ return yt_dlp.YoutubeDL(ydl_opts)
302
+
254
303
  def _download(self, _: str) -> list:
255
304
  raise NotImplementedError("You should to implement _download method")
305
+
306
+ def _download_yt_dlp(self, _: str) -> list:
307
+ raise NotImplementedError("You should to implement _download_yt_dlp method")
256
308
 
257
309
  def download(self, job: DownloadJob) -> list:
310
+ ret = []
258
311
  try:
259
- return self.download_hndlr(self._download, job.url, session=False)
260
- except Unavailable:
261
- logging.warning("Failed sessionless download attempt. Trying with session.")
262
- time.sleep(2)
312
+ ret = self.download_hndlr(self._download, job.url, session=True)
313
+ except (Unavailable, TimeOut):
314
+ logging.warning("Download failed, trying to download with yt_dlp")
263
315
 
264
- return self.download_hndlr(self._download, job.url, session=True)
316
+ try:
317
+ ret = self.download_hndlr(self._download_yt_dlp, job.url)
318
+ except NotImplementedError:
319
+ logging.info("yt_dlp is not supported for this submodule yet")
320
+ raise Unavailable("Video unvailable")
321
+
322
+ return ret
@@ -1,10 +1,10 @@
1
- from warp_beacon.jobs.types import JobType
2
- from warp_beacon.scraper.youtube.abstract import YoutubeAbstract
3
- from warp_beacon.scraper.exceptions import YoutubeLiveError, NotFound, YotubeAgeRestrictedError
1
+ import logging
4
2
 
5
3
  from pytubefix.exceptions import AgeRestrictedError
6
4
 
7
- import logging
5
+ from warp_beacon.jobs.types import JobType
6
+ from warp_beacon.scraper.youtube.abstract import YoutubeAbstract
7
+ from warp_beacon.scraper.exceptions import YoutubeLiveError, NotFound, YotubeAgeRestrictedError
8
8
 
9
9
  class YoutubeScraper(YoutubeAbstract):
10
10
  YT_MAX_RETRIES_DEFAULT = 8
@@ -32,14 +32,14 @@ class YoutubeScraper(YoutubeAbstract):
32
32
  res = []
33
33
  try:
34
34
  thumbnail = None
35
+ video_id = self.get_video_id(url)
36
+ if video_id:
37
+ thumbnail = self.download_hndlr(self.download_thumbnail, video_id)
35
38
  yt = self.build_yt(url, session=session)
36
39
 
37
40
  if self.is_live(yt.initial_data):
38
41
  raise YoutubeLiveError("Youtube Live is not supported")
39
42
 
40
- if yt:
41
- thumbnail = self.download_hndlr(self.download_thumbnail, yt.video_id)
42
-
43
43
  stream = yt.streams.get_highest_resolution()
44
44
 
45
45
  if not stream:
@@ -65,4 +65,24 @@ class YoutubeScraper(YoutubeAbstract):
65
65
  except AgeRestrictedError as e:
66
66
  raise YotubeAgeRestrictedError("Youtube Age Restricted error")
67
67
 
68
+ return res
69
+
70
+ def _download_yt_dlp(self, url: str) -> list:
71
+ res = []
72
+ thumbnail = None
73
+ video_id = self.get_video_id(url)
74
+ if video_id:
75
+ thumbnail = self.download_hndlr(self.download_thumbnail, video_id)
76
+ with self.build_yt_dlp() as ydl:
77
+ info = ydl.extract_info(url, download=True)
78
+ local_file = ydl.prepare_filename(info)
79
+ logging.debug("Temp filename: '%s'", local_file)
80
+ res.append({
81
+ "local_media_path": local_file,
82
+ "performer": info.get("uploader", "Unknown"),
83
+ "thumb": thumbnail,
84
+ "canonical_name": info.get("title", ''),
85
+ "media_type": JobType.VIDEO
86
+ })
87
+
68
88
  return res
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: warp_beacon
3
- Version: 2.3.38
3
+ Version: 2.3.40
4
4
  Summary: Telegram bot for expanding external media links
5
5
  Home-page: https://github.com/sb0y/warp_beacon
6
6
  Author: Andrey Bagrintsev
@@ -237,10 +237,13 @@ Requires-Dist: pillow
237
237
  Requires-Dist: pymongo
238
238
  Requires-Dist: instagrapi==2.0.0
239
239
  Requires-Dist: bs4
240
+ Requires-Dist: yt_dlp
240
241
  Dynamic: author
241
242
  Dynamic: home-page
243
+ Dynamic: license-file
242
244
 
243
245
  # warp_beacon [![Upload Python Package](https://github.com/sb0y/warp_beacon/actions/workflows/python-publish.yml/badge.svg)](https://github.com/sb0y/warp_beacon/actions/workflows/python-publish.yml) [![Docker Image CI](https://github.com/sb0y/warp_beacon/actions/workflows/docker-image.yml/badge.svg)](https://github.com/sb0y/warp_beacon/actions/workflows/docker-image.yml) [![Build DEB package](https://github.com/sb0y/warp_beacon/actions/workflows/build-deb.yml/badge.svg)](https://github.com/sb0y/warp_beacon/actions/workflows/build-deb.yml)
246
+ > because content should travel freely
244
247
 
245
248
  Telegram bot for external social networks media links expanding.
246
249
  Works with a links in personal messages and also with group chats.
@@ -253,6 +256,24 @@ Just send a media link to the chat with bot and get a video or audio reply.
253
256
  |<img width="700" alt="Instagram Photo post usage example" src="https://github.com/user-attachments/assets/29324b94-7314-4a38-8790-3483011d355d"> Instagram Photo post usage example|<img width="700" alt="Instagram Photo Carousel usage" src="https://github.com/user-attachments/assets/2598e329-e16e-455e-91e9-a027e8994283"> Instagram Photo Carousel usage example|<img width="757" alt="Instagram Photo bulk Strories download usage example" src="https://github.com/user-attachments/assets/2c8c91ac-6ade-4d1d-a677-2b36bb40ff39"> Instagram Photo bulk Strories download usage example|
254
257
  |<img width="700" alt="Instagram specific Story download usage example" src="https://github.com/user-attachments/assets/03dc70c5-6933-4122-9c7c-5f7d734d117b"> Instagram specific Story download usage example|<img width="700" alt="Group chat usage example" src="https://github.com/user-attachments/assets/649fcb1e-785b-4efd-9153-69644c6d898b"> Group chat usage example|
255
258
 
259
+ ### **Warp Beacon manifesto**
260
+
261
+ > Once, the Internet was built as a borderless network — a space where knowledge, culture, and ideas could flow freely across the globe.
262
+ > But over time, freedom gave way to artificial walls, anti-bot shields, and region locks.
263
+ >
264
+ > **warp_beacon** is our answer to that shift.
265
+ >
266
+ > This is a tool for those who refuse to accept "access denied by geolocation" or "content unavailable in your region."
267
+ > It is a bridge over ML filters, CAPTCHAs, and man-made barriers.
268
+ >
269
+ > We don’t break the rules — we restore the original spirit of the Internet:
270
+ > 📡 **free exchange of information**,
271
+ > 🌍 **unrestricted access to global content**,
272
+ > 🤖 **tools that serve the user**, not the platform.
273
+ >
274
+ > **warp_beacon** — the freedom to deliver content where it’s needed most.
275
+
276
+ ## Configuration example ##
256
277
 
257
278
  In order to setup your own instance, you will need:
258
279
 
@@ -261,8 +282,6 @@ In order to setup your own instance, you will need:
261
282
 
262
283
  All bot configuration stored in [warp_beacon.conf](https://github.com/sb0y/warp_beacon/blob/main/etc/warp_beacon.conf) file.
263
284
 
264
- ## Configuration example ##
265
-
266
285
  ```env
267
286
  TG_TOKEN="you telegram token received from @BotFather"
268
287
  # these 3 settings should be obtained at https://my.telegram.org/apps
@@ -4,7 +4,7 @@ var/warp_beacon/accounts.json,sha256=OsXdncs6h88xrF_AP6_WDCK1waGBn9SR-uYdIeK37GM
4
4
  var/warp_beacon/placeholder.gif,sha256=cE5CGJVaop4Sx21zx6j4AyoHU0ncmvQuS2o6hJfEH88,6064
5
5
  var/warp_beacon/proxies.json,sha256=VnjlQDXumOEq72ZFjbh6IqHS1TEHqn8HPYAZqWCeSIA,95
6
6
  warp_beacon/__init__.py,sha256=_rThNODmz0nDp_n4mWo_HKaNFE5jk1_7cRhHyYaencI,163
7
- warp_beacon/__version__.py,sha256=UmnivgpTPX3WFWoDJST4G4YTbxaMmCEc5cNERYmejdE,24
7
+ warp_beacon/__version__.py,sha256=OcXHHYWlAUshE_Yj-PGDQ_nKxIqsPouQB_HoWAmNDZA,24
8
8
  warp_beacon/warp_beacon.py,sha256=7KEtZDj-pdhtl6m-zFLsSojs1ZR4o7L0xbqtdmYPvfE,342
9
9
  warp_beacon/compress/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  warp_beacon/compress/video.py,sha256=_PDMVYCyzLYxHv1uZmmzGcG_8rjaZr7BTXsXTTy_oS4,2846
@@ -19,21 +19,21 @@ warp_beacon/mediainfo/audio.py,sha256=ous88kwQj4bDIChN5wnGil5LqTs0IQHH0d-nyrL0-Z
19
19
  warp_beacon/mediainfo/silencer.py,sha256=qxMuViOoVwUYb60uCVvqHiGrqByR1_4_rqMT-XdMkwc,1813
20
20
  warp_beacon/mediainfo/video.py,sha256=UBZrhTN5IDI-aYu6tsJEILo9nFkjHhkldGVFmvV7tEI,2480
21
21
  warp_beacon/scheduler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- warp_beacon/scheduler/instagram_human.py,sha256=b_Ec775QchL88X3JEZeO3EYrQ9Cj1BjVzuIX0EmqRYg,4689
23
- warp_beacon/scheduler/scheduler.py,sha256=2y2eDBxkE5vHRpSVcV-mwYnxFuueMalK3LOhgUecNSA,2796
22
+ warp_beacon/scheduler/instagram_human.py,sha256=K3S14uav0UBZidtREYwgCOCDKyDfWbay5GH-DWMK_JI,5020
23
+ warp_beacon/scheduler/scheduler.py,sha256=ddPhExSgj_RGR1eSDlIm0hVgTVM_76UEMEl9i-eYuQ8,2915
24
24
  warp_beacon/scraper/__init__.py,sha256=V_C5SmAmRtjFfVBtTotOHCW3ILMQ8m_ulrBF6ry59_A,16944
25
25
  warp_beacon/scraper/abstract.py,sha256=28a0aBKZpi8IKptLWdB6RuVbOkrUbrhT7LSZX7QRQtg,2725
26
26
  warp_beacon/scraper/account_selector.py,sha256=oqwtyT2_xBYkx_7ysoz0VLa-x8EpiBifmF12MUNLCW8,5316
27
- warp_beacon/scraper/exceptions.py,sha256=Qkz76yo-X5kucEZIP9tWaK-oYO-kvsPEl8Y0W63oDhU,1300
27
+ warp_beacon/scraper/exceptions.py,sha256=QBHLA8hK1sL8uJu5JhidbXoBXPZtMMtV26nYfHvO4NU,1339
28
28
  warp_beacon/scraper/fail_handler.py,sha256=_blvckfTZ4xWVancQKVRXH5ClKGwfrBxMwvXIFZh1qA,975
29
29
  warp_beacon/scraper/link_resolver.py,sha256=Rc9ZuMyOo3iPywDHwjngy-WRQ2SXhJwxcg-5ripx7tM,2447
30
30
  warp_beacon/scraper/instagram/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  warp_beacon/scraper/instagram/instagram.py,sha256=TpIBS9S3zcLbeGax4CENVo6WP75EE6oIttc-MjWYVjs,13815
32
32
  warp_beacon/scraper/youtube/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- warp_beacon/scraper/youtube/abstract.py,sha256=HnjSTGumo4uzxEZydH18zhsqMrus38Vx3SRGhuuXl0c,9707
33
+ warp_beacon/scraper/youtube/abstract.py,sha256=RcGmSu9E3o1TKD3EvU3C7y3uBKdHxnk3wEIV06oHWWk,11629
34
34
  warp_beacon/scraper/youtube/music.py,sha256=6FIU1tqKvW7Osh3jg8fqli2W30Lgp_GM33S9lfOnk0s,1418
35
35
  warp_beacon/scraper/youtube/shorts.py,sha256=k3yGF9b8HTzNE6h4VE0zsMGB6kWP-V2xiLhIY3QZXvs,1269
36
- warp_beacon/scraper/youtube/youtube.py,sha256=TH5od6UPh1lAzDU_UC9Y5uQ-O8scLfk6OWWKWLF6LDo,2173
36
+ warp_beacon/scraper/youtube/youtube.py,sha256=AC93ianrdI94VqL0WXAqnkekxLtzyY39N0sMcaNoYEo,2812
37
37
  warp_beacon/storage/__init__.py,sha256=0Vajd0oITKJfu2vmNx5uQSt3-L6vwIvUYWJo8HZCjco,3398
38
38
  warp_beacon/storage/mongo.py,sha256=qC4ZiO8XXvPnP0rJwz4CJx42pqFsyAjCiW10W5QdT6E,527
39
39
  warp_beacon/telegram/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -43,9 +43,9 @@ warp_beacon/telegram/handlers.py,sha256=XXIfdV_RCj7tyZMPXchuKmGoDdweOaR08ADDaBPW
43
43
  warp_beacon/telegram/placeholder_message.py,sha256=wN9-BRiyrtHG-EvXtZkGJHt2CX71munQ57ITttjt0mw,6400
44
44
  warp_beacon/telegram/utils.py,sha256=9uebX53G16mV7ER7WgfdWBLFHHw14S8HBt9URrIskg0,4440
45
45
  warp_beacon/uploader/__init__.py,sha256=E9rlZIf7xlQz6MutMOwJ8S5Vm2uheR5nv23Kv8duRQg,5427
46
- warp_beacon-2.3.38.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
47
- warp_beacon-2.3.38.dist-info/METADATA,sha256=JO259Z3taKEgcBQuqqnH1kRnnuHy8_gcKL9ORRgIf4U,21723
48
- warp_beacon-2.3.38.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
49
- warp_beacon-2.3.38.dist-info/entry_points.txt,sha256=eSB61Rb89d56WY0O-vEIQwkn18J-4CMrJcLA_R_8h3g,119
50
- warp_beacon-2.3.38.dist-info/top_level.txt,sha256=qGjHVVfyf6lTmbdSA-fQq0rHS1YVS4HoJT3rag5xgPE,1141
51
- warp_beacon-2.3.38.dist-info/RECORD,,
46
+ warp_beacon-2.3.40.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
47
+ warp_beacon-2.3.40.dist-info/METADATA,sha256=0vPgdw0j-VSzzoSeWP4x16Nz8NS9_3buYiKiUUN40GQ,22626
48
+ warp_beacon-2.3.40.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
49
+ warp_beacon-2.3.40.dist-info/entry_points.txt,sha256=eSB61Rb89d56WY0O-vEIQwkn18J-4CMrJcLA_R_8h3g,119
50
+ warp_beacon-2.3.40.dist-info/top_level.txt,sha256=qGjHVVfyf6lTmbdSA-fQq0rHS1YVS4HoJT3rag5xgPE,1141
51
+ warp_beacon-2.3.40.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.1.0)
2
+ Generator: setuptools (77.0.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5