sphh / mopidy-autoplay

Apache License 2.0
6 stars 2 forks source link

Local media URI #1

Closed cmbcbe closed 3 years ago

cmbcbe commented 3 years ago

Hello,

what is the URI to use for local media files, i cannot find the way to work. Thank you

[local]
enabled = true
media_dir = /data/music

[Mopidy-Autoplay]
enabled = true
tracklist.uris = local:Local media/Tracks
tracklist.index = auto
tracklist.consume = false
tracklist.random = true
tracklist.repeat = true
tracklist.single = false
playback.state = playing
playback.time_position = auto
mixer.volume = 90
mixer.mute = off
sphh commented 3 years ago

One way is to uncomment all tracklist option in the autoplay section of the config file, start Mopidy, play the file and while it is playing, stop Mopidy. Now look into the file /var/lib/mopidy/autoplay/autoplay.state and you will find the uris under "uris".

Here is an example.

/var/lib/mopidy/autoplay/autoplay.state

{
"tracklist": {
  "uris": ["http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio2_mf_p"],
  "index": 0,
  "consume": false,
  "random": false,
  "repeat": false,
  "single": false},
"mixer": {
  "mute": null,
  "volume": null},
"playback": {
  "state": "playing",
  "time_position": 8048568}
}

would become the following in Mopidy's configuration file:

[autoplay]
playback.state = playing
tracklist.uris = http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio2_mf_p

Important: Do not include the tracklist.uris in ". If you have more than one uri, separate them with ,. (This is not mentioned in the README yet.)

BTW, I noticed that you use [Mopidy-Autoplay] as a section in your configuration. Does that work for you? I use [autoplay] in my config file …

cmbcbe commented 3 years ago

Thanks, i get it for localmedia, thank you!

[Mopidy-Autoplay]
enabled = true
tracklist.uris = local:track:_Institut
tracklist.index = auto
tracklist.consume = false
tracklist.random = true
tracklist.repeat = true
tracklist.single = false
playback.state = playing
playback.time_position = auto
mixer.volume = 90
mixer.mute = off
sphh commented 3 years ago

Glad to hear, that it works!

I close it for now, but feel free to re-open it, if you run into any problem.

cmbcbe commented 3 years ago

Too fast happiying, i got this error now. It look ,like if state not existing, the extension does not play from scratch... Oct 15 11:58:53 pijukebox mopidy[783]: Autoplay: mopidy_autoplay.frontend Autoplay: Could not get tracklist index None: list indices must be integers or slices, not NoneType

sphh commented 3 years ago
  1. Could you please also post your /var/lib/mopidy/autoplay/autoplay.state? Thanks.
  2. Will it start playing the last track (preferably that one where it failed) with just this in your Mopidy's configuration file and everything else commented out?
    [autoplay]
    playback.state = playing
cmbcbe commented 3 years ago

i simply want to play all mp3 in a directory, this should work even it anything was playing at reboot, i don't know how to handle that

sphh commented 3 years ago

What autoplay does, is to restore Mopidy's queue (tracklist) and start playing the queue at a certain position. For that reason, you have to specify all files in that directory in Mopidy's configuration file under autoplay/tracklist.uris

If I understand you correctly, you just want to specify the directory, don't you? That would require the autoplay extension to load all the files in the specified directory into the queue (tracklist) and play them … This was not the original idea behind autoplay, but it might be possible to implement (and also to use a given playlist)

cmbcbe commented 3 years ago

OK this mean that that is normal that i cannot do it with autoplay, the feature need to be implemented? am i right?

sphh commented 3 years ago

Yes, playing all files from a directory is not implemented (a PR is always welcome). But you can always put all files in the tracklist.uris configuration option (but it is static and does not adapt to changes in the directory).

cmbcbe commented 3 years ago

perhaps playing with a script that list file and put it in the config file with sed or awk command... i will try to find something...

sphh commented 3 years ago

Yes, that's always possible! It might be easier to find the appropriate calls in https://docs.mopidy.com/en/latest/api/core/#library-controller and come up with a way to configure this feature in autoplay.

sphh commented 3 years ago

[Deleted, because it does not work as expected]

sphh commented 3 years ago

I did a bit of trial and error investigation.

You can always use file:///path/to/your/music.file to point to an (existing) music file. Pointing to a directory does unfortunately not work, because it looks, like the File extension does not support listing files in directories.

This would require a special handling inside autoplay, if it encounters a special directory:// uri …

Your other bet would be to use a playlist, but this also needs special treatment …

Well, here is the change to be made, to enable both – not yet uploaded to this repository, but you can apply the changes by hand to mopidy_autoplay/frontend.py: Replace line 142, which is

        uris = self._get_config(state, 'tracklist', 'uris')

with

        playlist_schemes = tuple(self.core.playlists.get_uri_schemes().get())
        uris = []
        for uri in self._get_config(state, 'tracklist', 'uris'):
            if uri.startswith('glob://'):
                uris.extend([f'file://{f}' for f in glob.glob(uri[len('glob://'):])])
            elif uri.startswith(playlist_schemes):
                uris.extend(
                    [track.uri
                     for track in self.core.playlists.get_items(uri).get() or []])
            else:
                uris.append(uri)

and add this import to the top of the file:

import glob

Now you can add the following items to the autoplay/tracklist.uris config:

[autoplay]
tracklist.uris = m3u:<yourplaylist>.m3u8, glob:///usr/share/sounds/alsa/*.wav

glob:// specifies a glob pattern as you would use in your shell. Note, that according to the Python documentation, the order of the items are unpredictable and depends on the OS.

BTW there is also a small bug in line 146 (before applying the above patch) or 157 (after applying the above patch). That line should have a or 0 appended:

            index = self._get_config(state, 'tracklist', 'index') or 0

I'll prepare an update in the next couple of days, but if you don't want to wait that long, give the change described above a try.

cmbcbe commented 3 years ago

Hello Tank you,

i have tried but failed on this error: mopidy_autoplay.frontend Autoplay: Could not get tracklist index 0: list index out of range

sphh commented 3 years ago

Well, if the index 0 is out of range, then the tracklist/queue is empty! Have you checked it with the client of your choice?

