warp-beacon 2.3.51__py3-none-any.whl → 2.4.1__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.51"
1
+ __version__ = "2.4.1"
2
2
 
@@ -121,6 +121,11 @@ class AsyncDownloader(object):
121
121
  if job.job_origin is Origin.INSTAGRAM:
122
122
  from warp_beacon.scraper.instagram.instagram import InstagramScraper
123
123
  actor = InstagramScraper(selector.get_current(), proxy)
124
+ selector.inc_ig_request_count()
125
+ if selector.get_ig_request_count() >= int(os.environ.get("IG_REQUESTS_PER_ACCOUNT", default="20")):
126
+ logging.info("The account request limit has been reached. Selecting the next account.")
127
+ selector.reset_ig_request_count()
128
+ selector.next()
124
129
  elif job.job_origin is Origin.YT_SHORTS:
125
130
  from warp_beacon.scraper.youtube.shorts import YoutubeShortsScraper
126
131
  actor = YoutubeShortsScraper(selector.get_current(), proxy)
@@ -23,6 +23,7 @@ class AccountSelector(object):
23
23
  manager = None
24
24
  account_index = {}
25
25
  current_proxy = None
26
+ ig_request_count = None
26
27
 
27
28
  def __init__(self, manager: multiprocessing.managers.SyncManager, acc_file_path: str, proxy_file_path: str=None) -> None:
28
29
  self.manager = manager
@@ -31,6 +32,7 @@ class AccountSelector(object):
31
32
  with open(acc_file_path, 'r', encoding="utf-8") as f:
32
33
  self.accounts = json.loads(f.read())
33
34
  if self.accounts:
35
+ self.ig_request_count = self.manager.Value('i', 0)
34
36
  self.__init_meta_data()
35
37
  #self.load_yt_sessions()
36
38
  for acc_type, _ in self.accounts.items():
@@ -170,4 +172,13 @@ class AccountSelector(object):
170
172
  module_name = 'youtube' if next((s for s in ("yt", "youtube", "youtu_be") if s in mod_name.value), None) else 'instagram'
171
173
  if module_name not in self.accounts:
172
174
  return 0
