2# +==== BEGIN CatFeeder =================+
5# ...............)..(.')
7# ...............\(__)|
8# Inspired by Joan Stark
9# source https://www.asciiart.eu/
13# FILE: image_to_image.py
14# CREATION DATE: 15-01-2026
15# LAST Modified: 1:37:6 17-01-2026
17# This is the backend server in charge of making the actual website work.
19# COPYRIGHT: (c) Cat Feeder
20# PURPOSE: The file containing the code for converting bytes to a base of the user's choice.
22# +==== END CatFeeder =================+
26from typing
import Optional
29from display_tty
import Disp, initialise_logger
31from .aliases
import VIDEO_FORMAT_ALIASES
32from .
import converters_constants
as CONV_CONST
34from ..http_constants
import DataTypes, MEDIA_TYPES
36from ...utils
import CONST
37from ...core
import FinalClass
38from ...fffamily
import FFMPEGDownloader
42 """Class used to convert video from one format to another using ffmpeg.
44 Optimized to minimize I/O costs:
45 - Uses ffmpeg with pipes (stdin/stdout) for in-memory conversion
46 - No temporary files created - data flows through memory buffers
49 disp: Disp = initialise_logger(__qualname__, CONST.DEBUG)
51 _instance: Optional[
"VideoToVideo"] =
None
53 _ffmpeg_ensured: bool =
False
61 self.
disp.log_debug(
"Initialising...")
62 self.
disp.log_debug(
"Ensuring FFMPEG is available...")
64 self.
disp.log_debug(
"FFMPEG is available.")
65 self.
disp.log_debug(
"Initialised.")
67 def __call__(self, data: bytes, source_format: DataTypes) -> CONV_CONST.ConversionResult:
71 """Ensure that FFMPEG is downloaded and available."""
75 self.
disp.log_debug(
"Ensuring FFMPEG is available...")
77 cwd=str(CONV_CONST.FF_FAMILY_PATH),
78 success=CONV_CONST.SUCCESS,
79 error=CONV_CONST.ERROR,
80 debug=CONV_CONST.DEBUG
85 except Exception
as e:
86 self.
disp.log_error(f
"FFMPEG is not available: {e}")
88 "FFMPEG is required for video conversion but could not be ensured."
90 self.
disp.log_debug(
"FFMPEG is available.")
94 Get the file extension for a given video DataType.
97 data_type: The DataType to get extension for
100 Extension string or None
102 return VIDEO_FORMAT_ALIASES.get(data_type)
107 source_format: DataTypes
108 ) -> tuple[Optional[DataTypes], Optional[str], Optional[str]]:
110 Validate conversion parameters and get destination format and extensions.
113 data: The video data to validate
114 source_format: The source video format
117 Tuple of (destination_format, source_ext, dest_ext)
118 Returns (None, None, None) if validation fails
121 destination_format = MEDIA_TYPES.get_conversion_target(
123 except (AttributeError, NameError):
124 destination_format =
None
126 if destination_format
is None:
127 self.
disp.log_debug(f
"No conversion target for {source_format}")
128 return None,
None,
None
130 if source_format == destination_format:
132 f
"Source and destination formats are the same: {source_format}"
134 return destination_format,
None,
None
139 if not source_ext
or not dest_ext:
140 self.
disp.log_warning(
141 f
"Unknown video extension for {source_format} -> {destination_format}"
143 return destination_format,
None,
None
145 return destination_format, source_ext, dest_ext
150 source_format: DataTypes,
151 destination_format: DataTypes,
154 ) -> Optional[bytes]:
156 Perform in-memory video conversion using ffmpeg with pipes.
157 MINIMAL I/O - data flows through stdin/stdout pipes, no temp files.
160 data: Source video data
161 source_format: Source video format
162 destination_format: Destination video format
163 source_ext: Source file extension
164 dest_ext: Destination file extension
167 Converted video data as bytes, or None if conversion failed
170 f
"Converting video via pipes (minimal I/O): {source_format} -> {destination_format}"
183 '-movflags',
'+faststart',
189 process = subprocess.Popen(
191 stdin=subprocess.PIPE,
192 stdout=subprocess.PIPE,
193 stderr=subprocess.PIPE
197 converted_data, stderr = process.communicate(input=data)
199 if process.returncode != 0:
201 f
"ffmpeg conversion failed: {stderr.decode('utf-8', errors='replace')}"
206 f
"Video conversion via pipes successful (minimal I/O cost)"
208 return converted_data
210 except Exception
as e:
211 self.
disp.log_error(f
"ffmpeg pipe conversion failed: {e}")
217 source_format: DataTypes,
218 destination_format: DataTypes,
219 result: Optional[bytes] =
None
220 ) -> CONV_CONST.ConversionResult:
221 """Create a failed conversion result."""
222 return CONV_CONST.ConversionResult(
225 from_type=source_format,
226 to_type=destination_format,
233 source_format: DataTypes,
234 destination_format: DataTypes,
235 converted_data: bytes
236 ) -> CONV_CONST.ConversionResult:
237 """Create a successful conversion result."""
238 return CONV_CONST.ConversionResult(
241 from_type=source_format,
242 to_type=destination_format,
243 result=converted_data
249 source_format: DataTypes,
250 destination_format: Optional[DataTypes],
251 source_ext: Optional[str],
252 dest_ext: Optional[str]
253 ) -> Optional[CONV_CONST.ConversionResult]:
254 """Handle validation failures and return appropriate result."""
255 if destination_format
is None:
257 data, source_format, source_format,
None
260 if source_ext
is None or dest_ext
is None:
261 result_data = data
if source_format == destination_format
else data
263 data, source_format, destination_format, result_data
268 def video_to_video(self, data: bytes, source_format: DataTypes) -> CONV_CONST.ConversionResult:
270 Convert video data from one format to another using ffmpeg.
271 Uses pipes for minimal I/O cost.
274 data (bytes): The video data to convert.
275 source_format (DataTypes): The original video format.
278 ConversionResult: The converted video data in a contained dataclass.
287 data, source_format, destination_format, source_ext, dest_ext
289 if validation_result
is not None:
290 return validation_result
293 if destination_format
is None or source_ext
is None or dest_ext
is None:
295 data, source_format, source_format,
None
300 data, source_format, destination_format, source_ext, dest_ext
303 if converted_data
is None:
305 data, source_format, destination_format,
None
309 data, source_format, destination_format, converted_data
Optional[CONV_CONST.ConversionResult] _handle_validation_failure(self, bytes data, DataTypes source_format, Optional[DataTypes] destination_format, Optional[str] source_ext, Optional[str] dest_ext)
CONV_CONST.ConversionResult video_to_video(self, bytes data, DataTypes source_format)
tuple[Optional[DataTypes], Optional[str], Optional[str]] _validate_conversion_params(self, bytes data, DataTypes source_format)
"VideoToVideo" __new__(cls)
None _ensure_ffmpeg(self)
Optional[str] get_video_extension(self, DataTypes data_type)
Optional[bytes] _convert_with_ffmpeg_pipes(self, bytes data, DataTypes source_format, DataTypes destination_format, str source_ext, str dest_ext)
CONV_CONST.ConversionResult _create_failed_result(self, bytes data, DataTypes source_format, DataTypes destination_format, Optional[bytes] result=None)
CONV_CONST.ConversionResult __call__(self, bytes data, DataTypes source_format)
CONV_CONST.ConversionResult _create_success_result(self, bytes data, DataTypes source_format, DataTypes destination_format, bytes converted_data)