privateone commited on
Commit
861d763
·
verified ·
1 Parent(s): a34a0ce

Upload 40 files

Browse files
.env ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ BASE_URL=https://privateone-telethon-upload.hf.space
2
+ BIND_ADDRESS=0.0.0.0
3
+ OWNER_ID=708296135
4
+ PORT=7860
5
+ SECRET_CODE_LENGTH=100
6
+ TELEGRAM_API_HASH=371f110baf9d09b9b0bce9766f9a606b
7
+ TELEGRAM_API_ID=4667470
8
+ TELEGRAM_BOT_TOKEN=1857136393:AAFRXz8OGqIH-ga-qb0rM22pwYeVNPmkS00
9
+ TELEGRAM_BOT_USERNAME=@MFBlendersBot
10
+ TELEGRAM_CHANNEL_ID=-1001498849913
.gitattributes CHANGED
@@ -1,35 +1,36 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ bot/server/templates/vlc.png filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.11.1
3
+ RUN useradd -ms /bin/bash admin
4
+
5
+ WORKDIR /app
6
+ COPY . /app
7
+
8
+
9
+ COPY requirements.txt ./requirements.txt
10
+ RUN apt-get update
11
+
12
+ #RUN python -m venv venv # Create virtual environment
13
+ #RUN /app/venv/bin/activate &&
14
+ RUN pip install --upgrade pip && pip install --no-cache-dir --upgrade -r requirements.txt
15
+
16
+
17
+ #RUN touch /app/event-log.txt && chmod 664 /app/event-log.txt
18
+ RUN chown -R admin:admin /app
19
+ RUN chmod 755 /app
20
+ #EXPOSE 7860
21
+ USER admin
22
+ #CMD ["docker","run","-p","7860:8080"]
23
+ #CMD ["uvicorn","bot.server.main:bp","--host","0.0.0.0","--port","7860"]
24
+ ENTRYPOINT ["python","-m","bot"]
README.md CHANGED
@@ -1,11 +1,11 @@
1
- ---
2
- title: Telethon Upload
3
- emoji: 🦀
4
- colorFrom: indigo
5
- colorTo: purple
6
- sdk: docker
7
- pinned: false
8
- license: gpl
9
- ---
10
-
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ ---
2
+ title: Telethon Upload
3
+ emoji: 🐠
4
+ colorFrom: red
5
+ colorTo: gray
6
+ sdk: docker
7
+ pinned: false
8
+ license: lgpl
9
+ ---
10
+
11
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
bot/__init__.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from telethon import TelegramClient
2
+ from logging import getLogger
3
+ from logging.config import dictConfig
4
+ from .config import Telegram, LOGGER_CONFIG_JSON
5
+
6
+ dictConfig(LOGGER_CONFIG_JSON)
7
+
8
+ version = 1.5
9
+ logger = getLogger('bot')
10
+
11
+ TelegramBot = TelegramClient(
12
+ session='bot',
13
+ api_id=Telegram.API_ID,
14
+ api_hash=Telegram.API_HASH
15
+ )
bot/__main__.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from importlib import import_module
2
+ from pathlib import Path
3
+ from bot import TelegramBot, logger
4
+ from bot.config import Telegram
5
+ from bot.server import server
6
+
7
+ from telethon import types
8
+ def load_plugins():
9
+ count = 0
10
+ for path in Path('bot/plugins').rglob('*.py'):
11
+ import_module(f'bot.plugins.{path.stem}')
12
+ count += 1
13
+ logger.info(f'Loaded {count} {"plugins" if count > 1 else "plugin"}.')
14
+
15
+ if __name__ == '__main__':
16
+ #def main():
17
+ try:
18
+ logger.info('initializing...')
19
+ TelegramBot.loop.create_task(server.serve())
20
+ TelegramBot.start(bot_token=Telegram.BOT_TOKEN)
21
+ logger.info('Telegram client is now started.')
22
+ logger.info('Loading bot plugins...')
23
+ load_plugins()
24
+ logger.info('Bot is now ready!')
25
+ #logger.info(TelegramBot(types.PhoneConnectionWebrtc.to_dict(TelegramBot)))
26
+ TelegramBot.run_until_disconnected()
27
+ except KeyboardInterrupt:
28
+ #pass
29
+ TelegramBot.disconnect()
30
+ logging.info('----------------------- Service Stopped -----------------------')
31
+
bot/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (707 Bytes). View file
 
bot/__pycache__/__main__.cpython-311.pyc ADDED
Binary file (2.1 kB). View file
 
bot/__pycache__/config.cpython-311.pyc ADDED
Binary file (2.52 kB). View file
 
bot/config.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from os import environ as env
2
+ import json
3
+
4
+
5
+ class Telegram:
6
+
7
+ API_ID = int(env.get("TELEGRAM_API_ID"))
8
+ API_HASH = env.get("TELEGRAM_API_HASH")
9
+ OWNER_ID = int(env.get("OWNER_ID"))
10
+ ALLOWED_USER_IDS = json.load(open('/app/bot/data.json'))
11
+ BOT_USERNAME = env.get("TELEGRAM_BOT_USERNAME")
12
+ BOT_TOKEN = env.get("TELEGRAM_BOT_TOKEN")
13
+ CHANNEL_ID = int(env.get("TELEGRAM_CHANNEL_ID"))
14
+ SECRET_CODE_LENGTH = int(env.get("SECRET_CODE_LENGTH"))
15
+
16
+
17
+
18
+ class Server:
19
+ BASE_URL = env.get("BASE_URL")
20
+ BIND_ADDRESS = env.get("BIND_ADDRESS", "0.0.0.0")
21
+ PORT = int(env.get("PORT", 7860))
22
+
23
+
24
+ # LOGGING CONFIGURATION
25
+ LOGGER_CONFIG_JSON = {
26
+ 'version': 1,
27
+ 'formatters': {
28
+ 'default': {
29
+ 'format': '[%(asctime)s][%(name)s][%(levelname)s] -> %(message)s',
30
+ 'datefmt': '%d/%m/%Y %H:%M:%S'
31
+ },
32
+ },
33
+ 'handlers': {
34
+ 'file_handler': {
35
+ 'class': 'logging.FileHandler',
36
+ 'filename': 'event-log.txt',
37
+ 'formatter': 'default'
38
+ },
39
+ 'stream_handler': {
40
+ 'class': 'logging.StreamHandler',
41
+ 'formatter': 'default'
42
+ }
43
+ },
44
+ 'loggers': {
45
+ 'uvicorn': {
46
+ 'level': 'INFO',
47
+ 'handlers': ['file_handler', 'stream_handler']
48
+ },
49
+ 'uvicorn.error': {
50
+ 'level': 'WARNING',
51
+ 'handlers': ['file_handler', 'stream_handler']
52
+ },
53
+ 'bot': {
54
+ 'level': 'INFO',
55
+ 'handlers': ['file_handler', 'stream_handler']
56
+ }
57
+ }
58
+ }
bot/data.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"my_array": [708296135]}
bot/modules/__pycache__/decorators.cpython-311.pyc ADDED
Binary file (1.61 kB). View file
 
bot/modules/__pycache__/static.cpython-311.pyc ADDED
Binary file (1.43 kB). View file
 
bot/modules/__pycache__/telegram.cpython-311.pyc ADDED
Binary file (2.96 kB). View file
 
