pychromecast icon indicating copy to clipboard operation
pychromecast copied to clipboard

Playing a Playlist (enqueuing files in play)

Open manatlan opened this issue 5 years ago • 4 comments

Hi, I understand that chromecast doesn't support m3u. But enqueuing multiple files is a common wish. I did a lot of research, and haven't found a common way to do that, so I build my own... I'd liked to find this piece of code, so I share it .. hope it could be useful for anybody

import pychromecast
import time

class Player:
    def __init__(self,cc):
        self.cc=cc
        self.cc.wait()
        self.cc.media_controller.register_status_listener(self)

    def play(self,pls):

        def media_producer():
            for i in pls:
                print("PLAY",i)
                self.cc.media_controller.play_media(**i)
                self.cc.media_controller.block_until_active ()
                yield
        self._media = media_producer()

        self.new_media_status(None)
        self.cc.join()

    def new_media_status(self, status):
        if status is None or (status.player_state == 'IDLE' and status.idle_reason == 'FINISHED'):
            try:
                next(self._media)
                time.sleep(3)
            except StopIteration:
                self.cc.quit_app()
                self.cc.__del__()

ccs=pychromecast.get_chromecasts()
cc = next(cc for cc in ccs if cc.device.friendly_name == "Nest Hub")

pls=[
    dict( content_type="audio/mp3", url="http://localhost/music1.mp3", title="title 1", thumb="https://www.numerama.com/content/uploads/2019/05/trou-noir-astronomie-univers-espace.jpg"),
    dict( content_type="image/jpeg", title="An image ;-)", url="http://www.sympatico.ca/image/policy:1.1666646:1456338819/Ciel-bleu.jpg?c=1%2C77%2C725%2C406&$p$c=3134e67"),
    dict( content_type="audio/mp3", url="http://localhost/music2.mp3",  title="title 2", thumb="https://www.numerama.com/content/uploads/2019/05/trou-noir-astronomie-univers-espace.jpg"),
    dict( content_type="audio/mp3", url="http://localhost/music3.mp3", title="title 3", thumb="https://www.numerama.com/content/uploads/2019/05/trou-noir-astronomie-univers-espace.jpg"),
]

p=Player(cc)
p.play( pls )

manatlan avatar Dec 22 '19 10:12 manatlan

BTW, the best (and only way) to be able to enqueue files (think: mp3 player of local files) ... in a CC is to build your own "custom caf receiver". To do so :

  • you'll need to register/purchase(5$) an APP_ID (https://cast.google.com/publish/#/overview)
  • create and host (on a public access (or in your LAN)) a html/js/css caf receiver. Count 20 to 30 lines of js for a really basic receiver.
  • without releasing to a public version (here you can found a list of published app); you'll need to authorize yours devices to access to your app_id, in the cast.google.com/publish ...
  • create your sender, with pychromecast : create a controller (by inheriting of pychromecast.basecontroller). And you'll be able to send, at launch, a payload to feed your receiver.
  • after that, you'll be able to use any controller to play/pause/next/previous track (or the voice, with google home/nest).

It's (a bit) complex to understand/do a "so" simple thing. But it's clearly the only way ;-( ... But, the benefit : you can create exactly what you need ... You'll need to understand a lot of concepts, but at the end : you can do something that is very powerful and answer your needs in all details.

pychromecast is very well coded (btw it could use asyncio in the core, to embrace the future ;-) ), and suit perfectly the complex architecture of the cc.

manatlan avatar Jan 02 '20 09:01 manatlan

Hi, I understand that chromecast doesn't support m3u. But enqueuing multiple files is a common wish. I did a lot of research, and haven't found a common way to do that, so I build my own... I'd liked to find this piece of code, so I share it .. hope it could be useful for anybody

import pychromecast
import time

class Player:
    def __init__(self,cc):
        self.cc=cc
        self.cc.wait()
        self.cc.media_controller.register_status_listener(self)

    def play(self,pls):

        def media_producer():
            for i in pls:
                print("PLAY",i)
                self.cc.media_controller.play_media(**i)
                self.cc.media_controller.block_until_active ()
                yield
        self._media = media_producer()

        self.new_media_status(None)
        self.cc.join()

    def new_media_status(self, status):
        if status is None or (status.player_state == 'IDLE' and status.idle_reason == 'FINISHED'):
            try:
                next(self._media)
                time.sleep(3)
            except StopIteration:
                self.cc.quit_app()
                self.cc.__del__()

ccs=pychromecast.get_chromecasts()
cc = next(cc for cc in ccs if cc.device.friendly_name == "Nest Hub")

pls=[
    dict( content_type="audio/mp3", url="http://localhost/music1.mp3", title="title 1", thumb="https://www.numerama.com/content/uploads/2019/05/trou-noir-astronomie-univers-espace.jpg"),
    dict( content_type="image/jpeg", title="An image ;-)", url="http://www.sympatico.ca/image/policy:1.1666646:1456338819/Ciel-bleu.jpg?c=1%2C77%2C725%2C406&$p$c=3134e67"),
    dict( content_type="audio/mp3", url="http://localhost/music2.mp3",  title="title 2", thumb="https://www.numerama.com/content/uploads/2019/05/trou-noir-astronomie-univers-espace.jpg"),
    dict( content_type="audio/mp3", url="http://localhost/music3.mp3", title="title 3", thumb="https://www.numerama.com/content/uploads/2019/05/trou-noir-astronomie-univers-espace.jpg"),
]

p=Player(cc)
p.play( pls )

I just wanted to make a note that I am using your bit of code on my project https://github.com/Findarato/Xander-Casts and it is working perfectly. This should be part of the root project.

Findarato avatar Apr 09 '20 12:04 Findarato

happy that it could serve someone ;-)

It's the "cheap way" to enqueue files, by making an active process to enqueue on demand (when previous ends).

By using the normal way (see) : you can do a lot more, but it's a LOT more complex ;-( ... but you can do all what you want !

manatlan avatar Apr 09 '20 16:04 manatlan

Came across this and it seems like this is what I am trying to accomplish. I have an m3u8 file that I want to play on my chromecast, but I have learned that the default media receiver does not quite support this - it will begin playing the playlist but eventually just gets stuck buffering indefinitely. I have created a custom receiver, and hosted it. I've tested this using Cactool, and it seems to work pretty well. My issues begin when trying to integrate this custom receiver into pychromecast. Something tells me that my issue is that I have not published the app. I need to provide sender details to publish the app, but I am not too sure what they are looking for here. I also see that you referenced the URL to the issue I am referring to (quoted below). I can only provide sender details for Android, iOS, or Chrome - I would imagine in this instance I would want Chrome, but I am unsure what they want in the "Website URL" field.

* you'll need to authorize yours devices to access to your app_id, in the cast.google.com/publish ...

Let me know if this way is also incorrect, I am really struggling to get around this indefinite buffering using the default media receiver, and I would love to be able to play this .m3u8 file.

Thanks for any help in advance!

joseph-morris928 avatar Aug 29 '21 17:08 joseph-morris928