Have you applied the changes outlined above? How does your autoplay/tracklist.uris look like?

cmbcbe commented 3 years ago

Hello, here it is, audio files are really there:

[autoplay]
enabled = true
tracklist.uris =  glob:///data/music/_Institut/*.*
tracklist.index = auto
tracklist.consume = false
tracklist.random = true
tracklist.repeat = true
tracklist.single = false
playback.state = playing
playback.time_position = auto
mixer.volume = 90
mixer.mute = off
cmbcbe commented 3 years ago

Here is the complete code:

root@pijukebox:/usr/local/lib/python3.7/dist-packages/mopidy_autoplay# cat frontend.py

"""Autoplay extension for Mopidy.

A Mopidy extension to automatically pick up where you left off and start
playing the last track from the position before Mopidy was shut down.
"""

import logging
import pathlib
import json
import pykka
import glob

from mopidy import core
from . import Extension, Recollection

logger = logging.getLogger(__name__)

class AutoplayFrontend(pykka.ThreadingActor, core.CoreListener):
    """Autoplay's frontend implementation."""

    def __init__(self, config, core):
        """Initialize the `AutoplayFrontend` class."""
        logger.debug(
            'Autoplay: __init__(%s, %s)',
            config, core)

        super(AutoplayFrontend, self).__init__()
        self.core = core
        self.config = config[Extension.ext_name]

        # State file
        data_dir = Extension.get_data_dir(config)
        self.statefile = pathlib.Path(data_dir) / 'autoplay.state'
        logger.debug(
            "Autoplay: Use '%s' as statefile.",
            self.statefile)

    # The frontend implementation

    def on_start(self):                                         # noqa: D401
        """Called, when the extension is started."""
        logger.debug('Autoplay: on_start()')

        state = self.read_state(self.statefile)
        if state:
            self.restore_state(state)

    def on_stop(self):                                          # noqa: D401
        """Called, when the extension is stopped."""
        logger.debug('Autoplay: on_stop()')

        state = self.store_state()
        self.write_state(state, self.statefile)

    # Helper functions

    def _get_config(self, state, controller, option):
        """
        Return the configuration from `config` and `state`.

        If the extension's configuration has a value other than "auto" (which
        is translated into the class `Recollection`), return this value,
        otherwise the saved value from the state variable.

        Args:
            state (dict):
                A dictionary with the states saved for the 'tracklist',
                'mixer' and 'playback' controllers.
            controller (str):
                The controller name.
            option (str):
                The option name.

        Returns:
            value:
                The configuration or state value.

        """
        config = self.config.get(f'{controller}.{option}', Recollection)
        if config is Recollection:
            s = state.get(controller, {}).get(option, None)
        else:
            s = config
        logger.debug(
            'Autoplay: _get_config(%s, %s, %s) = %s',
            state, controller, option, s)
        return s

    def _set_option(self, state, controller, option):
        """
        Set the state to the controller's option.

        Args:
            state (TYPE):
                A dictionary with the states saved for the 'tracklist',
                'mixer' and 'playback' controllers.
            controller (str):
                The controller name.
            option (str):
                The option name.

        Returns:
            None.

        """
        logger.debug(
            'Autoplay: _set_option(%s, %s, %s)',
            state, controller, option)

        # Get value to be set
        value = self._get_config(state, controller, option)
        if value is None:
            return

        # Get method to be used to set option
        setter = getattr(getattr(self.core, controller), f'set_{option}')

        # Set value (and log message, if failed)
        if not setter(value):
            logger.info(
                "Autoplay: Set %s/%s to '%s' failed.",
                controller, option, value)

    # Worker functions

    def restore_state(self, state):
        """
        Restore the saved state.

        Args:
            state (dict):
                A dictionary with the states saved for the 'tracklist',
                'mixer' and 'playback' controllers.

        Returns:
            None.

        """
        # Reset tracklist
        tlid = None
        playlist_schemes = tuple(self.core.playlists.get_uri_schemes().get())
        uris = []
        for uri in self._get_config(state, 'tracklist', 'uris'):
            if uri.startswith('glob://'):
                uris.extend([f'file://{f}' for f in glob.glob(uri[len('glob://'):])])
            elif uri.startswith(playlist_schemes):
                uris.extend(
                    [track.uri
                     for track in self.core.playlists.get_items(uri).get() or []])
            else:
                uris.append(uri)
        if uris:
            self.core.tracklist.clear()
            self.core.tracklist.add(uris=uris)
            index = self._get_config(state, 'tracklist', 'index') or 0
            try:
                tlid = self.core.tracklist.get_tl_tracks().get()[index].tlid
            except Exception as e:
                logger.warning(
                    "Autoplay: Could not get tracklist index %s: %s",
                    index, e)
                tlid = None
        self._set_option(state, 'tracklist', 'consume')
        self._set_option(state, 'tracklist', 'random')
        self._set_option(state, 'tracklist', 'repeat')
        self._set_option(state, 'tracklist', 'single')

        # Reset mixer
        self._set_option(state, 'mixer', 'mute')
        self._set_option(state, 'mixer', 'volume')

        # Reset playback state
        if tlid is not None:
            # Why does this not work?
            #   self._set_option(state, 'playback', 'state')
            playback = self._get_config(state, 'playback', 'state')
            if playback == 'stopped':
                self.core.playback.stop().get()
            elif playback == 'playing':
                self.core.playback.play(tlid=tlid)
            elif playback == 'paused':
                self.core.playback.pause()
            time_position = self._get_config(state, 'playback', 'time_position')
            if time_position is not None:
                self.core.playback.seek(time_position)

    def store_state(self):
        """
        Assemble and return the state.

        Returns:
            state (dict):
                A dictionary with the states saved for the 'tracklist',
                'mixer' and 'playback' controllers.

        """
        # Initialize 'state' variable
        state = {
            'tracklist': {},
            'mixer': {},
            'playback': {},
            }

        # Tracks in tracklist
        tracklist = self.core.tracklist
        state['tracklist']['uris'] = [
            t.uri
            for t in tracklist.get_tracks().get()
            if t is not None]
        # Get currently playing track (or None)
        state['tracklist']['index'] = tracklist.index().get()
        # Get options
        state['tracklist']['consume'] = tracklist.get_consume().get()
        state['tracklist']['random'] = tracklist.get_random().get()
        state['tracklist']['repeat'] = tracklist.get_repeat().get()
        state['tracklist']['single'] = tracklist.get_single().get()

        # Get the mixer state
        mixer = self.core.mixer
        # True, False or None
        state['mixer']['mute'] = mixer.get_mute().get()
        # [0..100] or None
        state['mixer']['volume'] = mixer.get_volume().get()

        # Get the playback state
        playback = self.core.playback
        # Returns "stopped", "playing" or "paused"
        state['playback']['state'] = playback.get_state().get()
        state['playback']['time_position'] = playback.get_time_position().get()

        return state

    def read_state(self, file):
        """
        Read the state from the a json file.

        Args:
            file (str|Path):
                A json-formated file with the state dictionary.

        Returns:
            state (dict):
                A dictionary with the states saved for the 'tracklist',
                'mixer' and 'playback' controllers.

        """
        try:
            with open(file, 'r') as f:
                state = json.load(f)
        except IOError as e:
            logger.warning(
                "Autoplay: No state restored, "
                "because there was a problem opening the state file '%s': %s",
                file, e)
            return
        except json.JSONDecodeError as e:
            logger.error(
                "Autoplay: Error reading state from file '%s': %s",
                file, e)
            return
        else:
            logger.debug(
                "Autoplay: State read from file '%s'.",
                file)

        return state

    def write_state(self, state, file):
        """
        Write the state to a json file.

        Args:
            state (dict):
                A dictionary with the states saved for the 'tracklist',
                'mixer' and 'playback' controllers.
            file (str|Path):
                A writeable file.

        Returns:
            None.

        """
        try:
            with open(file, 'w') as f:
                json.dump(state, f)
        except IOError as e:
            logger.error(
                "Autoplay: Cannot open state file '%s' for writing: %s",
                file, e)
        except Exception as e:
            logger.error(
                "Autoplay: Problem saving state to file '%s': %s",
                file, e)
            logger.debug(
                "Autoplay: State: %s",
                state)
        else:
            logger.debug(
                "Autoplay: State written to file '%s'.",
                file)

