inc streams ui
parent
73c957c9bb
commit
a5d568ba34
@ -0,0 +1,28 @@
|
|||||||
|
# from typing import List
|
||||||
|
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
|
||||||
|
from sqlalchemy.orm import relationship, declarative_base, sessionmaker
|
||||||
|
|
||||||
|
from .show import Base
|
||||||
|
|
||||||
|
|
||||||
|
class Track(Base):
|
||||||
|
"""
|
||||||
|
relationship(argument, opt1, opt2, ...)
|
||||||
|
argument is string of class or Mapped class of the target entity
|
||||||
|
backref creates a bi-directional corresponding relationship (back_populates preferred)
|
||||||
|
back_populates points to the corresponding relationship (the actual class attribute identifier)
|
||||||
|
|
||||||
|
See: https://docs.sqlalchemy.org/en/(14|20)/orm/basic_relationships.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = 'tracks'
|
||||||
|
|
||||||
|
# v1.x
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
|
||||||
|
track_type = Column(Integer)
|
||||||
|
|
||||||
|
# v1.x
|
||||||
|
pattern_id = Column(Integer, ForeignKey('patterns.id', ondelete="CASCADE"))
|
||||||
|
pattern = relationship('Pattern', back_populates='tracks')
|
||||||
|
|
@ -0,0 +1,92 @@
|
|||||||
|
import click
|
||||||
|
|
||||||
|
from ffx.model.track import Track
|
||||||
|
|
||||||
|
|
||||||
|
class TrackController():
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
|
||||||
|
self.context = context
|
||||||
|
self.Session = self.context['database_session'] # convenience
|
||||||
|
|
||||||
|
|
||||||
|
# def updatePattern(self, show_id, pattern):
|
||||||
|
#
|
||||||
|
# try:
|
||||||
|
# s = self.Session()
|
||||||
|
# q = s.query(Pattern).filter(Pattern.show_id == int(show_id), Pattern.pattern == str(pattern))
|
||||||
|
#
|
||||||
|
# if not q.count():
|
||||||
|
# pattern = Pattern(show_id = int(show_id), pattern = str(pattern))
|
||||||
|
# s.add(pattern)
|
||||||
|
# s.commit()
|
||||||
|
# return True
|
||||||
|
#
|
||||||
|
# except Exception as ex:
|
||||||
|
# raise click.ClickException(f"PatternController.updatePattern(): {repr(ex)}")
|
||||||
|
# finally:
|
||||||
|
# s.close()
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def findPattern(self, showId, pattern):
|
||||||
|
#
|
||||||
|
# try:
|
||||||
|
# s = self.Session()
|
||||||
|
# q = s.query(Pattern).filter(Pattern.show_id == int(showId), Pattern.pattern == str(pattern))
|
||||||
|
#
|
||||||
|
# if q.count():
|
||||||
|
# pattern = q.first()
|
||||||
|
# return int(pattern.id)
|
||||||
|
# else:
|
||||||
|
# return None
|
||||||
|
#
|
||||||
|
# except Exception as ex:
|
||||||
|
# raise click.ClickException(f"PatternController.findPattern(): {repr(ex)}")
|
||||||
|
# finally:
|
||||||
|
# s.close()
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def getPatternDescriptor(self, patternId):
|
||||||
|
#
|
||||||
|
# try:
|
||||||
|
# s = self.Session()
|
||||||
|
# q = s.query(Pattern).filter(Pattern.id == int(patternId))
|
||||||
|
#
|
||||||
|
# patternDescriptor = {}
|
||||||
|
# if q.count():
|
||||||
|
# pattern = q.first()
|
||||||
|
#
|
||||||
|
# patternDescriptor['id'] = pattern.id
|
||||||
|
# patternDescriptor['pattern'] = pattern.pattern
|
||||||
|
# patternDescriptor['show_id'] = pattern.show_id
|
||||||
|
#
|
||||||
|
# return patternDescriptor
|
||||||
|
#
|
||||||
|
# except Exception as ex:
|
||||||
|
# raise click.ClickException(f"PatternController.getPatternDescriptor(): {repr(ex)}")
|
||||||
|
# finally:
|
||||||
|
# s.close()
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def deletePattern(self, patternId):
|
||||||
|
# try:
|
||||||
|
# s = self.Session()
|
||||||
|
# q = s.query(Pattern).filter(Pattern.id == int(patternId))
|
||||||
|
#
|
||||||
|
# if q.count():
|
||||||
|
#
|
||||||
|
# #DAFUQ: https://stackoverflow.com/a/19245058
|
||||||
|
# # q.delete()
|
||||||
|
# pattern = q.first()
|
||||||
|
# s.delete(pattern)
|
||||||
|
#
|
||||||
|
# s.commit()
|
||||||
|
# return True
|
||||||
|
# return False
|
||||||
|
#
|
||||||
|
# except Exception as ex:
|
||||||
|
# raise click.ClickException(f"PatternController.deletePattern(): {repr(ex)}")
|
||||||
|
# finally:
|
||||||
|
# s.close()
|
@ -0,0 +1,114 @@
|
|||||||
|
import click
|
||||||
|
|
||||||
|
from textual import events
|
||||||
|
from textual.app import App, ComposeResult
|
||||||
|
from textual.screen import Screen
|
||||||
|
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input
|
||||||
|
from textual.containers import Grid, Horizontal
|
||||||
|
|
||||||
|
from ffx.model.pattern import Pattern
|
||||||
|
|
||||||
|
from .show_controller import ShowController
|
||||||
|
from .pattern_controller import PatternController
|
||||||
|
|
||||||
|
|
||||||
|
# Screen[dict[int, str, int]]
|
||||||
|
class TrackDeleteScreen(Screen):
|
||||||
|
|
||||||
|
CSS = """
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
grid-size: 2;
|
||||||
|
grid-rows: 2 auto;
|
||||||
|
grid-columns: 30 330;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Input {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
#toplabel {
|
||||||
|
height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.two {
|
||||||
|
column-span: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
height: 100%;
|
||||||
|
border: solid green;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, patternId = None, showId = None):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.context = self.app.getContext()
|
||||||
|
self.Session = self.context['database_session'] # convenience
|
||||||
|
|
||||||
|
self.__pc = PatternController(context = self.context)
|
||||||
|
self.__sc = ShowController(context = self.context)
|
||||||
|
|
||||||
|
self.pattern_obj = self.__pc.getPatternDescriptor(patternId) if patternId is not None else {}
|
||||||
|
self.show_obj = self.__sc.getShowDesciptor(showId) if showId is not None else {}
|
||||||
|
|
||||||
|
|
||||||
|
def on_mount(self):
|
||||||
|
if self.show_obj:
|
||||||
|
self.query_one("#showlabel", Static).update(f"{self.show_obj['id']} - {self.show_obj['name']} ({self.show_obj['year']})")
|
||||||
|
if self.pattern_obj:
|
||||||
|
self.query_one("#patternlabel", Static).update(str(self.pattern_obj['pattern']))
|
||||||
|
|
||||||
|
|
||||||
|
def compose(self):
|
||||||
|
|
||||||
|
yield Header()
|
||||||
|
|
||||||
|
with Grid():
|
||||||
|
|
||||||
|
yield Static("Are you sure to delete the following filename pattern?", id="toplabel", classes="two")
|
||||||
|
|
||||||
|
yield Static("", classes="two")
|
||||||
|
|
||||||
|
yield Static("Pattern")
|
||||||
|
yield Static("", id="patternlabel")
|
||||||
|
|
||||||
|
yield Static("", classes="two")
|
||||||
|
|
||||||
|
yield Static("from show")
|
||||||
|
yield Static("", id="showlabel")
|
||||||
|
|
||||||
|
yield Static("", classes="two")
|
||||||
|
|
||||||
|
yield Button("Delete", id="delete_button")
|
||||||
|
yield Button("Cancel", id="cancel_button")
|
||||||
|
|
||||||
|
yield Footer()
|
||||||
|
|
||||||
|
|
||||||
|
# Event handler for button press
|
||||||
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
|
|
||||||
|
if event.button.id == "delete_button":
|
||||||
|
|
||||||
|
if self.__pc.deletePattern(self.pattern_obj['id']):
|
||||||
|
|
||||||
|
screenResult = {}
|
||||||
|
screenResult['show_id'] = self.show_obj['id']
|
||||||
|
screenResult['pattern'] = self.pattern_obj['pattern']
|
||||||
|
|
||||||
|
self.dismiss(screenResult)
|
||||||
|
|
||||||
|
else:
|
||||||
|
#TODO: Meldung
|
||||||
|
self.app.pop_screen()
|
||||||
|
|
||||||
|
if event.button.id == "cancel_button":
|
||||||
|
self.app.pop_screen()
|
||||||
|
|
@ -0,0 +1,222 @@
|
|||||||
|
import click
|
||||||
|
|
||||||
|
from textual import events
|
||||||
|
from textual.app import App, ComposeResult
|
||||||
|
from textual.screen import Screen
|
||||||
|
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input
|
||||||
|
from textual.containers import Grid, Horizontal
|
||||||
|
|
||||||
|
from ffx.model.show import Show
|
||||||
|
from ffx.model.pattern import Pattern
|
||||||
|
|
||||||
|
from .track_controller import TrackController
|
||||||
|
# from .pattern_controller import PatternController
|
||||||
|
# from .show_controller import ShowController
|
||||||
|
|
||||||
|
from .track_type import TrackType
|
||||||
|
|
||||||
|
|
||||||
|
# Screen[dict[int, str, int]]
|
||||||
|
class TrackDetailsScreen(Screen):
|
||||||
|
|
||||||
|
CSS = """
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
grid-size: 5 11;
|
||||||
|
grid-rows: 2 2 2 2 6 2 2 6 2 2 2;
|
||||||
|
grid-columns: 25 25 25 25 25;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Input {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTable {
|
||||||
|
min-height: 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toplabel {
|
||||||
|
height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.three {
|
||||||
|
column-span: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.four {
|
||||||
|
column-span: 4;
|
||||||
|
}
|
||||||
|
.five {
|
||||||
|
column-span: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
height: 100%;
|
||||||
|
border: solid green;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
STREAM_TYPE_LABELS = [
|
||||||
|
'video',
|
||||||
|
'audio',
|
||||||
|
'subtitle'
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, trackType : TrackType, streamId = None, patternId = None):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.context = self.app.getContext()
|
||||||
|
self.Session = self.context['database_session'] # convenience
|
||||||
|
|
||||||
|
self.trackType = trackType
|
||||||
|
|
||||||
|
self.__tc = TrackController(context = self.context)
|
||||||
|
#self.__pc = PatternController(context = self.context)
|
||||||
|
#self.__sc = ShowController(context = self.context)
|
||||||
|
|
||||||
|
# self.pattern_obj = self.__pc.getPatternDescriptor(patternId) if patternId is not None else {}
|
||||||
|
# self.show_obj = self.__sc.getShowDesciptor(showId) if showId is not None else {}
|
||||||
|
self.track_obj = {}
|
||||||
|
|
||||||
|
# def loadPatterns(self, show_id):
|
||||||
|
#
|
||||||
|
# try:
|
||||||
|
# s = self.Session()
|
||||||
|
# q = s.query(Pattern).filter(Pattern.show_id == int(show_id))
|
||||||
|
#
|
||||||
|
# return [{'id': int(p.id), 'pattern': p.pattern} for p in q.all()]
|
||||||
|
#
|
||||||
|
# except Exception as ex:
|
||||||
|
# click.ClickException(f"loadPatterns(): {repr(ex)}")
|
||||||
|
# finally:
|
||||||
|
# s.close()
|
||||||
|
|
||||||
|
|
||||||
|
def on_mount(self):
|
||||||
|
pass
|
||||||
|
# if self.pattern_obj:
|
||||||
|
# self.query_one("#pattern_input", Input).value = str(self.pattern_obj['pattern'])
|
||||||
|
|
||||||
|
# if self.show_obj:
|
||||||
|
# self.query_one("#showlabel", Static).update(f"{self.show_obj['id']} - {self.show_obj['name']} ({self.show_obj['year']})")
|
||||||
|
|
||||||
|
# for pattern in self.loadPatterns(int(self.show_obj['id'])):
|
||||||
|
# row = (pattern['pattern'],)
|
||||||
|
# self.patternTable.add_row(*map(str, row))
|
||||||
|
|
||||||
|
|
||||||
|
# for subIndex in range(3):
|
||||||
|
#
|
||||||
|
# row4 = (str(subIndex),str(subIndex),str(subIndex),str(subIndex),)
|
||||||
|
# self.audioStreamsTable.add_row(*map(str, row4))
|
||||||
|
#
|
||||||
|
# row5 = (str(subIndex),str(subIndex),str(subIndex),str(subIndex),str(subIndex),)
|
||||||
|
# self.subtitleStreamsTable.add_row(*map(str, row5))
|
||||||
|
|
||||||
|
|
||||||
|
def compose(self):
|
||||||
|
|
||||||
|
# self.audioStreamsTable = DataTable(classes="five")
|
||||||
|
#
|
||||||
|
# # Define the columns with headers
|
||||||
|
# self.column_key_audio_subid = self.audioStreamsTable.add_column("Subindex", width=10)
|
||||||
|
# self.column_key_audio_layout = self.audioStreamsTable.add_column("Layout", width=10)
|
||||||
|
# self.column_key_audio_language = self.audioStreamsTable.add_column("Language", width=10)
|
||||||
|
# self.column_key_audio_title = self.audioStreamsTable.add_column("Title", width=10)
|
||||||
|
#
|
||||||
|
# self.audioStreamsTable.cursor_type = 'row'
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# self.subtitleStreamsTable = DataTable(classes="five")
|
||||||
|
#
|
||||||
|
# # Define the columns with headers
|
||||||
|
# self.column_key_subtitle_subid = self.subtitleStreamsTable.add_column("Subindex", width=10)
|
||||||
|
# self.column_key_subtitle_language = self.subtitleStreamsTable.add_column("Language", width=10)
|
||||||
|
# self.column_key_subtitle_title = self.subtitleStreamsTable.add_column("Title", width=10)
|
||||||
|
# self.column_key_subtitle_default = self.subtitleStreamsTable.add_column("Default", width=10)
|
||||||
|
# self.column_key_subtitle_forced = self.subtitleStreamsTable.add_column("Forced", width=10)
|
||||||
|
#
|
||||||
|
# self.subtitleStreamsTable.cursor_type = 'row'
|
||||||
|
|
||||||
|
typeLabel = TrackDetailsScreen.STREAM_TYPE_LABELS[self.trackType-1]
|
||||||
|
|
||||||
|
yield Header()
|
||||||
|
|
||||||
|
with Grid():
|
||||||
|
|
||||||
|
# 1
|
||||||
|
yield Static(f"Edit {typeLabel} stream" if self.track_obj else f"New {typeLabel} stream", id="toplabel", classes="five")
|
||||||
|
# yield Input(type="text", id="pattern_input", classes="four")
|
||||||
|
|
||||||
|
# 2
|
||||||
|
# yield Static("from show")
|
||||||
|
# yield Static("", id="showlabel")
|
||||||
|
#
|
||||||
|
# # 3
|
||||||
|
# yield Static(" ", classes="five")
|
||||||
|
# # 4
|
||||||
|
# yield Static(" ", classes="five")
|
||||||
|
#
|
||||||
|
# # 5
|
||||||
|
# yield Static("Audio streams")
|
||||||
|
# yield Static(" ")
|
||||||
|
# yield Button("Add", id="button_add_audio_stream")
|
||||||
|
# yield Button("Edit", id="button_edit_audio_stream")
|
||||||
|
# yield Button("Delete", id="button_delete_audio_stream")
|
||||||
|
# # 6
|
||||||
|
# yield self.audioStreamsTable
|
||||||
|
#
|
||||||
|
# # 7
|
||||||
|
# yield Static(" ", classes="five")
|
||||||
|
#
|
||||||
|
# # 8
|
||||||
|
# yield Static("Subtitle streams")
|
||||||
|
# yield Static(" ")
|
||||||
|
# yield Button("Add", id="button_add_subtitle_stream")
|
||||||
|
# yield Button("Edit", id="button_edit_subtitle_stream")
|
||||||
|
# yield Button("Delete", id="button_delete_subtitle_stream")
|
||||||
|
# # 9
|
||||||
|
# yield self.subtitleStreamsTable
|
||||||
|
#
|
||||||
|
# 10
|
||||||
|
yield Static(" ", classes="five")
|
||||||
|
|
||||||
|
# 11
|
||||||
|
yield Button("Save", id="save_button")
|
||||||
|
yield Button("Cancel", id="cancel_button")
|
||||||
|
|
||||||
|
yield Footer()
|
||||||
|
|
||||||
|
|
||||||
|
# def getPatternFromInput(self):
|
||||||
|
# return str(self.query_one("#pattern_input", Input).value)
|
||||||
|
|
||||||
|
|
||||||
|
# Event handler for button press
|
||||||
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
|
# Check if the button pressed is the one we are interested in
|
||||||
|
# if event.button.id == "save_button":
|
||||||
|
#
|
||||||
|
# pattern = self.getPatternFromInput()
|
||||||
|
#
|
||||||
|
# if self.__pc.updatePattern(self.show_obj['id'], pattern):
|
||||||
|
#
|
||||||
|
# screenResult = {}
|
||||||
|
# screenResult['show_id'] = self.show_obj['id']
|
||||||
|
# screenResult['pattern'] = pattern
|
||||||
|
#
|
||||||
|
# self.dismiss(screenResult)
|
||||||
|
# else:
|
||||||
|
# #TODO: Meldung
|
||||||
|
# self.app.pop_screen()
|
||||||
|
|
||||||
|
if event.button.id == "cancel_button":
|
||||||
|
self.app.pop_screen()
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
class StreamType(Enum):
|
class TrackType(Enum):
|
||||||
VIDEO = 1
|
VIDEO = 1
|
||||||
AUDIO = 2
|
AUDIO = 2
|
||||||
SUBTITLE = 3
|
SUBTITLE = 3
|
Loading…
Reference in New Issue