Skip to content

Commit

Permalink
Merge pull request #26 from romanin-rf/dev
Browse files Browse the repository at this point in the history
Update 0.7.5
  • Loading branch information
romanin-rf authored Dec 2, 2023
2 parents 6bfff22 + c3ede32 commit cb2a561
Show file tree
Hide file tree
Showing 13 changed files with 99 additions and 29 deletions.
19 changes: 13 additions & 6 deletions plugins/RichDiscordStatus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ class RichDiscordStatus(PluginBase):
def get_status(self):
data = {
"start": self.start_time,
"large_image": "icon"
"large_image": "icon",
"buttons": [{"label": "GitHub", "url": self.info.url}]
}
if AD_ENABLE:
data["buttons"] = [{"label": "GitHub", "url": self.info.url}]
if self.app.currect_sound is not None:
if (self.app.currect_sound.title is not None) and (self.app.currect_sound.artist is not None):
data["details"] = f"{self.app.currect_sound.artist} - {self.app.currect_sound.title}"
Expand Down Expand Up @@ -49,18 +48,26 @@ async def __status__(self) -> None:
rpc.update(**self.get_status())
await asyncio.sleep(1)
except DiscordNotFound:
await asyncio.sleep(10)
await asyncio.sleep(3)

def on_init(self) -> None:
self.running = False

def on_run(self) -> None:
self.start_time = time.time()

async def on_compose(self):
self.running = True
self.thread = self.app.run_worker(self.__status__, "Rich Discord Status", "seaplayer.plugins.discord.status", thread=True)
self.thread = self.app.run_worker(
self.__status__,
"Rich Discord Status",
"seaplayer.plugins.discord.status",
thread=True,
exit_on_error=False
)

async def on_quit(self) -> None:
self.running = False
await self.thread.wait()

# ! Registration Plugin Class
plugin_main = RichDiscordStatus
2 changes: 1 addition & 1 deletion plugins/RichDiscordStatus/info.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Rich Discord Status",
"name_id": "seaplayer.plugins.discord.status",
"version": "0.2.0",
"version": "0.2.1",
"author": "Romanin",
"description": "Now what you are listening to will be visible to everyone in Discord.",
"url": "https://github.com/romanin-rf/SeaPlayer"
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "SeaPlayer"
version = "0.7.4"
version = "0.7.5"
description = "SeaPlayer is a player that works in the terminal."
repository = "https://github.com/romanin-rf/SeaPlayer"
authors = ["Romanin <semina054@gmail.com>"]
Expand Down
3 changes: 3 additions & 0 deletions seaplayer/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ def rich_exception(exc: Exception) -> str:
return f"[red]{exc.__class__.__name__}[/red]: {exc.__str__()}"

# ! Functions
def formater(**kwargs) -> str:
return ", ".join([f"{key}={repr(value)}" for key, value in kwargs.items()])

def check_status(sound: CodecBase) -> Literal["Stoped", "Playing", "Paused"]:
if sound.playing:
if sound.paused:
Expand Down
3 changes: 2 additions & 1 deletion seaplayer/modules/colorizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,5 @@ def pullyper(tp: type) -> str:
else:
return tp.__name__

def richefication(tp: type) -> str: return replaces(pullyper(tp), REPLACE_TYPES)
def richefication(tp: type) -> str:
return replaces(pullyper(tp), REPLACE_TYPES)
1 change: 0 additions & 1 deletion seaplayer/plug/pipw.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import sys
import subprocess
from typing import Tuple

# ! Main Class
class PIPManager:
Expand Down
26 changes: 24 additions & 2 deletions seaplayer/plug/pluginbase.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
from pydantic import BaseModel
from textual.binding import Binding
from textual.screen import Screen
# > Typing
from typing import Optional, Generator, Type, Any
# > Local Import's
from typing import Optional
from ..codeсbase import CodecBase
from ..functions import formater

# ! Plugin Info Class
class PluginInfo(BaseModel):
Expand All @@ -14,7 +19,7 @@ class PluginInfo(BaseModel):
# ! Plugin Base Class
class PluginBase:
def __init_repr__(self) -> str:
return f"[green]{self.info.name}[/] ({repr(self.info.name_id)}) [#00ffee]v{self.info.version}[/#00ffee] [yellow]is initialized[/yellow]!"
return f"{self.info.name} ({repr(self.info.name_id)}) [#60fdff]v{self.info.version}[/#60fdff] is [yellow]initialized[/yellow]!"

def __init__(self, app, pl, info: PluginInfo) -> None:
self.app = app
Expand All @@ -23,7 +28,24 @@ def __init__(self, app, pl, info: PluginInfo) -> None:
# > Logs
self.app.info(self.__init_repr__())

def __str__(self) -> str:
return f"{self.__class__.__name__}({formater(info=self.info)})"

def __repr__(self) -> str:
return self.__str__()

# ! App Specific Functions
def install_screen(self, name: str, screen: Screen) -> None:
self.app.SCREENS[name] = screen
self.app.install_screen(screen, name)

def add_codecs(self, *codecs: Type[CodecBase]) -> None:
self.app.CODECS += [ *codecs ]

