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:32:3 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
28from display_tty
import Disp, initialise_logger
31from pydub
import AudioSegment
33from .aliases
import AUDIO_FORMAT_ALIASES
34from .
import converters_constants
as CONV_CONST
36from ..http_constants
import DataTypes, MEDIA_TYPES
38from ...core
import FinalClass
39from ...utils
import CONST
40from ...fffamily
import FFMPEGDownloader
44 """Class used to convert audio from one format to another using pydub/ffmpeg.
46 Optimized to minimize I/O costs:
47 - All conversions done in-memory using BytesIO (zero disk I/O)
48 - pydub handles format detection and conversion via ffmpeg
51 disp: Disp = initialise_logger(__qualname__, CONST.DEBUG)
53 _instance: Optional[
"AudioToAudio"] =
None
55 _ffmpeg_ensured: bool =
False
63 self.
disp.log_debug(
"Initialising...")
64 self.
disp.log_debug(
"Ensuring FFMPEG is available...")
66 self.
disp.log_debug(
"FFMPEG is available.")
67 self.
disp.log_debug(
"Initialised.")
69 def __call__(self, data: bytes, source_format: DataTypes) -> CONV_CONST.ConversionResult:
73 """Ensure that FFMPEG is downloaded and available."""
77 self.
disp.log_debug(
"Ensuring FFMPEG is available...")
79 cwd=str(CONV_CONST.FF_FAMILY_PATH),
80 success=CONV_CONST.SUCCESS,
81 error=CONV_CONST.ERROR,
82 debug=CONV_CONST.DEBUG
87 except Exception
as e:
88 self.
disp.log_error(f
"FFMPEG is not available: {e}")
90 "FFMPEG is required for audio conversion but could not be ensured."
92 self.
disp.log_debug(
"FFMPEG is available.")
96 Get the file extension for a given audio DataType.
99 data_type: The DataType to get extension for
102 Extension string or None
104 return AUDIO_FORMAT_ALIASES.get(data_type)
109 source_format: DataTypes
110 ) -> tuple[Optional[DataTypes], Optional[str], Optional[str]]:
112 Validate conversion parameters and get destination format and extensions.
115 data: The audio data to validate
116 source_format: The source audio format
119 Tuple of (destination_format, source_ext, dest_ext)
120 Returns (None, None, None) if validation fails
123 destination_format = MEDIA_TYPES.get_conversion_target(
125 except (AttributeError, NameError):
126 destination_format =
None
128 if destination_format
is None:
129 self.
disp.log_debug(f
"No conversion target for {source_format}")
130 return None,
None,
None
132 if source_format == destination_format:
134 f
"Source and destination formats are the same: {source_format}"
136 return destination_format,
None,
None
141 if not source_ext
or not dest_ext:
142 self.
disp.log_warning(
143 f
"Unknown audio extension for {source_format} -> {destination_format}"
145 return destination_format,
None,
None
147 return destination_format, source_ext, dest_ext
152 source_format: DataTypes,
153 destination_format: DataTypes,
156 ) -> Optional[bytes]:
158 Perform in-memory audio conversion using pydub.
159 ZERO I/O COST - everything happens in RAM via BytesIO.
162 data: Source audio data
163 source_format: Source audio format
164 destination_format: Destination audio format
165 source_ext: Source file extension
166 dest_ext: Destination file extension
169 Converted audio data as bytes, or None if conversion failed
172 f
"Converting in-memory (ZERO I/O): {source_format} -> {destination_format}"
177 input_buffer = BytesIO(data)
178 audio = AudioSegment.from_file(input_buffer, format=source_ext)
181 output_buffer = BytesIO()
188 converted_data = output_buffer.getvalue()
191 f
"In-memory audio conversion successful (ZERO I/O cost)"
193 return converted_data
195 except Exception
as e:
196 self.
disp.log_error(f
"In-memory audio conversion failed: {e}")
202 source_format: DataTypes,
203 destination_format: DataTypes,
204 result: Optional[bytes] =
None
205 ) -> CONV_CONST.ConversionResult:
206 """Create a failed conversion result."""
207 return CONV_CONST.ConversionResult(
210 from_type=source_format,
211 to_type=destination_format,
218 source_format: DataTypes,
219 destination_format: DataTypes,
220 converted_data: bytes
221 ) -> CONV_CONST.ConversionResult:
222 """Create a successful conversion result."""
223 return CONV_CONST.ConversionResult(
226 from_type=source_format,
227 to_type=destination_format,
228 result=converted_data
234 source_format: DataTypes,
235 destination_format: Optional[DataTypes],
236 source_ext: Optional[str],
237 dest_ext: Optional[str]
238 ) -> Optional[CONV_CONST.ConversionResult]:
239 """Handle validation failures and return appropriate result."""
240 if destination_format
is None:
242 data, source_format, source_format,
None
245 if source_ext
is None or dest_ext
is None:
246 result_data = data
if source_format == destination_format
else data
248 data, source_format, destination_format, result_data
253 def audio_to_audio(self, data: bytes, source_format: DataTypes) -> CONV_CONST.ConversionResult:
255 Convert audio data from one format to another using pydub/ffmpeg.
256 All operations done in-memory (ZERO I/O cost).
259 data (bytes): The audio data to convert.
260 source_format (DataTypes): The original audio format.
263 ConversionResult: The converted audio data in a contained dataclass.
272 data, source_format, destination_format, source_ext, dest_ext
274 if validation_result
is not None:
275 return validation_result
278 if destination_format
is None or source_ext
is None or dest_ext
is None:
281 data, source_format, source_format,
None
286 data, source_format, destination_format, source_ext, dest_ext
289 if converted_data
is None:
291 data, source_format, destination_format,
None
295 data, source_format, destination_format, converted_data
CONV_CONST.ConversionResult _create_failed_result(self, bytes data, DataTypes source_format, DataTypes destination_format, Optional[bytes] result=None)
CONV_CONST.ConversionResult audio_to_audio(self, bytes data, DataTypes source_format)
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 _create_success_result(self, bytes data, DataTypes source_format, DataTypes destination_format, bytes converted_data)
"AudioToAudio" __new__(cls)
Optional[bytes] _convert_in_memory(self, bytes data, DataTypes source_format, DataTypes destination_format, str source_ext, str dest_ext)
Optional[str] get_audio_extension(self, DataTypes data_type)
None _ensure_ffmpeg(self)
CONV_CONST.ConversionResult __call__(self, bytes data, DataTypes source_format)
tuple[Optional[DataTypes], Optional[str], Optional[str]] _validate_conversion_params(self, bytes data, DataTypes source_format)