Skip to content

Commit

Permalink
player: show some message(progress) after user play a model (#862)
Browse files Browse the repository at this point in the history
  • Loading branch information
cosven authored Aug 6, 2024
1 parent d3d95e5 commit 11c4ff2
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 13 deletions.
18 changes: 14 additions & 4 deletions feeluown/gui/components/line_song.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from PyQt5.QtGui import QPainter, QPalette, QColor
from PyQt5.QtWidgets import QLabel, QSizePolicy, QMenu, QVBoxLayout, QWidget

from feeluown.player import PlaylistPlayModelStage
from feeluown.library import fmt_artists_names
from feeluown.gui.components import SongMenuInitializer
from feeluown.gui.helpers import elided_text
Expand Down Expand Up @@ -35,8 +36,8 @@ def __init__(self, app: 'GuiApp', parent=None):
self._app.player.metadata_changed.connect(
self.on_metadata_changed, aioqueue=True
)
self._app.playlist.play_model_handling.connect(
self.on_play_model_handling, aioqueue=True
self._app.playlist.play_model_stage_changed.connect(
self.on_play_model_stage_changed, aioqueue=True
)

def on_metadata_changed(self, metadata):
Expand All @@ -53,8 +54,17 @@ def on_metadata_changed(self, metadata):
text += f" • {','.join(artists)}"
self.setText(text)

def on_play_model_handling(self):
self.setText('正在加载歌曲...')
def on_play_model_stage_changed(self, stage):
if stage == PlaylistPlayModelStage.prepare_media:
self.setText('正在获取歌曲播放链接...')
elif stage == PlaylistPlayModelStage.find_standby_by_mv:
self.setText('正在获取音乐的视频播放链接...')
elif stage == PlaylistPlayModelStage.find_standby:
self.setText('尝试寻找备用播放链接...')
elif stage == PlaylistPlayModelStage.prepare_metadata:
self.setText('尝试获取完整的歌曲元信息...')
elif stage == PlaylistPlayModelStage.load_media:
self.setText('正在加载歌曲资源...')

def change_text_position(self):
if not self.parent().isVisible(): # type: ignore
Expand Down
2 changes: 0 additions & 2 deletions feeluown/library/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,6 @@ def song_prepare_media(self, song: BriefSongModel, policy) -> Media:
if not media:
if self.ytdl is not None and isinstance(provider, SupportsSongWebUrl):
song_web_url = provider.song_get_web_url(song)
logger.info(f'use ytdl to get media for {song_web_url}')
media = self.ytdl.select_audio(song_web_url, policy, source=song.source)
found = media is not None
logger.debug(f'ytdl select audio for {song_web_url} finished, '
Expand Down Expand Up @@ -438,7 +437,6 @@ def video_prepare_media(self, video: BriefVideoModel, policy) -> Media:
except MediaNotFound:
if self.ytdl is not None and isinstance(provider, SupportsVideoWebUrl):
video_web_url = provider.video_get_web_url(video)
logger.info(f'use ytdl to get media for {video_web_url}')
media = self.ytdl.select_video(video_web_url,
policy,
source=video.source)
Expand Down
6 changes: 5 additions & 1 deletion feeluown/library/ytdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(self, rules: Optional[List[Any]] = None):
# TODO: valid rules
self._rules = rules or []

def match_rule(self, _, source=''):
def match_rule(self, url, source=''):
"""
Currently, only 'match_source' is supported. Maybe support 'match_url'
in the future.
Expand All @@ -39,6 +39,10 @@ def match_rule(self, _, source=''):
for rule in self._rules:
if rule['name'] == 'match_source' and source == rule['pattern']:
matched_rule = rule
if matched_rule:
logger.info(f"ytdl rule matched for {url}")
else:
logger.info(f"no ytdl rule matched for {url}")
return matched_rule

def select_audio(self, url, _: Optional[str] = None, source='') -> Optional[Media]:
Expand Down
4 changes: 3 additions & 1 deletion feeluown/player/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .metadata import MetadataFields, Metadata
from .playlist import PlaybackMode, PlaylistRepeatMode, PlaylistShuffleMode
from .playlist import PlaybackMode, PlaylistRepeatMode, PlaylistShuffleMode, \
PlaylistPlayModelStage
from .base_player import State
from .mpvplayer import MpvPlayer as Player
from .playlist import PlaylistMode, Playlist
Expand All @@ -15,6 +16,7 @@
'PlaybackMode',
'PlaylistRepeatMode',
'PlaylistShuffleMode',
'PlaylistPlayModelStage',
'State',

'FM',
Expand Down
24 changes: 22 additions & 2 deletions feeluown/player/playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ class PlaylistMode(IntEnum):
fm = 1 #: FM mode


class PlaylistPlayModelStage(IntEnum):
prepare_media = 10
find_standby_by_mv = 20
find_standby = 30
prepare_metadata = 40
load_media = 50


class Playlist:
def __init__(self, app: 'App', songs=None, playback_mode=PlaybackMode.loop,
audio_select_policy='hq<>'):
Expand Down Expand Up @@ -134,6 +142,9 @@ def __init__(self, app: 'App', songs=None, playback_mode=PlaybackMode.loop,
# .. versionadded:: 3.9.0
# The *play_model_handling* signal.
self.play_model_handling = Signal()
# .. versionadded:: 4.1.7
# The *play_model_handling* signal.
self.play_model_stage_changed = Signal()

self._app.player.media_finished.connect(self._on_media_finished)
self.song_changed.connect(self._on_song_changed)
Expand Down Expand Up @@ -493,6 +504,7 @@ async def a_set_current_song(self, song):
target_song = song # The song to be set.
media = None # The corresponding media to be set.
try:
self.play_model_stage_changed.emit(PlaylistPlayModelStage.prepare_media)
media = await self._prepare_media(song)
except MediaNotFound as e:
if e.reason is MediaNotFound.Reason.check_children:
Expand All @@ -513,12 +525,14 @@ async def a_set_current_song(self, song):
# The song has no media, try to find and use standby unless it is in fm mode.
if media is None:
if self._app.config.ENABLE_MV_AS_STANDBY:
self._app.show_msg('尝试获取音乐视频的播放资源...')
self.play_model_stage_changed.emit(
PlaylistPlayModelStage.find_standby_by_mv)
media = await self._prepare_mv_media(song)

if media:
self._app.show_msg('使用音乐视频作为其播放资源 ✅')
else:
self._app.show_msg('未找到可用的音乐视频资源 🙁')
# if mode is fm mode, do not find standby song, just skip the song.
if self.mode is PlaylistMode.fm:
self.mark_as_bad(song)
Expand All @@ -527,9 +541,14 @@ async def a_set_current_song(self, song):

logger.info(f"no media found for {song}, mark it as bad")
self.mark_as_bad(song)
self.play_model_stage_changed.emit(PlaylistPlayModelStage.find_standby)
target_song, media = await self.find_and_use_standby(song)

metadata = await self._metadata_mgr.prepare_for_song(target_song)
metadata = None
if media is not None:
self.play_model_stage_changed.emit(PlaylistPlayModelStage.prepare_metadata)
metadata = await self._metadata_mgr.prepare_for_song(target_song)
self.play_model_stage_changed.emit(PlaylistPlayModelStage.load_media)
self.pure_set_current_song(target_song, media, metadata)

async def a_set_current_song_children(self, song):
Expand Down Expand Up @@ -582,6 +601,7 @@ def pure_set_current_song(self, song, media, metadata=None):

if song is not None:
if media is None:
self._app.show_msg("没找到可用的播放链接,播放下一首...")
run_afn(self.a_next)
else:
# Note that the value of model v1 {}_display may be None.
Expand Down
4 changes: 1 addition & 3 deletions tests/player/test_playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,11 @@ async def test_set_current_song_with_bad_song_1(
pl_list_standby_return_empty):
mock_pure_set_current_song = mocker.patch.object(Playlist, 'pure_set_current_song')
mock_mark_as_bad = mocker.patch.object(Playlist, 'mark_as_bad')
sentinal = object()
mocker.patch.object(MetadataAssembler, 'prepare_for_song', return_value=sentinal)
await pl.a_set_current_song(song2)
# A song that has no valid media should be marked as bad
assert mock_mark_as_bad.called
# Since there is no standby song, the media should be None
mock_pure_set_current_song.assert_called_once_with(song2, None, sentinal)
mock_pure_set_current_song.assert_called_once_with(song2, None, None)


@pytest.mark.asyncio
Expand Down

0 comments on commit 11c4ff2

Please sign in to comment.