Initial commit
This commit is contained in:
commit
fa313ac811
|
@ -0,0 +1,2 @@
|
||||||
|
streamtg.session
|
||||||
|
config.yaml
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 blank X
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,15 @@
|
||||||
|
# StreamTG
|
||||||
|
|
||||||
|
Stream files from Telegram
|
||||||
|
|
||||||
|
### Installation Instructions
|
||||||
|
1. Install `python3`
|
||||||
|
2. `pip3 install -r requirements.txt`
|
||||||
|
3. Copy example-config.yaml to config.yaml and edit it
|
||||||
|
|
||||||
|
### Start
|
||||||
|
`python3 streamtg.py`
|
||||||
|
If you want to set a custom port, have a PORT environment variable
|
||||||
|
|
||||||
|
### How to Use
|
||||||
|
http://localhost:8080/?chat_id=-1001289824958&message_id=5302&message_id=5304&token=DIi4aXHn440PTPXJE1yVyIoU2L4bLGiyjC1Fd7usKAMZYWVcp5p0P792G4YlbNnIcWCLypXbUFJkVzKqhh0AkJYSWqJbsAy8TjA
|
|
@ -0,0 +1,8 @@
|
||||||
|
telegram:
|
||||||
|
api_id: 0
|
||||||
|
api_hash: https://my.telegram.org
|
||||||
|
bot_token: https://t.me/BotFather
|
||||||
|
# If authorized tokens does not exist, no authorization is required
|
||||||
|
authorized_tokens:
|
||||||
|
- DIi4aXHn440PTPXJE1yVyIoU2L4bLGiyjC1Fd7usKAMZYWVcp5p0P792G4YlbNnIcWCLypXbUFJkVzKqhh0AkJYSWqJbsAy8TjA
|
||||||
|
- RCywhzEkwqWmDjsqhBdNMwO1cQNi72SWsvAKZxdoeFylbioqKCZjEKyjgDXkYn6xeMQLj4dDq6QoonVAU1b1MDyOUX9CvT5W4MP
|
|
@ -0,0 +1,4 @@
|
||||||
|
telethon
|
||||||
|
aiohttp
|
||||||
|
cryptg
|
||||||
|
pyyaml
|
|
@ -0,0 +1,90 @@
|
||||||
|
import logging
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
from aiohttp import web
|
||||||
|
from telethon import TelegramClient
|
||||||
|
from telethon.utils import _get_file_info
|
||||||
|
|
||||||
|
with open('config.yaml') as file:
|
||||||
|
config = yaml.safe_load(file)
|
||||||
|
|
||||||
|
client = TelegramClient('streamtg', config['telegram']['api_id'], config['telegram']['api_hash'])
|
||||||
|
authorized_tokens = config.get('authorized_tokens')
|
||||||
|
port = os.environ.get('PORT', 8080)
|
||||||
|
|
||||||
|
async def handler(request):
|
||||||
|
query = request.query
|
||||||
|
if authorized_tokens:
|
||||||
|
if 'token' not in query:
|
||||||
|
return web.Response(status=401, text='Unauthorized')
|
||||||
|
if query['token'] not in authorized_tokens:
|
||||||
|
return web.Response(status=403, text='Forbidden')
|
||||||
|
if 'chat_id' not in query:
|
||||||
|
return web.Response(status=400, text='Missing chat_id')
|
||||||
|
chat_id = query['chat_id']
|
||||||
|
try:
|
||||||
|
chat_id = int(chat_id)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
if 'message_id' not in query:
|
||||||
|
return web.Response(status=400, text='Missing message_id')
|
||||||
|
message_ids = query.getall('message_id')
|
||||||
|
if any(True for i in message_ids if not i.isnumeric() or i == '0'):
|
||||||
|
return web.Response(status=400, text='Invalid message_id')
|
||||||
|
message_ids = list(map(int, message_ids))
|
||||||
|
messages = await client.get_messages(chat_id, ids=message_ids)
|
||||||
|
if any(True for i in messages if i is None):
|
||||||
|
return web.Response(status=400, text='At least one of the messages does not exist')
|
||||||
|
if any(True for i in messages if not i.media):
|
||||||
|
return web.Response(status=400, text='At least one of the messages do not contain media')
|
||||||
|
http_range = request.http_range
|
||||||
|
offset = http_range.start or 0
|
||||||
|
end = http_range.stop
|
||||||
|
max_size = 0
|
||||||
|
for i in messages:
|
||||||
|
max_size += _get_file_info(i).size
|
||||||
|
if end is None:
|
||||||
|
end = max_size
|
||||||
|
elif end > max_size:
|
||||||
|
return web.Response(status=416, text='Range end size is bigger than file sizes', headers={'Content-Range': f'bytes */{max_size}'})
|
||||||
|
length = end - offset
|
||||||
|
|
||||||
|
async def download():
|
||||||
|
tmp_offset = offset
|
||||||
|
tmp_length = length
|
||||||
|
for i in messages:
|
||||||
|
if tmp_length < 1:
|
||||||
|
break
|
||||||
|
size = _get_file_info(i).size
|
||||||
|
if tmp_offset > size:
|
||||||
|
tmp_offset -= size
|
||||||
|
continue
|
||||||
|
async for chunk in client._iter_download(i, offset=tmp_offset, msg_data=(chat_id, i.id)):
|
||||||
|
yield chunk[:tmp_length]
|
||||||
|
tmp_length -= len(chunk)
|
||||||
|
if tmp_length < 1:
|
||||||
|
break
|
||||||
|
|
||||||
|
return web.Response(status=206 if (end - offset != max_size) else 200,
|
||||||
|
body=download(),
|
||||||
|
headers={
|
||||||
|
'Content-Range': f'bytes {offset}-{end}/{max_size}',
|
||||||
|
'Content-Length': str(end - offset),
|
||||||
|
'Accept-Ranges': 'bytes'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
app = web.Application()
|
||||||
|
app.add_routes([web.get('/', handler)])
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await client.start(bot_token=config['telegram'].get('bot_token'))
|
||||||
|
runner = web.AppRunner(app)
|
||||||
|
await runner.setup()
|
||||||
|
site = web.TCPSite(runner, '127.0.0.1', port)
|
||||||
|
await site.start()
|
||||||
|
await client.run_until_disconnected()
|
||||||
|
|
||||||
|
client.loop.run_until_complete(main())
|
Loading…
Reference in New Issue