imseldrith commited on
Commit
0cee3b2
Β·
1 Parent(s): 5bdbbe8

Upload 3 files

Browse files
unzipper/client/caching.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ===================================================================== #
2
+ # Copyright (c) 2022 Itz-fork #
3
+ # #
4
+ # This program is distributed in the hope that it will be useful, #
5
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
6
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #
7
+ # See the GNU General Public License for more details. #
8
+ # #
9
+ # You should have received a copy of the GNU General Public License #
10
+ # along with this program. If not, see <http://www.gnu.org/licenses/> #
11
+ # ===================================================================== #
12
+
13
+ import logging
14
+ from json import loads
15
+ from asyncio import get_event_loop
16
+
17
+
18
+ # Cache dicts
19
+ USER_LANG = {}
20
+ STRINGS = {}
21
+
22
+
23
+ def update_languages_cache():
24
+ from unzipper.database.language import get_user_languages
25
+
26
+ async def _iter_and_update():
27
+ async for doc in await get_user_languages():
28
+ USER_LANG[doc["_id"]] = doc["lang"]
29
+
30
+ loop = get_event_loop()
31
+ loop.run_until_complete(_iter_and_update())
32
+
33
+
34
+ def update_text_strings():
35
+ def _read_json(file, as_items=False):
36
+ with open(file) as f:
37
+ return loads(f.read()).items() if as_items else loads(f.read())
38
+
39
+ subfolders = _read_json("unzipper/localization/languages.json", True)
40
+ for lcode, fnm in subfolders:
41
+ str_list = _read_json(f"unzipper/localization/{lcode}/messages.json")
42
+ btn_strs = _read_json(f"unzipper/localization/defaults/buttons.json")
43
+ STRINGS[lcode] = str_list
44
+ STRINGS["buttons"] = btn_strs
45
+
46
+
47
+ def update_cache():
48
+ logging.info(" >> Updating text strings cache...")
49
+ update_text_strings()
50
+
51
+ logging.info(" >> Updating language cache...")
52
+ update_languages_cache()
unzipper/client/patcher.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ===================================================================== #
2
+ # Copyright (c) 2022 Itz-fork #
3
+ # #
4
+ # This program is distributed in the hope that it will be useful, #
5
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
6
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #
7
+ # See the GNU General Public License for more details. #
8
+ # #
9
+ # You should have received a copy of the GNU General Public License #
10
+ # along with this program. If not, see <http://www.gnu.org/licenses/> #
11
+ # ===================================================================== #
12
+
13
+ import logging
14
+ from os import path, remove
15
+ from .pyro_client import UnzipperBot
16
+ from unzipper.database.thumbnail import get_thumbnail
17
+ from unzipper.helpers_nexa.utils import run_shell_cmds
18
+ from unzipper.database.users import add_user, is_user_in_db, is_user_in_bdb
19
+ from config import Config
20
+
21
+
22
+ class PatchMethods:
23
+ def __init__(self) -> None:
24
+ super().__init__()
25
+
26
+ async def check_user(self: UnzipperBot, message):
27
+ """
28
+ Checks database checks of new users
29
+ """
30
+ # Checking if user is banned
31
+ is_banned = await is_user_in_bdb(int(message.from_user.id))
32
+ if is_banned:
33
+ await message.reply("**Sorry You're Banned!** \n\nReport this at @Nexa_bots if you think this is a mistake")
34
+ raise UserIsBanned
35
+ # Chacking if user already in db
36
+ is_in_db = await is_user_in_db(int(message.from_user.id))
37
+ if not is_in_db:
38
+ try:
39
+ await add_user(int(message.from_user.id))
40
+ await self.send_message(
41
+ chat_id=Config.LOGS_CHANNEL,
42
+ text=f"**#NEW_USER** πŸŽ™ \n\n**User Profile:** `{message.from_user.mention}` \n**User ID:** `{message.from_user.id}` \n**Profile Url:** [Click here](tg://user?id={message.from_user.id})",
43
+ disable_web_page_preview=True
44
+ )
45
+ except Exception as e:
46
+ logging.warn(
47
+ f"Unable to add user to the database due to: \n{e}")
48
+
49
+ async def get_or_gen_thumb(self: UnzipperBot, uid: int, doc_f: str, isvid: bool = False):
50
+ """
51
+ Get saved thumbnail from the database. If there isn't any thumbnail saved, None will be returned.
52
+ For video files, a thumbnail will be generated using ffmpeg
53
+
54
+ Parameters:
55
+
56
+ - `uid` - User id
57
+ - `doc_f` - File path
58
+ - `isvid` - Pass True if file is a video
59
+ """
60
+ dbthumb = await get_thumbnail(int(uid), True)
61
+ if dbthumb:
62
+ return dbthumb
63
+ elif isvid:
64
+ thmb_pth = f"Dump/thumbnail_{path.basename(doc_f)}.jpg"
65
+ if path.exists(thmb_pth):
66
+ remove(thmb_pth)
67
+ await run_shell_cmds(f"ffmpeg -ss 00:00:01.00 -i {doc_f} -vf 'scale=320:320:force_original_aspect_ratio=decrease' -vframes 1 {thmb_pth}")
68
+ return thmb_pth
69
+ else:
70
+ return None
71
+
72
+
73
+ class UserIsBanned(Exception):
74
+ def __init__(self) -> None:
75
+ super().__init__("You're banned from using this bot!")
76
+
77
+
78
+ def init_patch():
79
+ """
80
+ Apply custom methods defined in CustomMethods class to pyrogram.Client class
81
+ """
82
+ for ckey, cval in PatchMethods.__dict__.items():
83
+ if ckey[:2] != "__":
84
+ setattr(UnzipperBot, ckey, cval)
unzipper/client/pyro_client.py ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ===================================================================== #
2
+ # Copyright (c) 2022 Itz-fork #
3
+ # #
4
+ # This program is distributed in the hope that it will be useful, #
5
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
6
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #
7
+ # See the GNU General Public License for more details. #
8
+ # #
9
+ # You should have received a copy of the GNU General Public License #
10
+ # along with this program. If not, see <http://www.gnu.org/licenses/> #
11
+ # ===================================================================== #
12
+
13
+ import logging
14
+ from time import time
15
+ from asyncio import sleep
16
+ from typing import Callable
17
+ from os import path, remove, stat
18
+
19
+ from config import Config
20
+ from pyrogram import Client
21
+ from .caching import STRINGS
22
+ from gofile2 import Async_Gofile
23
+ from pyrogram.errors import FloodWait
24
+ from pyrogram.types import CallbackQuery, Message
25
+ from unzipper.database.language import get_language
26
+ from unzipper.database.upload_mode import get_upload_mode
27
+ from unzipper.helpers_nexa.utils import (TimeFormatter, progress_for_pyrogram,
28
+ rm_mark_chars, run_shell_cmds)
29
+
30
+
31
+ class UnzipperBot(Client):
32
+ """
33
+ Unzipper bot client
34
+ """
35
+ version = "v1.0.2"
36
+
37
+ def __init__(self):
38
+ super().__init__("UnzipperBot",
39
+ api_id=Config.APP_ID,
40
+ api_hash=Config.API_HASH,
41
+ bot_token=Config.BOT_TOKEN,
42
+ plugins=dict(root="unzipper/modules"),
43
+ sleep_threshold=10)
44
+
45
+ ######## Decorators ########
46
+ def handle_erros(self, func: Callable) -> Callable:
47
+ """
48
+ Handle erros and database updates of users
49
+ """
50
+
51
+ async def decorator(client: Client, message: Message):
52
+ lang = await get_language(message.chat.id)
53
+ try:
54
+ await self.check_user(message)
55
+ return await func(client, message, STRINGS[lang])
56
+ except Exception as e:
57
+ logging.warn(e)
58
+ await self.send_message(message.chat.id, STRINGS[lang]["failed_main"].format(e))
59
+
60
+ return decorator
61
+
62
+ def handle_query(self, func: Callable) -> Callable:
63
+ """
64
+ Handle callback queries
65
+ """
66
+
67
+ async def decorator(client: Client, query: CallbackQuery):
68
+ lang = await get_language(query.message.chat.id)
69
+ try:
70
+ await func(client, query, STRINGS[lang])
71
+ except Exception as e:
72
+ logging.warn(e)
73
+ await self.send_message(query.message.chat.id, STRINGS[lang]["failed_main"].format(e))
74
+
75
+ return decorator
76
+
77
+ ######## File utils ########
78
+ async def send_file(self, c_id: int, doc_f: str, query: CallbackQuery, lang: str = "en", del_status: bool = False):
79
+ """
80
+ Send a file to the user
81
+
82
+ Parameters:
83
+
84
+ - `c_id` - Chat id
85
+ - `doc_f` - File path
86
+ - `query` - CallBackQuery object
87
+ - `del_status` - Whether if you want to delete progress message or not
88
+ """
89
+
90
+ try:
91
+ # This is my kingdom...
92
+ cum = await get_upload_mode(c_id)
93
+ # Checks if url file size is bigger than 2GB (Telegram limit)
94
+ file_size = stat(doc_f).st_size
95
+ if file_size > Config.TG_MAX_SIZE:
96
+ # Uploads the file to gofile.io
97
+ upmsg = await self.send_message(c_id, text=STRINGS[lang]["alert_file_too_large"])
98
+ try:
99
+ ga = Async_Gofile()
100
+ gfio = await ga.upload(doc_f)
101
+ from unzipper import Buttons
102
+ await upmsg.edit("**Your file has been uploaded to gofile! Click on the below button to download it πŸ‘‡**", reply_markup=await Buttons.make_button("Gofile link πŸ”—", url=gfio["downloadPage"]))
103
+ except:
104
+ await upmsg.edit("`Upload failed, Better luck next time πŸ˜”!`")
105
+ remove(doc_f)
106
+ return
107
+
108
+ tgupmsg = await self.send_message(c_id, STRINGS[lang]["processing"])
109
+ stm = time()
110
+
111
+ # Uplaod type: Video
112
+ if cum == "video":
113
+ sthumb = await self.get_or_gen_thumb(c_id, doc_f, True)
114
+ vid_duration = await run_shell_cmds(f"ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 {doc_f}")
115
+ await self.send_video(
116
+ chat_id=c_id,
117
+ video=doc_f,
118
+ caption="**Extracted by @NexaUnzipper_Bot**",
119
+ duration=int(
120
+ vid_duration) if vid_duration.isnumeric() else 0,
121
+ thumb=sthumb,
122
+ progress=progress_for_pyrogram,
123
+ progress_args=("**Trying to upload πŸ˜‡** \n", tgupmsg, stm))
124
+ # Upload type: Document
125
+ else:
126
+ sthumb = await self.get_or_gen_thumb(c_id, doc_f)
127
+ await self.send_document(
128
+ chat_id=c_id,
129
+ document=doc_f,
130
+ caption="**Extracted by @NexaUnzipper_Bot**",
131
+ thumb=sthumb,
132
+ progress=progress_for_pyrogram,
133
+ progress_args=("**Trying to upload πŸ˜‡** \n", tgupmsg, stm))
134
+ etm = time()
135
+
136
+ # Delete or edit the progress message
137
+ await tgupmsg.delete() if del_status else await tgupmsg.edit(STRINGS[lang]["ok_upload"].format(path.basename(doc_f), TimeFormatter(round(etm - stm))))
138
+ # Cleanup
139
+ try:
140
+ remove(doc_f)
141
+ if sthumb:
142
+ remove(sthumb)
143
+ except:
144
+ pass
145
+ except FloodWait as f:
146
+ await sleep(f.x)
147
+ return await self.send_file(c_id, doc_f, query)
148
+ except FileNotFoundError:
149
+ return await self.answer_query(query, "Sorry! I can't find that file", True)
150
+ except BaseException as e:
151
+ logging.warn(e)
152
+ await self.answer_query(query, f"**Error:** \n`{e}`")
153
+
154
+ ######## Utils ########
155
+ async def answer_query(self, query: CallbackQuery, text: str, alert: bool = False, *args, **kwargs):
156
+ """
157
+ Answer CallbackQuery with better error handling
158
+
159
+ Parameters:
160
+
161
+ - `query` - CallBackQuery object
162
+ - `text` - Message text
163
+ - `alert` - Pass True if you want to show the message as an alert
164
+ """
165
+ try:
166
+ if alert:
167
+ await query.answer(await rm_mark_chars(text), show_alert=True, *args, **kwargs)
168
+ else:
169
+ await query.message.edit(text, *args, **kwargs)
170
+ except:
171
+ try:
172
+ await query.message.delete()
173
+ except:
174
+ pass
175
+ await self.send_message(query.message.chat.id, text, *args, **kwargs)