Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: add a collection sys_pool #722

Merged
merged 1 commit into from
Jul 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions feeluown/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
logger = logging.getLogger(__name__)

COLL_LIBRARY_IDENTIFIER = 'library'
COLL_POOL_IDENTIFIER = 'pool'
# for backward compat, we should never change these filenames
LIBRARY_FILENAME = f'{COLL_LIBRARY_IDENTIFIER}.fuo'
POOL_FILENAME = f'{COLL_POOL_IDENTIFIER}.fuo'
DEPRECATED_FUO_FILENAMES = (
'Songs.fuo', 'Albums.fuo', 'Artists.fuo', 'Videos.fuo'
)
Expand All @@ -33,6 +35,7 @@ class CollectionAlreadyExists(Exception):

class CollectionType(Enum):
sys_library = 16
sys_pool = 13

mixed = 8

Expand Down Expand Up @@ -70,6 +73,8 @@ def load(self):
self.name = name
if name == COLL_LIBRARY_IDENTIFIER:
self.type = CollectionType.sys_library
elif name == COLL_POOL_IDENTIFIER:
self.type = CollectionType.sys_pool
else:
self.type = CollectionType.mixed

Expand Down Expand Up @@ -127,6 +132,11 @@ def create_empty(cls, fpath, title=''):
f.write(tomlkit.dumps(doc))
f.write(TOML_DELIMLF)

coll = cls(fpath)
coll._loads_metadata(doc)
coll.type = CollectionType.mixed
return coll