# ! Dev Functions
def on_bindings(self) -> Generator[Binding, Any, None]:
yield None

def on_init(self):
pass

Expand Down
10 changes: 9 additions & 1 deletion seaplayer/plug/pluginbase.pyi
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from pydantic import BaseModel
from textual.screen import Screen
from textual.binding import Binding
# > Typing
from typing import Optional
from typing import Optional, Generator, Type, Any
# > Local Import's
from ..seaplayer import SeaPlayer
from ..codeсbase import CodecBase
from .pluginloader import PluginLoader

# ! Plugin Info Class
Expand All @@ -22,6 +25,11 @@ class PluginBase:

def __init_repr__(self) -> str: ...
def __init__(self, app: SeaPlayer, pl: PluginLoader, info: PluginInfo) -> None: ...
# ! App Specific Methods
def install_screen(self, name: str, screen: Screen) -> None: ...
def add_codecs(self, *codecs: Type[CodecBase]) -> None: ...
def on_bindings(self) -> Generator[Binding, Any, None]: ...
# ! App On Methods
def on_init(self) -> None: ...
def on_run(self) -> None: ...
async def on_compose(self) -> None: ...
Expand Down
19 changes: 15 additions & 4 deletions seaplayer/plug/pluginloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
from pathlib import Path
from pydantic import BaseModel
from rich.console import Console
from textual.binding import Binding
# > ImportLib
from importlib.util import spec_from_file_location, module_from_spec
# > Typing
from types import ModuleType
from typing import Optional, Dict, Union, Any, List, Tuple, Type
from typing import Optional, Dict, Union, Any, List, Tuple, Type, Generator
# > Local Import's
from .pipw import pip
from .pluginbase import PluginInfo, PluginBase
Expand Down Expand Up @@ -47,7 +48,7 @@ def load_module(init_path: str) -> PluginModuleType:
)
module = module_from_spec(module_spec)

sys.modules[module_spec.name] = module
sys.modules[module_spec.name] = module
# TODO: Temporary option as there is a risk of replacing existing modules
# TODO: Make an environment-module to surround all these modules for security

Expand Down Expand Up @@ -127,7 +128,7 @@ def enable_plugin_by_name_id(self, name_id: str) -> None:
# ! Plugin Loader Class
class PluginLoader:
__title__: str = "PluginLoader"
__version__: str = "0.2.7"
__version__: str = "0.3.0"
__author__: str = "Romanin"
__email__: str = "semina054@gmail.com"

Expand Down Expand Up @@ -208,8 +209,9 @@ def load_plugin_info(path: str) -> PluginInfo:
data = file.read()
return PluginInfo.model_validate_json(data)

# ! On Init Method
def on_init(self) -> None:
self.app.info(f"{self.__title__} [#00ffee]v{self.__version__}[/#00ffee] from {self.__author__} ({self.__email__})", in_console=True)
self.app.info(f"{self.__title__} [#60fdff]v{self.__version__}[/#60fdff] from {self.__author__} ({self.__email__})", in_console=True)
plugins_paths = list(self.search_plugins_paths())
self.app.info(f"Found plugins : {repr([os.path.basename(os.path.dirname(i[0])) for i in plugins_paths])}", in_console=True)
self.app.info(f"Initialization plugins...", in_console=True)
Expand Down Expand Up @@ -249,6 +251,15 @@ def on_init(self) -> None:
self.app.info(f"Plugins loaded ([red]OFF[/red]) : {repr(self.off_plugins)}", in_console=True)
self.app.info(f"---", in_console=True)

# ! App Specific Methods
def on_bindings(self) -> Generator[Binding, Any, None]:
yield None
for plugin in self.on_plugins:
for binding in plugin.on_bindings():
if binding is not None:
yield binding

# ! On Methods
def on_run(self) -> None:
for i in self.on_plugins:
try:
Expand Down
5 changes: 5 additions & 0 deletions seaplayer/plug/pluginloader.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pathlib import Path
from pydantic import BaseModel
from textual.binding import Binding
# > Typing
from types import ModuleType
from typing import (
Expand Down Expand Up @@ -79,6 +80,10 @@ class PluginLoader:
@staticmethod
def load_plugin_info(path: str) -> PluginInfo: ...

# ! App Specific Methods
def on_bindings(self) -> Generator[Binding, Any, None]: ...

# ! App On Methods
def on_init(self) -> None: ...
def on_run(self) -> None: ...
async def on_compose(self) -> None: ...
Expand Down
24 changes: 17 additions & 7 deletions seaplayer/seaplayer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import time
import glob
import asyncio
# > Graphics
Expand All @@ -21,7 +22,8 @@
aiter,
check_status,
image_from_bytes,
get_sound_basename, aio_check_status_code
get_sound_basename,
aio_check_status_code
)
from .objects import (
Nofy,
Expand Down Expand Up @@ -80,13 +82,14 @@ class SeaPlayer(App):
"unknown": Unknown(id="screen_unknown"),
"configurate": Configurate(id="screen_configurate")
}
ENABLE_COMMAND_PALETTE = False

