import logging import os from enum import Enum LOG_FILE = 'textual.log' LOGGING_LEVEL = logging.DEBUG LOG_FORMAT = '[%(asctime)s] %(levelname)s in %(module)s: %(message)s' # Clear Log File os.remove(LOG_FILE) logging.basicConfig(filename=LOG_FILE, level=LOGGING_LEVEL, format=LOG_FORMAT) import SubSonic from textual import on, events from textual.app import App, ComposeResult from textual.widgets import Footer, Header, OptionList, DataTable, Tabs, Tab, TabbedContent, TabPane from textual.screen import Screen from textual.widgets.option_list import Option u = 'pseudo' p = 'telegram9dock-MICHEL' conn = SubSonic.SubpyConn(u, p, "https://music.0x01fe.net") class AlbumSongs(Screen): BINDINGS = [ ('escape', 'die()', "Back") ] def __init__(self, album_id: str): self.album_id = album_id super().__init__() def compose(self) -> ComposeResult: yield DataTable(id="albumSongs") yield Footer() def on_mount(self) -> None: songs = conn.getAlbumSongs(self.album_id) songsTable: DataTable = self.query_one(DataTable) songsTable.cursor_type = 'row' songsTable.add_columns("#", "Title", "Artist", "Duration", "Bitrate") for song in songs: songsTable.add_row(song.trackNumber, song.title, song.artist, song.duration, song.bitRate, key=song.id) # Pops and uninstalls self def action_die(self) -> None: app.pop_screen() app.uninstall_screen("albumSongs") class ArtistAlbums(Screen): BINDINGS = [ ('escape', 'die()', "Back") ] def __init__(self, artist_id: str): self.artist_id = artist_id super().__init__() def compose(self) -> ComposeResult: yield DataTable(id="Albums") yield Footer() def on_mount(self) -> None: albums = conn.getArtistAlbums(self.artist_id) albumTable: DataTable = self.query_one(DataTable) albumTable.cursor_type = 'row' albumTable.add_columns("Title", "Songs") for album in albums: albumTable.add_row(album.title, album.songCount, key=album.id) @on(DataTable.RowSelected) async def album_selected(self, event: DataTable.RowSelected) -> None: app.install_screen(AlbumSongs(event.row_key.value), "albumSongs") app.push_screen("albumSongs") # Pops and uninstalls self def action_die(self) -> None: app.pop_screen() app.uninstall_screen("artistAlbums") class Artists(Screen): BINDINGS = [ ('escape', 'app.pop_screen', "Back") ] def compose(self) -> ComposeResult: yield OptionList(id="Artists") yield Footer() def on_mount(self) -> None: artists = conn.getArtists() artistList = self.query_one(OptionList) for artist in artists: artistList.add_option(Option(artist.name, artist.id)) @on(OptionList.OptionSelected) def artist_selected(self, event: OptionList.OptionSelected) -> None: app.install_screen(ArtistAlbums(event.option_id), 'artistAlbums') app.push_screen('artistAlbums') class Albums(Screen): BINDINGS = [ ('escape', 'app.pop_screen', "Back") ] def compose(self) -> ComposeResult: yield DataTable() yield Footer() def on_mount(self) -> None: albums = conn.getAlbums() class TextualSubpyPlayer(App): BINDINGS = [ ("f1", "push_screen('artists')", "Artists"), ("f2", "push_screen('albums')", "Albums") ] def compose(self) -> ComposeResult: yield Footer() def on_mount(self) -> None: self.install_screen(Artists(), name="artists") def on_key(self, event: events.Key) -> None: logging.debug(f'Key Pressed {event.name}') if __name__ == '__main__': app = TextualSubpyPlayer() app.run()