173
- return len(self.accounts[module_name])
175
+ return len(self.accounts[module_name])
176
+
177
+ def inc_ig_request_count(self) -> None:
178
+ self.ig_request_count.value += 1
179
+
180
+ def reset_ig_request_count(self) -> None:
181
+ self.ig_request_count.value = 0
182
+
183
+ def get_ig_request_count(self) -> int:
184
+ return self.ig_request_count.value
warp_beacon/yt_auth.py ADDED
@@ -0,0 +1,197 @@
1
+ import os
2
+ import time
3
+
4
+ import logging
5
+
6
+ import json
7
+ import requests
8
+
9
+ class YtAuth(object):
10
+ TV_CLIENT_ID = "861556708454-d6dlm3lh05idd8npek18k6be8ba3oc68.apps.googleusercontent.com"
11
+ TV_CLIENT_SECRET = "SboVhoG9s0rNafixCSGGKXAT"
12
+ YT_SESSION_FILE_TPL = '/var/warp_beacon/yt_session_%d.json'
13
+
14
+ process_start_time = 0
15
+ account_index = 0
16
+ yt_session_file = ""
17
+
18
+ def __init__(self, account_index: int) -> None:
19
+ self.account_index = account_index
20
+ self.yt_session_file = self.YT_SESSION_FILE_TPL % account_index
21
+
22
+ def fetch_token(self) -> dict:
23
+ result = {"user_code": "", "device_code": "", "verification_url": ""}
24
+ http_code = 0
25
+ response_text = ''
26
+ try:
27
+ logging.info("Fetching YT token ...")
28
+ self.process_start_time = 0
29
+ # Subtracting 30 seconds is arbitrary to avoid potential time discrepencies
30
+ self.process_start_time = int(time.time() - 30)
31
+ data = {
32
+ 'client_id': self.TV_CLIENT_ID,
33
+ 'scope': 'https://www.googleapis.com/auth/youtube'
34
+ }
35
+ response = requests.post(
36
+ url='https://oauth2.googleapis.com/device/code',
37
+ headers={
38
+ "User-Agent": "Mozilla/5.0",
39
+ "accept-language": "en-US,en",
40
+ "Content-Type": "application/json"
41
+ },
42
+ json=data,
43
+ timeout=int(os.environ.get("YT_TIMEOUT", "30"))
44
+ )
45
+
46
+ http_code = response.status_code
47
+ response_text = response.text
48
+
49
+ if http_code != 200:
50
+ logging.error("Invalid YT HTTP code: '%d'", http_code)
51
+ logging.info("Request dump: '%s'", str(response.__dict__))
52
+ else:
53
+ response_data = response.json()
54
+ result["verification_url"] = response_data['verification_url']
55
+ result["user_code"] = response_data['user_code']
56
+ result["device_code"] = response_data['device_code']
57
+ logging.info("Fetched YT url '%s' and input code '%s'", result["verification_url"], result['user_code'])
58
+ except Exception as e:
59
+ logging.error("Youtube authorization failed!")
60
+ logging.exception(e)
61
+
62
+ if http_code != 200:
63
+ raise ValueError(f"Youtube HTTP response code is {http_code}: {response_text}")
64
+
65
+ return result
66
+
67
+ def confirm_token(self, device_code: str) -> dict:
68
+ response_data = {}
69
+ http_code = 0
70
+ response_text = ''
71
+ try:
72
+ logging.info("Confirming YT auth token ...")
73
+ self.process_start_time = int(time.time()) - self.process_start_time - 20
74
+ data = {
75
+ 'client_id': self.TV_CLIENT_ID,
76
+ 'client_secret': self.TV_CLIENT_SECRET,
77
+ 'device_code': device_code,
78
+ 'grant_type': 'urn:ietf:params:oauth:grant-type:device_code'
79
+ }
80
+ response = requests.post(
81
+ url='https://oauth2.googleapis.com/token',
82
+ headers={
83
+ "User-Agent": "Mozilla/5.0",
84
+ "accept-language": "en-US,en",
85
+ "Content-Type": "application/json"
86
+ },
87
+ json=data,
88
+ timeout=int(os.environ.get("YT_TIMEOUT", "30"))
89
+ )
90
+
91
+ http_code = response.status_code
92
+ response_text = response.text
93
+
94
+ if http_code != 200:
95
+ logging.error("Invalid YT HTTP code: '%d'", http_code)
96
+ logging.info("Request dump: '%s'", str(response.__dict__))
97
+ else:
98
+ response_data = response.json()
99
+ response_data["expires"] = self.process_start_time + int(response_data["expires_in"])
100
+ except Exception as e:
101
+ logging.error("Failed to confirm token!")
102
+ logging.exception(e)
103
+
104
+ if http_code != 200:
105
+ raise ValueError(f"Youtube HTTP response code is {http_code}: {response_text}")
106
+
107
+ return response_data
108
+
109
+ def refresh_token(self, refresh_token: str) -> dict:
110
+ response_data = {}
111
+ http_code = 0
112
+ response_text = ''
113
+ try:
114
+ logging.info("Refreshing YT token ...")
115
+ start_time = int(time.time() - 30)
116
+ data = {
117
+ 'client_id': self.TV_CLIENT_ID,
118
+ 'client_secret': self.TV_CLIENT_SECRET,
119
+ 'grant_type': 'refresh_token',
120
+ 'refresh_token': refresh_token
121
+ }
122
+ response = requests.post(
123
+ url='https://oauth2.googleapis.com/token',
124
+ headers={
125
+ "User-Agent": "Mozilla/5.0",
126
+ "accept-language": "en-US,en",
127
+ "Content-Type": "application/json"
128
+ },
129
+ json=data,
130
+ timeout=int(os.environ.get("YT_TIMEOUT", "30"))
131
+ )
132
+
133
+ http_code = response.status_code
134
+ response_text = response.text
135
+
136
+ if http_code != 200:
137
+ logging.error("Invalid YT HTTP code: '%d'", http_code)
138
+ logging.info("Request dump: '%s'", str(response.__dict__))
139
+ else:
140
+ response_data = response.json()
141
+ response_data["expires"] = start_time + int(response_data["expires_in"])
142
+ except Exception as e:
143
+ logging.error("Failed to refresh YT token")
144
+ logging.exception(e)
145
+
146
+ if http_code != 200:
147
+ raise ValueError(f"Youtube HTTP response code is {http_code}: {response_text}")
148
+
149
+ return response_data
150
+
151
+ def safe_write_session(self, token_data: dict) -> bool:
152
+ try:
153
+ tmp_filename = f"{self.yt_session_file}~"
154
+
155
+ if os.path.exists(tmp_filename):
156
+ os.unlink(tmp_filename)
157
+
158
+ with open(tmp_filename, "w+", encoding="utf-8") as f:
159
+ f.write(json.dumps(token_data))
160
+
161
+ if os.path.exists(tmp_filename):
162
+ if os.path.exists(self.yt_session_file):
163
+ os.unlink(self.yt_session_file)
164
+ os.rename(src=tmp_filename, dst=self.yt_session_file)
165
+ return True
166
+ except Exception as e:
167
+ logging.error("Failed to write token!")
168
+ logging.exception(e)
169
+
170
+ return False
171
+
172
+ def store_device_code(self, device_code: str) -> bool:
173
+ try:
174
+ device_code_file = f"/tmp/yt_device_code_acc_{self.account_index}"
175
+ logging.info("Storing device code in file '%s'", device_code_file)
176
+ with open(device_code_file, "w+", encoding="utf-8") as f:
177
+ f.write(device_code.strip())
178
+ except Exception as e:
179
+ logging.error("Failed to store device code!")
180
+ logging.exception(e)
181
+ return False
182
+
183
+ return True
184
+
185
+ def load_device_code(self) -> str:
186
+ device_code = ''
187
+ try:
188
+ device_code_file = f"/tmp/yt_device_code_acc_{self.account_index}"
189
+ logging.info("Loading device code from file '%s'", device_code_file)
190
+ with open(device_code_file, 'r', encoding="utf-8") as f:
191
+ device_code = f.read().strip()
192
+ os.unlink(device_code_file)
193
+ except Exception as e:
194
+ logging.error("Failed to load device code for account #%d", self.account_index)
195
+ logging.exception(e)
196
+
197
+ return device_code
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: warp_beacon
3
- Version: 2.3.51
3
+ Version: 2.4.1
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
@@ -4,8 +4,9 @@ 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=qoauBZVJH1GNZozTtQhg39aKWblw1Jo_CuPkyrihYSg,24
7
+ warp_beacon/__version__.py,sha256=N3GPwYcqNMEhFj_mvMJ1B1wGX85Yq81y2ePqg2BYiRs,23
8
8
  warp_beacon/warp_beacon.py,sha256=7KEtZDj-pdhtl6m-zFLsSojs1ZR4o7L0xbqtdmYPvfE,342