root@pijukebox:/usr/local/lib/python3.7/dist-packages/mopidy_autoplay#

sphh commented 3 years ago

Does Mopidy have read access to /data/music/_Institut/*.*? (ls -l /data/music/_Institut/*.*)

cmbcbe commented 3 years ago

yes it work from mpc command to mopidy daemon...

sphh commented 3 years ago

Well, that's really puzzling. If you still have the patience, let's try this: Just after the line for uri in self._get_config(state, 'tracklist', 'uris'): please add

            logger.warning('****** %s', uri)

and before elif uri.startswith(playlist_schemes)::

                logger.warning('****** %s', uri[len('glob://'):])
                logger.warning('****** %s', glob.glob(uri[len('glob://'):]))
                logger.warning('****** %s', uris)

so that the for-loop becomes

        for uri in self._get_config(state, 'tracklist', 'uris'):
            logger.warning('****** %s', uri)
            if uri.startswith('glob://'):
                uris.extend([f'file://{f}' for f in glob.glob(uri[len('glob://'):])])
                logger.warning('****** %s', uri[len('glob://'):])
                logger.warning('****** %s', glob.glob(uri[len('glob://'):]))
                logger.warning('****** %s', uris)
            elif uri.startswith(playlist_schemes):
                uris.extend(
                    [track.uri
                     for track in self.core.playlists.get_items(uri).get() or []])
            else:
                uris.append(uri)

Please restart Mopidy and post the output with the ****** here. Thanks.

cmbcbe commented 3 years ago

Here it is:

DEBUG    2020-10-16 11:51:28,728 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: State read from file '/var/lib/mopidy/.local/share/mopidy/autoplay/autoplay.state'.
INFO     2020-10-16 11:51:28,758 [5084:MainThread] mopidy_mpd.actor
  MPD server running at [::ffff:127.0.0.1]:6600
DEBUG    2020-10-16 11:51:28,789 [5084:MainThread] pykka
  Registered MpdFrontend (urn:uuid:4a5a4772-ca04-4d37-aab6-58ce976eb81d)
DEBUG    2020-10-16 11:51:28,796 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, uris) = ('glob:///data/music/_Institut/*.*',)
DEBUG    2020-10-16 11:51:28,797 [5084:MainThread] pykka
  Starting MpdFrontend (urn:uuid:4a5a4772-ca04-4d37-aab6-58ce976eb81d)
WARNING  2020-10-16 11:51:28,803 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  ****** glob:///data/music/_Institut/*.*
TRACE    2020-10-16 11:51:28,808 [5084:MainThread] mopidy.internal.timer
  MpdFrontend took 95ms
INFO     2020-10-16 11:51:28,812 [5084:MainThread] mopidy.commands
  Starting GLib mainloop
DEBUG    2020-10-16 11:51:28,813 [5084:HttpFrontend-11] mopidy.zeroconf
  Zeroconf service 'Mopidy HTTP server on pijukebox' (_http._tcp at []:6680): Published
WARNING  2020-10-16 11:51:28,826 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  ****** /data/music/_Institut/*.*
WARNING  2020-10-16 11:51:28,833 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  ****** ['/data/music/_Institut/14 - Calming Lullaby of Gentle Creek.flac', '/data/music/_Institut/15 - Felicidade.mp3', '/data/music/_Institut/Telepopmusik - Breathe.mp3', '/data/music/_Institut/Stan Getz - Samba De Uma Nota So.mp3', '/data/music/_Institut/09 - Playa Blanca Dream.mp3', "/data/music/_Institut/10 Voodoo Bliss (Aaron Bingle's Azure Mix).mp3", '/data/music/_Institut/01 - Trumpet Thing - Need You (Right Now) [Ambient Mix].mp3', '/data/music/_Institut/04 - Otra Vida.mp3', '/data/music/_Institut/12 - Evita.mp3', '/data/music/_Institut/1 - Relaxing Melancholy Meditation on the Sunset Beach.flac', '/data/music/_Institut/7 - Meditation and Music Massage by the Sea Waves on the Night Beach.flac', '/data/music/_Institut/13. Carl Bikkem - Ivory Tower (Chill Republic Mix).mp3', '/data/music/_Institut/04. Air Mallet.mp3', '/data/music/_Institut/01 Ambrosia.mp3', '/data/music/_Institut/02 - Sambox - Rising Sun.mp3', '/data/music/_Institut/12 - Sa Trincha - Smell Of Paradise.mp3', '/data/music/_Institut/06 - Transglobal Underground - TheKhaleegi Stomp (Thievery Corporation Mix).mp3', '/data/music/_Institut/01 - Bahramji & Maneesh De Moor - Dreamcatcher.mp3', '/data/music/_Institut/14 - Cantoma - Essaira.mp3', '/data/music/_Institut/13 - Beautiful Light.flac', '/data/music/_Institut/10 - Dos Hombres - The Alkemyst.mp3', '/data/music/_Institut/10 - Zen Men - El Fuego (Trote King Mix).mp3', '/data/music/_Institut/03. GoTan Project meets Chet Baker  Round About Midnight.mp3', '/data/music/_Institut/05 - Tango De Noche.mp3', '/data/music/_Institut/14 - Hotel Parasaio.mp3', '/data/music/_Institut/12 - Static Solution (Sunset Mix).flac', '/data/music/_Institut/10 - Ofrá - Mandingo.mp3', '/data/music/_Institut/11 - A Change of Mood.flac', '/data/music/_Institut/11 - Sambox - African Dream.mp3', '/data/music/_Institut/6 - Recasting Negative Events into Positive Light by Power of Music.flac', '/data/music/_Institut/06 - Musica Del Mar.mp3', '/data/music/_Institut/02 - Tibet (A Passage To) (Tibet Project).mp3', '/data/music/_Institut/11 - Hablare De Ti.mp3', "/data/music/_Institut/02 - Angel's Mountain.mp3", '/data/music/_Institut/07 - Bliss - Manvantara.mp3', '/data/music/_Institut/11. No Mood - Loan Mood.mp3', '/data/music/_Institut/08 - Io - Meanderin.mp3', '/data/music/_Institut/7 - Mindtrip.flac', '/data/music/_Institut/08 - African Tribal Orchestra - Sundown In Madagaskar.mp3', '/data/music/_Institut/15 Every Time (A Man Called Adam Balearic Remix).mp3']
WARNING  2020-10-16 11:51:28,836 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  ****** ['file:///data/music/_Institut/14 - Calming Lullaby of Gentle Creek.flac', 'file:///data/music/_Institut/15 - Felicidade.mp3', 'file:///data/music/_Institut/Telepopmusik - Breathe.mp3', 'file:///data/music/_Institut/Stan Getz - Samba De Uma Nota So.mp3', 'file:///data/music/_Institut/09 - Playa Blanca Dream.mp3', "file:///data/music/_Institut/10 Voodoo Bliss (Aaron Bingle's Azure Mix).mp3", 'file:///data/music/_Institut/01 - Trumpet Thing - Need You (Right Now) [Ambient Mix].mp3', 'file:///data/music/_Institut/04 - Otra Vida.mp3', 'file:///data/music/_Institut/12 - Evita.mp3', 'file:///data/music/_Institut/1 - Relaxing Melancholy Meditation on the Sunset Beach.flac', 'file:///data/music/_Institut/7 - Meditation and Music Massage by the Sea Waves on the Night Beach.flac', 'file:///data/music/_Institut/13. Carl Bikkem - Ivory Tower (Chill Republic Mix).mp3', 'file:///data/music/_Institut/04. Air Mallet.mp3', 'file:///data/music/_Institut/01 Ambrosia.mp3', 'file:///data/music/_Institut/02 - Sambox - Rising Sun.mp3', 'file:///data/music/_Institut/12 - Sa Trincha - Smell Of Paradise.mp3', 'file:///data/music/_Institut/06 - Transglobal Underground - TheKhaleegi Stomp (Thievery Corporation Mix).mp3', 'file:///data/music/_Institut/01 - Bahramji & Maneesh De Moor - Dreamcatcher.mp3', 'file:///data/music/_Institut/14 - Cantoma - Essaira.mp3', 'file:///data/music/_Institut/13 - Beautiful Light.flac', 'file:///data/music/_Institut/10 - Dos Hombres - The Alkemyst.mp3', 'file:///data/music/_Institut/10 - Zen Men - El Fuego (Trote King Mix).mp3', 'file:///data/music/_Institut/03. GoTan Project meets Chet Baker  Round About Midnight.mp3', 'file:///data/music/_Institut/05 - Tango De Noche.mp3', 'file:///data/music/_Institut/14 - Hotel Parasaio.mp3', 'file:///data/music/_Institut/12 - Static Solution (Sunset Mix).flac', 'file:///data/music/_Institut/10 - Ofrá - Mandingo.mp3', 'file:///data/music/_Institut/11 - A Change of Mood.flac', 'file:///data/music/_Institut/11 - Sambox - African Dream.mp3', 'file:///data/music/_Institut/6 - Recasting Negative Events into Positive Light by Power of Music.flac', 'file:///data/music/_Institut/06 - Musica Del Mar.mp3', 'file:///data/music/_Institut/02 - Tibet (A Passage To) (Tibet Project).mp3', 'file:///data/music/_Institut/11 - Hablare De Ti.mp3', "file:///data/music/_Institut/02 - Angel's Mountain.mp3", 'file:///data/music/_Institut/07 - Bliss - Manvantara.mp3', 'file:///data/music/_Institut/11. No Mood - Loan Mood.mp3', 'file:///data/music/_Institut/08 - Io - Meanderin.mp3', 'file:///data/music/_Institut/7 - Mindtrip.flac', 'file:///data/music/_Institut/08 - African Tribal Orchestra - Sundown In Madagaskar.mp3', 'file:///data/music/_Institut/15 Every Time (A Man Called Adam Balearic Remix).mp3']
DEBUG    2020-10-16 11:51:28,883 [5084:MpdFrontend-13] mopidy.zeroconf
  Zeroconf service 'Mopidy MPD server on pijukebox' (_mpd._tcp at []:6600): Published
DEBUG    2020-10-16 11:51:28,888 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, index) = None
DEBUG    2020-10-16 11:51:28,889 [5084:Core-9] mopidy.core.tracklist
  Triggering event: tracklist_changed()
DEBUG    2020-10-16 11:51:28,893 [5084:Core-9] mopidy.listener
  Sending tracklist_changed to CoreListener: {}
DEBUG    2020-10-16 11:51:28,890 [5084:HttpFrontend-11] mopidy.zeroconf
  Zeroconf service 'Mopidy HTTP server on pijukebox' (_mopidy-http._tcp at []:6680): Published
DEBUG    2020-10-16 11:51:28,905 [5084:MpdFrontend-13] mopidy.listener
  Sending playlist to MpdSession: {}
WARNING  2020-10-16 11:51:28,917 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: Could not get tracklist index 0: list index out of range
DEBUG    2020-10-16 11:51:28,919 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, consume)
DEBUG    2020-10-16 11:51:28,921 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, consume) = False
DEBUG    2020-10-16 11:51:28,923 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, random)
DEBUG    2020-10-16 11:51:28,925 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, random) = True
DEBUG    2020-10-16 11:51:28,928 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, repeat)
DEBUG    2020-10-16 11:51:28,930 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, repeat) = True
DEBUG    2020-10-16 11:51:28,932 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, single)
DEBUG    2020-10-16 11:51:28,934 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, single) = False
DEBUG    2020-10-16 11:51:28,936 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, mixer, mute)
DEBUG    2020-10-16 11:51:28,938 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, mixer, mute) = False
DEBUG    2020-10-16 11:51:28,990 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, mixer, volume)
DEBUG    2020-10-16 11:51:28,996 [5084:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, mixer, volume) = 90
DEBUG    2020-10-16 11:51:28,998 [5084:SoftwareMixer-1] mopidy.mixer
  Mixer event: mute_changed(mute=False)
DEBUG    2020-10-16 11:51:29,002 [5084:SoftwareMixer-1] mopidy.listener
  Sending mute_changed to MixerListener: {'mute': False}
DEBUG    2020-10-16 11:51:29,006 [5084:Core-9] mopidy.listener
  Sending mute_changed to CoreListener: {'mute': False}
DEBUG    2020-10-16 11:51:29,008 [5084:SoftwareMixer-1] mopidy.mixer
  Mixer event: volume_changed(volume=90)
DEBUG    2020-10-16 11:51:29,010 [5084:MpdFrontend-13] mopidy.listener
  Sending output to MpdSession: {}
DEBUG    2020-10-16 11:51:29,012 [5084:SoftwareMixer-1] mopidy.listener
  Sending volume_changed to MixerListener: {'volume': 90}
DEBUG    2020-10-16 11:51:29,014 [5084:Core-9] mopidy.listener
  Sending volume_changed to CoreListener: {'volume': 90}
DEBUG    2020-10-16 11:51:29,017 [5084:MpdFrontend-13] mopidy.listener
  Sending mixer to MpdSession: {}
cmbcbe commented 3 years ago

perhaps problem with audio file with space?

sphh commented 3 years ago

Yes, you are right! Too many spaces always calls for trouble ;-)

Here we go with another mod:

import urllib.parse

and (note the change in the f'file://{f}' string)

            if uri.startswith('glob://'):
                uris.extend([f'file://{urllib.parse.quote(f)}' for f in glob.glob(uri[len('glob://'):])])
cmbcbe commented 3 years ago

Still nothing with the modification, playlist look empty

DEBUG    2020-10-16 12:34:56,319 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, uris) = ('glob:///data/music/_Institut/*.*',)
WARNING  2020-10-16 12:34:56,328 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  ****** glob:///data/music/_Institut/*.*
TRACE    2020-10-16 12:34:56,331 [781:MainThread] mopidy.internal.timer
  MpdFrontend took 77ms
INFO     2020-10-16 12:34:56,368 [781:MainThread] mopidy.commands
  Starting GLib mainloop
DEBUG    2020-10-16 12:34:56,377 [781:HttpFrontend-11] mopidy.zeroconf
  Zeroconf service 'Mopidy HTTP server on pijukebox' (_mopidy-http._tcp at []:6680): Published
WARNING  2020-10-16 12:34:56,383 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  ****** /data/music/_Institut/*.*
WARNING  2020-10-16 12:34:56,403 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  ****** ['/data/music/_Institut/14 - Calming Lullaby of Gentle Creek.flac', '/data/music/_Institut/15 - Felicidade.mp3', '/data/music/_Institut/Telepopmusik - Breathe.mp3', '/data/music/_Institut/Stan Getz - Samba De Uma Nota So.mp3', '/data/music/_Institut/09 - Playa Blanca Dream.mp3', "/data/music/_Institut/10 Voodoo Bliss (Aaron Bingle's Azure Mix).mp3", '/data/music/_Institut/01 - Trumpet Thing - Need You (Right Now) [Ambient Mix].mp3', '/data/music/_Institut/04 - Otra Vida.mp3', '/data/music/_Institut/12 - Evita.mp3', '/data/music/_Institut/1 - Relaxing Melancholy Meditation on the Sunset Beach.flac', '/data/music/_Institut/7 - Meditation and Music Massage by the Sea Waves on the Night Beach.flac', '/data/music/_Institut/13. Carl Bikkem - Ivory Tower (Chill Republic Mix).mp3', '/data/music/_Institut/04. Air Mallet.mp3', '/data/music/_Institut/01 Ambrosia.mp3', '/data/music/_Institut/02 - Sambox - Rising Sun.mp3', '/data/music/_Institut/12 - Sa Trincha - Smell Of Paradise.mp3', '/data/music/_Institut/06 - Transglobal Underground - TheKhaleegi Stomp (Thievery Corporation Mix).mp3', '/data/music/_Institut/01 - Bahramji & Maneesh De Moor - Dreamcatcher.mp3', '/data/music/_Institut/14 - Cantoma - Essaira.mp3', '/data/music/_Institut/13 - Beautiful Light.flac', '/data/music/_Institut/10 - Dos Hombres - The Alkemyst.mp3', '/data/music/_Institut/10 - Zen Men - El Fuego (Trote King Mix).mp3', '/data/music/_Institut/03. GoTan Project meets Chet Baker  Round About Midnight.mp3', '/data/music/_Institut/05 - Tango De Noche.mp3', '/data/music/_Institut/14 - Hotel Parasaio.mp3', '/data/music/_Institut/12 - Static Solution (Sunset Mix).flac', '/data/music/_Institut/10 - Ofrá - Mandingo.mp3', '/data/music/_Institut/11 - A Change of Mood.flac', '/data/music/_Institut/11 - Sambox - African Dream.mp3', '/data/music/_Institut/6 - Recasting Negative Events into Positive Light by Power of Music.flac', '/data/music/_Institut/06 - Musica Del Mar.mp3', '/data/music/_Institut/02 - Tibet (A Passage To) (Tibet Project).mp3', '/data/music/_Institut/11 - Hablare De Ti.mp3', "/data/music/_Institut/02 - Angel's Mountain.mp3", '/data/music/_Institut/07 - Bliss - Manvantara.mp3', '/data/music/_Institut/11. No Mood - Loan Mood.mp3', '/data/music/_Institut/08 - Io - Meanderin.mp3', '/data/music/_Institut/7 - Mindtrip.flac', '/data/music/_Institut/08 - African Tribal Orchestra - Sundown In Madagaskar.mp3', '/data/music/_Institut/15 Every Time (A Man Called Adam Balearic Remix).mp3']
DEBUG    2020-10-16 12:34:56,405 [781:MpdFrontend-13] mopidy.zeroconf
  Zeroconf service 'Mopidy MPD server on pijukebox' (_mpd._tcp at []:6600): Published
WARNING  2020-10-16 12:34:56,405 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  ****** ['file:///data/music/_Institut/14%20-%20Calming%20Lullaby%20of%20Gentle%20Creek.flac', 'file:///data/music/_Institut/15%20-%20Felicidade.mp3', 'file:///data/music/_Institut/Telepopmusik%20-%20Breathe.mp3', 'file:///data/music/_Institut/Stan%20Getz%20-%20Samba%20De%20Uma%20Nota%20So.mp3', 'file:///data/music/_Institut/09%20-%20Playa%20Blanca%20Dream.mp3', 'file:///data/music/_Institut/10%20Voodoo%20Bliss%20%28Aaron%20Bingle%27s%20Azure%20Mix%29.mp3', 'file:///data/music/_Institut/01%20-%20Trumpet%20Thing%20-%20Need%20You%20%28Right%20Now%29%20%5BAmbient%20Mix%5D.mp3', 'file:///data/music/_Institut/04%20-%20Otra%20Vida.mp3', 'file:///data/music/_Institut/12%20-%20Evita.mp3', 'file:///data/music/_Institut/1%20-%20Relaxing%20Melancholy%20Meditation%20on%20the%20Sunset%20Beach.flac', 'file:///data/music/_Institut/7%20-%20Meditation%20and%20Music%20Massage%20by%20the%20Sea%20Waves%20on%20the%20Night%20Beach.flac', 'file:///data/music/_Institut/13.%20Carl%20Bikkem%20-%20Ivory%20Tower%20%28Chill%20Republic%20Mix%29.mp3', 'file:///data/music/_Institut/04.%20Air%20Mallet.mp3', 'file:///data/music/_Institut/01%20Ambrosia.mp3', 'file:///data/music/_Institut/02%20-%20Sambox%20-%20Rising%20Sun.mp3', 'file:///data/music/_Institut/12%20-%20Sa%20Trincha%20-%20Smell%20Of%20Paradise.mp3', 'file:///data/music/_Institut/06%20-%20Transglobal%20Underground%20-%20TheKhaleegi%20Stomp%20%28Thievery%20Corporation%20Mix%29.mp3', 'file:///data/music/_Institut/01%20-%20Bahramji%20%26%20Maneesh%20De%20Moor%20-%20Dreamcatcher.mp3', 'file:///data/music/_Institut/14%20-%20Cantoma%20-%20Essaira.mp3', 'file:///data/music/_Institut/13%20-%20Beautiful%20Light.flac', 'file:///data/music/_Institut/10%20-%20Dos%20Hombres%20-%20The%20Alkemyst.mp3', 'file:///data/music/_Institut/10%20-%20Zen%20Men%20-%20El%20Fuego%20%28Trote%20King%20Mix%29.mp3', 'file:///data/music/_Institut/03.%20GoTan%20Project%20meets%20Chet%20Baker%20%20Round%20About%20Midnight.mp3', 'file:///data/music/_Institut/05%20-%20Tango%20De%20Noche.mp3', 'file:///data/music/_Institut/14%20-%20Hotel%20Parasaio.mp3', 'file:///data/music/_Institut/12%20-%20Static%20Solution%20%28Sunset%20Mix%29.flac', 'file:///data/music/_Institut/10%20-%20Ofr%C3%A1%20-%20Mandingo.mp3', 'file:///data/music/_Institut/11%20-%20A%20Change%20of%20Mood.flac', 'file:///data/music/_Institut/11%20-%20Sambox%20-%20African%20Dream.mp3', 'file:///data/music/_Institut/6%20-%20Recasting%20Negative%20Events%20into%20Positive%20Light%20by%20Power%20of%20Music.flac', 'file:///data/music/_Institut/06%20-%20Musica%20Del%20Mar.mp3', 'file:///data/music/_Institut/02%20-%20Tibet%20%28A%20Passage%20To%29%20%28Tibet%20Project%29.mp3', 'file:///data/music/_Institut/11%20-%20Hablare%20De%20Ti.mp3', 'file:///data/music/_Institut/02%20-%20Angel%27s%20Mountain.mp3', 'file:///data/music/_Institut/07%20-%20Bliss%20-%20Manvantara.mp3', 'file:///data/music/_Institut/11.%20No%20Mood%20-%20Loan%20Mood.mp3', 'file:///data/music/_Institut/08%20-%20Io%20-%20Meanderin.mp3', 'file:///data/music/_Institut/7%20-%20Mindtrip.flac', 'file:///data/music/_Institut/08%20-%20African%20Tribal%20Orchestra%20-%20Sundown%20In%20Madagaskar.mp3', 'file:///data/music/_Institut/15%20Every%20Time%20%28A%20Man%20Called%20Adam%20Balearic%20Remix%29.mp3']
DEBUG    2020-10-16 12:34:56,444 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, index) = None
DEBUG    2020-10-16 12:34:56,445 [781:Core-9] mopidy.core.tracklist
  Triggering event: tracklist_changed()
DEBUG    2020-10-16 12:34:56,447 [781:Core-9] mopidy.listener
  Sending tracklist_changed to CoreListener: {}
DEBUG    2020-10-16 12:34:56,464 [781:MpdFrontend-13] mopidy.listener
  Sending playlist to MpdSession: {}
WARNING  2020-10-16 12:34:56,470 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: Could not get tracklist index 0: list index out of range
DEBUG    2020-10-16 12:34:56,472 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, consume)
DEBUG    2020-10-16 12:34:56,474 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, consume) = False
DEBUG    2020-10-16 12:34:56,476 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, random)
DEBUG    2020-10-16 12:34:56,477 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, random) = True
DEBUG    2020-10-16 12:34:56,480 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, repeat)
DEBUG    2020-10-16 12:34:56,482 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, repeat) = True
DEBUG    2020-10-16 12:34:56,485 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, single)
DEBUG    2020-10-16 12:34:56,487 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, tracklist, single) = False
DEBUG    2020-10-16 12:34:56,489 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, mixer, mute)
DEBUG    2020-10-16 12:34:56,491 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, mixer, mute) = False
DEBUG    2020-10-16 12:34:56,546 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _set_option({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, mixer, volume)
DEBUG    2020-10-16 12:34:56,548 [781:AutoplayFrontend-12] mopidy_autoplay.frontend
  Autoplay: _get_config({'tracklist': {'uris': [], 'index': None, 'consume': False, 'random': True, 'repeat': True, 'single': False}, 'mixer': {'mute': False, 'volume': 90}, 'playback': {'state': 'stopped', 'time_position': 0}}, mixer, volume) = 90
sphh commented 3 years ago

??? I don't understand it (because it is working here without – and now also with – spaces in the file name).

Ok, let us check, if it is a problem related to file permissions: Please use glob:///usr/share/sounds/alsa/*.wav as your autoplay/tracklist.uris option. Please check beforehand, if these files are installed.

You can also check, if the files are actually added to the tracklist/queue by inserting this into the code:

            logger.warning("****** %s", self.core.library.lookup(uris).get())

after the if uris: line and

            logger.warning("****** %s", self.core.tracklist.get_tl_tracks().get())

after the self.core.tracklist.add(uris=uris) line.

cmbcbe commented 3 years ago

glob:///usr/share/sounds/alsa/*.wav not working here, perhaps a mistake in my copy/paste python code indentation...

cmbcbe commented 3 years ago

it is working, i had to enable [file] extension in mopidy.conf

sphh commented 3 years ago

No surprise! It got a bit messy …

Here is the entire file... ```python3 """Autoplay extension for Mopidy. A Mopidy extension to automatically pick up where you left off and start playing the last track from the position before Mopidy was shut down. """ import logging import pathlib import urllib.parse import glob import json import pykka from mopidy import core from . import Extension, Recollection logger = logging.getLogger(__name__) class AutoplayFrontend(pykka.ThreadingActor, core.CoreListener): """Autoplay's frontend implementation.""" def __init__(self, config, core): """Initialize the `AutoplayFrontend` class.""" logger.debug( 'Autoplay: __init__(%s, %s)', config, core) super(AutoplayFrontend, self).__init__() self.core = core self.config = config[Extension.ext_name] # State file data_dir = Extension.get_data_dir(config) self.statefile = pathlib.Path(data_dir) / 'autoplay.state' logger.debug( "Autoplay: Use '%s' as statefile.", self.statefile) # The frontend implementation def on_start(self): # noqa: D401 """Called, when the extension is started.""" logger.debug('Autoplay: on_start()') state = self.read_state(self.statefile) if state: self.restore_state(state) def on_stop(self): # noqa: D401 """Called, when the extension is stopped.""" logger.debug('Autoplay: on_stop()') state = self.store_state() self.write_state(state, self.statefile) # Helper functions def _get_config(self, state, controller, option): """ Return the configuration from `config` and `state`. If the extension's configuration has a value other than "auto" (which is translated into the class `Recollection`), return this value, otherwise the saved value from the state variable. Args: state (dict): A dictionary with the states saved for the 'tracklist', 'mixer' and 'playback' controllers. controller (str): The controller name. option (str): The option name. Returns: value: The configuration or state value. """ config = self.config.get(f'{controller}.{option}', Recollection) if config is Recollection: s = state.get(controller, {}).get(option, None) else: s = config logger.debug( 'Autoplay: _get_config(%s, %s, %s) = %s', state, controller, option, s) return s def _set_option(self, state, controller, option): """ Set the state to the controller's option. Args: state (TYPE): A dictionary with the states saved for the 'tracklist', 'mixer' and 'playback' controllers. controller (str): The controller name. option (str): The option name. Returns: None. """ logger.debug( 'Autoplay: _set_option(%s, %s, %s)', state, controller, option) # Get value to be set value = self._get_config(state, controller, option) if value is None: return # Get method to be used to set option setter = getattr(getattr(self.core, controller), f'set_{option}') # Set value (and log message, if failed) if not setter(value): logger.info( "Autoplay: Set %s/%s to '%s' failed.", controller, option, value) # Worker functions def restore_state(self, state): """ Restore the saved state. Args: state (dict): A dictionary with the states saved for the 'tracklist', 'mixer' and 'playback' controllers. Returns: None. """ # Reset tracklist tlid = None playlist_schemes = tuple(self.core.playlists.get_uri_schemes().get()) uris = [] for uri in self._get_config(state, 'tracklist', 'uris'): if uri.startswith('glob://'): # Add files to the list of URIs uris.extend( [f'file://{urllib.parse.quote(f)}' for f in glob.glob(uri[len('glob://'):])]) elif uri.startswith(playlist_schemes): # Add contents of known playlists to the list of URIs uris.extend( [track.uri for track in self.core.playlists.get_items(uri).get() or []]) else: uris.append(uri) logger.warning("****** %s", uris) if uris: logger.warning("****** %s", self.core.library.lookup(uris).get()) # Clear tracklist and add URIs self.core.tracklist.clear() self.core.tracklist.add(uris=uris) logger.warning("****** %s", self.core.tracklist.get_tl_tracks().get()) # Switch to specified index index = self._get_config(state, 'tracklist', 'index') or 0 try: tlid = self.core.tracklist.get_tl_tracks().get()[index].tlid except Exception as e: logger.warning( "Autoplay: Could not get tracklist index %s: %s", index, e) tlid = None self._set_option(state, 'tracklist', 'consume') self._set_option(state, 'tracklist', 'random') self._set_option(state, 'tracklist', 'repeat') self._set_option(state, 'tracklist', 'single') # Reset mixer self._set_option(state, 'mixer', 'mute') self._set_option(state, 'mixer', 'volume') # Reset playback state if tlid is not None: # Why does this not work? # self._set_option(state, 'playback', 'state') playback = self._get_config(state, 'playback', 'state') if playback == 'stopped': self.core.playback.stop().get() elif playback == 'playing': self.core.playback.play(tlid=tlid) elif playback == 'paused': self.core.playback.pause() time_position = self._get_config(state, 'playback', 'time_position') if time_position is not None: self.core.playback.seek(time_position) def store_state(self): """ Assemble and return the state. Returns: state (dict): A dictionary with the states saved for the 'tracklist', 'mixer' and 'playback' controllers. """ # Initialize 'state' variable state = { 'tracklist': {}, 'mixer': {}, 'playback': {}, } # Tracks in tracklist tracklist = self.core.tracklist state['tracklist']['uris'] = [ t.uri for t in tracklist.get_tracks().get() if t is not None] # Get currently playing track (or None) state['tracklist']['index'] = tracklist.index().get() # Get options state['tracklist']['consume'] = tracklist.get_consume().get() state['tracklist']['random'] = tracklist.get_random().get() state['tracklist']['repeat'] = tracklist.get_repeat().get() state['tracklist']['single'] = tracklist.get_single().get() # Get the mixer state mixer = self.core.mixer # True, False or None state['mixer']['mute'] = mixer.get_mute().get() # [0..100] or None state['mixer']['volume'] = mixer.get_volume().get() # Get the playback state playback = self.core.playback # Returns "stopped", "playing" or "paused" state['playback']['state'] = playback.get_state().get() state['playback']['time_position'] = playback.get_time_position().get() return state def read_state(self, file): """ Read the state from the a json file. Args: file (str|Path): A json-formated file with the state dictionary. Returns: state (dict): A dictionary with the states saved for the 'tracklist', 'mixer' and 'playback' controllers. """ try: with open(file, 'r') as f: state = json.load(f) except IOError as e: logger.warning( "Autoplay: No state restored, " "because there was a problem opening the state file '%s': %s", file, e) return except json.JSONDecodeError as e: logger.error( "Autoplay: Error reading state from file '%s': %s", file, e) return else: logger.debug( "Autoplay: State read from file '%s'.", file) return state def write_state(self, state, file): """ Write the state to a json file. Args: state (dict): A dictionary with the states saved for the 'tracklist', 'mixer' and 'playback' controllers. file (str|Path): A writeable file. Returns: None. """ try: with open(file, 'w') as f: json.dump(state, f) except IOError as e: logger.error( "Autoplay: Cannot open state file '%s' for writing: %s", file, e) except Exception as e: logger.error( "Autoplay: Problem saving state to file '%s': %s", file, e) logger.debug( "Autoplay: State: %s", state) else: logger.debug( "Autoplay: State written to file '%s'.", file) ```
sphh commented 3 years ago

Well, if the File extension was not enabled, then it cannot work …

I always thought, that this is enabled by default. Did you disable it?

cmbcbe commented 3 years ago

yes, i was using the [local] extension

sphh commented 3 years ago

I have never tried to use Local. What are the advantages?

cmbcbe commented 3 years ago

it create a local DB are read tags of mp3 etc to sort by genre, artist, download coverart etc....

cmbcbe commented 3 years ago

the playlist is full but it only play the first music, any idea?

[autoplay]
enabled = true
tracklist.uris = glob:///data/music/_Institut/*.*
tracklist.index = auto
tracklist.consume = false
tracklist.random = true
tracklist.repeat = true
tracklist.single = false
playback.state = playing
playback.time_position = auto
mixer.volume = 90
mixer.mute = off
sphh commented 3 years ago

Honestly, no.

Can you get it to play all files in a GUI? If yes, exit Mopidy, look at /var/lib/mopidy/autoplay/autoplay.state and copy those settings into Mopidy's configuration file. After restarting Mopidy, check in the GUI, if the settings are the same as before.

sphh commented 3 years ago

@cmbce, could you please open another issue with your latest problem?

Also I want to thank you for your patience tracking down the problem. Even if it turned out not having the File extension enabled, it helped to find some other problems!

cmbcbe commented 3 years ago

@cmbce, could you please open another issue with your latest problem?

Also I want to thank you for your patience tracking down the problem. Even if it turned out not having the File extension enabled, it helped to find some other problems!

I finnaly set like this and it's working:

playback.state = playing
to
playback.state = auto
sphh commented 3 years ago

Glad, that it works, even if I don't know why ;-)

sphh commented 3 years ago

@cmbce: I uploaded this to PyPi as a new version. Please note, that I have changed glob:// to match:file://, so please update you Mopidy configuration file after updating this extension.

(The reason was, that some other wildchar loading might emerge, so by just prepending an existing URL with match: would make it easier to implement.)