├── nginx ├── Dockerfile └── vhost.conf ├── README.md ├── bot ├── requirements.txt ├── webgram │ ├── __init__.py │ ├── config.py │ ├── stream_tools.py │ └── bare.py ├── Dockerfile └── main.py ├── web ├── requirements.txt ├── webgram │ ├── __init__.py │ ├── config.py │ ├── checkers.py │ ├── bare.py │ ├── stream_tools.py │ ├── streamer.py │ └── app.html ├── Dockerfile └── main.py ├── heroku.yml ├── docker-compose.yml ├── Dockerfile └── LICENSE /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | ADD ./vhost.conf /etc/nginx/conf.d/default.conf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dlstar 2 | 3 | The new version : https://github.com/musa-42/stream-cloud 4 | -------------------------------------------------------------------------------- /bot/requirements.txt: -------------------------------------------------------------------------------- 1 | cryptg 2 | hachoir 3 | pillow 4 | werkzeug 5 | aiohttp 6 | Telethon 7 | requests 8 | gunicorn -------------------------------------------------------------------------------- /web/requirements.txt: -------------------------------------------------------------------------------- 1 | cryptg 2 | hachoir 3 | pillow 4 | werkzeug 5 | aiohttp 6 | Telethon 7 | requests 8 | gunicorn -------------------------------------------------------------------------------- /bot/webgram/__init__.py: -------------------------------------------------------------------------------- 1 | from .config import Config 2 | from .stream_tools import StreamTools 3 | from .bare import BareServer 4 | -------------------------------------------------------------------------------- /web/webgram/__init__.py: -------------------------------------------------------------------------------- 1 | from .config import Config 2 | from .stream_tools import StreamTools 3 | from .streamer import Streamer 4 | from .checkers import Checkers 5 | from .bare import BareServer 6 | -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | web: Dockerfile 4 | worker: bot/Dockerfile 5 | run: 6 | web: gunicorn --workers=3 --threads=3 main:main --bind 0.0.0.0:$PORT --worker-class aiohttp.GunicornWebWorker 7 | worker: python3 main.py -------------------------------------------------------------------------------- /bot/webgram/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | class Config: 4 | 5 | class config: 6 | APP_ID = 50807 7 | 8 | API_HASH = "......" 9 | 10 | BOT_TOKEN = "......." 11 | 12 | channel = 'UserlandApp' 13 | 14 | ROOT_URI = f"http://dl1.dlgram.ml" 15 | 16 | ENCODING = "utf8" 17 | -------------------------------------------------------------------------------- /nginx/vhost.conf: -------------------------------------------------------------------------------- 1 | 2 | server { 3 | listen 80; 4 | client_max_body_size 4G; 5 | 6 | location / { 7 | proxy_set_header Host $http_host; 8 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 9 | proxy_redirect off; 10 | proxy_buffering off; 11 | proxy_pass http://web:8080; 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /bot/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | RUN apt-get update && apt-get install -y locales python3 python3-pip wget && rm -rf /var/lib/apt/lists/* \ 4 | && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 5 | 6 | ENV LANG en_US.utf8 7 | 8 | COPY . /bot 9 | 10 | WORKDIR /bot 11 | 12 | RUN pip3 install -r requirements.txt 13 | 14 | -------------------------------------------------------------------------------- /web/webgram/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | class Config: 4 | 5 | class config: 6 | APP_ID = 50807 7 | 8 | API_HASH = "......" 9 | 10 | BOT_TOKEN = "...." 11 | 12 | HOST = "127.0.0.1" 13 | 14 | PORT = os.getenv('PORT') 15 | 16 | ROOT_URI = f"http://dlstarus.dlgram.ml" 17 | 18 | 19 | ENCODING = "utf8" 20 | 21 | 22 | # ALLOWED_EXT = ["mkv", "mp4", "flv"] 23 | -------------------------------------------------------------------------------- /web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | RUN apt-get update && apt-get install -y locales python3 python3-pip wget && rm -rf /var/lib/apt/lists/* \ 4 | && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 5 | 6 | ENV LANG en_US.utf8 7 | 8 | COPY . /app 9 | 10 | WORKDIR /app 11 | 12 | RUN pip3 install -r requirements.txt 13 | 14 | ENV PORT = 8080 15 | 16 | EXPOSE 8080 17 | 18 | #CMD gunicorn main:main --timeout 86400 -w 5 --bind 0.0.0.0:$PORT --worker-class aiohttp.GunicornWebWorker 19 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | 5 | bot: 6 | build: ./bot 7 | restart: always 8 | command: python3 main.py 9 | 10 | web: 11 | build: ./web 12 | restart: always 13 | command: gunicorn main:main --workers=3 --threads=3 --bind 0.0.0.0:8080 --worker-class aiohttp.GunicornWebWorker 14 | ports: 15 | - 8080:8080 16 | 17 | nginx: 18 | build: ./nginx 19 | restart: always 20 | ports: 21 | - 80:80 22 | depends_on: 23 | - web 24 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | RUN apt-get update && apt-get install -y locales python3 python3-pip wget && rm -rf /var/lib/apt/lists/* \ 4 | && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 5 | 6 | ENV LANG en_US.utf8 7 | 8 | COPY ./web /app 9 | 10 | WORKDIR /app 11 | 12 | RUN pip3 install -r requirements.txt 13 | 14 | ENV PORT = 8080 15 | 16 | EXPOSE 8080 17 | 18 | CMD gunicorn main:main --max-requests 1200 --bind 0.0.0.0:$PORT --worker-class aiohttp.GunicornWebWorker 19 | -------------------------------------------------------------------------------- /web/webgram/checkers.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | if typing.TYPE_CHECKING: 4 | import webgram 5 | 6 | 7 | class Checkers: 8 | async def validate_peer(self: 'webgram.BareServer', peer: str) -> bool: 9 | try: 10 | await self.client.get_peer_id(peer) 11 | return True 12 | 13 | except ValueError: 14 | return False 15 | 16 | @staticmethod 17 | def check_int(x: str) -> bool: 18 | if x[0] in ('-', '+'): 19 | return x[1:].isdigit() 20 | 21 | return x.isdigit() 22 | 23 | def to_int_safe(self: 'webgram.BareServer', x: str) -> typing.Union[str, int]: 24 | return int(x) if self.check_int(x) else x 25 | -------------------------------------------------------------------------------- /web/main.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import webgram 3 | import aiohttp.web 4 | import logging 5 | from concurrent.futures import CancelledError 6 | 7 | logging.basicConfig(level=logging.ERROR) 8 | #logging.basicConfig(level=logging.DEBUG) 9 | 10 | loop = asyncio.get_event_loop() 11 | server = webgram.BareServer(loop=loop) 12 | 13 | async def main(): 14 | app = aiohttp.web.Application(client_max_size=1024*1024*20) 15 | app.add_routes([ 16 | aiohttp.web.get('/', server.hello), 17 | aiohttp.web.get('/w/{hash}', server.watch_stream), 18 | aiohttp.web.get('/w/{hash}/{name}', server.watch_stream), 19 | aiohttp.web.get('/test_upload', server.test_upload), 20 | aiohttp.web.post('/upload_big', server.upload_big), 21 | aiohttp.web.post('/upload', server.upload), 22 | 23 | ]) 24 | return app 25 | 26 | -------------------------------------------------------------------------------- /web/webgram/bare.py: -------------------------------------------------------------------------------- 1 | import telethon 2 | from telethon.sync import TelegramClient as masterclient 3 | from telethon import errors, functions, types, events , helpers 4 | import asyncio 5 | import aiohttp 6 | import urllib.parse 7 | from . import ( 8 | Config, StreamTools, Streamer, Checkers 9 | ) 10 | import io 11 | import re 12 | import os.path 13 | import requests 14 | from telethon.sessions import StringSession 15 | 16 | 17 | class BareServer(Config, StreamTools, Streamer, Checkers): 18 | client: telethon.TelegramClient 19 | 20 | def __init__(self , loop: asyncio.AbstractEventLoop): 21 | 22 | self.client = telethon.TelegramClient( 23 | StringSession(), #self.config.SESS_NAME, 24 | self.config.APP_ID, 25 | self.config.API_HASH, 26 | loop=loop 27 | ).start(bot_token=self.config.BOT_TOKEN) 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 musa-42 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bot/webgram/stream_tools.py: -------------------------------------------------------------------------------- 1 | import base64 2 | from telethon import events 3 | from telethon.tl.custom import Message 4 | import typing 5 | import werkzeug.utils 6 | import re 7 | from typing import Tuple, Union 8 | if typing.TYPE_CHECKING: 9 | import webgram 10 | 11 | 12 | class StreamTools: 13 | 14 | @staticmethod 15 | def Find(string): 16 | regex = r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))" 17 | url = re.findall(regex,string) 18 | return [x[0] for x in url] 19 | 20 | @staticmethod 21 | def encode(clear): 22 | key="musa" 23 | enc = [] 24 | for i in range(len(clear)): 25 | key_c = key[i % len(key)] 26 | enc_c = chr((ord(clear[i]) + ord(key_c)) % 256) 27 | enc.append(enc_c) 28 | return base64.urlsafe_b64encode("".join(enc).encode()).decode() 29 | 30 | @staticmethod 31 | def size(siz): 32 | for x in ['bytes', 'KB', 'MB', 'GB', 'TB']: 33 | if siz < 1024.0: 34 | return "%3.1f %s" % (siz, x) 35 | siz /= 1024.0 36 | return siz 37 | 38 | @staticmethod 39 | def get_file_name(message: Union[Message, events.NewMessage.Event]) -> str: 40 | if message.file.name: 41 | return message.file.name 42 | ext = message.file.ext or "" 43 | return f"{message.date.strftime('%Y-%m-%d_%H-%M-%S')}{ext}" 44 | -------------------------------------------------------------------------------- /bot/main.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import webgram 3 | import aiohttp.web 4 | import logging 5 | from concurrent.futures import CancelledError 6 | import signal 7 | 8 | logging.basicConfig(level=logging.ERROR) 9 | #logging.basicConfig(level=logging.DEBUG) 10 | 11 | class AioHttpAppException(BaseException): 12 | """An exception specific to the AioHttp application.""" 13 | 14 | 15 | class GracefulExitException(AioHttpAppException): 16 | """Exception raised when an application exit is requested.""" 17 | 18 | 19 | class ResetException(AioHttpAppException): 20 | """Exception raised when an application reset is requested.""" 21 | 22 | def handle_sighup() -> None: 23 | logging.warning("Received SIGHUP") 24 | raise ResetException("Application reset requested via SIGHUP") 25 | 26 | 27 | def handle_sigterm() -> None: 28 | logging.warning("Received SIGTERM") 29 | raise ResetException("Application exit requested via SIGTERM") 30 | 31 | 32 | def cancel_tasks() -> None: 33 | for task in asyncio.Task.all_tasks(): 34 | task.cancel() 35 | 36 | 37 | 38 | loop = asyncio.get_event_loop() 39 | loop.add_signal_handler(signal.SIGHUP, handle_sighup) 40 | loop.add_signal_handler(signal.SIGTERM, handle_sigterm) 41 | server = webgram.BareServer(loop) 42 | 43 | 44 | if __name__ == "__main__": 45 | try: 46 | loop.run_forever() 47 | except ResetException: 48 | logging.warning("Reloading...") 49 | cancel_tasks() 50 | asyncio.set_event_loop(asyncio.new_event_loop()) 51 | except GracefulExitException: 52 | logging.warning("Exiting...") 53 | cancel_tasks() 54 | loop.close() -------------------------------------------------------------------------------- /bot/webgram/bare.py: -------------------------------------------------------------------------------- 1 | import telethon 2 | from telethon import errors, functions, types, events , helpers 3 | import asyncio 4 | import aiohttp 5 | import urllib.parse 6 | from . import ( 7 | Config, StreamTools 8 | ) 9 | import io 10 | import re 11 | import os.path 12 | import requests 13 | from telethon.sessions import StringSession 14 | 15 | class BareServer(Config, StreamTools): 16 | client: telethon.TelegramClient 17 | 18 | def __init__(self, loop: asyncio.AbstractEventLoop): 19 | 20 | self.client = telethon.TelegramClient( 21 | StringSession(), #self.config.SESS_NAME, 22 | self.config.APP_ID, 23 | self.config.API_HASH, 24 | loop=loop 25 | ).start(bot_token=self.config.BOT_TOKEN) 26 | 27 | 28 | @self.client.on(events.NewMessage) 29 | async def download(event : events.NewMessage.Event): 30 | if event.is_private : 31 | try: 32 | await event.client(functions.channels.GetParticipantRequest(channel=self.config.channel,user_id=event.sender_id)) 33 | except errors.UserNotParticipantError: 34 | await event.reply(f"First join to our official channel to access the bot or get the newest news about the bot\n\n@{self.config.channel}\n\nAfter that /start the bot aging.") 35 | return 36 | if event.file : 37 | hash = self.encode(f"{event.sender_id}:{event.id}") 38 | url = f"{hash}/{urllib.parse.quote(self.get_file_name(event))}" 39 | await event.reply(f"Link to download file: \n\n🌍 : {self.config.ROOT_URI}/w/{url}") 40 | return 41 | 42 | await event.reply("Send an image or file to get a link to download it") 43 | -------------------------------------------------------------------------------- /web/webgram/stream_tools.py: -------------------------------------------------------------------------------- 1 | from telethon.tl.functions.messages import SearchRequest 2 | from telethon.tl.types import MessageMediaDocument, InputMessagesFilterDocument 3 | from telethon.tl.types import DocumentAttributeFilename 4 | from telethon.tl.types import Document 5 | from telethon.tl.types import Message 6 | from telethon.tl.types.messages import MessagesNotModified 7 | import base64 8 | from telethon import events 9 | from telethon.tl.custom import Message 10 | import typing 11 | import werkzeug.utils 12 | import re 13 | from typing import Tuple, Union 14 | if typing.TYPE_CHECKING: 15 | import webgram 16 | 17 | 18 | class StreamTools: 19 | 20 | @staticmethod 21 | def Find(string): 22 | regex = r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))" 23 | url = re.findall(regex,string) 24 | return [x[0] for x in url] 25 | 26 | @staticmethod 27 | def encode(clear): 28 | key="musa" 29 | enc = [] 30 | for i in range(len(clear)): 31 | key_c = key[i % len(key)] 32 | enc_c = chr((ord(clear[i]) + ord(key_c)) % 256) 33 | enc.append(enc_c) 34 | return base64.urlsafe_b64encode("".join(enc).encode()).decode() 35 | 36 | @staticmethod 37 | def decode(enc): 38 | key="musa" 39 | dec = [] 40 | enc = base64.urlsafe_b64decode(enc).decode() 41 | for i in range(len(enc)): 42 | key_c = key[i % len(key)] 43 | dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256) 44 | dec.append(dec_c) 45 | return "".join(dec) 46 | 47 | @staticmethod 48 | def size(siz): 49 | for x in ['bytes', 'KB', 'MB', 'GB', 'TB']: 50 | if siz < 1024.0: 51 | return "%3.1f %s" % (siz, x) 52 | siz /= 1024.0 53 | return siz 54 | 55 | @staticmethod 56 | def get_file_name(message: Union[Message, events.NewMessage.Event]) -> str: 57 | if message.file.name: 58 | return message.file.name 59 | ext = message.file.ext or "" 60 | return f"{message.date.strftime('%Y-%m-%d_%H-%M-%S')}{ext}" 61 | 62 | def messages_to_m3u(self: 'webgram.BareServer', messages: typing.List[Message], peer) -> typing.Generator: 63 | for message in messages: 64 | if not isinstance(message.media, MessageMediaDocument): 65 | continue 66 | 67 | document = message.media.document 68 | filename = self.get_filename(document) 69 | 70 | if filename.split(".")[-1] in self.config.ALLOWED_EXT: 71 | if message.message: 72 | name = f"{message.message} {filename}" 73 | else: 74 | name = filename 75 | 76 | yield f"#EXTINF:-1, {werkzeug.utils.secure_filename(name)}" 77 | yield f"{self.config.ROOT_URI}/watch/{peer}/{message.id}" 78 | 79 | @staticmethod 80 | def get_filename(document: Document) -> str: 81 | return next( 82 | a.file_name 83 | for a in document.attributes 84 | if isinstance(a, DocumentAttributeFilename) 85 | ) 86 | 87 | async def iter_files(self: 'webgram.BareServer', peer) -> typing.AsyncGenerator: 88 | offset = 0 89 | 90 | while True: 91 | messages = await self.client(SearchRequest( 92 | peer=peer, add_offset=offset, hash=0, 93 | filter=InputMessagesFilterDocument(), 94 | limit=200, max_date=0, min_date=0, 95 | max_id=0, min_id=0, offset_id=0, q="" 96 | )) 97 | 98 | if isinstance(messages, MessagesNotModified): 99 | break 100 | 101 | if not messages.messages: 102 | break 103 | 104 | yield messages.messages 105 | offset += len(messages.messages) 106 | -------------------------------------------------------------------------------- /web/webgram/streamer.py: -------------------------------------------------------------------------------- 1 | from telethon.tl.types import MessageMediaDocument 2 | from telethon.tl.types import Message 3 | from telethon.tl import functions 4 | from aiohttp import web 5 | from telethon.tl import types 6 | import typing 7 | import re 8 | import telethon 9 | import io 10 | import urllib 11 | import asyncio 12 | import random 13 | 14 | if typing.TYPE_CHECKING: 15 | import webgram 16 | 17 | 18 | RANGE_REGEX = re.compile(r"bytes=([0-9]+)-") 19 | BLOCK_SIZE = telethon.client.downloads.MAX_CHUNK_SIZE 20 | 21 | 22 | class Streamer: 23 | 24 | async def hello(self: 'webgram.BareServer', request: web.Request) -> web.Response: 25 | return web.Response(text="Hello, world") 26 | 27 | async def watch_stream(self: 'webgram.BareServer', request: web.Request) -> web.Response: 28 | 29 | if request.match_info.get("hash"): 30 | hash = self.decode(request.match_info["hash"]).split(":") 31 | peer = self.to_int_safe(hash[0]) 32 | mid = hash[1] 33 | 34 | else: 35 | return web.Response(text="This link is no longer supported, please create a new link") 36 | 37 | if not mid.isdigit() or not await self.validate_peer(peer): 38 | return web.HTTPNotFound() 39 | 40 | message: Message = await self.client.get_messages(peer, ids=int(mid)) 41 | 42 | if not message or not message.file : 43 | return web.HTTPNotFound() 44 | 45 | offset = request.headers.get("Range", 0) 46 | 47 | if not isinstance(offset, int): 48 | matches = RANGE_REGEX.search(offset) 49 | 50 | if matches is None: 51 | return web.HTTPBadRequest() 52 | 53 | offset = matches.group(1) 54 | 55 | if not offset.isdigit(): 56 | return web.HTTPBadRequest() 57 | 58 | offset = int(offset) 59 | 60 | file_size = message.file.size 61 | download_skip = (offset // BLOCK_SIZE) * BLOCK_SIZE 62 | read_skip = offset - download_skip 63 | 64 | if request.match_info.get("name"): 65 | name = request.match_info["name"] 66 | else: 67 | name = self.get_file_name(message) 68 | 69 | if download_skip >= file_size: 70 | return web.HTTPRequestRangeNotSatisfiable() 71 | 72 | if read_skip > BLOCK_SIZE: 73 | return web.HTTPInternalServerError() 74 | 75 | resp = web.StreamResponse( 76 | headers={ 77 | 'Content-Type': message.file.mime_type, #'application/octet-stream', 78 | 'Accept-Ranges': 'bytes', 79 | 'Content-Range': f'bytes {offset}-{file_size}/{file_size}', 80 | "Content-Length": str(file_size), 81 | "Content-Disposition": f'attachment; filename={name}', 82 | }, 83 | 84 | status=206 if offset else 200, 85 | ) 86 | 87 | await resp.prepare(request) 88 | 89 | cls = self.client.iter_download(message.media, offset=download_skip) 90 | 91 | async for part in cls: 92 | if len(part) < read_skip: 93 | read_skip -= len(part) 94 | 95 | elif read_skip: 96 | await resp.write(part[read_skip:]) 97 | read_skip = 0 98 | 99 | else: 100 | await resp.write(part) 101 | 102 | return resp 103 | 104 | async def grab_m3u(self: 'webgram.BareServer', request: web.Request) -> web.Response: 105 | peer = self.to_int_safe(request.match_info["peer"]) 106 | 107 | if not await self.validate_peer(peer): 108 | return web.HTTPNotFound() 109 | 110 | resp = web.StreamResponse( 111 | status=200, 112 | headers={ 113 | 'Content-Type': 'application/octet-stream', 114 | 'Content-Disposition': f'filename={peer}.m3u' 115 | } 116 | ) 117 | 118 | await resp.prepare(request) 119 | 120 | async for messages in self.iter_files(peer): 121 | for part in self.messages_to_m3u(messages, peer): 122 | await resp.write(part.encode(self.config.ENCODING)) 123 | await resp.write(b"\n") 124 | 125 | await resp.drain() 126 | 127 | return resp 128 | 129 | async def test_upload(self: 'webgram.BareServer', request: web.Request) -> web.Response: 130 | f = open("webgram/app.html","r") 131 | text = f.read() 132 | return web.Response(text=text,content_type='text/html') 133 | 134 | async def upload_big(self: 'webgram.BareServer', request: web.Request) -> web.Response: 135 | data = await request.post() 136 | input_file = data["file"].file 137 | content = input_file.read() 138 | file_id = int(data["file_id"]) 139 | part = int(data["part"]) 140 | parts = int(data['parts']) 141 | end = int(data["end"]) 142 | size = int(data["size"]) 143 | r = await self.client(functions.upload.SaveBigFilePartRequest( 144 | file_id,part,parts, content)) 145 | # print(r , end ,size , part , parts) 146 | if end == size: 147 | r = types.InputFileBig(int(data["file_id"]),int(data['parts']) ,data["filename"]) 148 | msg = await self.client.send_file(self.config.STATS_CHANNEL,r) 149 | hash = self.encode(f"{msg.chat_id}:{msg.id}") 150 | link = f"{hash}/{urllib.parse.quote(self.get_file_name(msg))}" 151 | return web.Response(text=f'{end} {size} link {self.config.ROOT_URI}/watch/{link}' , content_type='text/html') 152 | 153 | return web.Response(text=f"{end} {size} {end*100 // size}") 154 | 155 | async def upload(self: 'webgram.BareServer', request: web.Request) -> web.Response: 156 | data = await request.post() 157 | input_file = data["file"].file 158 | content = input_file.read() 159 | f = io.BytesIO(content) 160 | f.name = data["filename"] 161 | end = int(data["end"]) 162 | msg = await self.client.send_file(self.config.STATS_CHANNEL,file=f) 163 | hash = self.encode(f"{msg.chat_id}:{msg.id}") 164 | link = f"{hash}/{urllib.parse.quote(self.get_file_name(msg))}" 165 | return web.Response(text=f'{end} {end} link {self.config.ROOT_URI}/watch/{link}' , content_type='text/html') 166 | -------------------------------------------------------------------------------- /web/webgram/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |1 B .. 2 GB UPLOAD FILE
142 | 143 |