Skip to content

Commit

Permalink
new, server: refactor playlists, store smartPlaylists (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
dxstiny committed Sep 12, 2023
1 parent 89bd9dd commit 8be1103
Show file tree
Hide file tree
Showing 18 changed files with 896 additions and 308 deletions.
27 changes: 17 additions & 10 deletions src/server/config/cacheStrategy.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
"""reAudioPlayer ONE"""
from __future__ import annotations

__copyright__ = "Copyright (c) 2023 https://github.com/reAudioPlayer"

from typing import Optional, TYPE_CHECKING
import asyncio

from player.playerPlaylist import PlayerPlaylist
from player.iPlayerPlaylist import IPlayerPlaylist
from dataModel.song import Song
from helper.singleton import Singleton
from helper.songCache import SongCache
Expand All @@ -17,14 +18,15 @@
from player.player import Player


class ICacheStrategy(metaclass = Singleton):
class ICacheStrategy(metaclass=Singleton):
"""ICacheStrategy"""

__slots__ = ("_playlist", "_downloader", "_player")
_STRATEGY: CacheStrategy = CacheStrategy.None_
_INSTANCE: Optional[ICacheStrategy] = None

def __init__(self, player: Player) -> None:
self._playlist: Optional[PlayerPlaylist] = None
self._playlist: Optional[IPlayerPlaylist] = None
self._downloader = Downloader()
self._player = player

Expand Down Expand Up @@ -53,11 +55,10 @@ def get(cls, strategy: CacheStrategy, player: Player) -> ICacheStrategy:
asyncio.create_task(cls._INSTANCE.onStrategyLoad())
return cls._INSTANCE


async def onSongLoad(self, song: Song) -> None:
"""on song change"""

async def onPlaylistLoad(self, playlist: PlayerPlaylist) -> None:
async def onPlaylistLoad(self, playlist: IPlayerPlaylist) -> None:
"""on playlist change"""
self._playlist = playlist

Expand All @@ -66,19 +67,23 @@ async def onStrategyLoad(self) -> None:
self._playlist = self._player.currentPlaylist


class CacheAllStrategy(ICacheStrategy, metaclass = Singleton):
class CacheAllStrategy(ICacheStrategy, metaclass=Singleton):
"""CacheAllStrategy"""

async def onStrategyLoad(self) -> None:
await super().onStrategyLoad()

async def _task() -> None:
for playlist in self._player.playlistManager.playlists:
for song in playlist:
await self._downloader.downloadSong(song.model)

asyncio.create_task(_task())


class CachePlaylistStrategy(ICacheStrategy, metaclass = Singleton):
class CachePlaylistStrategy(ICacheStrategy, metaclass=Singleton):
"""CachePlaylistStrategy"""

async def _downloadTask(self) -> None:
assert self._playlist is not None
SongCache.prune(self._playlist)
Expand All @@ -91,19 +96,21 @@ async def onStrategyLoad(self) -> None:
return
asyncio.create_task(self._downloadTask())

async def onPlaylistLoad(self, playlist: PlayerPlaylist) -> None:
async def onPlaylistLoad(self, playlist: IPlayerPlaylist) -> None:
await super().onPlaylistLoad(playlist)
asyncio.create_task(self._downloadTask())


class CacheCurrentStrategy(ICacheStrategy, metaclass = Singleton):
class CacheCurrentStrategy(ICacheStrategy, metaclass=Singleton):
"""CacheCurrentStrategy"""

async def onSongLoad(self, song: Song) -> None:
SongCache.prune([song])


class CacheCurrentNextStrategy(ICacheStrategy, metaclass = Singleton):
class CacheCurrentNextStrategy(ICacheStrategy, metaclass=Singleton):
"""CacheCurrentNextStrategy"""

async def onSongLoad(self, song: Song) -> None:
assert self._playlist is not None
currentSong, nextSong = song, self._playlist.next(True)
Expand Down
15 changes: 14 additions & 1 deletion src/server/db/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from helper.singleton import Singleton
from db.table.songs import SongsTable
from db.table.playlists import PlaylistsTable
from db.table.smartPlaylists import SmartPlaylistTable
from db.table.artists import ArtistsTable
from config.runtime import Runtime

Expand All @@ -22,13 +23,15 @@ class Database(metaclass=Singleton):
"_songs",
"_playlists",
"_artists",
"_smartPlaylists",
"_autoCommit",
"_logger")

def __init__(self) -> None:
self._db: Optional[aiosqlite.Connection] = None
self._songs: Optional[SongsTable] = None
self._playlists: Optional[PlaylistsTable] = None
self._smartPlaylists: Optional[SmartPlaylistTable] = None
self._artists: Optional[ArtistsTable] = None
self._autoCommit: Optional[asyncio.Task[None]] = None
self._logger = logging.getLogger("Database")
Expand All @@ -48,11 +51,13 @@ async def init(self) -> None:
self._songs = SongsTable(self._db)
self._playlists = PlaylistsTable(self._db)
self._artists = ArtistsTable(self._db)
self._smartPlaylists = SmartPlaylistTable(self._db)

