Skip to content
This repository was archived by the owner on Jan 15, 2026. It is now read-only.

Commit 92aad77

Browse files
committed
refactor: reorganized folders and updated some logic
* Reorganized project structure * Updated some function logic * Removed unused functions * Changed file info caching logic
1 parent 2e6e490 commit 92aad77

15 files changed

Lines changed: 150 additions & 267 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ you may also add as many as bots you want. (max limit is not tested yet)
130130
> **Note**
131131
> Leave this field empty and anyone will be able to use your bot instance.
132132
133+
`CACHE_SIZE` (default: 128) — Maximum number of file info entries cached per client. Each client (including those using MULTI_TOKEN) gets its own separate cache of this size
134+
133135
`CHUNK_SIZE`: Size of the chunk to request from Telegram server when streaming a file [See more](https://core.telegram.org/api/files#downloading-files)
134136

135137
`CONNECTION_LIMIT`: (default 20) - The maximum number of connections to a single Telegram datacenter.
@@ -154,8 +156,6 @@ you may also add as many as bots you want. (max limit is not tested yet)
154156

155157
`SLEEP_THRESHOLD` : Set a sleep threshold for flood wait exceptions happening globally in this telegram bot instance, below which any request that raises a flood wait will be automatically invoked again after sleeping for the required amount of time. Flood wait exceptions requiring higher waiting times will be raised. Defaults to 60 seconds.
156158

157-
`STREAM_MEDIA`: (default false, can be either `True` or `False`) If you want to play the media (audio or video) in browser
158-
159159
`TRUST_HEADERS`: (defaults to true) - Whether or not to trust X-Forwarded-For headers when logging requests.
160160

161161
`WEB_SERVER_BIND_ADDRESS` : Your server bind address. Defauls to `0.0.0.0`

WebStreamer/__main__.py

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,13 @@
66
import logging
77
import logging.handlers as handlers
88

9-
109
from aiohttp import web
11-
from WebStreamer.bot import StreamBot, BotInfo
12-
from WebStreamer.server import web_server
13-
from WebStreamer.utils.keepalive import ping_server
14-
from WebStreamer.utils.util import load_plugins, startup
15-
from WebStreamer.bot.clients import initialize_clients
10+
from .stream_routes import routes
11+
from .utils.keepalive import ping_server
12+
from .utils.util import load_plugins, startup
13+
from .clients import StreamBot, initialize_clients
1614
from .vars import Var
1715

18-
1916
logging.basicConfig(
2017
level=logging.DEBUG if Var.DEBUG else logging.INFO,
2118
datefmt="%d/%m/%Y %H:%M:%S",
@@ -27,13 +24,9 @@
2724
logging.getLogger("aiohttp.web").setLevel(logging.DEBUG if Var.DEBUG else logging.ERROR)
2825
logging.getLogger("telethon").setLevel(logging.INFO if Var.DEBUG else logging.ERROR)
2926

30-
server = web.AppRunner(web_server())
31-
32-
#if sys.version_info[1] > 9:
33-
# loop = asyncio.new_event_loop()
34-
# asyncio.set_event_loop(loop)
35-
#else:
36-
loop = asyncio.get_event_loop()
27+
app = web.Application(client_max_size=1024*8) # 8KB
28+
app.add_routes(routes)
29+
server = web.AppRunner(app)
3730

3831
async def start_services():
3932
logging.info("Initializing Telegram Bot")
@@ -45,8 +38,8 @@ async def start_services():
4538
logging.error("Bin Channel not found. Please ensure the bot has been added to the bin channel.")
4639
return
4740
bot_info = await StreamBot.get_me()
48-
BotInfo.username = bot_info.username
49-
BotInfo.fname=bot_info.first_name
41+
Var.USERNAME = bot_info.username
42+
Var.FIRST_NAME=bot_info.first_name
5043
logging.info("Initialized Telegram Bot")
5144
logging.info("Initializing Clients")
5245
await initialize_clients()
@@ -58,7 +51,7 @@ async def start_services():
5851
logging.warning("Bin Channel is a group. Use a channel for multi-client support.")
5952
if not Var.NO_UPDATE:
6053
logging.info('Importing plugins')
61-
load_plugins("WebStreamer/bot/plugins")
54+
load_plugins("WebStreamer/plugins")
6255
logging.info("Imported Plugins")
6356
if Var.KEEP_ALIVE:
6457
logging.info("Starting Keep Alive Service")
@@ -67,23 +60,26 @@ async def start_services():
6760
await server.setup()
6861
await web.TCPSite(server, Var.BIND_ADDRESS, Var.PORT).start()
6962
logging.info("Service Started")
70-
logging.info("bot =>> %s", BotInfo.fname)
63+
logging.info("bot =>> %s", Var.FIRST_NAME)
7164
logging.info("DC ID =>> %s", str(StreamBot.session.dc_id))
7265
logging.info(" URL =>> %s", Var.URL)
7366
await StreamBot.run_until_disconnected()
7467

68+
async def main():
69+
try:
70+
await start_services()
71+
finally:
72+
await cleanup()
73+
logging.info("Stopped Services")
74+
7575
async def cleanup():
7676
await server.cleanup()
7777
await StreamBot.disconnect()
7878

7979
if __name__ == "__main__":
8080
try:
81-
loop.run_until_complete(start_services())
81+
asyncio.run(main())
8282
except KeyboardInterrupt:
8383
pass
84-
except Exception as err:
84+
except Exception:
8585
logging.error(traceback.format_exc())
86-
finally:
87-
loop.run_until_complete(cleanup())
88-
loop.stop()
89-
logging.info("Stopped Services")

WebStreamer/bot/__init__.py

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,19 @@
66
from os import environ
77
from telethon import TelegramClient
88
from telethon.sessions import MemorySession
9-
from WebStreamer.utils.util import startup
10-
from ..vars import Var
11-
from . import multi_clients, work_loads, StreamBot
9+
from .utils.util import startup
10+
from .vars import Var
1211

12+
multi_clients: dict[int, TelegramClient] = {}
13+
work_loads: dict[int, int] = {}
14+
15+
StreamBot = TelegramClient(
16+
session="WebStreamer",
17+
api_id=Var.API_ID,
18+
api_hash=Var.API_HASH,
19+
flood_sleep_threshold=Var.SLEEP_THRESHOLD,
20+
receive_updates=not Var.NO_UPDATE
21+
)
1322

1423
async def initialize_clients():
1524
multi_clients[0] = StreamBot
@@ -51,7 +60,7 @@ async def start_client(client_id, token):
5160
logging.error("Failed starting Client - %s Error:", client_id, exc_info=True)
5261

5362
clients = await asyncio.gather(*[start_client(i, token) for i, token in all_tokens.items()])
54-
multi_clients.update(dict(clients))
63+
multi_clients.update(dict(filter(None,clients)))
5564
if len(multi_clients) != 1:
5665
Var.MULTI_CLIENT = True
5766
logging.info("Multi-client mode enabled")
Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# This file is a part of TG-FileStreamBot
2+
# pylint: disable=relative-beyond-top-level
23

34
from telethon.extensions import html
45
from telethon.events import NewMessage
5-
from WebStreamer import __version__
6-
from WebStreamer.bot import StreamBot
7-
from WebStreamer.vars import Var
6+
from .. import __version__
7+
from ..clients import StreamBot
8+
from ..vars import Var
89

910
@StreamBot.on(NewMessage(incoming=True,pattern=r"^\/start*", func=lambda e: e.is_private))
1011
async def start(event: NewMessage.Event):
@@ -16,7 +17,7 @@ async def start(event: NewMessage.Event):
1617
parse_mode=html
1718
)
1819
await event.message.reply(
19-
message=f'Hi <a href="tg://user?id={event.chat_id}">{event.chat.first_name}</a>, Send me a file to get an instant stream link.',
20+
message=f'Hi <a href="tg://user?id={user.id}">{user.first_name}</a>, Send me a file to get an instant stream link.',
2021
link_preview=False,
2122
parse_mode=html
2223
)
@@ -27,9 +28,9 @@ async def about(event: NewMessage.Event):
2728
message=f"""
2829
Maintained By: <a href="https://github.com/DeekshithSH">DeekshithSH</a>
2930
Source Code: <a href="https://github.com/SpringsFern/TG-FileStreamBot">TG-FileStreamBot</a>
30-
Based On: [<a href="bit.ly/tg-stream">tg filestream</a>] [<a href="https://github.com/EverythingSuckz/TG-FileStreamBot">TG-FileStreamBot</a>]
31+
Based On: [<a href="https://github.com/tulir/TGFileStream/">tg filestream</a>] [<a href="https://github.com/EverythingSuckz/TG-FileStreamBot">TG-FileStreamBot</a>]
3132
Version: {__version__}
32-
Last Updated: 15 March 20225
33+
Last Updated: 08 April 2025
3334
""",
3435
link_preview=False,
3536
parse_mode=html
Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
# This file is a part of TG-FileStreamBot
2+
# pylint: disable=relative-beyond-top-level
23

34
import logging
45
from telethon import Button, errors
56
from telethon.events import NewMessage
67
from telethon.extensions import html
7-
from WebStreamer.bot import StreamBot
8-
from WebStreamer.utils.file_properties import get_file_info, pack_file, get_short_hash
9-
from WebStreamer.vars import Var
8+
from ..clients import StreamBot
9+
from ..utils.file_properties import get_file_info, pack_file, get_short_hash
10+
from ..vars import Var
11+
12+
MEDIA={"video", "audio"} # we can expand it to include more media types
1013

1114
@StreamBot.on(NewMessage(func=lambda e: True if e.message.file and e.is_private else False))
1215
async def media_receive_handler(event: NewMessage.Event):
@@ -28,13 +31,16 @@ async def media_receive_handler(event: NewMessage.Event):
2831
)
2932
file_hash=get_short_hash(full_hash)
3033
stream_link = f"{Var.URL}stream/{log_msg.id}?hash={file_hash}"
31-
34+
is_media = bool(set(file_info.mime_type.split("/")) & MEDIA)
35+
buttons=[[Button.url("Open", url=stream_link)]]
36+
message=f"<code>{stream_link}</code>"
37+
if is_media:
38+
buttons.append([Button.url("Stream", url=stream_link+"&s=1")])
39+
message+=f"<a href='{stream_link}&s=1'>(Stream)</a>"
3240
await event.message.reply(
33-
message=f"<code>{stream_link}</code>",
41+
message=message,
3442
link_preview=False,
35-
buttons=[
36-
[Button.url("Open", url=stream_link)]
37-
],
43+
buttons=buttons,
3844
parse_mode=html
3945
)
4046
except errors.FloodWaitError as e:

