Browse Source

Initial commit

master
blank X 11 months ago
commit
fa313ac811
  1. 2
      .gitignore
  2. 21
      LICENSE
  3. 15
      README.md
  4. 8
      example-config.yaml
  5. 4
      requirements.txt
  6. 90
      streamtg.py

2
.gitignore

@ -0,0 +1,2 @@
streamtg.session
config.yaml

21
LICENSE

@ -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.

15
README.md

@ -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

8
example-config.yaml

@ -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

4
requirements.txt

@ -0,0 +1,4 @@
telethon
aiohttp
cryptg
pyyaml

90
streamtg.py

@ -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…
Cancel
Save