music-assistant-server

4.3 KBPY
mylist.py
4.3 KB112 lines • python
1"""Mylist adapter for nicovideo."""
2
3from __future__ import annotations
4
5from typing import TYPE_CHECKING
6
7from music_assistant.providers.nicovideo.helpers import PlaylistWithTracks
8from music_assistant.providers.nicovideo.services.base import NicovideoBaseService
9
10if TYPE_CHECKING:
11    from music_assistant_models.media_items import Playlist
12    from niconico.objects.nvapi import CreateMylistData
13
14    from music_assistant.providers.nicovideo.services.manager import NicovideoServiceManager
15
16
17class NicovideoMylistService(NicovideoBaseService):
18    """Handles mylist related operations for nicovideo."""
19
20    def __init__(self, adapter: NicovideoServiceManager) -> None:
21        """Initialize NicovideoMylistService with reference to parent adapter."""
22        super().__init__(adapter)
23
24    async def get_own_mylists(self) -> list[Playlist]:
25        """Get own mylists and convert them."""
26        results = await self.service_manager._call_with_throttler(
27            self.niconico_py_client.user.get_own_mylists
28        )
29        if results is None:
30            return []
31        return [self.converter_manager.playlist.convert_by_mylist(entry) for entry in results]
32
33    async def get_mylist_or_own_mylist(
34        self, mylist_id: str, page_size: int = 500, page: int = 1
35    ) -> PlaylistWithTracks | None:
36        """Get mylist with fallback to own_mylist for private mylists."""
37        # Try public mylist first
38        playlist_with_tracks = await self._get_mylist(mylist_id, page_size=page_size, page=page)
39        if not playlist_with_tracks:
40            # Fallback to own mylist (for private mylists)
41            playlist_with_tracks = await self.get_own_mylist(
42                mylist_id, page_size=page_size, page=page
43            )
44        return playlist_with_tracks
45
46    async def get_own_mylist(
47        self, mylist_id: str, page_size: int = 500, page: int = 1
48    ) -> PlaylistWithTracks | None:
49        """Get own mylist details and convert as Playlist."""
50        mylist = await self.service_manager._call_with_throttler(
51            self.niconico_py_client.user.get_own_mylist,
52            mylist_id,
53            page_size=page_size,
54            page=page,
55        )
56        if not mylist:
57            return None
58        playlist_with_tracks = self.converter_manager.playlist.convert_with_tracks_by_mylist(mylist)
59        self._update_positions_in_playlist(playlist_with_tracks)
60        return playlist_with_tracks
61
62    async def add_mylist_item(self, mylist_id: str, video_id: str) -> bool:
63        """Add a video to mylist."""
64        result = await self.service_manager._call_with_throttler(
65            self.niconico_py_client.user.add_mylist_item,
66            mylist_id,
67            video_id,
68        )
69        return bool(result)
70
71    async def remove_mylist_items(self, mylist_id: str, video_ids: list[str]) -> bool:
72        """Remove videos from mylist."""
73        result = await self.service_manager._call_with_throttler(
74            self.niconico_py_client.user.remove_mylist_items,
75            mylist_id,
76            video_ids,
77        )
78        return bool(result)
79
80    async def create_mylist(
81        self, name: str, description: str = "", is_public: bool = False
82    ) -> CreateMylistData | None:
83        """Create a new mylist."""
84        return await self.service_manager._call_with_throttler(
85            self.niconico_py_client.user.create_mylist,
86            name,
87            description=description,
88            is_public=is_public,
89        )
90
91    async def _get_mylist(
92        self, mylist_id: str, page_size: int = 500, page: int = 1
93    ) -> PlaylistWithTracks | None:
94        """Get mylist details and convert as Playlist."""
95        mylist = await self.service_manager._call_with_throttler(
96            self.niconico_py_client.video.get_mylist,
97            mylist_id,
98            page_size=page_size,
99            page=page,
100        )
101        if not mylist:
102            return None
103        playlist_with_tracks = self.converter_manager.playlist.convert_with_tracks_by_mylist(mylist)
104        self._update_positions_in_playlist(playlist_with_tracks)
105        return playlist_with_tracks
106
107    def _update_positions_in_playlist(self, playlist: PlaylistWithTracks) -> None:
108        """Update positions in playlist tracks."""
109        # Ensure tracks have position set (1-based)
110        for index, track in enumerate(playlist.tracks, start=1):
111            track.position = index
112