9
+ warp_beacon/yt_auth.py,sha256=GUTKqYr_tzDC-07Lx_ahWXSag8EyLxXBUnQbDBIkEmk,6022
9
10
  warp_beacon/compress/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
11
  warp_beacon/compress/video.py,sha256=_PDMVYCyzLYxHv1uZmmzGcG_8rjaZr7BTXsXTTy_oS4,2846
11
12
  warp_beacon/jobs/__init__.py,sha256=ED8_tPle4iL4kqNW0apAVkgNQtRRTnYfAJwBjO1g0JY,180
@@ -21,9 +22,9 @@ warp_beacon/mediainfo/video.py,sha256=UBZrhTN5IDI-aYu6tsJEILo9nFkjHhkldGVFmvV7tE
21
22
  warp_beacon/scheduler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
23
  warp_beacon/scheduler/instagram_human.py,sha256=GRzryMWws4ibJZ_gPGn_Y2I2plcPIVgMWK3Yubqywa0,5020
23
24
  warp_beacon/scheduler/scheduler.py,sha256=FPSrR1Z6lWbF1aCAMU2rRYCy1w4zdZ8Q4e7YWQE-Ahk,4041
24
- warp_beacon/scraper/__init__.py,sha256=bNZI9YBKQB4UyxEjethenXjvp9g1RrWfYgOyepH4O_U,17356
25
+ warp_beacon/scraper/__init__.py,sha256=iqWDK2vzKXkd9RPGYXxQ4O-IrydOBBFR89aX50sP2Yg,17669
25
26
  warp_beacon/scraper/abstract.py,sha256=28a0aBKZpi8IKptLWdB6RuVbOkrUbrhT7LSZX7QRQtg,2725