# ! SeaPlayer Configuration
cache = Cacher(CACHE_DIRPATH)
config = SeaPlayerConfig(CONFIG_FILEPATH)
image_type: Optional[Union[Type[AsyncImageLabel], Type[StandartImageLabel]]] = None

# ! Textual Keys Configuration
# ! Bindings
BINDINGS = list(build_bindings(config))

# ! Template Configuration
Expand Down Expand Up @@ -124,9 +127,17 @@ def __init__(self, *args, **kwargs) -> None:
if ENABLE_PLUGIN_SYSTEM:
self.plugin_loader = PluginLoader(self)
self.plugin_loader.on_init()
for _binding in self.plugin_loader.on_bindings():
if _binding is not None:
self.BINDINGS.append(_binding)

def update_bindings(self) -> None:
self._bindings = _Bindings(list(build_bindings(self.config)))
bindings = list(build_bindings(self.config))
if ENABLE_PLUGIN_SYSTEM:
for _binding in self.plugin_loader.on_bindings():
if _binding is not None:
bindings.append(_binding)
self._bindings = _Bindings(bindings)

# ! Inherited Functions
async def action_push_screen(self, screen: str) -> None:
Expand Down Expand Up @@ -158,6 +169,7 @@ def callnofy(
) -> CallNofy:
cn = CallNofy(text, dosk)
self.screen.mount(cn)
self.install_screen
return cn

async def aio_callnofy(
Expand Down Expand Up @@ -246,7 +258,7 @@ async def update_loop_playback(self) -> None:
def compose(self) -> ComposeResult:
# * Other
self.info("---")
self.info(f"{__title__} [#00ffee]v{__version__}[/#00ffee] from {__author__} ({__email__})")
self.info(f"{__title__} [#60fdff]v{__version__}[/#60fdff] from {__author__} ({__email__})")
self.info(f"Source : {__url__}")
self.info(f"Codecs : {repr(self.CODECS)}")
self.info(f"Config Path : {repr(self.config.filepath)}")
Expand Down Expand Up @@ -309,7 +321,6 @@ async def _spm(input: InputField, value: Any) -> None:
if self.config.log_menu_enable:
yield self.log_menu
yield Footer()

self.run_worker(
self.update_loop_playback,
name="PLAYBACK_CONTROLLER",
Expand Down Expand Up @@ -379,7 +390,6 @@ async def set_sound_for_playback(
async def add_sounds_to_list(self) -> None:
added_oks = 0
loading_nofy = await self.aio_callnofy(f"Found [cyan]{len(self.last_paths_globalized)}[/cyan] values. Loading...")

async for path in aiter(self.last_paths_globalized):
sound = None
async for codec in aiter(self.CODECS):
Expand Down Expand Up @@ -499,7 +509,7 @@ async def action_quit(self):
sound.unpause()
sound.stop()
return await super().action_quit()

# ! Other
def run(self, *args, **kwargs):
if ENABLE_PLUGIN_SYSTEM:
Expand Down
12 changes: 8 additions & 4 deletions seaplayer/types/Cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ class Cacher:
def __init__(self, cache_dirpath: str) -> None:
self.main_dirpath = os.path.abspath(cache_dirpath)
self.vars_dirpath = os.path.join(self.main_dirpath, "vars")

# * Create Directory
os.makedirs(self.main_dirpath, 0o755, True)
os.makedirs(self.vars_dirpath, 0o755, True)

# * Check Directory
assert os.path.isdir(self.main_dirpath)
assert os.path.isdir(self.vars_dirpath)

# ! I/O Methods
def write(self, data: Any, filepath: str) -> None:
with open(filepath, "wb") as file:
pickle.dump(data, file)
Expand All @@ -32,9 +31,14 @@ def read(self, filepath: str, default: D) -> D:
self.write(default, filepath)
return default

def write_var(self, value: Any, name: str, *, group: str="main") -> None: self.write(value, os.path.join(self.vars_dirpath, f"{name}-{group}.pycache"))
def read_var(self, name: str, default: D, *, group: str="main") -> D: return self.read(os.path.join(self.vars_dirpath, f"{name}-{group}.pycache"), default)
# ! Var Methods
def write_var(self, value: Any, name: str, *, group: str="main") -> None:
self.write(value, os.path.join(self.vars_dirpath, f"{name}-{group}.pycache"))

def read_var(self, name: str, default: D, *, group: str="main") -> D:
return self.read(os.path.join(self.vars_dirpath, f"{name}-{group}.pycache"), default)

# ! Main Methods
def var(self, name: str, default: D, *, group: str="main") -> D:
def setter(s, value: D) -> None:
self.write_var(value, name, group=group)
Expand Down
2 changes: 1 addition & 1 deletion seaplayer/units.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

# ! Metadata
__title__ = "SeaPlayer"
__version__ = "0.7.4"
__version__ = "0.7.5"
__author__ = "Romanin"
__email__ = "semina054@gmail.com"
__url__ = "https://github.com/romanin-rf/SeaPlayer"
Expand Down

0 comments on commit cb2a561

Please sign in to comment.