await asyncio.gather(
self._songs.create(),
self._playlists.create(),
self._artists.create()
self._artists.create(),
self._smartPlaylists.create()
)

self._autoCommit = asyncio.create_task(self._autoCommitTask())
Expand Down Expand Up @@ -80,6 +85,12 @@ def artists(self) -> ArtistsTable:
assert self._artists is not None
return self._artists

@property
def smartPlaylists(self) -> SmartPlaylistTable:
"""Return smartPlaylists table"""
assert self._smartPlaylists is not None
return self._smartPlaylists

@property
def ready(self) -> bool:
"""Return if database is ready"""
Expand All @@ -91,4 +102,6 @@ def ready(self) -> bool:
return False
if self._artists is None:
return False
if self._smartPlaylists is None:
return False
return True
27 changes: 27 additions & 0 deletions src/server/db/table/iPlaylistModel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from abc import ABC, abstractmethod

class IPlaylistModel(ABC):
@property
@abstractmethod
def name(self) -> str:
"""playlist name"""

@property
@abstractmethod
def description(self) -> str:
"""playlist description"""

@property
@abstractmethod
def cover(self) -> str:
"""playlist cover"""

@property
@abstractmethod
def plays(self) -> int:
"""plays"""

@property
@abstractmethod
def id(self) -> int:
"""db id"""
48 changes: 29 additions & 19 deletions src/server/db/table/playlists.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
# -*- coding: utf-8 -*-
"""reAudioPlayer ONE"""
from __future__ import annotations

__copyright__ = "Copyright (c) 2023 https://github.com/reAudioPlayer"

from typing import Type, Tuple, Optional, Dict, Any
from typing import Type, Tuple, Optional, Dict, Any, List
import json
import aiosqlite
from db.table.table import ITable, IModel
from db.table.iPlaylistModel import IPlaylistModel


class PlaylistModel(IModel):
class PlaylistModel(IModel, IPlaylistModel):
"""playlist model"""

__slots__ = ("_id", "_name", "_songs", "_description", "_cover", "_plays")
_SQLType = Tuple[int, str, str, str, str, int]
_SQLInsertType = Tuple[str, str, str, str, int]
COLUMNS = ["id", "name", "description", "cover", "songs", "plays"]

def __init__(self,
name: str,
description: Optional[str] = None,
cover: Optional[str] = None,
songs: str = "[]",
plays: Optional[int] = None,
id_: Optional[int] = None) -> None:
def __init__(
self,
name: str,
description: Optional[str] = None,
cover: Optional[str] = None,
songs: str = "[]",
plays: Optional[int] = None,
id_: Optional[int] = None,
) -> None:
self._id = id_
self._name = name or ""
self._songs = songs or "[]"
Expand All @@ -33,7 +39,7 @@ def __init__(self,
@classmethod
def fromTuple(cls, row: aiosqlite.Row) -> PlaylistModel:
id_, others = row[0], row[1:]
return cls(*others, id_) # type: ignore
return cls(*others, id_) # type: ignore

@property
def insertStatement(self) -> str:
Expand All @@ -48,13 +54,7 @@ def updateStatement(self) -> str:
return f"{', '.join([f'{item}=?' for item in items])}"

def toTuple(self) -> _SQLInsertType:
return (
self._name,
self._description,
self._cover,
self._songs,
self._plays
)
return (self._name, self._description, self._cover, self._songs, self._plays)

@property
def eq(self) -> str:
Expand Down Expand Up @@ -108,6 +108,15 @@ def songs(self, songs: str) -> None:
self._songs = songs
self._fireChanged()

@property
def songsList(self) -> List[int]:
"""list of songs"""
return json.loads(self._songs) # type: ignore

@songsList.setter
def songsList(self, songs: List[int]) -> None:
self._songs = json.dumps(songs)

@property
def plays(self) -> int:
"""plays of the playlist"""
Expand All @@ -134,12 +143,13 @@ def toDict(self) -> Dict[str, Any]:
"description": self._description,
"cover": self._cover,
"songs": self._songs,
"plays": self._plays
"plays": self._plays,
}


class PlaylistsTable(ITable[PlaylistModel]):
"""playlist table"""

NAME = "Playlists"
DESCRIPTION = """
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
Expand All @@ -155,7 +165,7 @@ def _model(self) -> Type[PlaylistModel]:

async def byId(self, id_: int) -> Optional[PlaylistModel]:
"""get playlist by id"""
return await self.selectOne(append = f"WHERE id = {id_}")
return await self.selectOne(append=f"WHERE id = {id_}")

async def deleteById(self, id_: int) -> None:
"""delete playlist by id"""
Expand Down
Loading

0 comments on commit 8be1103

Please sign in to comment.