Skip to content

Commit

Permalink
upnp autoreconnect
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-ld committed Mar 27, 2021
1 parent 8842752 commit cd92c49
Show file tree
Hide file tree
Showing 12 changed files with 284 additions and 51 deletions.
2 changes: 1 addition & 1 deletion config.ini.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ file_fake_fw_wait=0.2
[bot]
admins=[337885031,32432424,44353421]
block_size=1048576
request_gone_timeout=60
request_gone_timeout=900

[http]
listen_host=192.168.1.2
Expand Down
24 changes: 11 additions & 13 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
aiohttp==3.7.4
aiohttp==3.7.4.post0
async-generator==1.10
async-lru==1.0.2
async-timeout==3.0.1
async-upnp-client==0.14.15
async-upnp-client==0.15.0
attrs==20.3.0
casttube==0.2.1
certifi==2020.6.20
chardet==3.0.4
defusedxml==0.6.0
flake8==3.8.4
certifi==2020.12.5
chardet==4.0.0
defusedxml==0.7.1
idna==2.10
ifaddr==0.1.7
mccabe==0.6.1
multidict==5.1.0
protobuf==3.14.0
protobuf==3.15.6
pyaes==1.6.1
PyChromecast==9.1.1
pycodestyle==2.6.0
pyflakes==2.2.0
Pyrogram==1.1.5
pycodestyle==2.7.0
Pyrogram==1.2.5
PySocks==1.7.1
python-didl-lite==1.2.5
python-didl-lite==1.2.6
requests==2.25.1
six==1.15.0
TgCrypto==1.2.2
typing-extensions==3.7.4.3
urllib3==1.26.3
urllib3==1.26.4
voluptuous==0.12.1
wrapt==1.12.1
yarl==1.6.3
zeroconf==0.28.7
zeroconf==0.29.0
25 changes: 21 additions & 4 deletions smart_tv_telegram/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,31 @@ def __init__(self, msg_id: int, filename: str, devices: typing.List[Device]):
class OnStreamClosedHandler(OnStreamClosed):
_mtproto: Mtproto
_functions: typing.Dict[int, typing.Any]
_devices: typing.Dict[int, Device]

def __init__(self, mtproto: Mtproto, functions: typing.Dict[int, typing.Any]):
def __init__(self,
mtproto: Mtproto,
functions: typing.Dict[int, typing.Any],
devices: typing.Dict[int, Device]):
self._mtproto = mtproto
self._functions = functions
self._devices = devices

async def handle(self, remains: float, chat_id: int, message_id: int, local_token: int):
if local_token in self._functions:
del self._functions[local_token]

on_close: typing.Optional[typing.Callable[[int], typing.Coroutine]] = None

if local_token in self._devices:
on_close = self._devices[local_token].on_close
del self._devices[local_token]

await self._mtproto.reply_message(message_id, chat_id, f"download closed, {remains:0.2f}% remains")

if on_close is not None:
await on_close(local_token)


class TelegramStateMachine:
_states: typing.Dict[int, typing.Tuple[States, typing.Union[bool, StateData]]]
Expand Down Expand Up @@ -93,6 +107,7 @@ class Bot:
_http: Http
_finders: DeviceFinderCollection
_functions: typing.Dict[int, typing.Dict[int, DevicePlayerFunction]]
_devices: typing.Dict[int, Device]

def __init__(self, mtproto: Mtproto, config: Config, http: Http, finders: DeviceFinderCollection):
self._config = config
Expand All @@ -101,9 +116,10 @@ def __init__(self, mtproto: Mtproto, config: Config, http: Http, finders: Device
self._finders = finders
self._state_machine = TelegramStateMachine()
self._functions = dict()
self._devices = dict()

def get_on_stream_closed(self) -> OnStreamClosed:
return OnStreamClosedHandler(self._mtproto, self._functions)
return OnStreamClosedHandler(self._mtproto, self._functions, self._devices)

def prepare(self):
admin_filter = filters.chat(self._config.admins) & filters.private
Expand Down Expand Up @@ -144,7 +160,7 @@ async def _device_player_function(self, _: Client, message: CallbackQuery):
return

with async_timeout.timeout(self._config.device_request_timeout) as timeout_context:
await device_function.handle(self._mtproto)
await device_function.handle()

if timeout_context.expired:
await message.answer("request timeout")
Expand Down Expand Up @@ -180,7 +196,7 @@ async def _select_device(self, _: Client, message: Message):
# noinspection PyBroadException
try:
await device.stop()
await device.play(uri, data.filename)
await device.play(uri, data.filename, local_token)

except Exception as ex:
traceback.print_exc()
Expand All @@ -191,6 +207,7 @@ async def _select_device(self, _: Client, message: Message):
)

else:
self._devices[local_token] = device
physical_functions = device.get_player_functions()
functions = self._functions[local_token] = dict()

Expand Down
9 changes: 6 additions & 3 deletions smart_tv_telegram/devices/chromecast_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pychromecast.controllers.media import MediaController, TYPE_PAUSE, TYPE_PLAY, TYPE_STOP

from . import Device, DeviceFinder, RoutersDefType, DevicePlayerFunction
from .. import Config, Mtproto
from .. import Config
from ..tools import run_method_in_executor

__all__ = [
Expand Down Expand Up @@ -34,7 +34,7 @@ def __init__(self, command: str, device: pychromecast.Chromecast):
async def get_name(self) -> str:
return self._command

async def handle(self, mtproto: Mtproto):
async def handle(self):
await _send_command(self._device.media_controller, self._command)

async def is_enabled(self, config: Config):
Expand All @@ -53,7 +53,10 @@ def get_device_name(self) -> str:
async def stop(self):
pass

async def play(self, url: str, title: str):
async def on_close(self, local_token: int):
self._device.disconnect(blocking=False)

async def play(self, url: str, title: str, local_token: int):
await run_method_in_executor(self._device.wait)

if not self._device.is_idle:
Expand Down
14 changes: 11 additions & 3 deletions smart_tv_telegram/devices/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from aiohttp.web_request import Request
from aiohttp.web_response import Response

from .. import Config, Mtproto
from .. import Config


class RequestHandler(abc.ABC):
Expand All @@ -16,6 +16,10 @@ def get_path(self) -> str:
async def handle(self, request: Request) -> Response:
raise NotImplementedError

@abc.abstractmethod
def get_method(self) -> str:
raise NotImplementedError


RoutersDefType = typing.List[RequestHandler]

Expand All @@ -34,7 +38,7 @@ async def get_name(self) -> str:
raise NotImplementedError

@abc.abstractmethod
async def handle(self, mtproto: Mtproto):
async def handle(self):
raise NotImplementedError

@abc.abstractmethod
Expand All @@ -48,7 +52,7 @@ async def stop(self):
raise NotImplementedError

@abc.abstractmethod
async def play(self, url: str, title: str):
async def play(self, url: str, title: str, local_token: int):
raise NotImplementedError

@abc.abstractmethod
Expand All @@ -59,6 +63,10 @@ def get_device_name(self) -> str:
def get_player_functions(self) -> typing.List[DevicePlayerFunction]:
raise NotImplementedError

@abc.abstractmethod
def on_close(self, local_token: int):
raise NotImplementedError

def __repr__(self):
return self.get_device_name()

Expand Down
Loading

0 comments on commit cd92c49

Please sign in to comment.