Add ConversionService for AVI to MKV remux with metadata preservation

- Implemented a new service to convert AVI files to MKV format while preserving metadata.
- Added methods for validating AVI files, detecting subtitle files, and mapping audio languages.
- Built ffmpeg command for fast remuxing without re-encoding.
- Included error handling and logging for conversion processes.
This commit is contained in:
sha
2026-01-03 14:29:30 +00:00
parent 917d25b360
commit 6fee7d9f63
8 changed files with 632 additions and 26 deletions
+20 -19
View File
@@ -17,8 +17,8 @@ class MediaPanelView:
"""Return formatted file info panel string"""
return "\n".join(
[
self.fileinfo_section(),
self.selected_section(),
self.fileinfo_section(),
self.tmdb_section(),
self.tracksinfo_section(),
self.filename_section(),
@@ -27,6 +27,25 @@ class MediaPanelView:
]
)
@conditional_decorators.wrap("", "\n")
def selected_section(self) -> str:
"""Return formatted selected data"""
return "\n".join(
[
self._props.title("Media Info Summary"),
self._props.media_title,
self._props.media_year,
self._props.media_duration,
self._props.media_file_size,
self._props.selected_frame_class,
self._props.selected_source,
self._props.selected_special_info,
self._props.selected_audio_langs,
self._props.selected_database_info,
self._props.selected_order,
]
)
@conditional_decorators.wrap("", "\n")
def fileinfo_section(self) -> str:
"""Return formatted file info"""
@@ -41,24 +60,6 @@ class MediaPanelView:
]
)
@conditional_decorators.wrap("", "\n")
def selected_section(self) -> str:
"""Return formatted selected data"""
return "\n".join(
[
self._props.title("Selected Data"),
self._props.selected_order,
self._props.selected_title,
self._props.selected_year,
self._props.selected_special_info,
self._props.selected_source,
self._props.selected_frame_class,
self._props.selected_hdr,
self._props.selected_audio_langs,
self._props.selected_database_info,
]
)
@conditional_decorators.wrap("", "\n")
def tmdb_section(self) -> str:
"""Return formatted TMDB data"""
+21 -3
View File
@@ -328,9 +328,18 @@ class MediaPanelProperties:
return self._extractor.get("movie_db", "Filename")
# ============================================================
# Selected Data Properties
# Joined Data Properties
# ============================================================
@property
@text_decorators.blue()
@conditional_decorators.wrap("Duration: ")
@text_decorators.yellow()
@duration_decorators.duration_full()
def media_duration(self) -> str:
"""Get media duration from best available source."""
return self._extractor.get("duration")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Order: ")
@@ -345,7 +354,7 @@ class MediaPanelProperties:
@conditional_decorators.wrap("Title: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def selected_title(self) -> str:
def media_title(self) -> str:
"""Get selected title formatted with label."""
return self._extractor.get("title")
@@ -354,10 +363,19 @@ class MediaPanelProperties:
@conditional_decorators.wrap("Year: ")
@text_decorators.yellow()
@conditional_decorators.default("<None>")
def selected_year(self) -> str:
def media_year(self) -> str:
"""Get selected year formatted with label."""
return self._extractor.get("year")
@property
@text_decorators.blue()
@conditional_decorators.wrap("File size: ")
@text_decorators.green()
@size_decorators.size_full()
def media_file_size(self) -> str:
"""Get media file size formatted with label."""
return self._extractor.get("file_size")
@property
@text_decorators.blue()
@conditional_decorators.wrap("Special info: ")