diff --git a/feeluown/server/handlers/player.py b/feeluown/server/handlers/player.py index 79f62bf9b6..40d2c00c1d 100644 --- a/feeluown/server/handlers/player.py +++ b/feeluown/server/handlers/player.py @@ -2,8 +2,12 @@ from difflib import SequenceMatcher from typing import Any -from feeluown.library import resolve, reverse +from feeluown.library import ( + resolve, reverse, BriefSongModel, BriefPlaylistModel, + SupportsPlaylistSongsReader, +) from .base import AbstractHandler +from .excs import HandlerException def score(src, tar): @@ -47,12 +51,29 @@ def handle(self, cmd): # pylint: disable=inconsistent-return-statements self.player.toggle() def play(self, s): # pylint: disable=inconsistent-return-statements - # pylint: disable=no-else-return + # pylint: disable=no-else-return,too-many-branches if s.startswith('fuo://'): model = resolve(s) if model is None: return 'Invalid fuo uri.' - self._app.playlist.play_model(model) + elif isinstance(model, BriefSongModel): + self._app.playlist.play_model(model) + elif isinstance(model, BriefPlaylistModel): + provider = self._app.library.get(model.source) + if isinstance(provider, SupportsPlaylistSongsReader): + reader = provider.playlist_create_songs_rd(model) + songs = reader.readall() + self._app.playlist.set_models(songs, next_=True) + self._app.player.resume() + else: + raise HandlerException( + f"provider:{provider.identifier} does not support" + " SupportsPlaylistSongsReader" + ) + else: + model_type = model.meta.model_type + raise HandlerException(f"can't play this model type: {model_type}") + return elif s.startswith('http'): return self.player.play(s, video=False) diff --git a/feeluown/server/handlers/playlist.py b/feeluown/server/handlers/playlist.py index b19cf96e76..09cec12306 100644 --- a/feeluown/server/handlers/playlist.py +++ b/feeluown/server/handlers/playlist.py @@ -1,6 +1,5 @@ -from feeluown.library import ModelType +from feeluown.library import ModelType, SupportsPlaylistSongsReader from feeluown.library import resolve, reverse -from feeluown.utils.utils import to_readall_reader from .base import AbstractHandler @@ -32,9 +31,12 @@ def add(self, furi_list): if obj_type == ModelType.song: playlist.add(obj) elif obj_type == ModelType.playlist: - songs = to_readall_reader(obj, "songs").readall() - for song in songs: - playlist.add(song) + provider = self.library.get(obj.source) + if isinstance(provider, SupportsPlaylistSongsReader): + reader = provider.playlist_create_songs_rd(obj) + for song in reader: + playlist.add(song) + # TODO: raise error if it does not support def remove(self, song_uri): # FIXME: a little bit tricky diff --git a/feeluown/server/handlers/show.py b/feeluown/server/handlers/show.py index 3487aa862e..c6a1c17e98 100644 --- a/feeluown/server/handlers/show.py +++ b/feeluown/server/handlers/show.py @@ -12,11 +12,11 @@ from functools import wraps from urllib.parse import urlparse -from feeluown.utils.utils import to_readall_reader from feeluown.utils.router import Router, NotFound -from feeluown.library import ResourceNotFound -from feeluown.library import NS_TYPE_MAP -from feeluown.library import ModelType +from feeluown.library import ( + ResourceNotFound, NS_TYPE_MAP, ModelType, + SupportsPlaylistSongsReader, SupportsArtistAlbumsReader, +) from .base import AbstractHandler from .excs import HandlerException @@ -120,7 +120,11 @@ def lyric_(req, provider, sid): @use_provider def playlist_songs(req, provider, pid): playlist = get_model_or_raise(req.ctx['library'], provider, ModelType.playlist, pid) - return to_readall_reader(playlist, 'songs').readall() + if isinstance(provider, SupportsPlaylistSongsReader): + reader = provider.playlist_create_songs_rd(playlist) + return reader.readall() + raise HandlerException(f"provider:{provider.identifier} does not support" + f" {SupportsPlaylistSongsReader}") @route('//artists//albums') @@ -128,4 +132,8 @@ def playlist_songs(req, provider, pid): def albums_of_artist(req, provider, aid): """show all albums of an artist identified by artist id""" artist = get_model_or_raise(req.ctx['library'], provider, ModelType.artist, aid) - return to_readall_reader(artist, 'albums').readall() + if isinstance(provider, SupportsArtistAlbumsReader): + reader = provider.artist_create_albums_rd(artist) + return reader.readall() + raise HandlerException(f"provider:{provider.identifier} does not support" + f" {SupportsArtistAlbumsReader}") diff --git a/feeluown/utils/utils.py b/feeluown/utils/utils.py index 753a8f6983..c1481ced3c 100644 --- a/feeluown/utils/utils.py +++ b/feeluown/utils/utils.py @@ -10,9 +10,6 @@ from functools import wraps from itertools import filterfalse -from feeluown.utils.reader import wrap as reader_wrap - - logger = logging.getLogger(__name__) @@ -90,34 +87,6 @@ def get_osx_theme(): return 1 if theme == 'Dark' else -1 -def to_reader(model, field): - flag_attr = 'allow_create_{}_g'.format(field) - method_attr = 'create_{}_g'.format(field) - - flag_g = getattr(model.meta, flag_attr) - - if flag_g: - return reader_wrap(getattr(model, method_attr)()) - - value = getattr(model, field, None) - if value is None: - return reader_wrap([]) - if isinstance(value, (list, tuple)): - return reader_wrap(value) - return reader_wrap(iter(value)) # TypeError if not iterable - - -def to_readall_reader(*args, **kwargs): - """ - hack: set SequentialReader reader's count to 1000 if it is None - so that we can call readall method. - """ - reader = to_reader(*args, **kwargs) - if reader.count is None: - reader.count = 1000 - return reader - - class DedupList(list): """List that doesn't contain duplicate items