Skip to content

Commit

Permalink
player: add timeout when fetching song metadata (#853)
Browse files Browse the repository at this point in the history
  • Loading branch information
cosven authored Jul 15, 2024
1 parent 41bb8ba commit 8921ae2
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 12 deletions.
9 changes: 8 additions & 1 deletion feeluown/library/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ def song_prepare_media(self, song: BriefSongModel, policy) -> Media:
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, '
f'found: {found}')
if not media:
raise MediaNotFound('provider returns empty media')
return media
Expand Down Expand Up @@ -425,7 +428,6 @@ def video_prepare_media(self, video: BriefVideoModel, policy) -> Media:
:param video: either a v1 MvModel or a v2 (Brief)VideoModel.
"""
provider = self.get(video.source)

try:
if isinstance(provider, SupportsVideoMultiQuality):
media, _ = provider.video_select_media(video, policy)
Expand All @@ -440,6 +442,11 @@ def video_prepare_media(self, video: BriefVideoModel, policy) -> Media:
media = self.ytdl.select_video(video_web_url,
policy,
source=video.source)
found = media is not None
logger.debug(f'ytdl select video for {video_web_url} finished, '
f'found: {found}')
else:
media = None
if not media:
raise
return media
20 changes: 13 additions & 7 deletions feeluown/player/playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,26 +600,32 @@ async def _prepare_metadata_for_song(self, song):
MetadataFields.album: song.album_name_display or '',
})
try:
song = await aio.run_fn(self._app.library.song_upgrade, song)
song: SongModel = await aio.wait_for(
aio.run_fn(self._app.library.song_upgrade, song),
timeout=1,
)
except ResourceNotFound:
return metadata
except: # noqa
logger.exception(f"fetching song's meta failed, song:'{song.title_display}'")
return metadata

artwork = ''
released = ''
if song.album is not None:
artwork = song.pic_url
released = song.date
if not (artwork and released) and song.album is not None:
try:
album = await aio.run_fn(self._app.library.album_upgrade, song.album)
album = await aio.wait_for(
aio.run_fn(self._app.library.album_upgrade, song.album),
timeout=1
)
except ResourceNotFound:
pass
except: # noqa
logger.warning(
f"fetching song's album meta failed, song:{song.title_display}")
else:
artwork = album.cover
released = album.released
artwork = album.cover or artwork
released = album.released or released
# For model v1, the cover can be a Media object.
# For example, in fuo_local plugin, the album.cover is a Media
# object with url set to fuo://local/songs/{identifier}/data/cover.
Expand Down
3 changes: 3 additions & 0 deletions feeluown/utils/aio.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
#: gather is an alias of `asyncio.gather`.
gather = asyncio.gather

#: wait_for is an alias of `asyncio.wait_for`
wait_for = asyncio.wait_for


def run_in_executor(executor, func, *args):
"""alias for loop.run_in_executor"""
Expand Down
10 changes: 6 additions & 4 deletions tests/player/test_playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,13 +355,15 @@ def test_playlist_next_should_call_set_current_song(app_mock, mocker, song):


@pytest.mark.asyncio
async def test_playlist_prepare_metadata_for_song(app_mock, pl, ekaf_brief_song0):
async def test_playlist_prepare_metadata_for_song(
app_mock, library, pl, ekaf_brief_song0, mocker):
class Album:
cover = Media('fuo://')
released = '2018-01-01'

app_mock.library = library
album = Album()
f = asyncio.Future()
f.set_result(album)
app_mock.library.album_upgrade.return_value = album
mocker.patch.object(library, 'album_upgrade', return_value=album)
# app_mock.library.album_upgrade.return_value = album
# When cover is a media object, prepare_metadata should also succeed.
await pl._prepare_metadata_for_song(ekaf_brief_song0)

0 comments on commit 8921ae2

Please sign in to comment.