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
|
||||
|
||||
class StreamType(Enum):
|
||||
class TrackType(Enum):
|
||||
VIDEO = 1
|
||||
AUDIO = 2
|
||||
SUBTITLE = 3
|
Loading…
Reference in New Issue