Update chromecast api add ability to pause stream
This commit is contained in:
parent
63ddf6e3a6
commit
37825bb157
@ -1,8 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
""""UPNPDevice model"""
|
||||
""""Device model"""
|
||||
import graphene
|
||||
from .service import UPNPService
|
||||
from graphql.execution.base import ResolveInfo
|
||||
|
||||
|
||||
class CastStatus(graphene.ObjectType):
|
||||
"""Chromecast CastStatus"""
|
||||
@ -79,13 +80,18 @@ class ChromecastDevice(graphene.ObjectType):
|
||||
media_controller = graphene.Field(MediaController)
|
||||
status = graphene.Field(CastStatus)
|
||||
|
||||
class ChromecastPause(graphene.Mutation):
|
||||
"""Delete resource location"""
|
||||
class Arguments:
|
||||
"""Delete ResourceLocation arguments"""
|
||||
uid = graphene.String(required=True)
|
||||
|
||||
class UPNPDevice(graphene.ObjectType):
|
||||
"""UPNPDevice"""
|
||||
id = graphene.ID()
|
||||
deviceType = graphene.String()
|
||||
friendlyName = graphene.String()
|
||||
manufacturer = graphene.String()
|
||||
modelName = graphene.String()
|
||||
UDN = graphene.String()
|
||||
serviceList = graphene.List(UPNPService)
|
||||
Output = graphene.Boolean
|
||||
|
||||
def mutate(self, info: ResolveInfo, uid: graphene.String) -> graphene.Boolean: # pylint: disable=W0622
|
||||
"""Delete ResourceLocation"""
|
||||
if uid not in cache.CHROMECAST:
|
||||
raise error.ChromecastUUIDError(uid)
|
||||
data = cache.CHROMECAST[uid]
|
||||
data.device.media_controller.pause()
|
||||
return True
|
||||
|
@ -3,7 +3,7 @@
|
||||
"""Mutation"""
|
||||
import graphene
|
||||
from .model import firststart
|
||||
from .model import resource_location
|
||||
from .model import resource_location, device
|
||||
|
||||
|
||||
class Mutation(graphene.ObjectType):
|
||||
@ -17,3 +17,5 @@ class Mutation(graphene.ObjectType):
|
||||
resourceLocationAdd = resource_location.Add.Field()
|
||||
resourceLocationChange = resource_location.Change.Field()
|
||||
resourceLocationDelete = resource_location.Delete.Field()
|
||||
|
||||
chromecastPause = device.ChromecastPause.Field()
|
||||
|
@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Cache - temporary before database introduction"""
|
||||
from typing import Dict
|
||||
from .model import Device
|
||||
|
||||
FIRST_START = True
|
||||
|
||||
CHROMECAST = dict()
|
||||
CHROMECAST: Dict[str, Device] = dict()
|
||||
|
@ -9,3 +9,11 @@ class ResourcePathError(tornado.web.HTTPError):
|
||||
code = 1001
|
||||
def __init__(self, message):
|
||||
tornado.web.HTTPError.__init__(self, reason=message)
|
||||
|
||||
|
||||
class ChromecastUUIDError(tornado.web.HTTPError):
|
||||
"""Invalid Chromecast uuid"""
|
||||
code = 1001
|
||||
message = "Chromecast with uuid '{}' not found"
|
||||
def __init__(self, uid):
|
||||
tornado.web.HTTPError.__init__(self, reason=self.message.format(uid))
|
||||
|
21
playlistcast/model.py
Normal file
21
playlistcast/model.py
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Application models"""
|
||||
from .api.model.device import MediaStatus
|
||||
from .api.model.subscription import SubscriptionModel
|
||||
from playlistcast import util
|
||||
|
||||
class Device:
|
||||
"""Device with api and interface data"""
|
||||
def __init__(self, device, data):
|
||||
self.device = device
|
||||
self.data = data
|
||||
self.device.media_controller.register_status_listener(self)
|
||||
|
||||
def new_media_status(self, status):
|
||||
"""Subscribe for chromecast status messages"""
|
||||
s = MediaStatus()
|
||||
s.uuid = self.data.uuid
|
||||
util.convert(status, s, ('uuid',))
|
||||
SubscriptionModel.media_status.on_next(s)
|
||||
print(self.data.name, self.data.uuid, status)
|
@ -8,7 +8,7 @@ from datetime import timedelta
|
||||
import pychromecast
|
||||
import pychromecast.controllers.media as chromecast_media
|
||||
from playlistcast.api.model.device import ChromecastDevice, MediaController, MediaStatus, CastStatus
|
||||
from playlistcast import util, cache
|
||||
from playlistcast import util, cache, model
|
||||
from playlistcast.api.subscription import SubscriptionModel
|
||||
|
||||
LOG = logging.getLogger('playlistcast.protocol.chromecast')
|
||||
@ -122,23 +122,9 @@ class DummyChromeast:
|
||||
#LOG.debug(status)
|
||||
pass
|
||||
|
||||
class Device:
|
||||
def __init__(self, device, data):
|
||||
self.device = device
|
||||
self.data = data
|
||||
self.device.media_controller.register_status_listener(self)
|
||||
|
||||
def new_media_status(self, status):
|
||||
"""Subscribe for chromecast status messages"""
|
||||
s = MediaStatus()
|
||||
s.uuid = self.data.uuid
|
||||
util.convert(status, s, ('uuid',))
|
||||
SubscriptionModel.media_status.on_next(s)
|
||||
print(self.data.name, self.data.uuid, status)
|
||||
|
||||
async def list_devices() -> List[ChromecastDevice]:
|
||||
"""Detect and return chromecast devices"""
|
||||
chromecasts = pychromecast.get_chromecasts()
|
||||
chromecasts = await util.awaitable(pychromecast.get_chromecasts)
|
||||
output = []
|
||||
all_keys = list(cache.CHROMECAST.keys())
|
||||
for pych in chromecasts:
|
||||
@ -148,7 +134,7 @@ async def list_devices() -> List[ChromecastDevice]:
|
||||
device = cache.CHROMECAST[uid]
|
||||
output.append(device.data)
|
||||
else:
|
||||
pych.wait(timeout=30)
|
||||
await util.awaitable(pych.wait, timeout=30)
|
||||
# pychromecast
|
||||
ch = ChromecastDevice()
|
||||
util.convert(pych, ch, ('media_controller', 'status'))
|
||||
@ -174,7 +160,7 @@ async def list_devices() -> List[ChromecastDevice]:
|
||||
mc.status = ms
|
||||
ch.media_controller = mc
|
||||
output.append(ch)
|
||||
device = Device(pych, ch)
|
||||
device = model.Device(pych, ch)
|
||||
cache.CHROMECAST[uid] = device
|
||||
# REMOVE remaining keys cause those are expired devices
|
||||
# TODO send update to UI
|
||||
|
@ -3,7 +3,11 @@
|
||||
"""Utility methods"""
|
||||
from string import Template
|
||||
from datetime import timedelta
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import socket
|
||||
import asyncio
|
||||
|
||||
POOL = ThreadPoolExecutor()
|
||||
|
||||
#https://stackoverflow.com/a/8907269
|
||||
class TimeDeltaFormatter(Template):
|
||||
@ -41,3 +45,9 @@ def convert(src, dest, ignore):
|
||||
continue
|
||||
value = getattr(src, attr)
|
||||
setattr(dest, attr, value)
|
||||
|
||||
# https://gist.github.com/phizaz/20c36c6734878c6ec053245a477572ec
|
||||
def awaitable(fn, *args, **kwargs):
|
||||
"""Turn sync method to async"""
|
||||
future = POOL.submit(fn, *args, **kwargs)
|
||||
return asyncio.wrap_future(future)
|
||||
|
Loading…
Reference in New Issue
Block a user