bot/modules/decorators.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from telethon.events import NewMessage, CallbackQuery
2
+ from telethon.tl.custom import Message
3
+ from typing import Callable
4
+ from functools import wraps
5
+ from bot.config import Telegram
6
+ from bot.modules.static import *
7
+ def byte_to_gb_mb(size: int) -> str:
8
+ if not size:
9
+ return ""
10
+ power = 2 ** 10
11
+ number = 0
12
+ dict_power_n = {
13
+ 0: " ",
14
+ 1: "K",
15
+ 2: "M",
16
+ 3: "G",
17
+ 4: "T",
18
+ 5: "P"
19
+ }
20
+ while size > power:
21
+ size /= power
22
+ number += 1
23
+ return str(round(size, 2)) + " " + dict_power_n[number] + 'B'
24
+ def verify_user(private: bool = False):
25
+
26
+ def decorator(func: Callable):
27
+ @wraps(func)
28
+ async def wrapper(update: NewMessage.Event | CallbackQuery.Event):
29
+ if private and not update.is_private:
30
+ return
31
+
32
+ chat_id = str(update.chat_id)
33
+
34
+ if not Telegram.ALLOWED_USER_IDS or chat_id in Telegram.ALLOWED_USER_IDS:
35
+ return await func(update)
36
+
37
+ return wrapper
38
+ return decorator
bot/modules/static.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ WelcomeText = \
2
+ """
3
+ Hi **%(first_name)s**, send me a file or add me as an admin to any channel to instantly generate file links.
4
+
5
+ Add me to your channel to instantly generate links for any downloadable media. Once received, I will automatically attach appropriate buttons to the post containing the URL. If you want me to ignore a given post, you can insert `#pass` in the post.
6
+
7
+ - /start to get this message.
8
+ - /info to get user info.
9
+ - /log to get bot logs. (admin only!)
10
+ """
11
+
12
+ UserInfoText = \
13
+ """
14
+ **First Name:**
15
+ `{sender.first_name}`
16
+
17
+ **Last Name:**
18
+ `{sender.last_name}`
19
+
20
+ **User ID:**
21
+ `{sender.id}`
22
+
23
+ **Username:**
24
+ `@{sender.username}`
25
+ """
26
+
27
+ FileLinksText = \
28
+ """
29
+ **Download Link:**
30
+ `%(dl_link)s`
31
+ **Telegram File:**
32
+ `%(tg_link)s`
33
+ """
34
+
35
+ MediaLinksText = \
36
+ """
37
+ **Download Link:**
38
+ `%(dl_link)s`
39
+ **Stream Link:**
40
+ `%(stream_link)s`
41
+ **Telegram File:**
42
+ `%(tg_link)s`
43
+ """
44
+
45
+ InvalidQueryText = \
46
+ """
47
+ Query data mismatched.
48
+ """
49
+
50
+ MessageNotExist = \
51
+ """
52
+ File revoked or not exist.
53
+ """
54
+
55
+ LinkRevokedText = \
56
+ """
57
+ The link has been revoked. It may take some time for the changes to take effect.
58
+ """
59
+
60
+ InvalidPayloadText = \
61
+ """
62
+ Invalid payload.
63
+ """
64
+
65
+ MediaTypeNotSupportedText = \
66
+ """
67
+ Sorry, this media type is not supported.
68
+ """
bot/modules/telegram.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from telethon.events import NewMessage
2
+ from telethon.tl.custom import Message
3
+ from datetime import datetime
4
+ from mimetypes import guess_type
5
+ from bot import TelegramBot
6
+ from bot.config import Telegram
7
+ from bot.server.error import abort
8
+
9
+ async def get_message(message_id: int) -> Message | None:
10
+ message = None
11
+
12
+ try:
13
+ message = await TelegramBot.get_messages(Telegram.CHANNEL_ID, ids=message_id)
14
+ except Exception:
15
+ pass
16
+
17
+ return message
18
+
19
+ async def send_message(message:Message, send_to:int = Telegram.CHANNEL_ID) -> Message:
20
+ message.forward
21
+ return await TelegramBot.send_message(
22
+ entity=send_to,
23
+ message=message
24
+ )
25
+
26
+ def filter_files(update: NewMessage.Event | Message):
27
+ return bool(
28
+ (
29
+ update.document
30
+ or update.photo
31
+ or update.video
32
+ or update.video_note
33
+ or update.audio
34
+ or update.gif
35
+ )
36
+ and not update.sticker
37
+ )
38
+
39
+ def get_file_properties(message: Message):
40
+ file_name = message.file.name
41
+ file_size = message.file.size or 0
42
+ mime_type = message.file.mime_type
43
+
44
+ if not file_name:
45
+ attributes = {
46
+ 'video': 'mp4',
47
+ 'audio': 'mp3',
48
+ 'voice': 'ogg',
49
+ 'photo': 'jpg',
50
+ 'video_note': 'mp4'
51
+ }
52
+
53
+ for attribute in attributes:
54
+ media = getattr(message, attribute, None)
55
+ if media:
56
+ file_type, file_format = attribute, attributes[attribute]
57
+ break
58
+
59
+ if not media:
60
+ abort(400, 'Invalid media type.')
61
+
62
+ date = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
63
+ file_name = f'{file_type}-{date}.{file_format}'
64
+
65
+ if not mime_type:
66
+ mime_type = guess_type(file_name)[0] or 'application/octet-stream'
67
+
68
+ return file_name, file_size, mime_type
bot/plugins/__pycache__/callback.cpython-311.pyc ADDED
Binary file (4.43 kB). View file
 
bot/plugins/__pycache__/commands.cpython-311.pyc ADDED
Binary file (5.63 kB). View file
 
bot/plugins/__pycache__/deeplinks.cpython-311.pyc ADDED
Binary file (1.78 kB). View file
 
bot/plugins/__pycache__/files.cpython-311.pyc ADDED
Binary file (5.76 kB). View file
 
bot/plugins/__pycache__/upload.cpython-311.pyc ADDED
Binary file (5.25 kB). View file
 
