warp-beacon 2.3.15__py3-none-any.whl → 2.3.17__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.
- warp_beacon/__version__.py +1 -1
- warp_beacon/jobs/abstract.py +2 -0
- warp_beacon/scheduler/scheduler.py +7 -0
- warp_beacon/scraper/account_selector.py +10 -3
- warp_beacon/storage/__init__.py +5 -2
- warp_beacon/telegram/bot.py +21 -5
- warp_beacon/telegram/caption_shortener.py +66 -0
- warp_beacon/telegram/handlers.py +26 -1
- {warp_beacon-2.3.15.dist-info → warp_beacon-2.3.17.dist-info}/METADATA +2 -1
- {warp_beacon-2.3.15.dist-info → warp_beacon-2.3.17.dist-info}/RECORD +14 -13
- {warp_beacon-2.3.15.dist-info → warp_beacon-2.3.17.dist-info}/top_level.txt +1 -0
- {warp_beacon-2.3.15.dist-info → warp_beacon-2.3.17.dist-info}/LICENSE +0 -0
- {warp_beacon-2.3.15.dist-info → warp_beacon-2.3.17.dist-info}/WHEEL +0 -0
- {warp_beacon-2.3.15.dist-info → warp_beacon-2.3.17.dist-info}/entry_points.txt +0 -0
warp_beacon/__version__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
__version__ = "2.3.
|
1
|
+
__version__ = "2.3.17"
|
2
2
|
|
warp_beacon/jobs/abstract.py
CHANGED
@@ -44,6 +44,7 @@ class JobSettings(TypedDict):
|
|
44
44
|
job_postponed_until: int
|
45
45
|
message_leftover: str
|
46
46
|
replay: bool
|
47
|
+
short_text: bool
|
47
48
|
|
48
49
|
class AbstractJob(ABC):
|
49
50
|
job_id: uuid.UUID = None
|
@@ -80,6 +81,7 @@ class AbstractJob(ABC):
|
|
80
81
|
job_postponed_until: int = -1
|
81
82
|
message_leftover: str = ""
|
82
83
|
replay: bool = False
|
84
|
+
short_text: bool = False
|
83
85
|
|
84
86
|
def __init__(self, **kwargs: Unpack[JobSettings]) -> None:
|
85
87
|
if kwargs:
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
import time
|
3
3
|
from random import randrange
|
4
|
+
import datetime
|
4
5
|
import threading
|
5
6
|
import json
|
6
7
|
|
@@ -81,6 +82,12 @@ class IGScheduler(object):
|
|
81
82
|
self.load_state()
|
82
83
|
while self.running:
|
83
84
|
try:
|
85
|
+
now = datetime.datetime.now()
|
86
|
+
if 4 <= now.hour < 7:
|
87
|
+
logging.info("Scheduler is paused due to night hours (4:00 - 7:00)")
|
88
|
+
self.event.wait(timeout=10800)
|
89
|
+
continue
|
90
|
+
|
84
91
|
if self.state["remaining"] <= 0:
|
85
92
|
self.state["remaining"] = randrange(8400, 26200)
|
86
93
|
logging.info("Next scheduler activity in '%s' seconds", self.state["remaining"])
|
@@ -56,8 +56,15 @@ class AccountSelector(object):
|
|
56
56
|
logging.info("Account proxy matched '%s'", proxy)
|
57
57
|
matched_proxy.append(proxy)
|
58
58
|
if matched_proxy:
|
59
|
-
|
59
|
+
if len(matched_proxy) > 1:
|
60
|
+
random.seed(random.seed(time.time_ns() ^ int.from_bytes(os.urandom(len(matched_proxy)), "big")))
|
61
|
+
# ensure new proxy in case if previous account required captcha
|
62
|
+
last_proxy = self.accounts.get("last_proxy", None)
|
63
|
+
if last_proxy and last_proxy in matched_proxy:
|
64
|
+
matched_proxy.remove(last_proxy)
|
60
65
|
prox_choice = random.choice(matched_proxy)
|
66
|
+
# saving chosen proxy for history
|
67
|
+
self.accounts["last_proxy"] = prox_choice
|
61
68
|
logging.info("Chosen proxy: '%s'", prox_choice)
|
62
69
|
return prox_choice
|
63
70
|
except Exception as e:
|
@@ -103,8 +110,8 @@ class AccountSelector(object):
|
|
103
110
|
def bump_acc_fail(self, key: str, amount: int = 1) -> int:
|
104
111
|
try:
|
105
112
|
idx = self.account_index[self.current_module_name].value
|
106
|
-
self.accounts_meta_data[idx][key] += amount
|
107
|
-
return self.accounts_meta_data[idx][key]
|
113
|
+
self.accounts_meta_data[self.current_module_name][idx][key] += amount
|
114
|
+
return self.accounts_meta_data[self.current_module_name][idx][key]
|
108
115
|
except Exception as e:
|
109
116
|
logging.warning("Failed to record fail stats")
|
110
117
|
logging.exception(e)
|
warp_beacon/storage/__init__.py
CHANGED
@@ -52,12 +52,15 @@ class Storage(object):
|
|
52
52
|
path = urlparse(url).path.strip('/')
|
53
53
|
return path
|
54
54
|
|
55
|
-
def db_find(self, uniq_id: str) -> list[dict]:
|
55
|
+
def db_find(self, uniq_id: str, origin: str = "") -> list[dict]:
|
56
56
|
document = None
|
57
57
|
ret = []
|
58
58
|
try:
|
59
59
|
logging.debug("uniq_id to search is '%s'", uniq_id)
|
60
|
-
|
60
|
+
find_opts = {"uniq_id": uniq_id}
|
61
|
+
if origin:
|
62
|
+
find_opts["origin"] = origin
|
63
|
+
cursor = self.db.find(find_opts)
|
61
64
|
for document in cursor:
|
62
65
|
ret.append(
|
63
66
|
{
|
warp_beacon/telegram/bot.py
CHANGED
@@ -21,6 +21,7 @@ from warp_beacon.uploader import AsyncUploader
|
|
21
21
|
from warp_beacon.jobs.upload_job import UploadJob
|
22
22
|
from warp_beacon.jobs.types import JobType
|
23
23
|
from warp_beacon.telegram.utils import Utils
|
24
|
+
from warp_beacon.telegram.caption_shortener import CaptionShortner
|
24
25
|
from warp_beacon.scheduler.scheduler import IGScheduler
|
25
26
|
|
26
27
|
import logging
|
@@ -90,7 +91,9 @@ class Bot(object):
|
|
90
91
|
self.client.add_handler(MessageHandler(self.handlers.help, filters.command("help")))
|
91
92
|
self.client.add_handler(MessageHandler(self.handlers.random, filters.command("random")))
|
92
93
|
self.client.add_handler(MessageHandler(self.handlers.handler))
|
93
|
-
self.client.add_handler(
|
94
|
+
self.client.add_handler(self.handlers.simple_button_handler, filters=filters.create(lambda _, q: not q.data.startswith("readmore:")))
|
95
|
+
self.client.add_handler(CallbackQueryHandler(self.handlers.read_more_handler, filters=filters.create(lambda _, q: q.data.startswith("readmore:"))))
|
96
|
+
|
94
97
|
|
95
98
|
self.placeholder = PlaceholderMessage(self)
|
96
99
|
|
@@ -158,9 +161,14 @@ class Bot(object):
|
|
158
161
|
|
159
162
|
def build_signature_caption(self, job: UploadJob) -> str:
|
160
163
|
caption = ""
|
164
|
+
is_group = job.chat_type in (ChatType.GROUP, ChatType.SUPERGROUP)
|
161
165
|
if job.canonical_name:
|
162
|
-
|
163
|
-
|
166
|
+
if is_group and CaptionShortner.need_short(job.canonical_name):
|
167
|
+
caption = f"{html.escape(CaptionShortner.smart_truncate_html(job.canonical_name))} ..."
|
168
|
+
job.short_text = True
|
169
|
+
else:
|
170
|
+
caption = f"<b>{html.escape(job.canonical_name)}</b>"
|
171
|
+
if is_group:
|
164
172
|
if job.canonical_name:
|
165
173
|
caption += "\n—\n"
|
166
174
|
if job.message_leftover:
|
@@ -336,8 +344,16 @@ class Bot(object):
|
|
336
344
|
args["disable_notification"] = True
|
337
345
|
args["reply_to_message_id"] = job.message_id
|
338
346
|
|
339
|
-
if
|
340
|
-
|
347
|
+
if job.media_type is not JobType.COLLECTION:
|
348
|
+
render_donates = os.environ.get("ENABLE_DONATES", None) == "true"
|
349
|
+
keyboard_buttons = [[]]
|
350
|
+
if job.short_text:
|
351
|
+
keyboard_buttons[0].append(InlineKeyboardButton("📖 Read more", callback_data=f"read_more:{job.job_origin}:{job.uniq_id}"))
|
352
|
+
if render_donates:
|
353
|
+
keyboard_buttons[0].append(InlineKeyboardButton("❤ Donate", url=os.environ.get("DONATE_LINK", "https://pay.cryptocloud.plus/pos/W5BMtNQt5bJFoW2E")))
|
354
|
+
|
355
|
+
if keyboard_buttons[0]: #job.short_text or render_donates:
|
356
|
+
args["reply_markup"] = InlineKeyboardMarkup(keyboard_buttons)
|
341
357
|
|
342
358
|
return args
|
343
359
|
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import logging
|
2
|
+
from typing import Union
|
3
|
+
from bs4 import NavigableString, Tag, Comment
|
4
|
+
from bs4 import BeautifulSoup
|
5
|
+
|
6
|
+
CAPTION_LENGTH_LIMIT = 85
|
7
|
+
|
8
|
+
class CaptionShortner(object):
|
9
|
+
@staticmethod
|
10
|
+
def strip_html(text: str) -> str:
|
11
|
+
try:
|
12
|
+
soup = BeautifulSoup(text, "html.parser")
|
13
|
+
return soup.get_text()
|
14
|
+
except Exception as e:
|
15
|
+
logging.warning("Failed to stript HTML tags!")
|
16
|
+
logging.exception(e)
|
17
|
+
|
18
|
+
return text
|
19
|
+
|
20
|
+
@staticmethod
|
21
|
+
def need_short(text: str) -> bool:
|
22
|
+
wo_html = CaptionShortner.strip_html(text)
|
23
|
+
if len(wo_html) > CAPTION_LENGTH_LIMIT:
|
24
|
+
return True
|
25
|
+
return False
|
26
|
+
|
27
|
+
@staticmethod
|
28
|
+
def smart_truncate_html(html: str, limit: int = CAPTION_LENGTH_LIMIT) -> str:
|
29
|
+
result = ""
|
30
|
+
try:
|
31
|
+
soup = BeautifulSoup(html, "html.parser")
|
32
|
+
length = 0
|
33
|
+
|
34
|
+
def walk(node: Union[NavigableString, Tag, Comment]) -> None:
|
35
|
+
nonlocal result, length
|
36
|
+
if length >= limit:
|
37
|
+
return
|
38
|
+
|
39
|
+
if isinstance(node, str):
|
40
|
+
words = node.split()
|
41
|
+
for word in words:
|
42
|
+
if length + len(word) + 1 > limit:
|
43
|
+
return
|
44
|
+
if result and not result.endswith(" "):
|
45
|
+
result += " "
|
46
|
+
length += 1
|
47
|
+
result += word
|
48
|
+
length += len(word)
|
49
|
+
elif isinstance(node, Tag):
|
50
|
+
if node.name == '[document]':
|
51
|
+
for child in node.children:
|
52
|
+
walk(child)
|
53
|
+
return
|
54
|
+
|
55
|
+
for child in node.children:
|
56
|
+
walk(child)
|
57
|
+
if length >= limit:
|
58
|
+
break
|
59
|
+
|
60
|
+
result += f"</{node.name}>"
|
61
|
+
|
62
|
+
walk(soup)
|
63
|
+
except Exception as e:
|
64
|
+
logging.warning("Fail in smart_truncate_html!")
|
65
|
+
logging.exception(e)
|
66
|
+
return result
|
warp_beacon/telegram/handlers.py
CHANGED
@@ -213,6 +213,7 @@ class Handlers(object):
|
|
213
213
|
if chat.type not in (ChatType.GROUP, ChatType.SUPERGROUP) and not urls:
|
214
214
|
await self.bot.send_text(text=reply_text, reply_id=effective_message_id, chat_id=chat.id)
|
215
215
|
|
216
|
+
#TODO refactor to callback router
|
216
217
|
async def simple_button_handler(self, client: Client, query: CallbackQuery) -> None:
|
217
218
|
await client.answer_callback_query(
|
218
219
|
callback_query_id=query.id,
|
@@ -220,4 +221,28 @@ class Handlers(object):
|
|
220
221
|
show_alert=True
|
221
222
|
)
|
222
223
|
self.bot.downloader.auth_event.set()
|
223
|
-
self.bot.downloader.auth_event.clear()
|
224
|
+
self.bot.downloader.auth_event.clear()
|
225
|
+
|
226
|
+
async def read_more_handler(self, client: Client, query: CallbackQuery) -> None:
|
227
|
+
origin, uniq_id = '', ''
|
228
|
+
#read_more:{job.job_origin}:{job.uniq_id}
|
229
|
+
if query.data:
|
230
|
+
parts = query.data.split(':')
|
231
|
+
if len(parts) == 3:
|
232
|
+
_, origin, uniq_id = parts
|
233
|
+
db_results = []
|
234
|
+
if uniq_id and origin:
|
235
|
+
db_results = self.storage.db_find(uniq_id=uniq_id.strip(), origin=origin.strip())
|
236
|
+
first_entity = {}
|
237
|
+
if db_results:
|
238
|
+
first_entity = db_results[0]
|
239
|
+
|
240
|
+
try:
|
241
|
+
await client.answer_callback_query(
|
242
|
+
callback_query_id=query.id,
|
243
|
+
show_alert=True,
|
244
|
+
text=first_entity.get("canonical_name", "Failed to fetch data.")
|
245
|
+
)
|
246
|
+
except Exception as e:
|
247
|
+
logging.warning("read_more_handler: Failed for uniq_id='%s', origin='%s", uniq_id, origin)
|
248
|
+
logging.exception(e)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: warp_beacon
|
3
|
-
Version: 2.3.
|
3
|
+
Version: 2.3.17
|
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
|
@@ -236,6 +236,7 @@ Requires-Dist: urlextract
|
|
236
236
|
Requires-Dist: pillow
|
237
237
|
Requires-Dist: pymongo
|
238
238
|
Requires-Dist: instagrapi==2.0.0
|
239
|
+
Requires-Dist: bs4
|
239
240
|
Dynamic: author
|
240
241
|
Dynamic: home-page
|
241
242
|
|
@@ -4,12 +4,12 @@ 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=
|
7
|
+
warp_beacon/__version__.py,sha256=7kEUywY6HMmkf0hezoDB_dwDQMiBqA4wHs6q4S35P6Y,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
|
11
11
|
warp_beacon/jobs/__init__.py,sha256=ED8_tPle4iL4kqNW0apAVkgNQtRRTnYfAJwBjO1g0JY,180
|
12
|
-
warp_beacon/jobs/abstract.py,sha256=
|
12
|
+
warp_beacon/jobs/abstract.py,sha256=lYZplMq4Uo9vUB6ziMsC_FPer2NsvhdmFJ_I54L7v7Y,3087
|
13
13
|
warp_beacon/jobs/download_job.py,sha256=5HiPcnJppFMhO14___3eSkoMygM3y-vhpGkMAuNhK7s,854
|
14
14
|
warp_beacon/jobs/types.py,sha256=Ae8zINgbs7cOcYkYoOCOACA7duyhnIGMQAJ_SJB1QRQ,176
|
15
15
|
warp_beacon/jobs/upload_job.py,sha256=_ul4psPej1jLEs-BMcMR80GbXDSmm38jE9yoZtecclY,741
|
@@ -19,10 +19,10 @@ 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/scheduler.py,sha256=
|
22
|
+
warp_beacon/scheduler/scheduler.py,sha256=gcV-e-9MjL8JEfu7T3Gy1imUrXz266ub9Ub4O27W5Hw,2786
|
23
23
|
warp_beacon/scraper/__init__.py,sha256=V_C5SmAmRtjFfVBtTotOHCW3ILMQ8m_ulrBF6ry59_A,16944
|
24
24
|
warp_beacon/scraper/abstract.py,sha256=6A6KuBUHZhu8VAyBwLgmnxMPHJcLpgwLapmULy8hpoA,2726
|
25
|
-
warp_beacon/scraper/account_selector.py,sha256=
|
25
|
+
warp_beacon/scraper/account_selector.py,sha256=zv5ci_Y7W-tzKeFklffpLts19a1wFg69fqefK-_i_pk,5122
|
26
26
|
warp_beacon/scraper/exceptions.py,sha256=Qkz76yo-X5kucEZIP9tWaK-oYO-kvsPEl8Y0W63oDhU,1300
|
27
27
|
warp_beacon/scraper/fail_handler.py,sha256=_blvckfTZ4xWVancQKVRXH5ClKGwfrBxMwvXIFZh1qA,975
|
28
28
|
warp_beacon/scraper/link_resolver.py,sha256=Rc9ZuMyOo3iPywDHwjngy-WRQ2SXhJwxcg-5ripx7tM,2447
|
@@ -33,17 +33,18 @@ warp_beacon/scraper/youtube/abstract.py,sha256=cBtExei2Cb3o4YBtHqi8If_FdmE6NyJqN
|
|
33
33
|
warp_beacon/scraper/youtube/music.py,sha256=qbijpSv54fsrIYHeY-nfmw4vo6oBmedQHsVG8pXNfrc,1380
|
34
34
|
warp_beacon/scraper/youtube/shorts.py,sha256=ujGEV7ILXHqBRa99SyITsnR7ulAHJDtumAh51kVX880,1231
|
35
35
|
warp_beacon/scraper/youtube/youtube.py,sha256=fGrbjBngvvNdpzhb1yZVedNW0_tCrLc31VSYMSHzcQY,2135
|
36
|
-
warp_beacon/storage/__init__.py,sha256=
|
36
|
+
warp_beacon/storage/__init__.py,sha256=xEzexwWZTMtjVesQ73BLhS0VkWoqRXSUmuXS4h5HOvY,3402
|
37
37
|
warp_beacon/storage/mongo.py,sha256=qC4ZiO8XXvPnP0rJwz4CJx42pqFsyAjCiW10W5QdT6E,527
|
38
38
|
warp_beacon/telegram/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
39
|
-
warp_beacon/telegram/bot.py,sha256=
|
40
|
-
warp_beacon/telegram/
|
39
|
+
warp_beacon/telegram/bot.py,sha256=YgHTCZuPTC04Pkl18A9b6eA7pZBbDeQn_iEBtnRoVxs,16438
|
40
|
+
warp_beacon/telegram/caption_shortener.py,sha256=6J4Dp35mOmJEyctiuN8WXM39bkQ13m78HoghsYX3fbU,1548
|
41
|
+
warp_beacon/telegram/handlers.py,sha256=P9eR8DzFBSEQVaU0Fp0ABu8qeqFowu0GSU2SdZDfEdc,8511
|
41
42
|
warp_beacon/telegram/placeholder_message.py,sha256=wN9-BRiyrtHG-EvXtZkGJHt2CX71munQ57ITttjt0mw,6400
|
42
43
|
warp_beacon/telegram/utils.py,sha256=9uebX53G16mV7ER7WgfdWBLFHHw14S8HBt9URrIskg0,4440
|
43
44
|
warp_beacon/uploader/__init__.py,sha256=5KRWsxPRGuQ56YhCEnJsXnb-yQp8dpvWEsPDf0dD-fw,4964
|
44
|
-
warp_beacon-2.3.
|
45
|
-
warp_beacon-2.3.
|
46
|
-
warp_beacon-2.3.
|
47
|
-
warp_beacon-2.3.
|
48
|
-
warp_beacon-2.3.
|
49
|
-
warp_beacon-2.3.
|
45
|
+
warp_beacon-2.3.17.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
46
|
+
warp_beacon-2.3.17.dist-info/METADATA,sha256=NeHzbOuWLvTkhwo8d4UPZ7j3J4HyEKSYSn_HL5qD3KE,21723
|
47
|
+
warp_beacon-2.3.17.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
48
|
+
warp_beacon-2.3.17.dist-info/entry_points.txt,sha256=eSB61Rb89d56WY0O-vEIQwkn18J-4CMrJcLA_R_8h3g,119
|
49
|
+
warp_beacon-2.3.17.dist-info/top_level.txt,sha256=2iKFlYwJ-meO9sCX4OGEP1hhQN17t2KFksQ5dXMhXUA,1103
|
50
|
+
warp_beacon-2.3.17.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|