nightly
This commit is contained in:
113
bin/ffx/iso_language.py
Normal file
113
bin/ffx/iso_language.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
from enum import Enum
|
||||||
|
import difflib
|
||||||
|
|
||||||
|
class IsoLanguage(Enum):
|
||||||
|
|
||||||
|
AFRIKAANS = {"name": "Afrikaans", "iso639_1": "af", "iso639_2": "afr"}
|
||||||
|
ALBANIAN = {"name": "Albanian", "iso639_1": "sq", "iso639_2": "alb"}
|
||||||
|
ARABIC = {"name": "Arabic", "iso639_1": "ar", "iso639_2": "ara"}
|
||||||
|
ARMENIAN = {"name": "Armenian", "iso639_1": "hy", "iso639_2": "arm"}
|
||||||
|
AZERBAIJANI = {"name": "Azerbaijani", "iso639_1": "az", "iso639_2": "aze"}
|
||||||
|
BASQUE = {"name": "Basque", "iso639_1": "eu", "iso639_2": "baq"}
|
||||||
|
BELARUSIAN = {"name": "Belarusian", "iso639_1": "be", "iso639_2": "bel"}
|
||||||
|
BULGARIAN = {"name": "Bulgarian", "iso639_1": "bg", "iso639_2": "bul"}
|
||||||
|
CATALAN = {"name": "Catalan", "iso639_1": "ca", "iso639_2": "cat"}
|
||||||
|
CHINESE = {"name": "Chinese", "iso639_1": "zh", "iso639_2": "chi"}
|
||||||
|
CROATIAN = {"name": "Croatian", "iso639_1": "hr", "iso639_2": "hrv"}
|
||||||
|
CZECH = {"name": "Czech", "iso639_1": "cs", "iso639_2": "cze"}
|
||||||
|
DANISH = {"name": "Danish", "iso639_1": "da", "iso639_2": "dan"}
|
||||||
|
DUTCH = {"name": "Dutch", "iso639_1": "nl", "iso639_2": "dut"}
|
||||||
|
ENGLISH = {"name": "English", "iso639_1": "en", "iso639_2": "eng"}
|
||||||
|
ESTONIAN = {"name": "Estonian", "iso639_1": "et", "iso639_2": "est"}
|
||||||
|
FINNISH = {"name": "Finnish", "iso639_1": "fi", "iso639_2": "fin"}
|
||||||
|
FRENCH = {"name": "French", "iso639_1": "fr", "iso639_2": "fre"}
|
||||||
|
GEORGIAN = {"name": "Georgian", "iso639_1": "ka", "iso639_2": "geo"}
|
||||||
|
GERMAN = {"name": "German", "iso639_1": "de", "iso639_2": "ger"}
|
||||||
|
GREEK = {"name": "Greek", "iso639_1": "el", "iso639_2": "gre"}
|
||||||
|
HEBREW = {"name": "Hebrew", "iso639_1": "he", "iso639_2": "heb"}
|
||||||
|
HINDI = {"name": "Hindi", "iso639_1": "hi", "iso639_2": "hin"}
|
||||||
|
HUNGARIAN = {"name": "Hungarian", "iso639_1": "hu", "iso639_2": "hun"}
|
||||||
|
ICELANDIC = {"name": "Icelandic", "iso639_1": "is", "iso639_2": "ice"}
|
||||||
|
INDONESIAN = {"name": "Indonesian", "iso639_1": "id", "iso639_2": "ind"}
|
||||||
|
IRISH = {"name": "Irish", "iso639_1": "ga", "iso639_2": "gle"}
|
||||||
|
ITALIAN = {"name": "Italian", "iso639_1": "it", "iso639_2": "ita"}
|
||||||
|
JAPANESE = {"name": "Japanese", "iso639_1": "ja", "iso639_2": "jpn"}
|
||||||
|
KAZAKH = {"name": "Kazakh", "iso639_1": "kk", "iso639_2": "kaz"}
|
||||||
|
KOREAN = {"name": "Korean", "iso639_1": "ko", "iso639_2": "kor"}
|
||||||
|
LATIN = {"name": "Latin", "iso639_1": "la", "iso639_2": "lat"}
|
||||||
|
LATVIAN = {"name": "Latvian", "iso639_1": "lv", "iso639_2": "lav"}
|
||||||
|
LITHUANIAN = {"name": "Lithuanian", "iso639_1": "lt", "iso639_2": "lit"}
|
||||||
|
MACEDONIAN = {"name": "Macedonian", "iso639_1": "mk", "iso639_2": "mac"}
|
||||||
|
MALAY = {"name": "Malay", "iso639_1": "ms", "iso639_2": "may"}
|
||||||
|
MALTESE = {"name": "Maltese", "iso639_1": "mt", "iso639_2": "mlt"}
|
||||||
|
NORWEGIAN = {"name": "Norwegian", "iso639_1": "no", "iso639_2": "nor"}
|
||||||
|
PERSIAN = {"name": "Persian", "iso639_1": "fa", "iso639_2": "per"}
|
||||||
|
POLISH = {"name": "Polish", "iso639_1": "pl", "iso639_2": "pol"}
|
||||||
|
PORTUGUESE = {"name": "Portuguese", "iso639_1": "pt", "iso639_2": "por"}
|
||||||
|
ROMANIAN = {"name": "Romanian", "iso639_1": "ro", "iso639_2": "rum"}
|
||||||
|
RUSSIAN = {"name": "Russian", "iso639_1": "ru", "iso639_2": "rus"}
|
||||||
|
NORTHERN_SAMI = {"name": "Northern Sami", "iso639_1": "se", "iso639_2": "sme"}
|
||||||
|
SAMOAN = {"name": "Samoan", "iso639_1": "sm", "iso639_2": "smo"}
|
||||||
|
SANGO = {"name": "Sango", "iso639_1": "sg", "iso639_2": "sag"}
|
||||||
|
SANSKRIT = {"name": "Sanskrit", "iso639_1": "sa", "iso639_2": "san"}
|
||||||
|
SARDINIAN = {"name": "Sardinian", "iso639_1": "sc", "iso639_2": "srd"}
|
||||||
|
SERBIAN = {"name": "Serbian", "iso639_1": "sr", "iso639_2": "srp"}
|
||||||
|
SHONA = {"name": "Shona", "iso639_1": "sn", "iso639_2": "sna"}
|
||||||
|
SINDHI = {"name": "Sindhi", "iso639_1": "sd", "iso639_2": "snd"}
|
||||||
|
SINHALA = {"name": "Sinhala", "iso639_1": "si", "iso639_2": "sin"}
|
||||||
|
SLOVAK = {"name": "Slovak", "iso639_1": "sk", "iso639_2": "slk"}
|
||||||
|
SLOVENIAN = {"name": "Slovenian", "iso639_1": "sl", "iso639_2": "slv"}
|
||||||
|
SOMALI = {"name": "Somali", "iso639_1": "so", "iso639_2": "som"}
|
||||||
|
SOUTHERN_SOTHO = {"name": "Southern Sotho", "iso639_1": "st", "iso639_2": "sot"}
|
||||||
|
SPANISH = {"name": "Spanish", "iso639_1": "es", "iso639_2": "spa"}
|
||||||
|
SUNDANESE = {"name": "Sundanese", "iso639_1": "su", "iso639_2": "sun"}
|
||||||
|
SWAHILI = {"name": "Swahili", "iso639_1": "sw", "iso639_2": "swa"}
|
||||||
|
SWATI = {"name": "Swati", "iso639_1": "ss", "iso639_2": "ssw"}
|
||||||
|
SWEDISH = {"name": "Swedish", "iso639_1": "sv", "iso639_2": "swe"}
|
||||||
|
TAGALOG = {"name": "Tagalog", "iso639_1": "tl", "iso639_2": "tgl"}
|
||||||
|
TAMIL = {"name": "Tamil", "iso639_1": "ta", "iso639_2": "tam"}
|
||||||
|
THAI = {"name": "Thai", "iso639_1": "th", "iso639_2": "tha"}
|
||||||
|
TURKISH = {"name": "Turkish", "iso639_1": "tr", "iso639_2": "tur"}
|
||||||
|
UKRAINIAN = {"name": "Ukrainian", "iso639_1": "uk", "iso639_2": "ukr"}
|
||||||
|
URDU = {"name": "Urdu", "iso639_1": "ur", "iso639_2": "urd"}
|
||||||
|
VIETNAMESE = {"name": "Vietnamese", "iso639_1": "vi", "iso639_2": "vie"}
|
||||||
|
WELSH = {"name": "Welsh", "iso639_1": "cy", "iso639_2": "wel"}
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def find(label : str):
|
||||||
|
|
||||||
|
closestMatches = difflib.get_close_matches(label, [l.value["name"] for l in IsoLanguage], n=1)
|
||||||
|
|
||||||
|
if closestMatches:
|
||||||
|
foundLangs = [l for l in IsoLanguage if l.value['name'] == closestMatches[0]]
|
||||||
|
return foundLangs[0] if foundLangs else None
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def findThreeLetter(theeLetter : str):
|
||||||
|
foundLangs = [l for l in IsoLanguage if l.value['iso639_2'] == str(theeLetter)]
|
||||||
|
return foundLangs[0] if foundLangs else None
|
||||||
|
|
||||||
|
|
||||||
|
# def get(lang : str):
|
||||||
|
#
|
||||||
|
# selectedLangs = [l for l in IsoLanguage if l.value['iso639_2'] == lang]
|
||||||
|
#
|
||||||
|
# if selectedLangs:
|
||||||
|
# return selectedLangs[0]
|
||||||
|
# else:
|
||||||
|
# return None
|
||||||
|
|
||||||
|
def label(self):
|
||||||
|
return str(self.value['name'])
|
||||||
|
|
||||||
|
def twoLetter(self):
|
||||||
|
return str(self.value['iso639_1'])
|
||||||
|
|
||||||
|
def threeLetter(self):
|
||||||
|
return str(self.value['iso639_2'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
30
bin/ffx/model/tag.py
Normal file
30
bin/ffx/model/tag.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# from typing import List
|
||||||
|
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, Enum
|
||||||
|
from sqlalchemy.orm import relationship, declarative_base, sessionmaker
|
||||||
|
|
||||||
|
from .show import Base
|
||||||
|
|
||||||
|
from ffx.track_type import TrackType
|
||||||
|
|
||||||
|
|
||||||
|
class Tag(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__ = 'tags'
|
||||||
|
|
||||||
|
# v1.x
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
|
||||||
|
key = Column(String)
|
||||||
|
value = Column(String)
|
||||||
|
|
||||||
|
# v1.x
|
||||||
|
track_id = Column(Integer, ForeignKey('tracks.id', ondelete="CASCADE"))
|
||||||
|
track = relationship('Track', back_populates='tags')
|
||||||
@@ -1,11 +1,16 @@
|
|||||||
# from typing import List
|
# from typing import List
|
||||||
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, Enum
|
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
|
||||||
from sqlalchemy.orm import relationship, declarative_base, sessionmaker
|
from sqlalchemy.orm import relationship, declarative_base, sessionmaker
|
||||||
|
|
||||||
from .show import Base
|
from .show import Base
|
||||||
|
|
||||||
from ffx.track_type import TrackType
|
from ffx.track_type import TrackType
|
||||||
|
|
||||||
|
from ffx.iso_language import IsoLanguage
|
||||||
|
|
||||||
|
from ffx.model.tag import Tag
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Track(Base):
|
class Track(Base):
|
||||||
"""
|
"""
|
||||||
@@ -20,11 +25,21 @@ class Track(Base):
|
|||||||
__tablename__ = 'tracks'
|
__tablename__ = 'tracks'
|
||||||
|
|
||||||
# v1.x
|
# v1.x
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True, autoincrement = True)
|
||||||
|
|
||||||
track_type = Column(Enum[TrackType])
|
# P=pattern_id+sub_index+track_type
|
||||||
|
track_type = Column(Integer) # TrackType
|
||||||
|
sub_index = Column(Integer)
|
||||||
|
|
||||||
# v1.x
|
# v1.x
|
||||||
pattern_id = Column(Integer, ForeignKey('patterns.id', ondelete="CASCADE"))
|
pattern_id = Column(Integer, ForeignKey('patterns.id', ondelete="CASCADE"))
|
||||||
pattern = relationship('Pattern', back_populates='tracks')
|
pattern = relationship('Pattern', back_populates='tracks')
|
||||||
|
|
||||||
|
|
||||||
|
language = Column(String) # IsoLanguage threeLetter
|
||||||
|
title = Column(String)
|
||||||
|
|
||||||
|
tags = relationship('Tag', back_populates='track', cascade="all, delete")
|
||||||
|
|
||||||
|
|
||||||
|
disposition_flags = Column(Integer)
|
||||||
|
|||||||
@@ -11,12 +11,16 @@ from ffx.model.pattern import Pattern
|
|||||||
|
|
||||||
from .pattern_controller import PatternController
|
from .pattern_controller import PatternController
|
||||||
from .show_controller import ShowController
|
from .show_controller import ShowController
|
||||||
|
from .track_controller import TrackController
|
||||||
|
|
||||||
from .track_details_screen import TrackDetailsScreen
|
from .track_details_screen import TrackDetailsScreen
|
||||||
from .track_delete_screen import TrackDeleteScreen
|
from .track_delete_screen import TrackDeleteScreen
|
||||||
|
|
||||||
from ffx.track_type import TrackType
|
from ffx.track_type import TrackType
|
||||||
|
|
||||||
|
from ffx.track_disposition import TrackDisposition
|
||||||
|
|
||||||
|
|
||||||
# Screen[dict[int, str, int]]
|
# Screen[dict[int, str, int]]
|
||||||
class PatternDetailsScreen(Screen):
|
class PatternDetailsScreen(Screen):
|
||||||
|
|
||||||
@@ -71,23 +75,29 @@ class PatternDetailsScreen(Screen):
|
|||||||
|
|
||||||
self.__pc = PatternController(context = self.context)
|
self.__pc = PatternController(context = self.context)
|
||||||
self.__sc = ShowController(context = self.context)
|
self.__sc = ShowController(context = self.context)
|
||||||
|
self.__tc = TrackController(context = self.context)
|
||||||
|
|
||||||
self.pattern_obj = self.__pc.getPatternDescriptor(patternId) if patternId is not None else {}
|
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.show_obj = self.__sc.getShowDesciptor(showId) if showId is not None else {}
|
||||||
|
|
||||||
|
|
||||||
# def loadPatterns(self, show_id):
|
def loadTracks(self, show_id):
|
||||||
#
|
|
||||||
# try:
|
try:
|
||||||
# s = self.Session()
|
|
||||||
# q = s.query(Pattern).filter(Pattern.show_id == int(show_id))
|
tracks = {}
|
||||||
#
|
tracks['audio'] = {}
|
||||||
# return [{'id': int(p.id), 'pattern': p.pattern} for p in q.all()]
|
tracks['subtitle'] = {}
|
||||||
#
|
|
||||||
# except Exception as ex:
|
s = self.Session()
|
||||||
# click.ClickException(f"loadPatterns(): {repr(ex)}")
|
q = s.query(Pattern).filter(Pattern.show_id == int(show_id))
|
||||||
# finally:
|
|
||||||
# s.close()
|
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):
|
def on_mount(self):
|
||||||
@@ -98,18 +108,38 @@ class PatternDetailsScreen(Screen):
|
|||||||
if self.show_obj:
|
if self.show_obj:
|
||||||
self.query_one("#showlabel", Static).update(f"{self.show_obj['id']} - {self.show_obj['name']} ({self.show_obj['year']})")
|
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))
|
|
||||||
|
|
||||||
|
if self.pattern_obj:
|
||||||
|
|
||||||
for subIndex in range(3):
|
trackIds = self.__tc.findAllTracks(self.pattern_obj['id'])
|
||||||
|
|
||||||
row4 = (str(subIndex),str(subIndex),str(subIndex),str(subIndex),)
|
for audioTrackId in trackIds['audio']:
|
||||||
self.audioStreamsTable.add_row(*map(str, row4))
|
|
||||||
|
|
||||||
row5 = (str(subIndex),str(subIndex),str(subIndex),str(subIndex),str(subIndex),)
|
ad = self.__tc.getTrackDescriptor(audioTrackId)
|
||||||
self.subtitleStreamsTable.add_row(*map(str, row5))
|
dispoList = ad['disposition_list']
|
||||||
|
|
||||||
|
row = (ad['sub_index'],
|
||||||
|
" ",
|
||||||
|
ad['language'].label(),
|
||||||
|
ad['title'],
|
||||||
|
'Yes' if TrackDisposition.DEFAULT in dispoList else 'No',
|
||||||
|
'Yes' if TrackDisposition.FORCED in dispoList else 'No')
|
||||||
|
|
||||||
|
self.audioStreamsTable.add_row(*map(str, row))
|
||||||
|
|
||||||
|
for subtitleTrackId in trackIds['subtitle']:
|
||||||
|
|
||||||
|
sd = self.__tc.getTrackDescriptor(subtitleTrackId)
|
||||||
|
dispoList = sd['disposition_list']
|
||||||
|
|
||||||
|
row = (sd['sub_index'],
|
||||||
|
" ",
|
||||||
|
sd['language'].label(),
|
||||||
|
sd['title'],
|
||||||
|
'Yes' if TrackDisposition.DEFAULT in dispoList else 'No',
|
||||||
|
'Yes' if TrackDisposition.FORCED in dispoList else 'No')
|
||||||
|
|
||||||
|
self.subtitleStreamsTable.add_row(*map(str, row))
|
||||||
|
|
||||||
|
|
||||||
def compose(self):
|
def compose(self):
|
||||||
@@ -117,10 +147,12 @@ class PatternDetailsScreen(Screen):
|
|||||||
self.audioStreamsTable = DataTable(classes="five")
|
self.audioStreamsTable = DataTable(classes="five")
|
||||||
|
|
||||||
# Define the columns with headers
|
# Define the columns with headers
|
||||||
self.column_key_audio_subid = self.audioStreamsTable.add_column("Subindex", width=10)
|
self.column_key_audio_subid = self.audioStreamsTable.add_column("Subindex", width=20)
|
||||||
self.column_key_audio_layout = self.audioStreamsTable.add_column("Layout", width=10)
|
self.column_key_audio_layout = self.audioStreamsTable.add_column("Layout", width=20)
|
||||||
self.column_key_audio_language = self.audioStreamsTable.add_column("Language", width=10)
|
self.column_key_audio_language = self.audioStreamsTable.add_column("Language", width=20)
|
||||||
self.column_key_audio_title = self.audioStreamsTable.add_column("Title", width=10)
|
self.column_key_audio_title = self.audioStreamsTable.add_column("Title", width=30)
|
||||||
|
self.column_key_subtitle_default = self.audioStreamsTable.add_column("Default", width=10)
|
||||||
|
self.column_key_subtitle_forced = self.audioStreamsTable.add_column("Forced", width=10)
|
||||||
|
|
||||||
self.audioStreamsTable.cursor_type = 'row'
|
self.audioStreamsTable.cursor_type = 'row'
|
||||||
|
|
||||||
@@ -128,9 +160,10 @@ class PatternDetailsScreen(Screen):
|
|||||||
self.subtitleStreamsTable = DataTable(classes="five")
|
self.subtitleStreamsTable = DataTable(classes="five")
|
||||||
|
|
||||||
# Define the columns with headers
|
# Define the columns with headers
|
||||||
self.column_key_subtitle_subid = self.subtitleStreamsTable.add_column("Subindex", width=10)
|
self.column_key_subtitle_subid = self.subtitleStreamsTable.add_column("Subindex", width=20)
|
||||||
self.column_key_subtitle_language = self.subtitleStreamsTable.add_column("Language", width=10)
|
self.column_key_subtitle_spacer = self.subtitleStreamsTable.add_column(" ", width=20)
|
||||||
self.column_key_subtitle_title = self.subtitleStreamsTable.add_column("Title", width=10)
|
self.column_key_subtitle_language = self.subtitleStreamsTable.add_column("Language", width=20)
|
||||||
|
self.column_key_subtitle_title = self.subtitleStreamsTable.add_column("Title", width=30)
|
||||||
self.column_key_subtitle_default = self.subtitleStreamsTable.add_column("Default", 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.column_key_subtitle_forced = self.subtitleStreamsTable.add_column("Forced", width=10)
|
||||||
|
|
||||||
@@ -157,9 +190,15 @@ class PatternDetailsScreen(Screen):
|
|||||||
# 5
|
# 5
|
||||||
yield Static("Audio streams")
|
yield Static("Audio streams")
|
||||||
yield Static(" ")
|
yield Static(" ")
|
||||||
|
|
||||||
|
if self.pattern_obj:
|
||||||
yield Button("Add", id="button_add_audio_stream")
|
yield Button("Add", id="button_add_audio_stream")
|
||||||
yield Button("Edit", id="button_edit_audio_stream")
|
yield Button("Edit", id="button_edit_audio_stream")
|
||||||
yield Button("Delete", id="button_delete_audio_stream")
|
yield Button("Delete", id="button_delete_audio_stream")
|
||||||
|
else:
|
||||||
|
yield Static("")
|
||||||
|
yield Static("")
|
||||||
|
yield Static("")
|
||||||
# 6
|
# 6
|
||||||
yield self.audioStreamsTable
|
yield self.audioStreamsTable
|
||||||
|
|
||||||
@@ -169,9 +208,15 @@ class PatternDetailsScreen(Screen):
|
|||||||
# 8
|
# 8
|
||||||
yield Static("Subtitle streams")
|
yield Static("Subtitle streams")
|
||||||
yield Static(" ")
|
yield Static(" ")
|
||||||
|
|
||||||
|
if self.pattern_obj:
|
||||||
yield Button("Add", id="button_add_subtitle_stream")
|
yield Button("Add", id="button_add_subtitle_stream")
|
||||||
yield Button("Edit", id="button_edit_subtitle_stream")
|
yield Button("Edit", id="button_edit_subtitle_stream")
|
||||||
yield Button("Delete", id="button_delete_subtitle_stream")
|
yield Button("Delete", id="button_delete_subtitle_stream")
|
||||||
|
else:
|
||||||
|
yield Static("")
|
||||||
|
yield Static("")
|
||||||
|
yield Static("")
|
||||||
# 9
|
# 9
|
||||||
yield self.subtitleStreamsTable
|
yield self.subtitleStreamsTable
|
||||||
|
|
||||||
@@ -211,24 +256,51 @@ class PatternDetailsScreen(Screen):
|
|||||||
self.app.pop_screen()
|
self.app.pop_screen()
|
||||||
|
|
||||||
|
|
||||||
|
# Save pattern when just created before adding streams
|
||||||
|
if self.pattern_obj:
|
||||||
|
|
||||||
if event.button.id == "button_add_audio_stream":
|
if event.button.id == "button_add_audio_stream":
|
||||||
self.app.push_screen(TrackDetailsScreen(TrackType.AUDIO), self.handle_add_stream)
|
self.app.push_screen(TrackDetailsScreen(trackType = TrackType.AUDIO, patternId = self.pattern_obj['id'], subIndex = len(self.audioStreamsTable.rows)), self.handle_add_stream)
|
||||||
if event.button.id == "button_edit_audio_stream":
|
if event.button.id == "button_edit_audio_stream":
|
||||||
self.app.push_screen(TrackDetailsScreen(TrackType.AUDIO), self.handle_edit_stream)
|
self.app.push_screen(TrackDetailsScreen(trackType = TrackType.AUDIO, patternId = self.pattern_obj['id']), self.handle_edit_stream)
|
||||||
if event.button.id == "button_delete_audio_stream":
|
if event.button.id == "button_delete_audio_stream":
|
||||||
self.app.push_screen(TrackDeleteScreen(TrackType.AUDIO), self.handle_delete_stream)
|
self.app.push_screen(TrackDeleteScreen(trackType = TrackType.AUDIO, patternId = self.pattern_obj['id']), self.handle_delete_stream)
|
||||||
|
|
||||||
if event.button.id == "button_add_subtitle_stream":
|
if event.button.id == "button_add_subtitle_stream":
|
||||||
self.app.push_screen(TrackDetailsScreen(TrackType.SUBTITLE), self.handle_add_stream)
|
self.app.push_screen(TrackDetailsScreen(trackType = TrackType.SUBTITLE, patternId = self.pattern_obj['id'], subIndex = len(self.subtitleStreamsTable.rows)), self.handle_add_stream)
|
||||||
if event.button.id == "button_edit_subtitle_stream":
|
if event.button.id == "button_edit_subtitle_stream":
|
||||||
self.app.push_screen(TrackDetailsScreen(TrackType.SUBTITLE), self.handle_edit_stream)
|
self.app.push_screen(TrackDetailsScreen(trackType = TrackType.SUBTITLE, patternId = self.pattern_obj['id']), self.handle_edit_stream)
|
||||||
if event.button.id == "button_delete_subtitle_stream":
|
if event.button.id == "button_delete_subtitle_stream":
|
||||||
self.app.push_screen(TrackDeleteScreen(TrackType.SUBTITLE), self.handle_delete_stream)
|
self.app.push_screen(TrackDeleteScreen(trackType = TrackType.SUBTITLE, patternId = self.pattern_obj['id']), self.handle_delete_stream)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_add_stream(self, trackDescriptor):
|
||||||
|
|
||||||
|
dispoList = trackDescriptor['disposition_list']
|
||||||
|
|
||||||
|
if trackDescriptor['type'] == TrackType.AUDIO:
|
||||||
|
|
||||||
|
row = (trackDescriptor['sub_index'],
|
||||||
|
" ",
|
||||||
|
trackDescriptor['language'].label(),
|
||||||
|
trackDescriptor['title'],
|
||||||
|
'Yes' if TrackDisposition.DEFAULT in dispoList else 'No',
|
||||||
|
'Yes' if TrackDisposition.FORCED in dispoList else 'No')
|
||||||
|
|
||||||
|
self.audioStreamsTable.add_row(*map(str, row))
|
||||||
|
|
||||||
|
if trackDescriptor['type'] == TrackType.SUBTITLE:
|
||||||
|
|
||||||
|
row = (trackDescriptor['sub_index'],
|
||||||
|
" ",
|
||||||
|
trackDescriptor['language'].label(),
|
||||||
|
trackDescriptor['title'],
|
||||||
|
'Yes' if TrackDisposition.DEFAULT in dispoList else 'No',
|
||||||
|
'Yes' if TrackDisposition.FORCED in dispoList else 'No')
|
||||||
|
|
||||||
|
self.subtitleStreamsTable.add_row(*map(str, row))
|
||||||
|
|
||||||
|
|
||||||
def handle_add_stream(self):
|
|
||||||
pass
|
|
||||||
def handle_edit_stream(self):
|
def handle_edit_stream(self):
|
||||||
pass
|
pass
|
||||||
def handle_delete_stream(self):
|
def handle_delete_stream(self):
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ from textual.app import App, ComposeResult
|
|||||||
from textual.screen import Screen
|
from textual.screen import Screen
|
||||||
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input
|
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input
|
||||||
from textual.containers import Grid, Horizontal
|
from textual.containers import Grid, Horizontal
|
||||||
|
from textual.widgets._data_table import CellDoesNotExist
|
||||||
|
|
||||||
|
|
||||||
from ffx.model.show import Show
|
from ffx.model.show import Show
|
||||||
from ffx.model.pattern import Pattern
|
from ffx.model.pattern import Pattern
|
||||||
@@ -21,9 +23,9 @@ class ShowDetailsScreen(Screen):
|
|||||||
CSS = """
|
CSS = """
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
grid-size: 2;
|
grid-size: 2 14;
|
||||||
grid-rows: 2 auto;
|
grid-rows: 2 2 2 2 2 2 2 2 2 2 2 6 2 2;
|
||||||
grid-columns: 30 330;
|
grid-columns: 30 90;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 1;
|
padding: 1;
|
||||||
@@ -114,11 +116,14 @@ class ShowDetailsScreen(Screen):
|
|||||||
|
|
||||||
def getSelectedPattern(self):
|
def getSelectedPattern(self):
|
||||||
|
|
||||||
|
selectedPattern = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
# Fetch the currently selected row when 'Enter' is pressed
|
# Fetch the currently selected row when 'Enter' is pressed
|
||||||
#selected_row_index = self.table.cursor_row
|
#selected_row_index = self.table.cursor_row
|
||||||
row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate)
|
row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate)
|
||||||
|
|
||||||
selectedPattern = {}
|
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
selected_row_data = self.patternTable.get_row(row_key)
|
selected_row_data = self.patternTable.get_row(row_key)
|
||||||
@@ -126,10 +131,15 @@ class ShowDetailsScreen(Screen):
|
|||||||
selectedPattern['pattern'] = str(selected_row_data[0])
|
selectedPattern['pattern'] = str(selected_row_data[0])
|
||||||
#selectedPattern['pattern'] = selected_row_data[1]
|
#selectedPattern['pattern'] = selected_row_data[1]
|
||||||
|
|
||||||
|
except CellDoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
return selectedPattern
|
return selectedPattern
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def action_add_pattern(self):
|
def action_add_pattern(self):
|
||||||
if self.show_obj:
|
if self.show_obj:
|
||||||
self.app.push_screen(PatternDetailsScreen(showId = self.show_obj['id']), self.handle_add_pattern)
|
self.app.push_screen(PatternDetailsScreen(showId = self.show_obj['id']), self.handle_add_pattern)
|
||||||
@@ -186,7 +196,7 @@ class ShowDetailsScreen(Screen):
|
|||||||
self.patternTable = DataTable(classes="two")
|
self.patternTable = DataTable(classes="two")
|
||||||
|
|
||||||
# Define the columns with headers
|
# Define the columns with headers
|
||||||
self.column_key_id = self.patternTable.add_column("Pattern", width=60)
|
self.column_key_id = self.patternTable.add_column("Pattern", width=90)
|
||||||
#self.column_key_name = self.patternTable.add_column("Name", width=50)
|
#self.column_key_name = self.patternTable.add_column("Name", width=50)
|
||||||
#self.column_key_year = self.patternTable.add_column("Year", width=10)
|
#self.column_key_year = self.patternTable.add_column("Year", width=10)
|
||||||
|
|
||||||
@@ -197,36 +207,55 @@ class ShowDetailsScreen(Screen):
|
|||||||
|
|
||||||
with Grid():
|
with Grid():
|
||||||
|
|
||||||
|
# 1
|
||||||
yield Static("Show" if self.show_obj else "New Show", id="toplabel", classes="two")
|
yield Static("Show" if self.show_obj else "New Show", id="toplabel", classes="two")
|
||||||
|
|
||||||
|
# 2
|
||||||
yield Static("ID")
|
yield Static("ID")
|
||||||
if self.show_obj:
|
if self.show_obj:
|
||||||
yield Static("", id="id_wdg")
|
yield Static("", id="id_wdg")
|
||||||
else:
|
else:
|
||||||
yield Input(type="integer", id="id_wdg")
|
yield Input(type="integer", id="id_wdg")
|
||||||
|
|
||||||
|
# 3
|
||||||
yield Static("Name")
|
yield Static("Name")
|
||||||
yield Input(type="text", id="name_input")
|
yield Input(type="text", id="name_input")
|
||||||
|
|
||||||
|
# 4
|
||||||
yield Static("Year")
|
yield Static("Year")
|
||||||
yield Input(type="integer", id="year_input")
|
yield Input(type="integer", id="year_input")
|
||||||
|
|
||||||
|
#5
|
||||||
yield Static(" ", classes="two")
|
yield Static(" ", classes="two")
|
||||||
|
|
||||||
|
#6
|
||||||
yield Static("Index Season Digits")
|
yield Static("Index Season Digits")
|
||||||
yield Input(type="integer", id="index_season_digits_input")
|
yield Input(type="integer", id="index_season_digits_input")
|
||||||
|
|
||||||
|
#7
|
||||||
yield Static("Index Episode Digits")
|
yield Static("Index Episode Digits")
|
||||||
yield Input(type="integer", id="index_episode_digits_input")
|
yield Input(type="integer", id="index_episode_digits_input")
|
||||||
|
|
||||||
|
#8
|
||||||
yield Static("Indicator Season Digits")
|
yield Static("Indicator Season Digits")
|
||||||
yield Input(type="integer", id="indicator_season_digits_input")
|
yield Input(type="integer", id="indicator_season_digits_input")
|
||||||
|
|
||||||
|
#9
|
||||||
yield Static("Indicator Edisode Digits")
|
yield Static("Indicator Edisode Digits")
|
||||||
yield Input(type="integer", id="indicator_episode_digits_input")
|
yield Input(type="integer", id="indicator_episode_digits_input")
|
||||||
|
|
||||||
|
# 10
|
||||||
yield Static(" ", classes="two")
|
yield Static(" ", classes="two")
|
||||||
|
|
||||||
|
# 11
|
||||||
|
yield Static("File patterns", classes="two")
|
||||||
|
# 12
|
||||||
yield self.patternTable
|
yield self.patternTable
|
||||||
|
|
||||||
|
# 13
|
||||||
yield Static(" ", classes="two")
|
yield Static(" ", classes="two")
|
||||||
|
|
||||||
|
# 14
|
||||||
yield Button("Save", id="save_button")
|
yield Button("Save", id="save_button")
|
||||||
yield Button("Cancel", id="cancel_button")
|
yield Button("Cancel", id="cancel_button")
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ import click
|
|||||||
|
|
||||||
from ffx.model.track import Track
|
from ffx.model.track import Track
|
||||||
|
|
||||||
|
from .track_type import TrackType
|
||||||
|
|
||||||
|
from .track_disposition import TrackDisposition
|
||||||
|
from .iso_language import IsoLanguage
|
||||||
|
|
||||||
|
|
||||||
class TrackController():
|
class TrackController():
|
||||||
|
|
||||||
@@ -11,82 +16,151 @@ class TrackController():
|
|||||||
self.Session = self.context['database_session'] # convenience
|
self.Session = self.context['database_session'] # convenience
|
||||||
|
|
||||||
|
|
||||||
# def updatePattern(self, show_id, pattern):
|
def addTrack(self, trackDescriptor):
|
||||||
|
|
||||||
|
try:
|
||||||
|
s = self.Session()
|
||||||
|
|
||||||
|
track = Track(pattern_id = int(trackDescriptor['pattern_id']),
|
||||||
|
|
||||||
|
track_type = int(trackDescriptor['type'].value),
|
||||||
|
|
||||||
|
sub_index = int(trackDescriptor['sub_index']),
|
||||||
|
|
||||||
|
language = str(trackDescriptor['language'].threeLetter()),
|
||||||
|
|
||||||
|
title = str(trackDescriptor['title']),
|
||||||
|
|
||||||
|
disposition_flags = int(TrackDisposition.toFlags(trackDescriptor['disposition_list'])))
|
||||||
|
|
||||||
|
s.add(track)
|
||||||
|
s.commit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
raise click.ClickException(f"TrackController.addTrack(): {repr(ex)}")
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
|
# def updateTrack(self, trackDescriptor):
|
||||||
#
|
#
|
||||||
# try:
|
# try:
|
||||||
# s = self.Session()
|
# s = self.Session()
|
||||||
# q = s.query(Pattern).filter(Pattern.show_id == int(show_id), Pattern.pattern == str(pattern))
|
# q = s.query(Track).filter(Track.id == int(trackId))
|
||||||
#
|
#
|
||||||
# if not q.count():
|
# if not q.count():
|
||||||
# pattern = Pattern(show_id = int(show_id), pattern = str(pattern))
|
# track = Track(pattern_id = int(trackDescriptor['pattern_id']),
|
||||||
# s.add(pattern)
|
# track_type = TrackType(trackDescriptor['type']),
|
||||||
|
# sub_index = int(trackDescriptor['sub_index']),
|
||||||
|
# language = IsoLanguage(trackDescriptor['language']),
|
||||||
|
# title = str(trackDescriptor['title']),
|
||||||
|
# disposition_flags = TrackDisposition.toFlags(trackDescriptor['disposition_list']))
|
||||||
|
# s.add(track)
|
||||||
# s.commit()
|
# s.commit()
|
||||||
# return True
|
# 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:
|
# 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
|
# return False
|
||||||
#
|
#
|
||||||
# except Exception as ex:
|
# except Exception as ex:
|
||||||
# raise click.ClickException(f"PatternController.deletePattern(): {repr(ex)}")
|
# raise click.ClickException(f"TrackController.updateTrack(): {repr(ex)}")
|
||||||
# finally:
|
# finally:
|
||||||
# s.close()
|
# s.close()
|
||||||
|
|
||||||
|
|
||||||
|
def findAllTracks(self, patternId):
|
||||||
|
|
||||||
|
try:
|
||||||
|
s = self.Session()
|
||||||
|
|
||||||
|
trackDescriptors = {}
|
||||||
|
trackDescriptors['audio'] = []
|
||||||
|
trackDescriptors['subtitle'] = []
|
||||||
|
|
||||||
|
q_audio = s.query(Track).filter(Track.pattern_id == int(patternId), Track.track_type == TrackType.AUDIO.value)
|
||||||
|
|
||||||
|
for audioTrack in q_audio.all():
|
||||||
|
trackDescriptors['audio'].append(audioTrack.id)
|
||||||
|
|
||||||
|
q_subtitle = s.query(Track).filter(Track.pattern_id == int(patternId), Track.track_type == TrackType.SUBTITLE.value)
|
||||||
|
for subtitleTrack in q_subtitle.all():
|
||||||
|
trackDescriptors['subtitle'].append(subtitleTrack.id)
|
||||||
|
|
||||||
|
|
||||||
|
return trackDescriptors
|
||||||
|
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
raise click.ClickException(f"TrackController.findAllTracks(): {repr(ex)}")
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
|
def findTrack(self, patternId, trackType, subIndex):
|
||||||
|
|
||||||
|
try:
|
||||||
|
s = self.Session()
|
||||||
|
q = s.query(Track).filter(Track.pattern_id == int(patternId), Track.track_type == trackType, Track.sub_index == int(subIndex))
|
||||||
|
|
||||||
|
if q.count():
|
||||||
|
track = q.first()
|
||||||
|
return int(track.id)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
raise click.ClickException(f"TrackController.findTrack(): {repr(ex)}")
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
|
def getTrackDict(self, track):
|
||||||
|
trackDescriptor = {}
|
||||||
|
trackDescriptor['pattern_id'] = int(track.pattern_id)
|
||||||
|
trackDescriptor['type'] = TrackType(track.track_type)
|
||||||
|
trackDescriptor['sub_index'] = int(track.sub_index)
|
||||||
|
trackDescriptor['language'] = IsoLanguage.findThreeLetter(track.language)
|
||||||
|
trackDescriptor['title'] = str(track.title)
|
||||||
|
trackDescriptor['disposition_list'] = TrackDisposition.toList(track.disposition_flags)
|
||||||
|
return trackDescriptor
|
||||||
|
|
||||||
|
|
||||||
|
def getTrackDescriptor(self, trackId):
|
||||||
|
|
||||||
|
try:
|
||||||
|
s = self.Session()
|
||||||
|
q = s.query(Track).filter(Track.id == int(trackId))
|
||||||
|
|
||||||
|
if q.count():
|
||||||
|
track = q.first()
|
||||||
|
return self.getTrackDict(track)
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
raise click.ClickException(f"TrackController.getTrackDescriptor(): {repr(ex)}")
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
|
def deleteTrack(self, trackId):
|
||||||
|
try:
|
||||||
|
s = self.Session()
|
||||||
|
q = s.query(Track).filter(Track.id == int(trackId))
|
||||||
|
|
||||||
|
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"TrackController.deleteTrack(): {repr(ex)}")
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
import click
|
import click, time
|
||||||
|
|
||||||
from textual import events
|
from textual import events
|
||||||
from textual.app import App, ComposeResult
|
from textual.app import App, ComposeResult
|
||||||
from textual.screen import Screen
|
from textual.screen import Screen
|
||||||
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input
|
from textual.widgets import Header, Footer, Placeholder, Label, ListView, ListItem, Static, DataTable, Button, Input, Checkbox, SelectionList, Select
|
||||||
from textual.containers import Grid, Horizontal
|
from textual.containers import Grid, Horizontal
|
||||||
|
|
||||||
|
|
||||||
from ffx.model.show import Show
|
from ffx.model.show import Show
|
||||||
from ffx.model.pattern import Pattern
|
from ffx.model.pattern import Pattern
|
||||||
|
|
||||||
from .track_controller import TrackController
|
from .track_controller import TrackController
|
||||||
# from .pattern_controller import PatternController
|
from .pattern_controller import PatternController
|
||||||
# from .show_controller import ShowController
|
# from .show_controller import ShowController
|
||||||
|
|
||||||
from .track_type import TrackType
|
from .track_type import TrackType
|
||||||
|
|
||||||
|
from .iso_language import IsoLanguage
|
||||||
|
from .track_disposition import TrackDisposition
|
||||||
|
|
||||||
|
|
||||||
# Screen[dict[int, str, int]]
|
# Screen[dict[int, str, int]]
|
||||||
class TrackDetailsScreen(Screen):
|
class TrackDetailsScreen(Screen):
|
||||||
@@ -22,8 +26,8 @@ class TrackDetailsScreen(Screen):
|
|||||||
CSS = """
|
CSS = """
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
grid-size: 5 11;
|
grid-size: 5 18;
|
||||||
grid-rows: 2 2 2 2 6 2 2 6 2 2 2;
|
grid-rows: 2 2 2 2 2 3 2 2 2 2 2 6 2 2 6 2 2 2;
|
||||||
grid-columns: 25 25 25 25 25;
|
grid-columns: 25 25 25 25 25;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -36,7 +40,13 @@ class TrackDetailsScreen(Screen):
|
|||||||
Button {
|
Button {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
SelectionList {
|
||||||
|
border: none;
|
||||||
|
min-height: 6;
|
||||||
|
}
|
||||||
|
Select {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
DataTable {
|
DataTable {
|
||||||
min-height: 6;
|
min-height: 6;
|
||||||
}
|
}
|
||||||
@@ -45,6 +55,9 @@ class TrackDetailsScreen(Screen):
|
|||||||
height: 1;
|
height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.two {
|
||||||
|
column-span: 2;
|
||||||
|
}
|
||||||
.three {
|
.three {
|
||||||
column-span: 3;
|
column-span: 3;
|
||||||
}
|
}
|
||||||
@@ -62,21 +75,25 @@ class TrackDetailsScreen(Screen):
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, trackType : TrackType, streamId = None, patternId = None):
|
def __init__(self, trackId = None, patternId = None, trackType : TrackType = None, subIndex = None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.context = self.app.getContext()
|
self.context = self.app.getContext()
|
||||||
self.Session = self.context['database_session'] # convenience
|
self.Session = self.context['database_session'] # convenience
|
||||||
|
|
||||||
self.trackType = trackType
|
|
||||||
|
|
||||||
self.__tc = TrackController(context = self.context)
|
self.__tc = TrackController(context = self.context)
|
||||||
#self.__pc = PatternController(context = self.context)
|
self.__pc = PatternController(context = self.context)
|
||||||
#self.__sc = ShowController(context = self.context)
|
|
||||||
|
self.track_obj = self.__tc.getTrackDescriptor(trackId) if trackId is not None else {} #TODO: Overwriting alternative values if set
|
||||||
|
|
||||||
|
if trackType is None:
|
||||||
|
raise click.ClickException('Track type is required to be set')
|
||||||
|
|
||||||
|
self.trackType = trackType
|
||||||
|
self.subIndex = subIndex
|
||||||
|
|
||||||
|
self.pattern_obj = self.__pc.getPatternDescriptor(patternId) if patternId is not None else {}
|
||||||
|
|
||||||
# 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):
|
# def loadPatterns(self, show_id):
|
||||||
#
|
#
|
||||||
@@ -93,9 +110,12 @@ class TrackDetailsScreen(Screen):
|
|||||||
|
|
||||||
|
|
||||||
def on_mount(self):
|
def on_mount(self):
|
||||||
pass
|
|
||||||
# if self.pattern_obj:
|
if self.pattern_obj:
|
||||||
# self.query_one("#pattern_input", Input).value = str(self.pattern_obj['pattern'])
|
self.query_one("#patternlabel", Static).update(str(self.pattern_obj['pattern']))
|
||||||
|
|
||||||
|
if self.subIndex is not None:
|
||||||
|
self.query_one("#subindexlabel", Static).update(str(self.subIndex))
|
||||||
|
|
||||||
# if self.show_obj:
|
# if self.show_obj:
|
||||||
# self.query_one("#showlabel", Static).update(f"{self.show_obj['id']} - {self.show_obj['name']} ({self.show_obj['year']})")
|
# self.query_one("#showlabel", Static).update(f"{self.show_obj['id']} - {self.show_obj['name']} ({self.show_obj['year']})")
|
||||||
@@ -116,27 +136,19 @@ class TrackDetailsScreen(Screen):
|
|||||||
|
|
||||||
def compose(self):
|
def compose(self):
|
||||||
|
|
||||||
# self.audioStreamsTable = DataTable(classes="five")
|
self.trackTagsTable = DataTable(classes="five")
|
||||||
#
|
|
||||||
# # Define the columns with headers
|
# Define the columns with headers
|
||||||
# self.column_key_audio_subid = self.audioStreamsTable.add_column("Subindex", width=10)
|
self.column_key_track_tag_key = self.trackTagsTable.add_column("Key", width=10)
|
||||||
# self.column_key_audio_layout = self.audioStreamsTable.add_column("Layout", width=10)
|
self.column_key_track_tag_value = self.trackTagsTable.add_column("Value", width=30)
|
||||||
# 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.trackTagsTable.cursor_type = 'row'
|
||||||
#
|
|
||||||
# self.audioStreamsTable.cursor_type = 'row'
|
|
||||||
#
|
languages = [l.label() for l in IsoLanguage]
|
||||||
#
|
|
||||||
# self.subtitleStreamsTable = DataTable(classes="five")
|
dispositions = [(d.label(), d.index(), False) for d in TrackDisposition]
|
||||||
#
|
|
||||||
# # 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'
|
|
||||||
|
|
||||||
yield Header()
|
yield Header()
|
||||||
|
|
||||||
@@ -144,69 +156,102 @@ class TrackDetailsScreen(Screen):
|
|||||||
|
|
||||||
# 1
|
# 1
|
||||||
yield Static(f"Edit {self.trackType.label()} stream" if self.track_obj else f"New {self.trackType.label()} stream", id="toplabel", classes="five")
|
yield Static(f"Edit {self.trackType.label()} stream" if self.track_obj else f"New {self.trackType.label()} stream", id="toplabel", classes="five")
|
||||||
# yield Input(type="text", id="pattern_input", classes="four")
|
|
||||||
|
|
||||||
# 2
|
# 2
|
||||||
# yield Static("from show")
|
yield Static("for pattern")
|
||||||
# yield Static("", id="showlabel")
|
yield Static("", id="patternlabel", classes="four")
|
||||||
#
|
|
||||||
# # 3
|
# 3
|
||||||
# yield Static(" ", classes="five")
|
yield Static("sub index")
|
||||||
# # 4
|
yield Static("", id="subindexlabel", classes="four")
|
||||||
# yield Static(" ", classes="five")
|
|
||||||
#
|
# 4
|
||||||
# # 5
|
yield Static(" ", classes="five")
|
||||||
# yield Static("Audio streams")
|
# 5
|
||||||
# yield Static(" ")
|
yield Static(" ", classes="five")
|
||||||
# yield Button("Add", id="button_add_audio_stream")
|
|
||||||
# yield Button("Edit", id="button_edit_audio_stream")
|
# 6
|
||||||
# yield Button("Delete", id="button_delete_audio_stream")
|
yield Static("Language")
|
||||||
# # 6
|
yield Select.from_values(languages, classes="four", id="language_select")
|
||||||
# yield self.audioStreamsTable
|
# 7
|
||||||
#
|
yield Static(" ", classes="five")
|
||||||
# # 7
|
|
||||||
# yield Static(" ", classes="five")
|
# 8
|
||||||
#
|
yield Static("Title")
|
||||||
# # 8
|
yield Input(id="title_input", classes="four")
|
||||||
# yield Static("Subtitle streams")
|
|
||||||
# yield Static(" ")
|
# 9
|
||||||
# yield Button("Add", id="button_add_subtitle_stream")
|
yield Static(" ", classes="five")
|
||||||
# yield Button("Edit", id="button_edit_subtitle_stream")
|
|
||||||
# yield Button("Delete", id="button_delete_subtitle_stream")
|
|
||||||
# # 9
|
|
||||||
# yield self.subtitleStreamsTable
|
|
||||||
#
|
|
||||||
# 10
|
# 10
|
||||||
yield Static(" ", classes="five")
|
yield Static(" ", classes="five")
|
||||||
|
|
||||||
# 11
|
# 11
|
||||||
|
yield Static("Stream tags")
|
||||||
|
yield Static(" ", classes="two")
|
||||||
|
yield Button("Add", id="button_add_stream_tag")
|
||||||
|
yield Button("Delete", id="button_delete_stream_tag")
|
||||||
|
# 12
|
||||||
|
yield self.trackTagsTable
|
||||||
|
|
||||||
|
# 13
|
||||||
|
yield Static(" ", classes="five")
|
||||||
|
|
||||||
|
# 14
|
||||||
|
yield Static("Stream dispositions", classes="five")
|
||||||
|
|
||||||
|
# 15
|
||||||
|
yield SelectionList[int](
|
||||||
|
*dispositions,
|
||||||
|
classes="five",
|
||||||
|
id = "dispositions_selection_list"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 16
|
||||||
|
yield Static(" ", classes="five")
|
||||||
|
# 17
|
||||||
|
yield Static(" ", classes="five")
|
||||||
|
|
||||||
|
# 18
|
||||||
yield Button("Save", id="save_button")
|
yield Button("Save", id="save_button")
|
||||||
yield Button("Cancel", id="cancel_button")
|
yield Button("Cancel", id="cancel_button")
|
||||||
|
|
||||||
yield Footer()
|
yield Footer()
|
||||||
|
|
||||||
|
|
||||||
# def getPatternFromInput(self):
|
def getTrackDescriptorFromInput(self):
|
||||||
# return str(self.query_one("#pattern_input", Input).value)
|
|
||||||
|
trackDescriptor = {}
|
||||||
|
|
||||||
|
trackDescriptor['pattern_id'] = int(self.pattern_obj['id'])
|
||||||
|
|
||||||
|
trackDescriptor['type'] = TrackType(self.trackType)
|
||||||
|
trackDescriptor['sub_index'] = self.subIndex
|
||||||
|
|
||||||
|
trackDescriptor['language'] = IsoLanguage.find(str(self.query_one("#language_select", Select).value))
|
||||||
|
trackDescriptor['title'] = str(self.query_one("#title_input", Input).value)
|
||||||
|
|
||||||
|
|
||||||
|
disposition_flags = sum([2**f for f in self.query_one("#dispositions_selection_list", SelectionList).selected])
|
||||||
|
|
||||||
|
trackDescriptor['disposition_list'] = TrackDisposition.toList(disposition_flags)
|
||||||
|
|
||||||
|
|
||||||
|
return trackDescriptor
|
||||||
|
|
||||||
|
|
||||||
# Event handler for button press
|
# Event handler for button press
|
||||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
# Check if the button pressed is the one we are interested in
|
# Check if the button pressed is the one we are interested in
|
||||||
# if event.button.id == "save_button":
|
if event.button.id == "save_button":
|
||||||
#
|
|
||||||
# pattern = self.getPatternFromInput()
|
trackDescriptor = self.getTrackDescriptorFromInput()
|
||||||
#
|
|
||||||
# if self.__pc.updatePattern(self.show_obj['id'], pattern):
|
if self.__tc.addTrack(trackDescriptor): #!
|
||||||
#
|
self.dismiss(trackDescriptor)
|
||||||
# screenResult = {}
|
else:
|
||||||
# screenResult['show_id'] = self.show_obj['id']
|
#TODO: Meldung
|
||||||
# screenResult['pattern'] = pattern
|
self.app.pop_screen()
|
||||||
#
|
|
||||||
# self.dismiss(screenResult)
|
|
||||||
# else:
|
|
||||||
# #TODO: Meldung
|
|
||||||
# self.app.pop_screen()
|
|
||||||
|
|
||||||
if event.button.id == "cancel_button":
|
if event.button.id == "cancel_button":
|
||||||
self.app.pop_screen()
|
self.app.pop_screen()
|
||||||
|
|||||||
49
bin/ffx/track_disposition.py
Normal file
49
bin/ffx/track_disposition.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
from enum import Enum
|
||||||
|
import difflib
|
||||||
|
|
||||||
|
class TrackDisposition(Enum):
|
||||||
|
|
||||||
|
DEFAULT = {"name": "default", "index": 0}
|
||||||
|
FORCED = {"name": "forced", "index": 1}
|
||||||
|
|
||||||
|
DUB = {"name": "dub", "index": 2}
|
||||||
|
ORIGINAL = {"name": "original", "index": 3}
|
||||||
|
COMMENT = {"name": "comment", "index": 4}
|
||||||
|
LYRICS = {"name": "lyrics", "index": 5}
|
||||||
|
KARAOKE = {"name": "karaoke", "index": 6}
|
||||||
|
HEARING_IMPAIRED = {"name": "hearing_impaired", "index": 7}
|
||||||
|
VISUAL_IMPAIRED = {"name": "visual_impaired", "index": 8}
|
||||||
|
CLEAN_EFFECTS = {"name": "clean_effects", "index": 9}
|
||||||
|
ATTACHED_PIC = {"name": "attached_pic", "index": 10}
|
||||||
|
TIMED_THUMBNAILS = {"name": "timed_thumbnails", "index": 11}
|
||||||
|
NON_DIEGETICS = {"name": "non_diegetic", "index": 12}
|
||||||
|
CAPTIONS = {"name": "captions", "index": 13}
|
||||||
|
DESCRIPTIONS = {"name": "descriptions", "index": 14}
|
||||||
|
METADATA = {"name": "metadata", "index": 15}
|
||||||
|
DEPENDENT = {"name": "dependent", "index": 16}
|
||||||
|
STILL_IMAGE = {"name": "still_image", "index": 17}
|
||||||
|
|
||||||
|
def label(self):
|
||||||
|
return str(self.value['name'])
|
||||||
|
|
||||||
|
def index(self):
|
||||||
|
return int(self.value['index'])
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def toFlags(dispositionList):
|
||||||
|
"""Flags stored in integer bits (2**index)"""
|
||||||
|
|
||||||
|
flags = 0
|
||||||
|
for d in dispositionList:
|
||||||
|
flags += 2 ** d.index()
|
||||||
|
return flags
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def toList(flags):
|
||||||
|
|
||||||
|
dispositionList = []
|
||||||
|
for d in TrackDisposition:
|
||||||
|
if flags & int(2 ** d.index()):
|
||||||
|
dispositionList += [d]
|
||||||
|
return dispositionList
|
||||||
Reference in New Issue
Block a user