Compare commits
5 Commits
1e7d9db9cc
...
6ace97ff83
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ace97ff83 | |||
| 9234da67fe | |||
| 3227730a37 | |||
| afb7a456a1 | |||
| a38221cca2 |
+123
-50
@@ -1,30 +1,54 @@
|
|||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from urllib import parse
|
import urllib.parse
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QApplication
|
from PyQt5.QtWidgets import QApplication
|
||||||
from PyQt5.QtQml import qmlRegisterType, QQmlApplicationEngine
|
from PyQt5.QtQml import qmlRegisterType, QQmlApplicationEngine
|
||||||
from PyQt5.QtQuick import QQuickImageProvider
|
from PyQt5.QtQuick import QQuickImageProvider
|
||||||
|
|
||||||
# from PyQt5.QtQuick import QQuickView
|
|
||||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot
|
||||||
|
|
||||||
from PyQt5.QtGui import QImage
|
from PyQt5.QtGui import QImage
|
||||||
|
|
||||||
# from PyQt5.QtCore import QObject, QUrl, pyqtProperty
|
|
||||||
|
|
||||||
|
|
||||||
from .qtmpv import MpvObject
|
from .qtmpv import MpvObject
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import toml
|
||||||
|
|
||||||
|
|
||||||
class Show(QObject):
|
class Episode(QObject):
|
||||||
def __init__(self, source, parent=None):
|
def __init__(self, source, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._source = source
|
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)
|
@pyqtProperty("QString", constant=True)
|
||||||
def title(self) -> str:
|
def title(self) -> str:
|
||||||
return self._source["title"]
|
return self._source["title"]
|
||||||
@@ -37,10 +61,6 @@ class Show(QObject):
|
|||||||
def description(self) -> str:
|
def description(self) -> str:
|
||||||
return self._source["description"]
|
return self._source["description"]
|
||||||
|
|
||||||
@pyqtProperty(int, constant=True)
|
|
||||||
def episodes(self) -> int:
|
|
||||||
return self._source["episodes"]
|
|
||||||
|
|
||||||
@pyqtProperty(int, constant=True)
|
@pyqtProperty(int, constant=True)
|
||||||
def watched(self) -> int:
|
def watched(self) -> int:
|
||||||
return self._source["watched"]
|
return self._source["watched"]
|
||||||
@@ -49,6 +69,10 @@ class Show(QObject):
|
|||||||
def poster(self) -> str:
|
def poster(self) -> str:
|
||||||
return self._source["poster"]
|
return self._source["poster"]
|
||||||
|
|
||||||
|
@pyqtProperty(list, constant=True)
|
||||||
|
def episodes(self) -> list[Episode]:
|
||||||
|
return self._episodes
|
||||||
|
|
||||||
|
|
||||||
class ProviderImageProvider(QQuickImageProvider):
|
class ProviderImageProvider(QQuickImageProvider):
|
||||||
def __init__(self, icon_data):
|
def __init__(self, icon_data):
|
||||||
@@ -60,26 +84,21 @@ class ProviderImageProvider(QQuickImageProvider):
|
|||||||
print(p_str)
|
print(p_str)
|
||||||
print(size)
|
print(size)
|
||||||
|
|
||||||
# img = QImage.fromData(self._icon_data.encode("utf-8"))
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
data: bytes = base64.b64decode(self._icon_data)
|
data: bytes = base64.b64decode(self._icon_data)
|
||||||
img = QImage.fromData(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()
|
return img, img.size()
|
||||||
|
|
||||||
|
|
||||||
def getUrl(base: str, path: str) -> dict:
|
def getUrl(base: str, path: str) -> dict:
|
||||||
url: str = parse.urljoin(base, path)
|
url: str = urllib.parse.urljoin(base, path)
|
||||||
r: requests.Response = requests.get(url)
|
r: requests.Response = requests.get(url)
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
|
||||||
class Provider(QObject):
|
class Provider(QObject):
|
||||||
def __init__(self, url: str, parent=None):
|
def __init__(self, url: str, data_dir: str, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.url: str = url
|
self.url: str = url
|
||||||
|
|
||||||
@@ -89,8 +108,47 @@ class Provider(QObject):
|
|||||||
describe["icon"]
|
describe["icon"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Create dictionary of show episodes
|
||||||
|
episodes: dict = getUrl(self.url, "episodes")
|
||||||
|
_episodes: defaultdict[str, list[Episode]] = defaultdict(lambda: [])
|
||||||
|
|
||||||
|
for e in episodes["episodes"]:
|
||||||
|
_episodes[e["ShowTitle"]].append(Episode(e))
|
||||||
|
|
||||||
shows: dict = getUrl(self.url, "shows")
|
shows: dict = getUrl(self.url, "shows")
|
||||||
self._shows: dict[int, Show] = {e["id"]: Show(e) for e in shows["data"]}
|
|
||||||
|
# Create image_cache directory
|
||||||
|
provider_data_dir: str = os.path.join(
|
||||||
|
data_dir, "image_cache", "providers", self._name
|
||||||
|
)
|
||||||
|
os.makedirs(provider_data_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Cache show posters
|
||||||
|
for s in shows["data"]:
|
||||||
|
# Get local cache path
|
||||||
|
poster_url: str = s["poster"]
|
||||||
|
poster_path: str = urllib.parse.urlparse(poster_url).path
|
||||||
|
poster_ext: str = os.path.splitext(poster_path)[1]
|
||||||
|
download_path: str = os.path.join(
|
||||||
|
provider_data_dir, str(s["id"]) + poster_ext
|
||||||
|
)
|
||||||
|
|
||||||
|
# Download poster
|
||||||
|
try:
|
||||||
|
with open(download_path, "xb") as f:
|
||||||
|
r = requests.get(poster_url, stream=True)
|
||||||
|
if r.status_code == 200:
|
||||||
|
r.raw.decode_content = True
|
||||||
|
shutil.copyfileobj(r.raw, f)
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Overwrite poster URL with local path
|
||||||
|
s["poster"] = download_path
|
||||||
|
|
||||||
|
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")
|
recently_added: dict = getUrl(self.url, "recently_added")
|
||||||
self._recently_added: list[int] = recently_added["data"]
|
self._recently_added: list[int] = recently_added["data"]
|
||||||
@@ -106,7 +164,6 @@ class Provider(QObject):
|
|||||||
def logo(self) -> str:
|
def logo(self) -> str:
|
||||||
return f"image://{self._name}/logo"
|
return f"image://{self._name}/logo"
|
||||||
|
|
||||||
# @pyqtProperty("QObject")
|
|
||||||
@pyqtSlot(int, result=QObject)
|
@pyqtSlot(int, result=QObject)
|
||||||
def getShow(self, id) -> Show:
|
def getShow(self, id) -> Show:
|
||||||
return self._shows[id]
|
return self._shows[id]
|
||||||
@@ -131,8 +188,8 @@ class Provider(QObject):
|
|||||||
|
|
||||||
|
|
||||||
class DataSource:
|
class DataSource:
|
||||||
def __init__(self, providers=[]):
|
def __init__(self, providers: list[str], data_dir: str):
|
||||||
self.providers: list[Provider] = [Provider(url) for url in providers]
|
self.providers: list[Provider] = [Provider(url, data_dir) for url in providers]
|
||||||
|
|
||||||
|
|
||||||
def DatabaseType(data_source) -> Type:
|
def DatabaseType(data_source) -> Type:
|
||||||
@@ -149,6 +206,42 @@ def DatabaseType(data_source) -> Type:
|
|||||||
return Database
|
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 get_data_dir() -> str:
|
||||||
|
try:
|
||||||
|
data_dir: str = os.path.join(os.environ["XDG_DATA_HOME"], "ikinuki")
|
||||||
|
except:
|
||||||
|
data_dir: str = os.path.join(os.environ["HOME"], ".local", "share", "ikinuki")
|
||||||
|
|
||||||
|
os.makedirs(data_dir, exist_ok=True)
|
||||||
|
|
||||||
|
return data_dir
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
@@ -157,16 +250,17 @@ def main():
|
|||||||
|
|
||||||
locale.setlocale(locale.LC_NUMERIC, "C")
|
locale.setlocale(locale.LC_NUMERIC, "C")
|
||||||
|
|
||||||
data_source = DataSource(
|
try:
|
||||||
[
|
backends: list[str] = load_config()
|
||||||
"http://127.0.0.1:8080/a/",
|
except Exception as e:
|
||||||
"http://127.0.0.1:8080/b/",
|
print(f"ERROR: Could not load config file: {repr(e)}")
|
||||||
"http://127.0.0.1:8080/c/",
|
sys.exit(-1)
|
||||||
]
|
|
||||||
)
|
data_dir: str = get_data_dir()
|
||||||
|
|
||||||
|
data_source = DataSource(backends, data_dir)
|
||||||
|
|
||||||
qmlRegisterType(DatabaseType(data_source), "Ikinuki.Client", 1, 0, "Database")
|
qmlRegisterType(DatabaseType(data_source), "Ikinuki.Client", 1, 0, "Database")
|
||||||
# qmlRegisterType(Provider, "Ikinuki.Client", 1, 0, "Provider")
|
|
||||||
|
|
||||||
engine = QQmlApplicationEngine()
|
engine = QQmlApplicationEngine()
|
||||||
for provider in data_source.providers:
|
for provider in data_source.providers:
|
||||||
@@ -182,24 +276,3 @@ def main():
|
|||||||
win.show()
|
win.show()
|
||||||
|
|
||||||
sys.exit(app.exec_())
|
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_()
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ Row {
|
|||||||
ContentView {
|
ContentView {
|
||||||
id: view
|
id: view
|
||||||
viewSelected: selectedView == 1
|
viewSelected: selectedView == 1
|
||||||
currentIndex: selectedProvider + (browse ? db.Providers.length : 0)
|
parentIndex: selectedProvider + (browse ? db.Providers.length : 0)
|
||||||
providers: db.Providers
|
providers: db.Providers
|
||||||
}
|
}
|
||||||
function mod(n, m) {
|
function mod(n, m) {
|
||||||
|
|||||||
@@ -11,8 +11,14 @@ StackLayout {
|
|||||||
id: tabView
|
id: tabView
|
||||||
property var providers: []
|
property var providers: []
|
||||||
property bool viewSelected
|
property bool viewSelected
|
||||||
state: viewSelected ? "selected" : "deselected"
|
property int parentIndex
|
||||||
|
|
||||||
property int ySelect: 0
|
property int ySelect: 0
|
||||||
|
property bool showViewActive: false
|
||||||
|
|
||||||
|
currentIndex: showViewActive ? tabView.children.length - 3 : parentIndex
|
||||||
|
|
||||||
|
state: viewSelected ? "selected" : "deselected"
|
||||||
width: parent.width * viewSelected ? 0.95 : 0.8
|
width: parent.width * viewSelected ? 0.95 : 0.8
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
@@ -28,6 +34,10 @@ StackLayout {
|
|||||||
provider: modelData
|
provider: modelData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ShowView {
|
||||||
|
id: showView
|
||||||
|
show: providers[0].getShow(providers[0].showsAlphabetic[0])
|
||||||
|
}
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
name: "deselected"
|
name: "deselected"
|
||||||
@@ -54,14 +64,32 @@ StackLayout {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function getCurrentIndex() {
|
||||||
|
if (showViewActive) {
|
||||||
|
var x = tabView.children.length - 1;
|
||||||
|
} else {
|
||||||
|
var x = currentIndex > (providers.length - 1) ? currentIndex + 1 : currentIndex;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
Keys.onPressed: (event)=> {
|
Keys.onPressed: (event)=> {
|
||||||
var x = currentIndex > (providers.length - 1) ? currentIndex + 1 : currentIndex;
|
var x = getCurrentIndex()
|
||||||
//tabView.children[currentIndex].Keys.pressed(event);
|
|
||||||
tabView.children[x].Keys.pressed(event);
|
tabView.children[x].Keys.pressed(event);
|
||||||
if (tabView.children[x].viewExit) {
|
if (tabView.children[x].enterShow) {
|
||||||
tabView.children[x].viewExit = false;
|
showViewActive = true;
|
||||||
parent.browse = false;
|
showView.show = tabView.children[x].enterShowShow;
|
||||||
parent.selectedView = 0;
|
} else if (tabView.children[x].viewExit) {
|
||||||
|
if (showViewActive) {
|
||||||
|
showViewActive = false;
|
||||||
|
tabView.children[x].xIndex = 0;
|
||||||
|
tabView.children[x].viewExit = false;
|
||||||
|
tabView.children[getCurrentIndex()].enterShow = false;
|
||||||
|
} else {
|
||||||
|
tabView.children[x].viewExit = false;
|
||||||
|
parent.browse = false;
|
||||||
|
parent.selectedView = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
import Ikinuki.Client 1.0
|
||||||
|
|
||||||
|
import "./ShowView"
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: root
|
||||||
|
property var episodeModel
|
||||||
|
property int scrollIndex: 0
|
||||||
|
contentHeight: root.height * 0.1 * episodeModel.length
|
||||||
|
ScrollBar.vertical.position: scrollIndex / (episodeModel.length)
|
||||||
|
clip: true
|
||||||
|
Behavior on ScrollBar.vertical.position {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 200
|
||||||
|
easing.type: Easing.Linear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
Repeater {
|
||||||
|
model: episodeModel
|
||||||
|
Episode {
|
||||||
|
episode: modelData
|
||||||
|
selected: index == xIndex
|
||||||
|
height: root.height * 0.1
|
||||||
|
width: root.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@ Rectangle {
|
|||||||
id: root
|
id: root
|
||||||
property var provider
|
property var provider
|
||||||
property bool viewExit: false
|
property bool viewExit: false
|
||||||
|
property bool enterShow: false
|
||||||
|
property var enterShowShow
|
||||||
property int currentView: 0
|
property int currentView: 0
|
||||||
color: "#22282A"
|
color: "#22282A"
|
||||||
Row {
|
Row {
|
||||||
@@ -76,6 +78,9 @@ Rectangle {
|
|||||||
coverGrid.scrollIndex--;
|
coverGrid.scrollIndex--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (event.key == Qt.Key_Return) {
|
||||||
|
enterShowShow = root.provider.getShow(root.provider.showsAlphabetic[(coverGrid.xIndex + coverGrid.yIndex * coverGrid.numColumns)])
|
||||||
|
enterShow = true;
|
||||||
}
|
}
|
||||||
} else if (currentView == 1) { // alphabet
|
} else if (currentView == 1) { // alphabet
|
||||||
if (event.key == Qt.Key_Left) {
|
if (event.key == Qt.Key_Left) {
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ Rectangle {
|
|||||||
id: root
|
id: root
|
||||||
property var provider
|
property var provider
|
||||||
property int ySelect: 0
|
property int ySelect: 0
|
||||||
property int xSelect: 0
|
|
||||||
property bool viewExit: false
|
property bool viewExit: false
|
||||||
|
property bool enterShow: false
|
||||||
|
property var enterShowShow
|
||||||
color: "#22282A"
|
color: "#22282A"
|
||||||
Row {
|
Row {
|
||||||
Item {
|
Item {
|
||||||
@@ -82,6 +83,9 @@ Rectangle {
|
|||||||
ySelect++;
|
ySelect++;
|
||||||
} else if (event.key == Qt.Key_Up) {
|
} else if (event.key == Qt.Key_Up) {
|
||||||
ySelect--;
|
ySelect--;
|
||||||
|
} else if (event.key == Qt.Key_Return) {
|
||||||
|
enterShowShow = provider.getShow(elementColumn.children[ySelect].showId)
|
||||||
|
enterShow = true;
|
||||||
}
|
}
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
import Ikinuki.Client 1.0
|
||||||
|
|
||||||
|
import "./ShowView"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
property var show
|
||||||
|
property bool viewExit: false
|
||||||
|
property bool enterShow: false
|
||||||
|
property int xIndex: 0
|
||||||
|
color: "#22282A"
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: parent.width * 0.01
|
||||||
|
anchors.rightMargin: parent.width * 0.01
|
||||||
|
anchors.topMargin: parent.height * 0.05
|
||||||
|
anchors.bottomMargin: parent.height * 0.01
|
||||||
|
Text { // header
|
||||||
|
height: parent.height * 0.1
|
||||||
|
width: parent.width
|
||||||
|
text: show.title
|
||||||
|
font.pointSize: 20
|
||||||
|
color: "#cdd7d9"
|
||||||
|
}
|
||||||
|
Row { // main view
|
||||||
|
height: parent.height * 0.8
|
||||||
|
width: parent.width
|
||||||
|
spacing: parent.width * 0.01
|
||||||
|
Item {
|
||||||
|
height: parent.height
|
||||||
|
width: height * 0.68
|
||||||
|
Image {
|
||||||
|
source: show.poster
|
||||||
|
anchors.fill: parent
|
||||||
|
mipmap: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EpisodeView {
|
||||||
|
id: episodeView
|
||||||
|
height: parent.height
|
||||||
|
width: parent.width * 0.65
|
||||||
|
episodeModel: show.episodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
height: parent.height * 0.1
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: (event)=> {
|
||||||
|
if (event.key == Qt.Key_Up) {
|
||||||
|
if (xIndex > 0) {
|
||||||
|
xIndex--;
|
||||||
|
if (episodeView.scrollIndex > xIndex) {
|
||||||
|
episodeView.scrollIndex--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event.key == Qt.Key_Down) {
|
||||||
|
if (xIndex < show.episodes.length - 1) {
|
||||||
|
if (episodeView.scrollIndex < (xIndex - 8)) {
|
||||||
|
episodeView.scrollIndex++;
|
||||||
|
}
|
||||||
|
xIndex++;
|
||||||
|
}
|
||||||
|
} else if (event.key == Qt.Key_Escape) {
|
||||||
|
viewExit = true;
|
||||||
|
}
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
import Ikinuki.Client 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property var episode
|
||||||
|
property bool selected
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "white"
|
||||||
|
visible: selected
|
||||||
|
radius: 10
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
anchors.fill: parent
|
||||||
|
Item {
|
||||||
|
height: parent.height
|
||||||
|
width: parent.width * 0.04
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.verticalCenterOffset: 4
|
||||||
|
Text {
|
||||||
|
text: {
|
||||||
|
if (modelData.season == 0) {
|
||||||
|
return "S" + modelData.episode + " " + modelData.title
|
||||||
|
} else {
|
||||||
|
return String(modelData.episode).padStart(2, "0") + ". " + modelData.title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font.pointSize: 20
|
||||||
|
color: selected ? "#3c3c3c" : "#99afb4"
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
height: parent.height * 0.1
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: " air date"
|
||||||
|
font.pointSize: 12
|
||||||
|
color: selected ? "#3c3c3c" : "#99afb4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,6 @@ Item {
|
|||||||
DropShadow {
|
DropShadow {
|
||||||
anchors.fill: selector
|
anchors.fill: selector
|
||||||
verticalOffset: 5
|
verticalOffset: 5
|
||||||
//horizontalOffset: 5
|
|
||||||
samples: 20
|
samples: 20
|
||||||
color: "black"
|
color: "black"
|
||||||
opacity: 0.5
|
opacity: 0.5
|
||||||
@@ -24,7 +23,6 @@ Item {
|
|||||||
color: "white"
|
color: "white"
|
||||||
height: parent.height
|
height: parent.height
|
||||||
width: parent.width * 0.95
|
width: parent.width * 0.95
|
||||||
//anchors.fill: parent
|
|
||||||
visible: selected && maximized
|
visible: selected && maximized
|
||||||
radius: 10
|
radius: 10
|
||||||
}
|
}
|
||||||
@@ -42,11 +40,6 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
id: logo
|
id: logo
|
||||||
source: provider.logo
|
source: provider.logo
|
||||||
//y: parent.y + (parent.height / 2) - height / 2
|
|
||||||
//anchors.top: parent.verticalCenter
|
|
||||||
// anchors.verticalCenter: text.verticalCenter
|
|
||||||
//sourceSize.height: 50
|
|
||||||
//sourceSize.width: 50
|
|
||||||
}
|
}
|
||||||
ColorOverlay {
|
ColorOverlay {
|
||||||
anchors.fill: logo
|
anchors.fill: logo
|
||||||
@@ -66,8 +59,6 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.verticalCenterOffset: 4
|
anchors.verticalCenterOffset: 4
|
||||||
visible: maximized
|
visible: maximized
|
||||||
//verticalAlignment: Text.AlignVCenter
|
|
||||||
//height: parent.height
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+14
-2
@@ -62,7 +62,7 @@ optional = false
|
|||||||
python-versions = ">=3.5"
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
screenshot_raw = ["pillow"]
|
screenshot_raw = ["Pillow"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
@@ -82,6 +82,14 @@ urllib3 = ">=1.21.1,<1.27"
|
|||||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
|
use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.10.2"
|
||||||
|
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "1.26.12"
|
version = "1.26.12"
|
||||||
@@ -98,7 +106,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "7e77956c19bb0148f37be8283857fbd29805184149d6f2c1027daab624c66b80"
|
content-hash = "ab4b6be20253adf487e007f81b07f9f585bd4a61d4e51889f9356dfc0e03e206"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
certifi = [
|
certifi = [
|
||||||
@@ -152,6 +160,10 @@ requests = [
|
|||||||
{file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
|
{file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
|
||||||
{file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
|
{file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
|
||||||
]
|
]
|
||||||
|
toml = [
|
||||||
|
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
|
||||||
|
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
||||||
|
]
|
||||||
urllib3 = [
|
urllib3 = [
|
||||||
{file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"},
|
{file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"},
|
||||||
{file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"},
|
{file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"},
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ python = "^3.10"
|
|||||||
python-mpv = "^0.5.2"
|
python-mpv = "^0.5.2"
|
||||||
PyQt5 = "^5.15.1"
|
PyQt5 = "^5.15.1"
|
||||||
requests = "^2.28.1"
|
requests = "^2.28.1"
|
||||||
|
toml = "^0.10.2"
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
|
|||||||
Reference in New Issue
Block a user