def add(self, model):
"""add model to collection

Expand Down Expand Up @@ -213,10 +223,13 @@ def __init__(self, app):
self._library = app.library
self.default_dir = COLLECTIONS_DIR

self._id_coll_mapping: Dict[str, Collection] = {}
self._id_coll_mapping: Dict[int, Collection] = {}
self._sys_colls = {}

def get(self, identifier):
return self._id_coll_mapping.get(int(identifier), None)
if identifier in (CollectionType.sys_pool, CollectionType.sys_library):
return self._sys_colls[identifier]
return self._id_coll_mapping[int(identifier)]

def get_coll_library(self):
for coll in self._id_coll_mapping.values():
Expand Down Expand Up @@ -259,12 +272,24 @@ def _get_dirs(self, ):

def scan(self):
colls: List[Collection] = []
library_coll = None
for coll in self._scan():
if coll.type == CollectionType.sys_library:
library_coll = coll
continue
colls.append(coll)
self._sys_colls[CollectionType.sys_library] = coll
elif coll.type == CollectionType.sys_pool:
self._sys_colls[CollectionType.sys_pool] = coll
else:
colls.append(coll)

if CollectionType.sys_pool not in self._sys_colls:
pool_fpath = os.path.join(self.default_dir, POOL_FILENAME)
assert not os.path.exists(pool_fpath)
logger.info('Generating collection pool.')
coll = Collection.create_empty(pool_fpath, '想听')
self._sys_colls[CollectionType.sys_pool] = coll

pool_coll = self._sys_colls[CollectionType.sys_pool]
library_coll = self._sys_colls[CollectionType.sys_library]
colls.insert(0, pool_coll)
colls.insert(0, library_coll)
for collection in colls:
coll_id = collection.identifier
Expand Down
2 changes: 1 addition & 1 deletion feeluown/gui/components/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def data(self, index, role=Qt.DisplayRole):
item = self._items[row]
if role == Qt.DisplayRole:
icon = '◎ '
if item.type == CollectionType.sys_library:
if item.type in (CollectionType.sys_library, CollectionType.sys_pool):
icon = '◉ '
return icon + item.name
if role == Qt.ToolTipRole:
Expand Down
19 changes: 11 additions & 8 deletions feeluown/gui/uimain/sidebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
from PyQt5.QtWidgets import QFrame, QLabel, QVBoxLayout, QSizePolicy, QScrollArea, \
QHBoxLayout, QFormLayout, QDialog, QLineEdit, QDialogButtonBox, QMessageBox

from feeluown.collection import CollectionAlreadyExists
from feeluown.collection import CollectionAlreadyExists, CollectionType
from feeluown.gui.widgets import (
RecentlyPlayedButton, HomeButton, PlusButton, TriagleButton,
DiscoveryButton, HomeButton, PlusButton, TriagleButton,
)
from feeluown.gui.widgets.playlists import PlaylistsView
from feeluown.gui.components import CollectionListView
Expand Down Expand Up @@ -94,8 +94,8 @@ def __init__(self, app: 'GuiApp', parent=None):
self._app = app

self.home_btn = HomeButton(height=30, parent=self)
self.recently_played_btn = RecentlyPlayedButton(height=30, parent=self)
self.collections_header = QLabel('本地收藏', self)
self.discovery_btn = DiscoveryButton(height=30, padding=0.2, parent=self)
self.collections_header = QLabel('本地收藏集', self)
self.collections_header.setToolTip(
'我们可以在本地建立『收藏集』来收藏自己喜欢的音乐资源\n\n'
'每个收藏集都以一个独立 .fuo 文件的存在,'
Expand Down Expand Up @@ -129,9 +129,9 @@ def __init__(self, app: 'GuiApp', parent=None):
self._layout.addLayout(self._top_layout)
self._layout.addLayout(self._sub_layout)

self._top_layout.addWidget(self.home_btn)
self._top_layout.addWidget(self.recently_played_btn)
self._top_layout.setContentsMargins(15, 16, 16, 0)
self._top_layout.addWidget(self.home_btn)
self._top_layout.addWidget(self.discovery_btn)
self._sub_layout.setContentsMargins(16, 8, 16, 0)
self._sub_layout.addWidget(self.collections_con)
self._sub_layout.addWidget(self.my_music_con)
Expand All @@ -148,8 +148,7 @@ def __init__(self, app: 'GuiApp', parent=None):
self.my_music_con.hide()

self.home_btn.clicked.connect(self.show_library)
self.recently_played_btn.clicked.connect(
lambda: self._app.browser.goto(page='/recently_played'))
self.discovery_btn.clicked.connect(self.show_pool)
self.playlists_view.show_playlist.connect(
lambda pl: self._app.browser.goto(model=pl))
self.collections_view.show_collection.connect(
Expand Down Expand Up @@ -189,6 +188,10 @@ def show_library(self):
coll_library = self._app.coll_mgr.get_coll_library()
self._app.browser.goto(page=f'/colls/{coll_library.identifier}')

def show_pool(self):
coll = self._app.coll_mgr.get(CollectionType.sys_pool)
self._app.browser.goto(page=f'/colls/{coll.identifier}')

def remove_coll(self, coll):
def do():
self._app.coll_mgr.remove(coll)
Expand Down
2 changes: 1 addition & 1 deletion feeluown/gui/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
from .selfpaint_btn import ( # noqa
SelfPaintAbstractSquareButton, RecentlyPlayedButton,
HomeButton, LeftArrowButton, RightArrowButton, SearchButton, SettingsButton,
PlusButton, TriagleButton
PlusButton, TriagleButton, DiscoveryButton,
)
54 changes: 48 additions & 6 deletions feeluown/gui/widgets/selfpaint_btn.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from PyQt5.QtCore import QPoint, Qt, QRect, QRectF
from PyQt5.QtCore import QPoint, Qt, QRect, QRectF, QTimer, QPointF
from PyQt5.QtWidgets import QPushButton, QStyle, QStyleOptionButton
from PyQt5.QtGui import QPainter, QPalette
from PyQt5.QtGui import QPainter, QPalette, QPainterPath

from feeluown.gui.drawers import HomeIconDrawer, PlusIconDrawer, TriangleIconDrawer
from feeluown.gui.helpers import darker_or_lighter
Expand Down Expand Up @@ -32,10 +32,10 @@ def paint_border_bg_when_hover(self, painter, radius=3):


class SelfPaintAbstractIconTextButton(SelfPaintAbstractButton):
def __init__(self, text, height=30, padding=0.25, parent=None):
def __init__(self, text='', height=30, padding=0.25, parent=None):
super().__init__(parent=parent)

self._padding = int(height * padding) if padding < 1 else padding
self._padding: int = int(height * padding if padding < 1 else padding)
self._text_width = self.fontMetrics().horizontalAdvance(text)
self._text = text

Expand Down Expand Up @@ -200,8 +200,8 @@ def paintEvent(self, _):


class RecentlyPlayedButton(SelfPaintAbstractIconTextButton):
def __init__(self, *args, **kwargs):
super().__init__('最近播放', *args, **kwargs)
def __init__(self, text='最近播放', **kwargs):
super().__init__(text, **kwargs)

def draw_icon(self, painter):
pen_width = 1.5
Expand All @@ -225,6 +225,47 @@ def draw_icon(self, painter):
painter.drawPoint(QPoint(self._padding, center))


class DiscoveryButton(SelfPaintAbstractIconTextButton):
def __init__(self, text='发现', **kwargs):
super().__init__(text=text, **kwargs)

self._timer = QTimer(self)

length = self.height()
self._half = length // 2
self._v1 = self._half - self._padding
self._v2 = self._v1 / 2.5

self._triagle = QPainterPath(QPointF(-self._v2, 0))
self._triagle.lineTo(QPointF(0, self._v1))
self._triagle.lineTo(QPointF(0, self._v2))
self._rotate = 0
self._rotate_mod = 360

self._timer.timeout.connect(self.on_timeout)
self._timer.start(30)

def on_timeout(self):
self._rotate = (self._rotate + 2) % self._rotate_mod
self.update()

def draw_icon(self, painter: QPainter):
opt = QStyleOptionButton()
self.initStyleOption(opt)

pen = painter.pen()
pen.setWidthF(1.5)
painter.setPen(pen)

painter.save()
painter.translate(self._half, self._half)
painter.rotate(self._rotate)
for ratio in range(4):
painter.rotate(90*ratio)
painter.drawPath(self._triagle)
painter.restore()


class HomeButton(SelfPaintAbstractIconTextButton):
def __init__(self, *args, **kwargs):
super().__init__('主页', *args, **kwargs)
Expand All @@ -248,5 +289,6 @@ def draw_icon(self, painter):
layout.addWidget(SettingsButton(length=length))
layout.addWidget(RecentlyPlayedButton(height=length))
layout.addWidget(HomeButton(height=length))
layout.addWidget(DiscoveryButton(height=length))

layout.addWidget(TriagleButton(length=length, direction='up'))
8 changes: 5 additions & 3 deletions tests/test_collection.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from feeluown.models.uri import ResolveFailed, ResolverNotFound, reverse
from feeluown.collection import Collection, CollectionManager, LIBRARY_FILENAME
from feeluown.collection import Collection, CollectionManager, LIBRARY_FILENAME, \
POOL_FILENAME


def test_collection_load(tmp_path, song, mocker):
Expand Down Expand Up @@ -160,9 +161,10 @@ def new_collection(path):
coll1 = new_collection(tmp_path / '1.fuo')
coll2 = new_collection(tmp_path / '2.fuo')
coll_library = new_collection(tmp_path / LIBRARY_FILENAME)
coll_pool = new_collection(tmp_path / POOL_FILENAME)

coll_mgr = CollectionManager(app_mock)
mocker.patch.object(CollectionManager, '_scan',
return_value=[coll1, coll_library, coll2])
return_value=[coll1, coll_library, coll_pool, coll2])
coll_mgr.scan()
assert list(coll_mgr.listall()) == [coll_library, coll1, coll2]
assert list(coll_mgr.listall()) == [coll_library, coll_pool, coll1, coll2]
Loading