bot/plugins/callback.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from telethon.events import CallbackQuery
2
+ from bot import TelegramBot
3
+ from bot.modules.decorators import verify_user,byte_to_gb_mb
4
+ from bot.modules.static import *
5
+ from bot.modules.telegram import get_message, get_file_properties
6
+ from bot.config import Telegram, Server
7
+
8
+ '''async def upload_file_in_chunks(TelegramBot, chat_id, file_path, chunk_size_kb):
9
+ file_id = None
10
+ total_parts = math.ceil(file_size / (chunk_size_kb * 1024))
11
+ current_part = 1
12
+ with open(file_path, "rb") as f:
13
+ while True:
14
+ data = f.read(chunk_size_kb * 1024)
15
+ if not data:
16
+ break
17
+ # Upload the current chunk
18
+ file_part = await client.upload_file_part(file_id, current_part, data)
19
+ if not file_id:
20
+ file_id = file_part.file_id
21
+ current_part += 1
22
+ # Show progress if desired
23
+ progress = current_part / total_parts * 100
24
+ print(f"Uploaded {progress:.2f}%")
25
+ # Complete the upload
26
+ complete_file = await client.upload_file_completed(file_id, total_parts)
27
+ # Send the uploaded file to the chat
28
+ await client.send_file(chat_id, complete_file)
29
+
30
+
31
+ '''
32
+
33
+ @TelegramBot.on(CallbackQuery(pattern=r'^rm_'))
34
+ #@verify_user(private=True)
35
+ async def delete_file(event: CallbackQuery.Event):
36
+ query_data = event.query.data.decode().split('_')
37
+
38
+ if len(query_data) != 3:
39
+ return await event.answer(InvalidQueryText, alert=True)
40
+
41
+ message = await get_message(int(query_data[1]))
42
+
43
+ if not message:
44
+ return await event.answer(MessageNotExist, alert=True)
45
+
46
+ await message.delete()
47
+
48
+ return await event.answer(LinkRevokedText, alert=True)
49
+
50
+ @TelegramBot.on(CallbackQuery(pattern=r'^up_'))
51
+ #@verify_user(private=True)
52
+ async def up_file(event:CallbackQuery.Event):
53
+ query_data = event.query.data.decode().split('_')
54
+
55
+ if len(query_data) != 5:
56
+ return await event.answer(InvalidQueryText, alert=True)
57
+ message_id=int(query_data[1])
58
+ event_id=int(query_data[3])
59
+ event_peer=int(query_data[4])
60
+ message = await get_message(int(query_data[1]))
61
+ main_event = await TelegramBot.get_messages(event_peer, ids=event_id)
62
+
63
+ #print(event_id,event_peer)
64
+ #print(main_event)
65
+ code = str(query_data[2])
66
+ def callback(current, total,event_peer,event_id):
67
+ print('Uploaded', current, 'out of', total,'bytes: {:.2%}'.format(current / total))
68
+ TelegramBot.edit_message(event_peer, event_id, f'Uploaded, {current}, out of, {total}')
69
+ if not message or code != message.raw_text:
70
+ return await event.answer(MessageNotExist, alert=True)
71
+ else:
72
+ dl_link = f'{Server.BASE_URL}/dl/{message_id}?code={code}'
73
+ file_name, file_size, mime_type = get_file_properties(main_event)
74
+ await main_event.reply(
75
+ message= f'**File name:{file_name} \nFile size:{byte_to_gb_mb(file_size)} \nID:{message_id} \nAccess Code:{code} \n*If you want to upload with different name please send name with reply of the message \n reply with n for original file name ***',
76
+ parse_mode="Markdown"
77
+ )
78
+
bot/plugins/commands.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from telethon import Button
2
+ from telethon import functions, types,utils,helpers,custom
3
+ from telethon.events import NewMessage
4
+ from telethon.tl.custom.message import Message
5
+ from bot import TelegramBot
6
+ from bot.config import Telegram
7
+ from bot.modules.static import *
8
+ from bot.modules.decorators import verify_user
9
+ from bot.plugins.upload import upload_chunk
10
+ from bot.modules.telegram import get_message, get_file_properties
11
+ import json
12
+
13
+ async def refresh():
14
+ with open("/app/bot/data.json", "r") as infile:
15
+ Telegram.ALLOWED_USER_IDS = json.load(infile)
16
+ # Add a value
17
+ async def add_id(id):
18
+ await refresh()
19
+ if id in Telegram.ALLOWED_USER_IDS["my_array"]:
20
+ await TelegramBot.send_message(id, "You are already exists")
21
+
22
+ else:
23
+ Telegram.ALLOWED_USER_IDS["my_array"].append(id)
24
+ await TelegramBot.send_message(id, "Now you are in whitelist !!")
25
+ with open("/app/bot/data.json", "w") as outfile:
26
+ json.dump(Telegram.ALLOWED_USER_IDS, outfile)
27
+ await refresh()
28
+
29
+ #data["my_array"].append("new_value")
30
+
31
+ # Remove a value (index 2 in this example)
32
+ async def del_id(id):
33
+ await refresh()
34
+ for i in range(len(Telegram.ALLOWED_USER_IDS["my_array"])):
35
+ if Telegram.ALLOWED_USER_IDS["my_array"][i] == id:
36
+ Telegram.ALLOWED_USER_IDS["my_array"].pop(i)
37
+ await TelegramBot.send_message(id, "You are removed from whitelist")
38
+ break
39
+ with open("/app/bot/data.json", "w") as outfile:
40
+ json.dump(Telegram.ALLOWED_USER_IDS, outfile)
41
+ await refresh()
42
+
43
+
44
+
45
+
46
+
47
+ @TelegramBot.on(NewMessage(incoming=True))
48
+ #@verify_user(private=True)
49
+ async def reply_message(event: NewMessage.Event | Message):
50
+ if event.message.reply_to:
51
+ #print('this is reply message', event)
52
+ message=await TelegramBot.get_messages(event.message.peer_id.user_id, ids=event.message.reply_to.reply_to_msg_id)
53
+ event_message=str(event.message.message)
54
+ message_text=message.message
55
+ parts = message_text.split("\n")
56
+ filename = str(parts[0].split(":")[1].strip()) # Remove leading/trailing spaces
57
+ #size = int(parts[1].split(":")[1].strip())
58
+ message_id = int(parts[2].split(":")[1].strip())
59
+ code = str(parts[3].split(":")[1].strip())
60
+ file = await get_message(message_id=int(message_id))
61
+ file_name, file_size, mime_type = get_file_properties(file)
62
+
63
+ #print(filename,size,message_id,code)
64
+ result,new_name=await upload_chunk(message_id,code,event.message.id,event_message,event.message.peer_id.user_id,event.message.reply_to.reply_to_msg_id)
65
+ attributes, mime_type = utils.get_attributes(
66
+ new_name,
67
+ mime_type=mime_type,
68
+ attributes=None,
69
+ force_document=True,
70
+ voice_note=None,
71
+ video_note=None,
72
+ supports_streaming=True,
73
+ thumb=None
74
+ )
75
+ #await TelegramBot.send_file(event.message.peer_id.user_id, file=result,force_document=True)
76
+ await TelegramBot(functions.messages.SendMediaRequest(
77
+ peer=event.message.peer_id.user_id,
78
+ media=types.InputMediaUploadedDocument(
79
+ file=result,
80
+ mime_type=mime_type,
81
+ attributes=attributes,
82
+
83
+ ),
84
+ message='File Uploaded successfully !'
85
+ ))
86
+ #print(result.stringify())
87
+
88
+ #print(result)
89
+ '''if event_message.lower() =='n':
90
+
91
+ else:
92
+ message_text=message.message
93
+ parts = message_text.split("\n")
94
+ filename = event_message # Remove leading/trailing spaces
95
+ size = int(parts[1].split(":")[1].strip())
96
+ message_id = int(parts[2].split(":")[1].strip())
97
+ code = str(parts[3].split(":")[1].strip())
98
+ print(filename,size,message_id,code)
99
+ upload_chunk(filename,message_id,code,event.message.id)'''
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+ @TelegramBot.on(NewMessage(incoming=True, pattern=r'^/start$'))
108
+ #@verify_user(private=True)
109
+ async def welcome(event: NewMessage.Event | Message):
110
+ await event.reply(
111
+ message=WelcomeText % {'first_name': event.sender.first_name},
112
+ buttons=[
113
+ [
114
+ Button.url('Add to Channel', f'https://t.me/{Telegram.BOT_USERNAME}?startchannel&admin=post_messages+edit_messages+delete_messages')
115
+ ]
116
+ ]
117
+ )
118
+
119
+ @TelegramBot.on(NewMessage(incoming=True, pattern=r'^/info$'))
120
+ #@verify_user(private=True)
121
+ async def user_info(event: Message):
122
+ await event.reply(UserInfoText.format(sender=event.sender))
123
+
124
+ @TelegramBot.on(NewMessage(chats=Telegram.OWNER_ID, incoming=True, pattern=r'^/log$'))
125
+ async def send_log(event: NewMessage.Event | Message):
126
+ await event.reply(file='event-log.txt')
127
+ @TelegramBot.on(NewMessage(incoming=True, pattern=r'^/in$'))
128
+ async def add_user(event: NewMessage.Event | Message):
129
+ await add_id(event.sender.id)
130
+
131
+ @TelegramBot.on(NewMessage(incoming=True, pattern=r'^/out$'))
132
+ async def add_user(event: NewMessage.Event | Message):
133
+ await del_id(event.sender.id)
134
+
135
+
bot/plugins/data.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"my_array": [708296135]}
bot/plugins/deeplinks.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from telethon.events import NewMessage
2
+ from telethon.tl.custom import Message
3
+ from bot import TelegramBot
4
+ from bot.modules.decorators import verify_user
5
+ from bot.modules.telegram import get_message, send_message
6
+ from bot.modules.static import *
7
+
8
+ @TelegramBot.on(NewMessage(incoming=True, pattern=r'^/start file_'))
9
+ #@verify_user(private=True)
10
+ async def send_file(event: NewMessage.Event | Message):
11
+ payload = event.raw_text.split()[-1].split('_')
12
+
13
+ if len(payload) != 3:
14
+ return await event.reply(InvalidPayloadText)
15
+
16
+ message = await get_message(int(payload[1]))
17
+
18
+ if not message:
19
+ return await event.reply(MessageNotExist)
20
+
21
+ message.raw_text = ''
22
+ await send_message(message, send_to=event.chat_id)
bot/plugins/files.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from telethon import Button
2
+ from telethon.events import NewMessage
3
+ from telethon.errors import MessageAuthorRequiredError, MessageNotModifiedError, MessageIdInvalidError
4
+ from telethon.tl.custom import Message
5
+ from secrets import token_hex
6
+ from bot import TelegramBot
7
+ from bot.config import Telegram, Server
8
+ from bot.modules.decorators import verify_user
9
+ from bot.modules.telegram import send_message, filter_files
10
+ from bot.modules.static import *
11
+
12
+ @TelegramBot.on(NewMessage(incoming=True, func=filter_files))
13
+ #@verify_user(private=True)
14
+ async def user_file_handler(event: NewMessage.Event | Message):
15
+ secret_code = token_hex(Telegram.SECRET_CODE_LENGTH)
16
+ event.message.text = f'`{secret_code}`'
17
+ message = await send_message(event.message)
18
+ message_id = message.id
19
+ #print(event)
20
+
21
+ event_id=event.message.id
22
+ event_peer=event.message.peer_id.user_id
23
+ dl_link = f'{Server.BASE_URL}/dl/{message_id}?code={secret_code}'
24
+ tg_link = f'{Server.BASE_URL}/file/{message_id}?code={secret_code}'
25
+ deep_link = f'https://t.me/{Telegram.BOT_USERNAME}?start=file_{message_id}_{secret_code}'
26
+
27
+ if (event.document and 'video' in event.document.mime_type) or event.video:
28
+ stream_link = f'{Server.BASE_URL}/stream/{message_id}?code={secret_code}'
29
+ await event.reply(
30
+ message= MediaLinksText % {'dl_link': dl_link, 'tg_link': tg_link, 'tg_link': tg_link, 'stream_link': stream_link},
31
+ buttons=[
32
+ [
33
+ Button.url('Download', dl_link),
34
+ Button.url('Stream', stream_link)
35
+ ],
36
+ [
37
+ Button.inline('Upload', f'up_{message_id}_{secret_code}_{event_id}_{event_peer}')
38
+ ],
39
+ [
40
+ Button.url('Get File', deep_link),
41
+ Button.inline('Revoke', f'rm_{message_id}_{secret_code}')
42
+ ]
43
+ ]
44
+ )
45
+ else:
46
+ await event.reply(
47
+ message=FileLinksText % {'dl_link': dl_link, 'tg_link': tg_link},
48
+ buttons=[
49
+ [
50
+ Button.url('Download', dl_link),
51
+ Button.url('Get File', deep_link)
52
+ ],
53
+ [
54
+ Button.inline('Upload', f'up_{message_id}_{secret_code}_{event_id}_{event_peer}')
55
+ ],
56
+ [
57
+ Button.inline('Revoke', f'rm_{message_id}_{secret_code}')
58
+ ]
59
+ ]
60
+ )
61
+
62
+ @TelegramBot.on(NewMessage(incoming=True, func=filter_files, forwards=False))
63
+ #@verify_user()
64
+ async def channel_file_handler(event: NewMessage.Event | Message):
65
+ secret_code = token_hex(Telegram.SECRET_CODE_LENGTH)
66
+ event.message.text = f"`{secret_code}`"
67
+ message = await send_message(event.message)
68
+ message_id = message.id
69
+ event_id=event.message.id
70
+ event_peer=event.message.peer_id.user_id
71
+ #print(event)
72
+ #print(event.message.id,event.message.peer_id.user_id)
73
+ dl_link = f"{Server.BASE_URL}/dl/{message_id}?code={secret_code}"
74
+ tg_link = f"{Server.BASE_URL}/file/{message_id}?code={secret_code}"
75
+
76
+ if (event.document and "video" in event.document.mime_type) or event.video:
77
+ stream_link = f"{Server.BASE_URL}/stream/{message_id}?code={secret_code}"
78
+
79
+ try:
80
+ await event.edit(
81
+ buttons=[
82
+ [Button.url("Download", dl_link), Button.url("Stream", stream_link)],
83
+ [
84
+ Button.inline('Upload', f'up_{message_id}_{secret_code}_{event_id}_{event_peer}')
85
+ ],
86
+ [Button.url("Get File", tg_link)],
87
+ ]
88
+ )
89
+ except (
90
+ MessageAuthorRequiredError,
91
+ MessageIdInvalidError,
92
+ MessageNotModifiedError,
93
+ ):
94
+ pass
95
+ else:
96
+ try:
97
+ await event.edit(
98
+ buttons=[
99
+ [Button.url("Download", dl_link), Button.url("Get File", tg_link)],
100
+ [
101
+ Button.inline('Upload', f'up_{message_id}_{secret_code}')
102
+ ],
103
+ ]
104
+ )
105
+ except (
106
+ MessageAuthorRequiredError,
107
+ MessageIdInvalidError,
108
+ MessageNotModifiedError,
109
+ ):
110
+ pass
bot/plugins/upload.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import hashlib
2
+ import io
3
+ import requests
4
+ from bot import TelegramBot
5
+ from bot.modules.decorators import verify_user,byte_to_gb_mb
6
+ from telethon import functions, types,utils,helpers,custom,errors
7
+ from bot.config import Telegram, Server
8
+ from math import ceil, floor
9
+ from bot.modules.telegram import get_message, get_file_properties
10
+ MIN_CHUNK_SIZE = 4096
11
+ async def callback(current,current_part,part_size,part_count,total,event_peer,event_id,file_name):
12
+ c=int(30*current_part//part_count)
13
+ progress_bar = '#' * c + '-' * (30 - c)
14
+ progress_text = f'**File name:{file_name} \nFile size:{byte_to_gb_mb(total)} \nUploading: {int(100*current_part//part_count)}%\n[{progress_bar}]'
15
+ print(current_part,part_count,part_size,'Uploaded', current, 'out of', total,'bytes: {:.2%}'.format(current / total))
16
+ try:
17
+ await TelegramBot.edit_message(event_peer, event_id, progress_text)
18
+
19
+ except errors.rpcerrorlist.MessageNotModifiedError as e:
20
+ print(f"Error: {e}")
21
+ except Exception as e: # Catch other potential errors
22
+ print(f"An unexpected error occurred: {e}")
23
+
24
+
25
+ async def upload_chunk(message_id,code,event_id,event_message,peer_id,mesage_update_id):
26
+ file_ = await get_message(message_id=int(message_id))
27
+ file_name, file_size, mime_type = get_file_properties(file_)
28
+ info = utils._get_file_info(file_)
29
+ dc_id = info.dc_id
30
+
31
+ file_size = info.size
32
+
33
+ file = info.location
34
+
35
+ part_size_kb = utils.get_appropriated_part_size(file_size)
36
+
37
+ part_size = int(part_size_kb * 1024)
38
+ if part_size % MIN_CHUNK_SIZE != 0:
39
+ raise ValueError(
40
+ 'The part size must be evenly divisible by 4096.')
41
+
42
+ if part_size_kb > 512:
43
+ raise ValueError('The part size must be less or equal to 512KB')
44
+
45
+
46
+ if part_size % 1024 != 0:
47
+ raise ValueError(
48
+ 'The part size must be evenly divisible by 1024')
49
+
50
+ # Set a default file name if None was specified
51
+ file_id = helpers.generate_random_long()
52
+
53
+ if event_message.lower() =='n':
54
+ filename=file_name
55
+ else:
56
+ ext = utils._get_extension(file_name)
57
+ filename = event_message+ext
58
+
59
+
60
+ is_big = file_size > 10 * 1024 * 1024
61
+ hash_md5 = hashlib.md5()
62
+
63
+ part_count = (file_size + part_size - 1) // part_size
64
+ until_bytes = file_size - 1
65
+ from_bytes=0
66
+ until_bytes = min(until_bytes, file_size - 1)
67
+ offset = from_bytes - (from_bytes % part_size)
68
+
69
+
70
+ pos =0
71
+ part_index=0
72
+ #for part_index in range(part_count):
73
+
74
+ async for chunk in TelegramBot.iter_download(file, offset=offset, chunk_size=part_size, stride=part_size, file_size=file_size):
75
+
76
+ #limit = part_size
77
+
78
+ if type(chunk)!="<class 'bytes'>":
79
+ chunk=bytes(chunk)
80
+ #chunk = await TelegramBot(functions.upload.GetFileRequest(
81
+ #precise=True, location=file, offset=pos, limit=limit
82
+ # ))
83
+ if not chunk:
84
+
85
+ break
86
+
87
+ elif part_index >= part_count:
88
+
89
+ break
90
+ else:
91
+
92
+ if not is_big:
93
+ # Bit odd that MD5 is only needed for small files and not
94
+ # big ones with more chance for corruption, but that's
95
+ # what Telegram wants.
96
+ hash_md5.update(chunk)
97
+
98
+ # The SavePartRequest is different depending on whether
99
+ # the file is too large or not (over or less than 10MB)
100
+ if is_big:
101
+ await TelegramBot(functions.upload.SaveBigFilePartRequest(
102
+ file_id, part_index, part_count, chunk))
103
+ else:
104
+ await TelegramBot(functions.upload.SaveFilePartRequest(
105
+ file_id, part_index, chunk))
106
+
107
+ #yield chunk
108
+
109
+
110
+
111
+
112
+ pos += len(chunk)
113
+ part_index += 1
114
+ await callback(pos,part_index,part_size,part_count,file_size,peer_id,mesage_update_id,filename)
115
+ if is_big:
116
+ return types.InputFileBig(file_id, part_count, file_name),filename
117
+ else:
118
+ return custom.InputSizedFile(
119
+ file_id, part_count, file_name, md5=hash_md5, size=file_size
120
+ ),filename
121
+
122
+
123
+ ''' if not chunk:
124
+ break
125
+ elif part_count == 1:
126
+ if not is_big:
127
+ # Bit odd that MD5 is only needed for small files and not
128
+ # big ones with more chance for corruption, but that's
129
+ # what Telegram wants.
130
+ hash_md5.update(chunk[first_part_cut:last_part_cut])
131
+ if is_big:
132
+ request = functions.upload.SaveBigFilePartRequest(file_id=file_id,file_part=current_part,file_total_parts=part_count,bytes=chunk[first_part_cut:last_part_cut])
133
+ else:
134
+ request = functions.upload.SaveFilePartRequest(file_id=file_id,file_part=current_part,bytes=chunk[first_part_cut:last_part_cut])
135
+ #yield chunk[first_part_cut:last_part_cut]
136
+ elif current_part == 0:
137
+ if not is_big:
138
+ # Bit odd that MD5 is only needed for small files and not
139
+ # big ones with more chance for corruption, but that's
140
+ # what Telegram wants.
141
+ hash_md5.update(chunk[first_part_cut:])
142
+ if is_big:
143
+ request = functions.upload.SaveBigFilePartRequest(
144
+ file_id=file_id,file_part=current_part,file_total_parts=part_count,bytes=chunk[first_part_cut:])
145
+ #file_id, current_part, part_count, chunk[first_part_cut:])
146
+ else:
147
+ request = functions.upload.SaveFilePartRequest(
148
+ file_id=file_id,file_part=current_part,bytes=chunk[first_part_cut:])
149
+ #yield chunk[first_part_cut:]
150
+ elif current_part == part_count-1:
151
+ if not is_big:
152
+ # Bit odd that MD5 is only needed for small files and not
153
+ # big ones with more chance for corruption, but that's
154
+ # what Telegram wants.
155
+ hash_md5.update(chunk[:last_part_cut])
156
+ if is_big:
157
+ request = functions.upload.SaveBigFilePartRequest(
158
+ file_id=file_id,file_part=current_part,file_total_parts=part_count,bytes=chunk[:last_part_cut])
159
+ #file_id, current_part, part_count, chunk[:last_part_cut])
160
+ else:
161
+ request = functions.upload.SaveFilePartRequest(
162
+ file_id=file_id,file_part=current_part,bytes=chunk[:last_part_cut])
163
+
164
+ #yield chunk[:last_part_cut]
165
+ else:
166
+ if not is_big:
167
+ # Bit odd that MD5 is only needed for small files and not
168
+ # big ones with more chance for corruption, but that's
169
+ # what Telegram wants.
170
+ hash_md5.update(chunk)
171
+ if is_big:
172
+ request = functions.upload.SaveBigFilePartRequest(
173
+ file_id=file_id,file_part=current_part,file_total_parts=part_count,bytes=chunk)
174
+ #file_id, current_part, part_count, chunk)
175
+ else:
176
+ request = functions.upload.SaveFilePartRequest(
177
+ file_id=file_id,file_part=current_part,bytes=chunk)
178
+ #file_id, current_part, chunk)
179
+ #yield chunk
180
+
181
+
182
+
183
+ current_part += 1
184
+ pos +=len(chunk)
185
+
186
+ await callback(pos,current_part,part_size,part_count,file_size,peer_id,mesage_update_id)
187
+
188
+ if is_big:
189
+ return types.InputFileBig(file_id, part_count, filename)
190
+ else:
191
+ return custom.InputSizedFile(
192
+ file_id, part_count, filename, md5=hash_md5, size=file_size
193
+ )'''
bot/server/__init__.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from quart import Quart
2
+ from uvicorn import Server as UvicornServer, Config
3
+ from logging import getLogger
4
+ from bot.config import Server, LOGGER_CONFIG_JSON
5
+
6
+ from . import main, error
7
+
8
+ logger = getLogger('uvicorn')
9
+ instance = Quart(__name__)
10
+ instance.config['RESPONSE_TIMEOUT'] = None
11
+
12
+ @instance.before_serving
13
+ async def before_serve():
14
+ logger.info('Web server is started!')
15
+ logger.info(f'Server running on {Server.BIND_ADDRESS}:{Server.PORT}')
16
+
17
+ instance.register_blueprint(main.bp)
18
+
19
+ instance.register_error_handler(400, error.invalid_request)
20
+ instance.register_error_handler(404, error.not_found)
21
+ instance.register_error_handler(405, error.invalid_method)
22
+ instance.register_error_handler(error.HTTPError, error.http_error)
23
+
24
+ server = UvicornServer (
25
+ Config (
26
+ app=instance,
27
+ host=Server.BIND_ADDRESS,
28
+ port=Server.PORT,
29
+ log_config=LOGGER_CONFIG_JSON
30
+ )
31
+ )
bot/server/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (1.88 kB). View file
 
bot/server/__pycache__/error.cpython-311.pyc ADDED
Binary file (2.18 kB). View file
 
bot/server/__pycache__/main.cpython-311.pyc ADDED
Binary file (5.24 kB). View file
 
bot/server/error.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class HTTPError(Exception):
2
+ status_code:int = None
3
+ description:str = None
4
+ def __init__(self, status_code, description):
5
+ self.status_code = status_code
6
+ self.description = description
7
+ super().__init__(self.status_code, self.description)
8
+
9
+ error_messages = {
10
+ 400: 'Invalid request.',
11
+ 401: 'File code is required to download the file.',
12
+ 403: 'Invalid file code.',
13
+ 404: 'File not found.',
14
+ 500: 'Internal server error.'
15
+ }
16
+
17
+ async def invalid_request(_):
18
+ return 'Invalid request.', 400
19
+
20
+ async def not_found(_):
21
+ return 'Resource not found.', 404
22
+
23
+ async def invalid_method(_):
24
+ return 'Invalid request method.', 405
25
+
26
+ async def http_error(error: HTTPError):
27
+ error_message = error_messages.get(error.status_code)
28
+ return error.description or error_message, error.status_code
29
+
30
+ def abort(status_code: int = 500, description: str = None):
31
+ raise HTTPError(status_code, description)
bot/server/main.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from quart import Blueprint, Response, request, render_template, redirect
2
+ from .error import abort
3
+ from bot import TelegramBot
4
+ from bot.modules.decorators import byte_to_gb_mb
5
+ from bot.config import Telegram, Server
6
+ from math import ceil, floor
7
+ from bot.modules.telegram import get_message, get_file_properties
8
+
9
+ bp = Blueprint('main', __name__)
10
+
11
+ @bp.route('/')
12
+ async def home():
13
+ return "Welcome!!"
14
+ #return redirect(f'https://t.me/{Telegram.BOT_USERNAME}')
15
+
16
+ @bp.route('/dl/<int:file_id>')
17
+ async def transmit_file(file_id):
18
+ file = await get_message(message_id=int(file_id)) or abort(404)
19
+ code = request.args.get('code') or abort(401)
20
+ range_header = request.headers.get('Range', 0)
21
+
22
+ if code != file.raw_text:
23
+ abort(403)
24
+
25
+ file_name, file_size, mime_type = get_file_properties(file)
26
+
27
+ if range_header:
28
+ from_bytes, until_bytes = range_header.replace("bytes=", "").split("-")
29
+ from_bytes = int(from_bytes)
30
+ until_bytes = int(until_bytes) if until_bytes else file_size - 1
31
+ else:
32
+ from_bytes = 0
33
+ until_bytes = file_size - 1
34
+
35
+ if (until_bytes > file_size) or (from_bytes < 0) or (until_bytes < from_bytes):
36
+ abort(416, 'Invalid range.')
37
+
38
+ chunk_size = 1024 * 1024
39
+ until_bytes = min(until_bytes, file_size - 1)
40
+
41
+ offset = from_bytes - (from_bytes % chunk_size)
42
+ first_part_cut = from_bytes - offset
43
+ last_part_cut = until_bytes % chunk_size + 1
44
+
45
+ req_length = until_bytes - from_bytes + 1
46
+ part_count = ceil(until_bytes / chunk_size) - floor(offset / chunk_size)
47
+
48
+ headers = {
49
+ "Content-Type": f"{mime_type}",
50
+ "Content-Range": f"bytes {from_bytes}-{until_bytes}/{file_size}",
51
+ "Content-Length": str(req_length),
52
+ "Content-Disposition": f'attachment; filename="{file_name}"',
53
+ "Accept-Ranges": "bytes",
54
+ }
55
+
56
+ async def file_generator():
57
+ current_part = 1
58
+ async for chunk in TelegramBot.iter_download(file, offset=offset, chunk_size=chunk_size, stride=chunk_size, file_size=file_size):
59
+ if not chunk:
60
+ break
61
+ elif part_count == 1:
62
+ yield chunk[first_part_cut:last_part_cut]
63
+ elif current_part == 1:
64
+ yield chunk[first_part_cut:]
65
+ elif current_part == part_count:
66
+ yield chunk[:last_part_cut]
67
+ else:
68
+ yield chunk
69
+
70
+ current_part += 1
71
+
72
+ if current_part > part_count:
73
+ break
74
+
75
+ return Response(file_generator(), headers=headers, status=206 if range_header else 200)
76
+
77
+ @bp.route('/stream/<int:file_id>')
78
+ async def stream_file(file_id):
79
+ code = request.args.get('code') or abort(401)
80
+ file = await get_message(message_id=int(file_id)) or abort(404)
81
+ file_name, file_size, mime_type = get_file_properties(file)
82
+ return await render_template('player.html', mediaLink=f'{Server.BASE_URL}/dl/{file_id}?code={code}',file_name=file_name,file_size=byte_to_gb_mb(file_size))
83
+
84
+ @bp.route('/file/<int:file_id>')
85
+ async def file_deeplink(file_id):
86
+ code = request.args.get('code') or abort(401)
87
+
88
+ return redirect(f'https://t.me/{Telegram.BOT_USERNAME}?start=file_{file_id}_{code}')
bot/server/templates/link.png ADDED
bot/server/templates/mx.png ADDED
bot/server/templates/player.html ADDED
@@ -0,0 +1,781 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>Play | {{file_name}}</title>
5
+
6
+ <meta charset="UTF-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+ <meta http-equiv="X-Frame-Options" content="deny">
9
+
10
+ <link rel="stylesheet" href="https://cdn.plyr.io/3.7.8/plyr.css" />
11
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
12
+
13
+ <script src="https://cdn.plyr.io/3.7.8/plyr.polyfilled.js"></script>
14
+
15
+ <style>
16
+ html, body {
17
+ height: 100%;
18
+ width: 100%;
19
+ background-image: url(https://i.postimg.cc/T2mcBGtv/pxfuel-2.jpg);
20
+
21
+ }
22
+
23
+ #stream-media {
24
+ height: 100%;
25
+ width: 100%;
26
+ }
27
+
28
+ #error-message {
29
+ color: red;
30
+ font-size: 24px;
31
+ text-align: center;
32
+ margin-top: 20px;
33
+ }
34
+
35
+ .plyr__video-wrapper .plyr-download-button{
36
+ position: absolute;
37
+ top: 10px;
38
+ left: 10px;
39
+ width: 30px;
40
+ height: 30px;
41
+ background-color: rgba(0, 0, 0, 0.7);
42
+ border-radius: 50%;
43
+ text-align: center;
44
+ line-height: 30px;
45
+ color: white;
46
+ z-index: 10;
47
+ }
48
+
49
+ .plyr__volume {
50
+ max-width: initial;
51
+ min-width: initial;
52
+ width: auto;
53
+ position: relative;
54
+ }
55
+
56
+
57
+ .plyr__video-wrapper .plyr-share-button{
58
+ position: absolute;
59
+ top: 50px;
60
+ left: 10px;
61
+ width: 30px;
62
+ height: 30px;
63
+ background-color: rgba(0, 0, 0, 0.7);
64
+ border-radius: 50%;
65
+ text-align: center;
66
+ line-height: 30px;
67
+ color: white;
68
+ z-index: 10;
69
+ }
70
+
71
+ .plyr__video-wrapper .plyr-download-button:hover,
72
+ .plyr__video-wrapper .plyr-share-button:hover{
73
+ background-color: rgba(255, 255, 255, 0.7);
74
+ color: black;
75
+ }
76
+
77
+ .plyr__video-wrapper .plyr-download-button:before {
78
+ font-family: "Font Awesome 5 Free";
79
+ content: "\f019";
80
+ font-weight: bold;
81
+ }
82
+
83
+ .plyr__video-wrapper .plyr-share-button:before {
84
+ font-family: "Font Awesome 5 Free";
85
+ content: "\f064";
86
+ font-weight: bold;
87
+ }
88
+
89
+ .plyr, .plyr__video-wrapper, .plyr__video-embed iframe {
90
+ height: auto;
91
+ width:100vw;
92
+ }
93
+
94
+ :root {
95
+ --mycol: #ff003c;
96
+ --gcol: linear-gradient(to right, red, blue);
97
+ }
98
+
99
+ span {
100
+ color: var(--mycol);
101
+ }
102
+
103
+ * {
104
+ margin: 0;
105
+ padding: 0;
106
+ box-sizing: border-box;
107
+ color: white;
108
+ font-family: 'Josefin Sans', sans-serif;
109
+ scroll-behavior: smooth;
110
+ text-transform: capitalize;
111
+ }
112
+
113
+ *::-webkit-scrollbar {
114
+ display: none;
115
+ }
116
+
117
+
118
+
119
+
120
+
121
+ a {
122
+ text-decoration: none;
123
+ }
124
+
125
+ .file-name {
126
+ overflow: hidden;
127
+ margin-top: 20px;
128
+ width: 100vw;
129
+ height: auto;
130
+ padding: 20px;
131
+ border-radius: 5px;
132
+ background: linear-gradient(to bottom, rgba(52, 52, 52, 0.301), rgba(153, 153, 153, 0.075));
133
+ }
134
+
135
+ .file-name h4 {
136
+ color: var(--mycol);
137
+ }
138
+
139
+ .downloadBtn {
140
+ padding: 30px 0;
141
+ display: flex;
142
+ align-items: center;
143
+ justify-content: center;
144
+ /* flex-direction: column; */
145
+ flex-wrap: wrap;
146
+ gap: 20px;
147
+
148
+ }
149
+
150
+ .downloadBtn button {
151
+ opacity: 1;
152
+ border-radius: 6px;
153
+ background: linear-gradient(to bottom, rgba(247, 247, 247, 0.187), rgba(240, 240, 240, 0.105));
154
+ height: 50px;
155
+ width: 300px;
156
+ display: flex;
157
+ align-items: center;
158
+ font-weight: 700;
159
+ gap: 10px;
160
+ padding-left: 50px;
161
+ border: none;
162
+ text-transform: uppercase;
163
+ }
164
+
165
+ .downloadBtn img {
166
+ height: 20px;
167
+ }
168
+
169
+
170
+
171
+
172
+
173
+ /* about sec edit */
174
+ .abt {
175
+
176
+ overflow: hidden;
177
+ }
178
+
179
+ .about {
180
+ /* width: 100%; */
181
+ width: 100vw;
182
+ background-size: cover;
183
+ backdrop-filter: blur(1px);
184
+ height: 100vh;
185
+ position: relative;
186
+ /* overflow: hidden; */
187
+ transition: all 0.4s ease;
188
+ /* display: none; */
189
+ overflow: hidden;
190
+
191
+ }
192
+
193
+ .about::-webkit-scrollbar {
194
+ display: none;
195
+ }
196
+
197
+ .about-nav {
198
+ /* height: 50px; */
199
+ width: 100%;
200
+ align-items: center;
201
+ justify-content: space-evenly;
202
+ backdrop-filter: blur(1px);
203
+ position: fixed;
204
+ left: 0%;
205
+ z-index: 200;
206
+ font-size: 14px;
207
+ top: 12%;
208
+ display: none;
209
+ }
210
+
211
+ .about-nav a {
212
+ position: relative;
213
+ margin: 0 7px;
214
+ }
215
+
216
+ .about-nav a::after {
217
+ content: "";
218
+ position: absolute;
219
+ height: 2px;
220
+ width: 0%;
221
+ background-color: var(--mycol);
222
+ bottom: -5px;
223
+ left: 1px;
224
+ border-radius: 30px;
225
+ transition: all 0.4s ease;
226
+
227
+ }
228
+
229
+ .about-nav a.active::after {
230
+ width: 90%;
231
+ }
232
+
233
+ .about-dets {
234
+ height: 100vh;
235
+ width: 400vw;
236
+ position: absolute;
237
+ display: flex;
238
+ align-items: center;
239
+ overflow: hidden;
240
+ transition: all 0.4s ease;
241
+ }
242
+
243
+ .abt-sec {
244
+ height: 100%;
245
+ width: 100vw;
246
+ display: flex;
247
+ flex-direction: column;
248
+ align-items: center;
249
+ /* justify-content: center; */
250
+ z-index: 100;
251
+ gap: 10%;
252
+ padding-top: 130px;
253
+ backdrop-filter: blur(5px);
254
+ overflow: hidden;
255
+
256
+ }
257
+
258
+ #sec4 {
259
+ /* transform: translateY(60px); */
260
+ gap: 22px;
261
+ padding-left: 20px;
262
+ padding-right: 20px;
263
+ }
264
+
265
+ #sec4 h1 {
266
+ margin-bottom: 30px;
267
+ }
268
+
269
+ .abt-sec h1 {
270
+ text-align: center;
271
+ transform: translateY(20px);
272
+ font-weight: 700;
273
+ }
274
+
275
+ .abt-sec p {
276
+ text-align: center;
277
+ font-weight: 700;
278
+ text-transform: capitalize;
279
+ font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
280
+ }
281
+
282
+
283
+
284
+ .links {
285
+ display: flex;
286
+ flex-direction: column;
287
+ align-items: center;
288
+ gap: 10px;
289
+ }
290
+
291
+ .links button {
292
+ width: 350px;
293
+ height: 50px;
294
+ border-radius: 6px;
295
+ border: none;
296
+ background: linear-gradient(to top, rgba(46, 46, 46, 0.365), rgba(46, 46, 46, 0.443));
297
+ font-size: 15px;
298
+ font-weight: 550;
299
+ transition: all 0.4s ease;
300
+ /* opacity: 0; */
301
+ }
302
+
303
+ .links a {
304
+ opacity: 0;
305
+ }
306
+
307
+ button {
308
+ transition: all 1s ease;
309
+ /* opacity: 0; */
310
+ /* animation: linksBtnAn 2s ease 0.3s infinite, strtLoad 4s ease 0.5s forwards; */
311
+ position: relative;
312
+ overflow: hidden;
313
+ }
314
+
315
+ .links button::before,
316
+ .downloadBtn button::before {
317
+ opacity: 0;
318
+ left: -10px;
319
+ top: -20px;
320
+ content: "";
321
+ width: 20%;
322
+ height: 200%;
323
+ position: absolute;
324
+ background-color: #ffffff18;
325
+ box-shadow: 2px 2px 30px 30px #ffffff18;
326
+ rotate: 20deg;
327
+ animation: var(--beforestyl);
328
+ filter: contrast(100);
329
+ }
330
+
331
+ .links button:hover {
332
+ scale: 1.05;
333
+ }
334
+
335
+ button:active {
336
+ scale: 0.7;
337
+ }
338
+
339
+ .box {
340
+ margin-bottom: 60px;
341
+ }
342
+
343
+ .box h3 {
344
+ margin-bottom: 15px;
345
+ position: relative;
346
+ }
347
+
348
+ .box a {
349
+ margin-top: 15px;
350
+ }
351
+
352
+ .box p {
353
+ margin-top: 5px;
354
+ }
355
+
356
+ .box h3::after {
357
+ content: "";
358
+ position: absolute;
359
+ height: 1.5px;
360
+ width: 90%;
361
+ background-color: var(--mycol);
362
+ bottom: -3px;
363
+ left: 0%;
364
+ border-radius: 30px;
365
+ transition: all 0.4s ease;
366
+ }
367
+
368
+ /* middle part */
369
+ .mid {
370
+ font-size: 40px;
371
+ font-weight: 600;
372
+ text-align: center;
373
+ padding: 10%;
374
+ }
375
+
376
+ .last-text {
377
+ text-align: center;
378
+ padding: 10%;
379
+ }
380
+
381
+ .movie-cont {
382
+ height: fit-content;
383
+ width: 100vw;
384
+ display: flex;
385
+ flex-direction: column;
386
+ align-items: center;
387
+ gap: 30px;
388
+ }
389
+
390
+ .movieSug {
391
+ height: 500px;
392
+ width: 95vw;
393
+ border-radius: 2%;
394
+ position: relative;
395
+ display: flex;
396
+ align-items: center;
397
+ justify-content: space-around;
398
+ /* background-image: url(https://image.tmdb.org/t/p/w1280//8Gxv8gSFCU0XGDykEGv7zR1n2ua.jpg); */
399
+ background-size: cover;
400
+ background-position: center;
401
+ overflow: hidden;
402
+
403
+ }
404
+
405
+ .movieSug::before {
406
+ content: '';
407
+ height: 110%;
408
+ width: 110%;
409
+ position: absolute;
410
+ background: linear-gradient(to right, black 20%, rgba(0, 0, 0, 0.322) 75%, rgba(0, 0, 0, 0));
411
+ top: 0%;
412
+ left: -10px;
413
+ }
414
+
415
+ .movieDets {
416
+ padding: 5%;
417
+ height: 100%;
418
+ width: 45vw;
419
+ display: flex;
420
+ flex-direction: column;
421
+ text-align: start;
422
+ justify-content: center;
423
+ gap: 10px;
424
+ z-index: 100;
425
+ }
426
+
427
+ .movieDets h3:first-child {
428
+ font-size: 32px;
429
+ font-weight: 600;
430
+ }
431
+
432
+ .movieimg {
433
+ /* height: 100%; */
434
+ width: 45vw;
435
+ /* background-color: #100206; */
436
+ display: flex;
437
+ justify-content: center;
438
+ align-items: center;
439
+ gap: 10px;
440
+ }
441
+
442
+ .movieimg img {
443
+ max-height: 400px;
444
+ box-shadow: 2px 2px 100px 70px rgba(0, 0, 0, 0.566);
445
+ }
446
+
447
+ .movieDets span {
448
+ font-weight: 700;
449
+ font-size: 20px;
450
+ }
451
+
452
+ .movieDets h4:nth-child(2) {
453
+ margin-top: 20px;
454
+ font-size: 23px;
455
+ font-weight: 700;
456
+ }
457
+
458
+ .movieDets h4:nth-child(3) {
459
+
460
+ font-size: 15px;
461
+ font-weight: 700;
462
+ }
463
+
464
+ .movieStsBar {
465
+ display: none;
466
+ }
467
+
468
+ .ranMovBtn {
469
+
470
+ border-radius: 6px;
471
+ background: linear-gradient(to bottom, rgba(247, 247, 247, 0.187), rgba(240, 240, 240, 0.105));
472
+ height: 50px;
473
+ width: 300px;
474
+ display: flex;
475
+ align-items: center;
476
+ font-weight: 700;
477
+ gap: 10px;
478
+ padding-left: 50px;
479
+ border: none;
480
+ }
481
+
482
+ .copyright {
483
+ margin: 30px;
484
+ gap: 10px;
485
+ display: flex;
486
+ flex-direction: column;
487
+ align-items: center;
488
+
489
+ }
490
+
491
+ .copyright h5 {
492
+ font-size: 13px;
493
+ }
494
+
495
+ @keyframes linksBtnAn {
496
+
497
+ from {
498
+ scale: 1;
499
+ }
500
+
501
+ 50% {
502
+ scale: 1.02;
503
+ }
504
+
505
+ to {
506
+ scale: 1;
507
+ }
508
+ }
509
+
510
+ @keyframes strtLoad {
511
+ from {
512
+ opacity: 0;
513
+ transform: translateX(-200px);
514
+ }
515
+
516
+ to {
517
+ opacity: 1;
518
+ transform: translateX(0px);
519
+ }
520
+
521
+ }
522
+
523
+ @keyframes button_shine {
524
+ from {
525
+ opacity: .9;
526
+ left: -100px;
527
+ }
528
+
529
+ to {
530
+ opacity: 1;
531
+ left: 400px;
532
+ }
533
+ }
534
+
535
+ @media (max-width : 1029px) {
536
+
537
+ .movieDets h3:first-child {
538
+ font-size: 25px;
539
+ }
540
+ }
541
+
542
+ @media (max-width : 992px) {
543
+ .movieSug {
544
+ scale: 0.9;
545
+ }
546
+
547
+ .movie-cont {
548
+ scale: 0.9;
549
+ }
550
+
551
+ }
552
+
553
+ @media (max-width : 800px) {
554
+ .movie-cont {
555
+ scale: 0.9;
556
+ }
557
+
558
+ .movieSug {
559
+ height: 400px;
560
+ }
561
+
562
+ .movieimg img {
563
+ max-height: 300px;
564
+
565
+ }
566
+
567
+ .movieDets {
568
+ scale: 0.8;
569
+ }
570
+
571
+ }
572
+
573
+ @media (max-width : 637px) {
574
+ .movieSug {
575
+ background-position: right;
576
+ padding: 5%;
577
+ scale: 1;
578
+ width: 90vw;
579
+ }
580
+
581
+ .movie-cont {
582
+ width: 90vw;
583
+ padding: 5%;
584
+ scale: 1;
585
+ }
586
+
587
+ .movieDets {
588
+ display: none;
589
+ }
590
+
591
+ .movieStsBar {
592
+ display: block;
593
+ border-radius: 6%;
594
+ }
595
+
596
+ .movieDets-mini {
597
+ position: absolute;
598
+ display: flex;
599
+ flex-direction: column;
600
+ text-align: start;
601
+ width: 80%;
602
+ left: 50px;
603
+ transform: translate(-35px, -120px);
604
+
605
+ }
606
+
607
+ .movieSug::before {
608
+ content: '';
609
+ height: 100%;
610
+ width: 100%;
611
+ position: absolute;
612
+ background: linear-gradient(to top, black 20%, rgba(0, 0, 0, 0.322) 75%, rgba(0, 0, 0, 0));
613
+ top: 10%;
614
+ left: 0px;
615
+ }
616
+
617
+ .movieimg img {
618
+ transform: translate(75px, -40px);
619
+
620
+ }
621
+ }
622
+ </style>
623
+ </head>
624
+
625
+ <body>
626
+
627
+
628
+ <video id="stream-media" controls preload="auto">
629
+ <source src="" type="">
630
+ <p class="vjs-no-js">
631
+ To view this video please enable JavaScript, and consider upgrading to a web browser that supports HTML5 video
632
+ </p>
633
+ </video>
634
+ <div class="file-name">
635
+ <h4 style="display: inline;">File Name: </h4>
636
+ <p style="display: inline;" id="myDiv">{{file_name}}</p><br>
637
+ <h4 style="display: inline;">File Size: </h4>
638
+ <p style="display: inline;">{{file_size}}</p>
639
+ </div>
640
+ <div class="downloadBtn">
641
+ <button class="magnet" onclick="copyStreamLink()">
642
+ <img src="https://i.ibb.co/CM4Y586/link.png" alt="Copy Link">copy link
643
+ </button>
644
+ <button class="magnet share" onclick="link_share()">
645
+ <img src="https://i.ibb.co/vx5D2g5/share.png" alt="">share link
646
+ </button>
647
+ <button class="magnet" onclick="vlc_player()">
648
+ <img src="https://i.ibb.co/px6fQs1/vlc.png" alt="">watch in VLC PLAYER
649
+ </button>
650
+ <button class="magnet" onclick="mx_player()">
651
+ <img src="https://i.ibb.co/41WvtQ3/mx.png" alt="">watch in MX PLAYER
652
+ </button>
653
+
654
+
655
+ </div>
656
+ <div id="error-message"></div>
657
+
658
+
659
+ <script>
660
+ var player = new Plyr('#stream-media', {
661
+ controls:['play-large', 'rewind', 'play', 'fast-forward', 'progress', 'current-time', 'mute', 'settings','download', 'pip', 'fullscreen'],
662
+ settings:['speed','loop'],
663
+ speed:{selected:1,options:[0.25,0.5,0.75,1,1.25,1.5,1.75,2]},
664
+ seek: 10,
665
+ keyboard: { focused: true, global: true },
666
+ });
667
+
668
+ var mediaLink = "{{ mediaLink }}";
669
+
670
+ if (mediaLink) {
671
+ document.querySelector('#stream-media source').setAttribute('src', mediaLink);
672
+ player.restart();
673
+
674
+ /*var downloadButton = document.createElement('div');
675
+ downloadButton.className = 'plyr-download-button';
676
+
677
+ downloadButton.onclick = function() {
678
+ event.stopPropagation();
679
+ var link = document.createElement('a');
680
+ link.href = mediaLink;
681
+ document.body.appendChild(link);
682
+ link.click();
683
+ document.body.removeChild(link);
684
+ };
685
+
686
+ player.elements.container.querySelector('.plyr__video-wrapper').appendChild(downloadButton);
687
+
688
+ var shareButton = document.createElement('div');
689
+ shareButton.className = 'plyr-share-button';
690
+
691
+ shareButton.onclick = function() {
692
+ event.stopPropagation();
693
+ if (navigator.share) {
694
+ navigator.share({
695
+ title: "Play",
696
+ url: window.location.href
697
+ });
698
+ }
699
+ };
700
+
701
+ player.elements.container.querySelector('.plyr__video-wrapper').appendChild(shareButton);
702
+ */
703
+
704
+ } else {
705
+ document.getElementById('error-message').textContent = 'Error: Media URL not provided';
706
+ }
707
+ function link_share() {
708
+ if (navigator.share) {
709
+ navigator.share({
710
+ title: mediaLink,
711
+ url: window.location.href
712
+ });
713
+ }
714
+
715
+ }
716
+ function vlc_player() {
717
+
718
+ const openstreamlink = mediaLink;
719
+ const openVlc = `vlc://${openstreamlink}`;
720
+ if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
721
+ // Try opening VLC first, then MX Player if VLC is unavailable
722
+ window.location.href = openVlc;
723
+
724
+ } else {
725
+ alert("This feature is currently only supported on Android devices.");
726
+ }
727
+ //window.location.href = openVlc;
728
+ }
729
+
730
+ function mx_player() {
731
+ const openstreamlink = mediaLink;
732
+ const openMx = `intent:${openstreamlink}#Intent;package=com.mxtech.videoplayer.ad;end`;
733
+ if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
734
+ // Try opening VLC first, then MX Player if VLC is unavailable
735
+ window.location.href = openMx;;
736
+
737
+ } else {
738
+ alert("This feature is currently only supported on Android devices.");
739
+ }
740
+
741
+ }
742
+ function copyStreamLink() {
743
+ const linkToCopy = mediaLink.toLowerCase();
744
+
745
+ if (!navigator.clipboard) {
746
+ navigator.clipboard = {
747
+ writeText: function(text) {
748
+ return new Promise((resolve, reject) => {
749
+ try {
750
+ const textArea = document.createElement("textarea");
751
+ textArea.value = text;
752
+ document.body.appendChild(textArea);
753
+ textArea.focus();
754
+ textArea.select();
755
+ document.execCommand('copy');
756
+ document.body.removeChild(textArea);
757
+ resolve();
758
+ } catch (err) {
759
+ reject(err);
760
+ }
761
+ });
762
+ }
763
+ };
764
+ }
765
+
766
+ navigator.clipboard.writeText(linkToCopy)
767
+ .then(() => {
768
+ console.log('Stream link copied to clipboard!');
769
+ alert('Stream link copied successfully!');
770
+ })
771
+ .catch(err => {
772
+ console.error('Failed to copy link: ', err);
773
+ alert('Failed to copy link. Please try manually.');
774
+ });
775
+ }
776
+
777
+
778
+ </script>
779
+
780
+ </body>
781
+ </html>
bot/server/templates/share.png ADDED
bot/server/templates/vlc.png ADDED

Git LFS Details

  • SHA256: 9d1f243d59e5a3d7c1098584ffcc7e62cf1d940d955c3b72a848a40541848a3b
  • Pointer size: 131 Bytes
  • Size of remote file: 501 kB
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ telethon
2
+ cryptg
3
+ quart
4
+ uvicorn
5
+ requests