Compare commits
5 Commits
51febdfcc0
...
db7700a6b9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db7700a6b9 | ||
|
|
222234f978 | ||
|
|
3672474ff5 | ||
|
|
5ff0fc3fad | ||
|
|
554ca4cc03 |
@@ -39,3 +39,10 @@ Signature, Tags cleaning, Bugfixes, Refactoring
|
|||||||
### 0.2.2
|
### 0.2.2
|
||||||
|
|
||||||
CLI-Overrides
|
CLI-Overrides
|
||||||
|
|
||||||
|
### 0.2.3
|
||||||
|
|
||||||
|
PyPi packaging
|
||||||
|
Templating output filename
|
||||||
|
Season shiftung
|
||||||
|
DB-Versionierung
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "ffx"
|
name = "ffx"
|
||||||
description = "FFX recoding and metadata managing tool"
|
description = "FFX recoding and metadata managing tool"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
license = {file = "LICENSE.md"}
|
license = {file = "LICENSE.md"}
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"requests",
|
"requests",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
VERSION='0.2.2'
|
VERSION='0.2.3'
|
||||||
DATABASE_VERSION = 2
|
DATABASE_VERSION = 2
|
||||||
|
|
||||||
DEFAULT_QUALITY = 32
|
DEFAULT_QUALITY = 32
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from ffx.track_disposition import TrackDisposition
|
|||||||
from ffx.track_codec import TrackCodec
|
from ffx.track_codec import TrackCodec
|
||||||
|
|
||||||
from ffx.process import executeProcess
|
from ffx.process import executeProcess
|
||||||
from ffx.helper import filterFilename
|
from ffx.helper import filterFilename, substituteTmdbFilename
|
||||||
from ffx.helper import getEpisodeFileBasename
|
from ffx.helper import getEpisodeFileBasename
|
||||||
|
|
||||||
from ffx.constants import DEFAULT_STEREO_BANDWIDTH, DEFAULT_AC3_BANDWIDTH, DEFAULT_DTS_BANDWIDTH, DEFAULT_7_1_BANDWIDTH
|
from ffx.constants import DEFAULT_STEREO_BANDWIDTH, DEFAULT_AC3_BANDWIDTH, DEFAULT_DTS_BANDWIDTH, DEFAULT_7_1_BANDWIDTH
|
||||||
@@ -653,9 +653,9 @@ def convert(ctx,
|
|||||||
ctx.obj['logger'].debug(f"tmdbEpisodeResult={tmdbEpisodeResult}")
|
ctx.obj['logger'].debug(f"tmdbEpisodeResult={tmdbEpisodeResult}")
|
||||||
|
|
||||||
if tmdbEpisodeResult:
|
if tmdbEpisodeResult:
|
||||||
filteredEpisodeName = filterFilename(tmdbEpisodeResult['name'])
|
substitutedEpisodeName = filterFilename(substituteTmdbFilename(tmdbEpisodeResult['name']))
|
||||||
sourceFileBasename = getEpisodeFileBasename(showFilenamePrefix,
|
sourceFileBasename = getEpisodeFileBasename(showFilenamePrefix,
|
||||||
filteredEpisodeName,
|
substitutedEpisodeName,
|
||||||
shiftedShowSeason,
|
shiftedShowSeason,
|
||||||
shiftedShowEpisode,
|
shiftedShowEpisode,
|
||||||
indexSeasonDigits,
|
indexSeasonDigits,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import logging
|
import re, logging
|
||||||
|
|
||||||
from jinja2 import Environment, Undefined
|
from jinja2 import Environment, Undefined
|
||||||
from .constants import DEFAULT_OUTPUT_FILENAME_TEMPLATE
|
from .constants import DEFAULT_OUTPUT_FILENAME_TEMPLATE
|
||||||
@@ -78,10 +78,7 @@ def filterFilename(fileName: str) -> str:
|
|||||||
"""This filter replaces charactes from TMDB responses with characters
|
"""This filter replaces charactes from TMDB responses with characters
|
||||||
less problemating when using in filenames or removes them"""
|
less problemating when using in filenames or removes them"""
|
||||||
|
|
||||||
# This appears in TMDB episode names
|
fileName = str(fileName).replace('/', '-')
|
||||||
fileName = str(fileName).replace(' (*)', '')
|
|
||||||
fileName = str(fileName).replace('(*)', '')
|
|
||||||
|
|
||||||
fileName = str(fileName).replace(':', ';')
|
fileName = str(fileName).replace(':', ';')
|
||||||
fileName = str(fileName).replace('*', '')
|
fileName = str(fileName).replace('*', '')
|
||||||
fileName = str(fileName).replace("'", '')
|
fileName = str(fileName).replace("'", '')
|
||||||
@@ -89,6 +86,30 @@ def filterFilename(fileName: str) -> str:
|
|||||||
|
|
||||||
return fileName.strip()
|
return fileName.strip()
|
||||||
|
|
||||||
|
def substituteTmdbFilename(fileName: str) -> str:
|
||||||
|
"""If chaining this method with filterFilename use this one first as the latter will destroy some patterns"""
|
||||||
|
|
||||||
|
# This indicates filler episodes in TMDB episode names
|
||||||
|
fileName = str(fileName).replace(' (*)', '')
|
||||||
|
fileName = str(fileName).replace('(*)', '')
|
||||||
|
|
||||||
|
# This indicates the index of multi-episode files
|
||||||
|
episodePartMatch = re.search("\\(([0-9]+)\\)$", fileName)
|
||||||
|
if episodePartMatch is not None:
|
||||||
|
partSuffix = str(episodePartMatch.group(0))
|
||||||
|
partIndex = episodePartMatch.groups()[0]
|
||||||
|
fileName = str(fileName).replace(partSuffix, f"Teil {partIndex}")
|
||||||
|
|
||||||
|
# Also multi-episodes with first and last episode index
|
||||||
|
episodePartMatch = re.search("\\(([0-9]+)[-\\/]([0-9]+)\\)$", fileName)
|
||||||
|
if episodePartMatch is not None:
|
||||||
|
partSuffix = str(episodePartMatch.group(0))
|
||||||
|
partFirstIndex = episodePartMatch.groups()[0]
|
||||||
|
partLastIndex = episodePartMatch.groups()[1]
|
||||||
|
fileName = str(fileName).replace(partSuffix, f"Teil {partFirstIndex}-{partLastIndex}")
|
||||||
|
|
||||||
|
return fileName
|
||||||
|
|
||||||
|
|
||||||
def getEpisodeFileBasename(showName,
|
def getEpisodeFileBasename(showName,
|
||||||
episodeName,
|
episodeName,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from .show_details_screen import ShowDetailsScreen
|
|||||||
from .pattern_details_screen import PatternDetailsScreen
|
from .pattern_details_screen import PatternDetailsScreen
|
||||||
|
|
||||||
from ffx.track_type import TrackType
|
from ffx.track_type import TrackType
|
||||||
|
from ffx.track_codec import TrackCodec
|
||||||
from ffx.model.track import Track
|
from ffx.model.track import Track
|
||||||
|
|
||||||
from ffx.track_disposition import TrackDisposition
|
from ffx.track_disposition import TrackDisposition
|
||||||
@@ -36,7 +37,7 @@ class MediaDetailsScreen(Screen):
|
|||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
grid-size: 5 8;
|
grid-size: 5 8;
|
||||||
grid-rows: 8 2 2 2 8 2 2 8;
|
grid-rows: 8 2 2 2 2 8 2 2 8;
|
||||||
grid-columns: 25 25 120 10 75;
|
grid-columns: 25 25 120 10 75;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -90,6 +91,10 @@ class MediaDetailsScreen(Screen):
|
|||||||
border: solid green;
|
border: solid green;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.purple {
|
||||||
|
tint: purple 40%;
|
||||||
|
}
|
||||||
|
|
||||||
.yellow {
|
.yellow {
|
||||||
tint: yellow 40%;
|
tint: yellow 40%;
|
||||||
}
|
}
|
||||||
@@ -137,7 +142,25 @@ class MediaDetailsScreen(Screen):
|
|||||||
self.loadProperties()
|
self.loadProperties()
|
||||||
|
|
||||||
|
|
||||||
def getRowIndexFromShowId(self, showId : int) -> int:
|
def removeShow(self, showId : int = -1):
|
||||||
|
"""Remove show entry from DataTable.
|
||||||
|
Removes the <New show> entry if showId is not set"""
|
||||||
|
|
||||||
|
for rowKey, row in self.showsTable.rows.items(): # dict[RowKey, Row]
|
||||||
|
|
||||||
|
rowData = self.showsTable.get_row(rowKey)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if (showId == -1 and rowData[0] == ' '
|
||||||
|
or showId == int(rowData[0])):
|
||||||
|
self.showsTable.remove_row(rowKey)
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getRowIndexFromShowId(self, showId : int = -1) -> int:
|
||||||
"""Find the index of the row where the value in the specified column matches the target_value."""
|
"""Find the index of the row where the value in the specified column matches the target_value."""
|
||||||
|
|
||||||
for rowKey, row in self.showsTable.rows.items(): # dict[RowKey, Row]
|
for rowKey, row in self.showsTable.rows.items(): # dict[RowKey, Row]
|
||||||
@@ -145,7 +168,8 @@ class MediaDetailsScreen(Screen):
|
|||||||
rowData = self.showsTable.get_row(rowKey)
|
rowData = self.showsTable.get_row(rowKey)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if showId == int(rowData[0]):
|
if ((showId == -1 and rowData[0] == ' ')
|
||||||
|
or showId == int(rowData[0])):
|
||||||
return int(self.showsTable.get_row_index(rowKey))
|
return int(self.showsTable.get_row_index(rowKey))
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
@@ -378,33 +402,36 @@ class MediaDetailsScreen(Screen):
|
|||||||
yield self.differencesTable
|
yield self.differencesTable
|
||||||
|
|
||||||
# 2
|
# 2
|
||||||
|
yield Static(" ", classes="four")
|
||||||
|
|
||||||
|
# 3
|
||||||
yield Static(" ")
|
yield Static(" ")
|
||||||
yield Button("Substitute", id="pattern_button")
|
yield Button("Substitute", id="pattern_button")
|
||||||
yield Static(" ", classes="two")
|
yield Static(" ", classes="two")
|
||||||
|
|
||||||
# 3
|
# 4
|
||||||
yield Static("Pattern")
|
yield Static("Pattern")
|
||||||
yield Input(type="text", id='pattern_input', classes="two")
|
yield Input(type="text", id='pattern_input', classes="two")
|
||||||
|
|
||||||
yield Static(" ")
|
yield Static(" ")
|
||||||
|
|
||||||
# 4
|
# 5
|
||||||
yield Static(" ", classes="four")
|
yield Static(" ", classes="four")
|
||||||
|
|
||||||
# 5
|
# 6
|
||||||
yield Static("Media Tags")
|
yield Static("Media Tags")
|
||||||
yield self.mediaTagsTable
|
yield self.mediaTagsTable
|
||||||
yield Static(" ")
|
yield Static(" ")
|
||||||
|
|
||||||
# 6
|
# 7
|
||||||
yield Static(" ", classes="four")
|
yield Static(" ", classes="four")
|
||||||
|
|
||||||
# 7
|
# 8
|
||||||
yield Static(" ")
|
yield Static(" ")
|
||||||
yield Button("Set Default", id="select_default_button")
|
yield Button("Set Default", id="select_default_button")
|
||||||
yield Button("Set Forced", id="select_forced_button")
|
yield Button("Set Forced", id="select_forced_button")
|
||||||
yield Static(" ")
|
yield Static(" ")
|
||||||
# 8
|
# 9
|
||||||
yield Static("Streams")
|
yield Static("Streams")
|
||||||
yield self.tracksTable
|
yield self.tracksTable
|
||||||
yield Static(" ")
|
yield Static(" ")
|
||||||
@@ -462,7 +489,7 @@ class MediaDetailsScreen(Screen):
|
|||||||
kwargs[TrackDescriptor.INDEX_KEY] = int(selected_track_data[0])
|
kwargs[TrackDescriptor.INDEX_KEY] = int(selected_track_data[0])
|
||||||
kwargs[TrackDescriptor.TRACK_TYPE_KEY] = TrackType.fromLabel(selected_track_data[1])
|
kwargs[TrackDescriptor.TRACK_TYPE_KEY] = TrackType.fromLabel(selected_track_data[1])
|
||||||
kwargs[TrackDescriptor.SUB_INDEX_KEY] = int(selected_track_data[2])
|
kwargs[TrackDescriptor.SUB_INDEX_KEY] = int(selected_track_data[2])
|
||||||
kwargs[TrackDescriptor.CODEC_NAME_KEY] = int(selected_track_data[3])
|
kwargs[TrackDescriptor.CODEC_KEY] = TrackCodec.fromLabel(selected_track_data[3])
|
||||||
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = AudioLayout.fromLabel(selected_track_data[4])
|
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = AudioLayout.fromLabel(selected_track_data[4])
|
||||||
|
|
||||||
return TrackDescriptor(**kwargs)
|
return TrackDescriptor(**kwargs)
|
||||||
@@ -473,11 +500,10 @@ class MediaDetailsScreen(Screen):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def getSelectedShowDescriptor(self):
|
def getSelectedShowDescriptor(self) -> ShowDescriptor:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Fetch the currently selected row when 'Enter' is pressed
|
|
||||||
#selected_row_index = self.table.cursor_row
|
|
||||||
row_key, col_key = self.showsTable.coordinate_to_cell_key(self.showsTable.cursor_coordinate)
|
row_key, col_key = self.showsTable.coordinate_to_cell_key(self.showsTable.cursor_coordinate)
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
@@ -501,6 +527,11 @@ class MediaDetailsScreen(Screen):
|
|||||||
|
|
||||||
def handle_new_pattern(self, showDescriptor: ShowDescriptor):
|
def handle_new_pattern(self, showDescriptor: ShowDescriptor):
|
||||||
|
|
||||||
|
if type(showDescriptor) is not ShowDescriptor:
|
||||||
|
raise TypeError("MediaDetailsScreen.handle_new_pattern(): Argument 'showDescriptor' has to be of type ShowDescriptor")
|
||||||
|
|
||||||
|
showRowIndex = self.getRowIndexFromShowId(showDescriptor.getId())
|
||||||
|
if showRowIndex is None:
|
||||||
show = (showDescriptor.getId(), showDescriptor.getName(), showDescriptor.getYear())
|
show = (showDescriptor.getId(), showDescriptor.getName(), showDescriptor.getYear())
|
||||||
self.showsTable.add_row(*map(str, show))
|
self.showsTable.add_row(*map(str, show))
|
||||||
|
|
||||||
@@ -508,6 +539,8 @@ class MediaDetailsScreen(Screen):
|
|||||||
if showRowIndex is not None:
|
if showRowIndex is not None:
|
||||||
self.showsTable.move_cursor(row=showRowIndex)
|
self.showsTable.move_cursor(row=showRowIndex)
|
||||||
|
|
||||||
|
self.removeShow()
|
||||||
|
|
||||||
patternDescriptor = self.getPatternDescriptorFromInput()
|
patternDescriptor = self.getPatternDescriptorFromInput()
|
||||||
|
|
||||||
if patternDescriptor:
|
if patternDescriptor:
|
||||||
@@ -524,10 +557,11 @@ class MediaDetailsScreen(Screen):
|
|||||||
|
|
||||||
def action_new_pattern(self):
|
def action_new_pattern(self):
|
||||||
|
|
||||||
try:
|
#TODO #427: Fehlermeldung in TUI
|
||||||
self.__currentMediaDescriptor.checkConfiguration()
|
# try:
|
||||||
except ValueError:
|
# self.__currentMediaDescriptor.checkConfiguration()
|
||||||
return
|
# except ValueError:
|
||||||
|
# return
|
||||||
|
|
||||||
selectedShowDescriptor = self.getSelectedShowDescriptor()
|
selectedShowDescriptor = self.getSelectedShowDescriptor()
|
||||||
|
|
||||||
|
|||||||
@@ -491,13 +491,14 @@ class PatternDetailsScreen(Screen):
|
|||||||
trackType = trackDescriptor.getType()
|
trackType = trackDescriptor.getType()
|
||||||
index = trackDescriptor.getIndex()
|
index = trackDescriptor.getIndex()
|
||||||
subIndex = trackDescriptor.getSubIndex()
|
subIndex = trackDescriptor.getSubIndex()
|
||||||
|
codec = trackDescriptor.getCodec()
|
||||||
language = trackDescriptor.getLanguage()
|
language = trackDescriptor.getLanguage()
|
||||||
title = trackDescriptor.getTitle()
|
title = trackDescriptor.getTitle()
|
||||||
|
|
||||||
row = (index,
|
row = (index,
|
||||||
trackType.label(),
|
trackType.label(),
|
||||||
subIndex,
|
subIndex,
|
||||||
" ",
|
codec.label(),
|
||||||
language.label(),
|
language.label(),
|
||||||
title,
|
title,
|
||||||
'Yes' if TrackDisposition.DEFAULT in dispoSet else 'No',
|
'Yes' if TrackDisposition.DEFAULT in dispoSet else 'No',
|
||||||
@@ -512,7 +513,10 @@ class PatternDetailsScreen(Screen):
|
|||||||
|
|
||||||
row_key, col_key = self.tracksTable.coordinate_to_cell_key(self.tracksTable.cursor_coordinate)
|
row_key, col_key = self.tracksTable.coordinate_to_cell_key(self.tracksTable.cursor_coordinate)
|
||||||
|
|
||||||
self.tracksTable.update_cell(row_key, self.column_key_track_audio_layout, trackDescriptor.getAudioLayout().label())
|
self.tracksTable.update_cell(row_key, self.column_key_track_audio_layout,
|
||||||
|
trackDescriptor.getAudioLayout().label()
|
||||||
|
if trackDescriptor.getType() == TrackType.AUDIO else ' ')
|
||||||
|
|
||||||
self.tracksTable.update_cell(row_key, self.column_key_track_language, trackDescriptor.getLanguage().label())
|
self.tracksTable.update_cell(row_key, self.column_key_track_language, trackDescriptor.getLanguage().label())
|
||||||
self.tracksTable.update_cell(row_key, self.column_key_track_title, trackDescriptor.getTitle())
|
self.tracksTable.update_cell(row_key, self.column_key_track_title, trackDescriptor.getTitle())
|
||||||
self.tracksTable.update_cell(row_key, self.column_key_track_default, 'Yes' if TrackDisposition.DEFAULT in trackDescriptor.getDispositionSet() else 'No')
|
self.tracksTable.update_cell(row_key, self.column_key_track_default, 'Yes' if TrackDisposition.DEFAULT in trackDescriptor.getDispositionSet() else 'No')
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ class ShowDetailsScreen(Screen):
|
|||||||
yield Footer()
|
yield Footer()
|
||||||
|
|
||||||
|
|
||||||
def getShowDescriptorFromInput(self):
|
def getShowDescriptorFromInput(self) -> ShowDescriptor:
|
||||||
|
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class TrackController():
|
|||||||
s = self.Session()
|
s = self.Session()
|
||||||
track = Track(pattern_id = patId,
|
track = Track(pattern_id = patId,
|
||||||
track_type = int(trackDescriptor.getType().index()),
|
track_type = int(trackDescriptor.getType().index()),
|
||||||
codec_name = str(trackDescriptor.getCodec().label()),
|
codec_name = str(trackDescriptor.getCodec().identifier()),
|
||||||
index = int(trackDescriptor.getIndex()),
|
index = int(trackDescriptor.getIndex()),
|
||||||
source_index = int(trackDescriptor.getSourceIndex()),
|
source_index = int(trackDescriptor.getSourceIndex()),
|
||||||
disposition_flags = int(TrackDisposition.toFlags(trackDescriptor.getDispositionSet())),
|
disposition_flags = int(TrackDisposition.toFlags(trackDescriptor.getDispositionSet())),
|
||||||
|
|||||||
@@ -292,7 +292,11 @@ class TrackDetailsScreen(Screen):
|
|||||||
kwargs[TrackDescriptor.TRACK_TYPE_KEY] = TrackType.fromLabel(self.query_one("#type_select", Select).value)
|
kwargs[TrackDescriptor.TRACK_TYPE_KEY] = TrackType.fromLabel(self.query_one("#type_select", Select).value)
|
||||||
|
|
||||||
kwargs[TrackDescriptor.CODEC_KEY] = self.__trackCodec
|
kwargs[TrackDescriptor.CODEC_KEY] = self.__trackCodec
|
||||||
|
|
||||||
|
if self.__trackType == TrackType.AUDIO:
|
||||||
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = AudioLayout.fromLabel(self.query_one("#audio_layout_select", Select).value)
|
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = AudioLayout.fromLabel(self.query_one("#audio_layout_select", Select).value)
|
||||||
|
else:
|
||||||
|
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = AudioLayout.LAYOUT_UNDEFINED
|
||||||
|
|
||||||
trackTags = {}
|
trackTags = {}
|
||||||
language = self.query_one("#language_select", Select).value
|
language = self.query_one("#language_select", Select).value
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
. ~/.local/share/ffx.venv/bin/activate
|
. ~/.local/share/ffx.venv/bin/activate
|
||||||
pushd ~/.local/src/ffx/
|
pushd ~/.local/src/ffx/
|
||||||
|
git checkout main
|
||||||
|
git pull
|
||||||
pip install --editable .
|
pip install --editable .
|
||||||
popd
|
popd
|
||||||
deactivate
|
deactivate
|
||||||
|
|||||||
Reference in New Issue
Block a user