Files
htpc-client/ikinuki_client/__main__.py
T

270 lines
7.0 KiB
Python

from typing import Type
import os
import sys
from urllib import parse
from collections import defaultdict
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQml import qmlRegisterType, QQmlApplicationEngine
from PyQt5.QtQuick import QQuickImageProvider
# from PyQt5.QtQuick import QQuickView
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot
from PyQt5.QtGui import QImage
# from PyQt5.QtCore import QObject, QUrl, pyqtProperty
from .qtmpv import MpvObject
import requests
import toml
class Episode(QObject):
def __init__(self, source, parent=None):
super().__init__(parent)
self._source = source
@pyqtProperty("QString", constant=True)
def title(self):
return self._source["Title"]
@pyqtProperty(int, constant=True)
def season(self):
return self._source["Season"]
@pyqtProperty(int, constant=True)
def episode(self):
return self._source["Episode"]
@pyqtProperty("QString", constant=True)
def filename(self):
return self._source["OriginalFilename"]
class Show(QObject):
def __init__(self, source, episodes, parent=None):
super().__init__(parent)
self._source = source
self._episodes = episodes
@pyqtProperty("QString", constant=True)
def title(self) -> str:
return self._source["title"]
@pyqtProperty(int, constant=True)
def year(self) -> int:
return self._source["year"]
@pyqtProperty("QString", constant=True)
def description(self) -> str:
return self._source["description"]
@pyqtProperty(int, constant=True)
def watched(self) -> int:
return self._source["watched"]
@pyqtProperty("QString", constant=True)
def poster(self) -> str:
return self._source["poster"]
@pyqtProperty(list, constant=True)
def episodes(self) -> list[Episode]:
return self._episodes
class ProviderImageProvider(QQuickImageProvider):
def __init__(self, icon_data):
self._icon_data = icon_data
super(ProviderImageProvider, self).__init__(QQuickImageProvider.Image)
def requestImage(self, p_str, size):
print(p_str)
print(size)
# img = QImage.fromData(self._icon_data.encode("utf-8"))
import base64
data: bytes = base64.b64decode(self._icon_data)
img = QImage.fromData(data)
# img = QImage.fromData(self._icon_data.encode("utf-8"))
# img = QImage(300, 300, QImage.Format_RGBA8888)
# img.fill(Qt.red)
return img, img.size()
def getUrl(base: str, path: str) -> dict:
url: str = parse.urljoin(base, path)
r: requests.Response = requests.get(url)
return r.json()
class Provider(QObject):
def __init__(self, url: str, parent=None):
super().__init__(parent)
self.url: str = url
describe: dict = getUrl(self.url, "describe")
self._name: str = describe["name"]
self.logo_provider: ProviderImageProvider = ProviderImageProvider(
describe["icon"]
)
def default_val():
return []
episodes: dict = getUrl(self.url, "episodes")
_episodes: defaultdict[str, list[Episode]] = defaultdict(default_val)
for e in episodes["episodes"]:
_episodes[e["ShowTitle"]].append(Episode(e))
shows: dict = getUrl(self.url, "shows")
self._shows: dict[int, Show] = {
e["id"]: Show(e, _episodes[e["title"]]) for e in shows["data"]
}
recently_added: dict = getUrl(self.url, "recently_added")
self._recently_added: list[int] = recently_added["data"]
in_progress: dict = getUrl(self.url, "in_progress")
self._in_progress: list[int] = in_progress["data"]
@pyqtProperty("QString", constant=True)
def name(self) -> str:
return self._name
@pyqtProperty("QString", constant=True)
def logo(self) -> str:
return f"image://{self._name}/logo"
# @pyqtProperty("QObject")
@pyqtSlot(int, result=QObject)
def getShow(self, id) -> Show:
return self._shows[id]
@pyqtProperty(list, constant=True)
def showsAlphabetic(self) -> list[int]:
return [
elem[0]
for elem in sorted(
[(id, show) for id, show in self._shows.items()],
key=lambda elem: elem[1].title,
)
]
@pyqtProperty(list, constant=True)
def recentlyAdded(self) -> list[int]:
return self._recently_added
@pyqtProperty(list, constant=True)
def inProgress(self) -> list[int]:
return self._in_progress
class DataSource:
def __init__(self, providers=[]):
self.providers: list[Provider] = [Provider(url) for url in providers]
def DatabaseType(data_source) -> Type:
class Database(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self.data_source: DataSource = data_source
@pyqtProperty(list, constant=True)
def Providers(self) -> list[Provider]:
return self.data_source.providers
return Database
def load_config() -> list[str]:
try:
config_dir: str = os.path.join(os.environ["XDG_CONFIG_HOME"], "ikinuki")
except:
config_dir: str = os.path.join(os.environ["HOME"], ".config", "ikinuki")
os.makedirs(config_dir, exist_ok=True)
config_file: str = os.path.join(config_dir, "client.toml")
try:
config: dict = toml.load(config_file)
except FileNotFoundError:
print(f'Config file not found at "{config_file}"')
print("Writing example config file. Please update and relaunch.")
default_config = """# [[backends]]
# address = "127.0.0.1"
# port = 32520"""
with open(config_file, "w") as f:
f.write(default_config)
sys.exit(-1)
return [f'http://{b["address"]}:{b["port"]}/' for b in config["backends"]]
def main():
app = QApplication(sys.argv)
qmlRegisterType(MpvObject, "Ikinuki.Client", 1, 0, "Mpv")
import locale
locale.setlocale(locale.LC_NUMERIC, "C")
try:
backends: list[str] = load_config()
except Exception as e:
print(f"ERROR: Could not load config file: {repr(e)}")
sys.exit(-1)
data_source = DataSource(backends)
qmlRegisterType(DatabaseType(data_source), "Ikinuki.Client", 1, 0, "Database")
# qmlRegisterType(Provider, "Ikinuki.Client", 1, 0, "Provider")
engine = QQmlApplicationEngine()
for provider in data_source.providers:
print(f"Registering provider with name {provider._name}")
engine.addImageProvider(
provider._name,
provider.logo_provider,
)
engine.load("layouts/ikinuki-default.qml")
win = QObject()
win = engine.rootObjects()[0]
win.show()
sys.exit(app.exec_())
#
#
#
# app = QApplication([])
#
#
# window = QQmlApplicationEngine("layouts/mpv.qml")
# window.run
#
# view = QQuickView()
# url = QUrl("layouts/mpv.qml")
#
# import locale
#
# locale.setlocale(locale.LC_NUMERIC, 'C')
#
# view.setSource(url)
# view.show()
# app.exec_()