WebStreamer/server/__init__.py

Lines changed: 0 additions & 12 deletions
This file was deleted.

WebStreamer/server/exceptions.py

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66
import mimetypes
77
from aiohttp import web
88
from aiohttp.http_exceptions import BadStatusLine
9-
from WebStreamer.bot import multi_clients, work_loads, BotInfo
10-
from WebStreamer.utils.file_properties import get_short_hash, pack_file
11-
from WebStreamer.utils.util import allow_request, get_requester_ip, get_readable_time
12-
from WebStreamer.vars import Var
13-
from WebStreamer.server.exceptions import FIleNotFound, InvalidHash
14-
from WebStreamer import StartTime, __version__
15-
from WebStreamer.utils.paralleltransfer import ParallelTransferrer
9+
from .clients import multi_clients, work_loads
10+
from .utils.file_properties import get_short_hash, pack_file
11+
from .utils.util import allow_request, get_requester_ip, get_readable_time
12+
from .vars import Var
13+
from . import StartTime, __version__
14+
from .utils.paralleltransfer import ParallelTransferrer
1615

1716

1817
routes = web.RouteTableDef()
@@ -24,7 +23,7 @@ async def root_route_handler(_: web.Request):
2423
{
2524
"server_status": "running",
2625
"uptime": get_readable_time(time.time() - StartTime),
27-
"telegram_bot": "@" + BotInfo.username,
26+
"telegram_bot": "@" + Var.USERNAME,
2827
"connected_bots": len(multi_clients),
2928
"loads": dict(
3029
(f"bot{c + 1}", l)
@@ -43,10 +42,6 @@ async def stream_handler(request: web.Request):
4342
message_id = int(request.match_info["messageID"])
4443
secure_hash = request.rel_url.query.get("hash")
4544
return await media_streamer(request, message_id, secure_hash)
46-
except InvalidHash as e:
47-
raise web.HTTPForbidden(text=e.message)
48-
except FIleNotFound as e:
49-
raise web.HTTPNotFound(text=e.message)
5045
except (AttributeError, BadStatusLine, ConnectionResetError):
5146
pass
5247
except Exception as e:
@@ -75,9 +70,8 @@ async def media_streamer(request: web.Request, message_id: int, secure_hash: str
7570
class_cache[faster_client] = transfer
7671
logging.debug("Created new ByteStreamer object for client %s", index)
7772
logging.debug("before calling get_file_properties")
78-
try:
79-
file_id = await transfer.get_file_properties(message_id)
80-
except FIleNotFound:
73+
file_id = await transfer.get_file_properties(message_id)
74+
if not file_id:
8175
return web.Response(status=404, text="File not found")
8276

8377
full_hash = pack_file(
@@ -88,7 +82,7 @@ async def media_streamer(request: web.Request, message_id: int, secure_hash: str
8882
)
8983
if get_short_hash(full_hash) != secure_hash:
9084
logging.debug("Invalid hash for message with ID %s", message_id)
91-
raise InvalidHash
85+
return web.HTTPForbidden(text="Invalid hash")
9286

9387
file_size = file_id.file_size
9488

@@ -125,7 +119,7 @@ async def media_streamer(request: web.Request, message_id: int, secure_hash: str
125119
mime_type = mimetypes.guess_type(
126120
file_name)[0] or "application/octet-stream"
127121

128-
if ("video/" in mime_type or "audio/" in mime_type) and Var.STREAM_MEDIA:
122+
if request.rel_url.query.get("s"):
129123
disposition = "inline"
130124

131125
return web.Response(

0 commit comments

Comments
 (0)