Skip to content

Commit

Permalink
wip: recommendation page
Browse files Browse the repository at this point in the history
  • Loading branch information
cosven committed Jan 2, 2024
1 parent 300251c commit dec6316
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 4 deletions.
2 changes: 2 additions & 0 deletions feeluown/gui/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ def initialize(self):
from feeluown.gui.pages.song_explore import render as render_song_explore
from feeluown.gui.pages.provider_home import render as render_provider_home
from feeluown.gui.pages.recently_played import render as render_recently_played
from feeluown.gui.pages.recommendation import render as render_rec

model_prefix = f'{MODEL_PAGE_PREFIX}<provider>'

Expand All @@ -209,6 +210,7 @@ async def dummy_render(req, *args, **kwargs):
('/providers/<identifier>', render_provider_home),
('/recently_played', render_recently_played),
('/search', render_search),
('/rec', render_rec),
]
for url, renderer in urlpatterns:
self.route(url)(renderer)
107 changes: 107 additions & 0 deletions feeluown/gui/pages/recommendation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
from typing import TYPE_CHECKING

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QVBoxLayout

from feeluown.utils.reader import create_reader
from feeluown.utils.aio import run_fn
from feeluown.gui.widgets.header import LargeHeader, MidHeader
from feeluown.gui.widgets.img_card_list import (
PlaylistCardListView, PlaylistCardListModel, PlaylistFilterProxyModel,
PlaylistCardListDelegate,
)

from feeluown.library import SupportsRecListDailyPlaylists, SupportsRecListDailySongs
from feeluown.gui.widgets.textbtn import TextButton
from feeluown.gui.helpers import fetch_cover_wrapper, BgTransparentMixin
from feeluown.gui.widgets.song_minicard_list import (
SongMiniCardListView,
SongMiniCardListModel,
SongMiniCardListDelegate,
)

from fuo_netease import provider


if TYPE_CHECKING:
from feeluown.app.gui_app import GuiApp


async def render(req, **kwargs):
app: 'GuiApp' = req.ctx['app']

view = View(app)
app.ui.right_panel.set_body(view)
await view.render()


class View(QWidget):
def __init__(self, app: 'GuiApp'):
super().__init__(parent=None)
self._app = app

self.header_title = LargeHeader()
self.header_playlist_list = MidHeader()
self.header_daily_rec = MidHeader()
self.playlist_list_view = PlaylistCardListView(fixed_row_count=1)
self.playlist_list_view.setItemDelegate(
PlaylistCardListDelegate(self.playlist_list_view,
card_min_width=100,))

self.daily_rec_view = SongMiniCardListView(no_scroll_v=False, fixed_row_count=2)
delegate = SongMiniCardListDelegate(
self.daily_rec_view,
card_min_width=150,
card_height=40,
card_padding=(5 + SongMiniCardListDelegate.img_padding, 5, 0, 5),
card_right_spacing=10,
)
self.daily_rec_view.setItemDelegate(delegate)

self.header_title.setText('发现音乐')
self.header_playlist_list.setText('个性化推荐')
self.header_daily_rec.setText('每日推荐')

self._layout = QVBoxLayout(self)
self._setup_ui()

self.daily_rec_view.play_song_needed.connect(self._app.playlist.play_model)
self.playlist_list_view.show_playlist_needed.connect(
lambda model: self.browser.goto(model=model))

def _setup_ui(self):
self._layout.setContentsMargins(20, 10, 20, 0)
self._layout.setSpacing(0)
self._layout.addWidget(self.header_title)
self._layout.addSpacing(10)
self._layout.addWidget(self.header_daily_rec)
self._layout.addSpacing(5)
self._layout.addWidget(self.daily_rec_view)
self._layout.addSpacing(10)
self._layout.addWidget(self.header_playlist_list)
self._layout.addSpacing(10)
self._layout.addWidget(self.playlist_list_view)
self._layout.addStretch(0)

async def render(self):
pvd_ui = self._app.current_pvd_ui_mgr.get()
if pvd_ui is None:
self._app.show_msg('wtf!')
return

provider = pvd_ui.provider
if isinstance(provider, SupportsRecListDailyPlaylists):
playlists = await run_fn(provider.rec_list_daily_playlists)
model = PlaylistCardListModel(
create_reader(playlists),
fetch_cover_wrapper(self._app),
{p.identifier: p.name for p in self._app.library.list()})
filter_model = PlaylistFilterProxyModel()
filter_model.setSourceModel(model)
self.playlist_list_view.setModel(filter_model)

if isinstance(provider, SupportsRecListDailySongs):
songs = await run_fn(provider.rec_list_daily_songs)
model = SongMiniCardListModel(create_reader(songs),
fetch_cover_wrapper(self._app))
self.daily_rec_view.setModel(model)
6 changes: 4 additions & 2 deletions feeluown/gui/uimain/sidebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,10 @@ def __init__(self, app: 'GuiApp', parent=None):
self.collections_con.create_btn.clicked.connect(
self.popup_collection_adding_dialog)
self.playlists_con.create_btn.clicked.connect(self._create_playlist)
self._app.current_pvd_ui_mgr.changed.connect(
self.on_current_pvd_ui_changed)
# self._app.current_pvd_ui_mgr.changed.connect(
# self.on_current_pvd_ui_changed)
self.discovery_btn.clicked.connect(
lambda: self._app.browser.goto(page='/rec'))

def popup_collection_adding_dialog(self):
dialog = QDialog(self)
Expand Down
2 changes: 1 addition & 1 deletion feeluown/gui/widgets/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ def __init__(self, *args, **kwargs):

class MidHeader(BaseHeader):
def __init__(self, *args, **kwargs):
super().__init__(15, *args, **kwargs)
super().__init__(16, *args, **kwargs)
29 changes: 28 additions & 1 deletion feeluown/library/provider_protocol.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from typing import runtime_checkable, Protocol, List, Tuple, Optional, Dict
from abc import abstractmethod

from feeluown.media import Quality, Media
from .models import (
BriefCommentModel, SongModel, VideoModel, AlbumModel, ArtistModel,
Expand Down Expand Up @@ -41,6 +40,10 @@

'SupportsVideoGet',
'SupportsVideoMultiQuality',

'SupportsRecListDailySongs',
'SupportsRecListDailyAlbums',
'SupportsRecListDailyPlaylists',
)


Expand Down Expand Up @@ -344,3 +347,27 @@ def get_current_user(self) -> UserModel:
:raises NoUserLoggedIn: there is no logged in user.
"""


#
# Protocols for recommendation.
#
@runtime_checkable
class SupportsRecListDailySongs(Protocol):
@abstractmethod
def rec_list_daily_songs(self) -> List[SongModel]:
pass


@runtime_checkable
class SupportsRecListDailyPlaylists(Protocol):
@abstractmethod
def rec_list_daily_playlists(self) -> List[PlaylistModel]:
pass


@runtime_checkable
class SupportsRecListDailyAlbums(Protocol):
@abstractmethod
def rec_list_daily_albums(self) -> List[AlbumModel]:
pass

0 comments on commit dec6316

Please sign in to comment.