26
- warp_beacon/scraper/account_selector.py,sha256=HSfmi5H73aWYTjDa8GErCCQpTwWtDLBw92Q-I8TZilg,6282
27
+ warp_beacon/scraper/account_selector.py,sha256=TzAh4fQigsRcS2AomAMvlms8sH5RKKbPT20LJemWGtU,6596
27
28
  warp_beacon/scraper/exceptions.py,sha256=L4UCZqDOLKu5-TPUcTErIbNDLrAQJghkMaPqzTfsm1g,1376
28
29
  warp_beacon/scraper/fail_handler.py,sha256=_blvckfTZ4xWVancQKVRXH5ClKGwfrBxMwvXIFZh1qA,975
29
30
  warp_beacon/scraper/link_resolver.py,sha256=Rc9ZuMyOo3iPywDHwjngy-WRQ2SXhJwxcg-5ripx7tM,2447
@@ -43,9 +44,9 @@ warp_beacon/telegram/handlers.py,sha256=XXIfdV_RCj7tyZMPXchuKmGoDdweOaR08ADDaBPW
43
44
  warp_beacon/telegram/placeholder_message.py,sha256=wN9-BRiyrtHG-EvXtZkGJHt2CX71munQ57ITttjt0mw,6400
44
45
  warp_beacon/telegram/utils.py,sha256=9uebX53G16mV7ER7WgfdWBLFHHw14S8HBt9URrIskg0,4440
45
46
  warp_beacon/uploader/__init__.py,sha256=E9rlZIf7xlQz6MutMOwJ8S5Vm2uheR5nv23Kv8duRQg,5427
46
- warp_beacon-2.3.51.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
47
- warp_beacon-2.3.51.dist-info/METADATA,sha256=CMn79Q5lJ-opcZwsBPfWIHf3-Zll4vWJAXERZq518t8,22626
48
- warp_beacon-2.3.51.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
49
- warp_beacon-2.3.51.dist-info/entry_points.txt,sha256=eSB61Rb89d56WY0O-vEIQwkn18J-4CMrJcLA_R_8h3g,119
50
- warp_beacon-2.3.51.dist-info/top_level.txt,sha256=qGjHVVfyf6lTmbdSA-fQq0rHS1YVS4HoJT3rag5xgPE,1141
51
- warp_beacon-2.3.51.dist-info/RECORD,,
47
+ warp_beacon-2.4.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
48
+ warp_beacon-2.4.1.dist-info/METADATA,sha256=79HmXMfW3Jw74KnY1NtVVJYU2pgvQTkcD6MVPF48IhE,22625
49
+ warp_beacon-2.4.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
50
+ warp_beacon-2.4.1.dist-info/entry_points.txt,sha256=eSB61Rb89d56WY0O-vEIQwkn18J-4CMrJcLA_R_8h3g,119
51
+ warp_beacon-2.4.1.dist-info/top_level.txt,sha256=qGjHVVfyf6lTmbdSA-fQq0rHS1YVS4HoJT3rag5xgPE,1141
52
+ warp_beacon-2.4.1.dist-info/RECORD,,