#!/bin/bash

# Copyright © 2012-2026 ScriptFanix
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# A copy of the GNU General Public License v3 is includded in the LICENSE file
# at the root of the project.

# soxtaskid persists across destinations so encode tasks share a single sox task
declare soxtaskid
decodeFile() {
	# copy destinations bypass decoding entirely
	if [[ ${destinationformat["$destination"]} == copy ]]
	then
		copied=1
	else
		# Dispatch to the appropriate decoder based on the source
		# MIME type.
		# sox_needed is set when normalization, resampling, or channel
		# up/downmixing is required. Used to determine whether to
		# insert an intermediate sox processing task.
		case "$mimetype" in
			'video/'*)
				# Extract audio if ffmpeg is available
				(( disablevideo )) && continue
				extractAudio
				if (( ${destinationnormalize["$destination"]}))\
				|| (
				[ -n "${destinationfrequency["$destination"]}" ]\
				&& (( ${rate:-0} != ${destinationfrequency["$destination"]}))\
				) || (
				[ -n "${destinationchannels["$destination"]}" ]\
				&& (( ${channels:-0} != ${destinationchannels["$destination"]} ))
				)
				then
					sox_needed=1
				fi
			;;
			'audio/mpeg')
				# Copy MP3 as-is if format and quality match
				# otherwise decode with sox
				if [[ ${destinationformat[$destination]} = mp3 ]] \
				&& checkCopy
				then
					copied=1
				else
					decodeSox
				fi
			;;
			'application/ogg opus'|'audio/ogg opus')
				# Copy Opus as-is if format and quality match
				# otherwise decode with opusdec
				if [[ ${destinationformat[$destination]} = opus ]] \
				&& checkCopy
				then
					copied=1
				else
					(( disableopusdec )) && continue
					decodeOpusdec
					if (( ${destinationnormalize["$destination"]}))\
					|| (
					[ -n "${destinationfrequency["$destination"]}" ]\
					&& (( ${rate:-0} != ${destinationfrequency["$destination"]}))\
					) || (
					[ -n "${destinationchannels["$destination"]}" ]\
					&& (( ${channels:-0} != ${destinationchannels["$destination"]} ))
					)
					then
						sox_needed=1
					fi
				fi
			;;
			'application/ogg'*|'audio/ogg'*)
				# Ogg Vorbis: copy if format/quality match
				# otherwise decode with sox
				if [[ ${destinationformat[$destination]} = vorbis ]] \
				&& checkCopy
				then
					copied=1
				else
					decodeSox
				fi
			;;
			'audio/x-flac'|'audio/flac')
				# FLAC: always decode via sox
				# copy for FLAC makes little sense
				decodeSox
			;;
			*)
				# Unknown MIME type: probe with file to detect
				# Musepack
				extendedtype=$(file -b "$sourcepath/$filename")
				case "$extendedtype" in
					*'Musepack '*)
						(( disablempcdec )) && continue
						decodeMpcdec
						if (( ${destinationnormalize["$destination"]}))\
						|| (
						[ -n "${destinationfrequency["$destination"]}" ]\
						&& (( ${rate:-0} != ${destinationfrequency["$destination"]}))\
						) || (
						[ -n "${destinationchannels["$destination"]}" ]\
						&& (( ${channels:-0} != ${destinationchannels["$destination"]} ))
						)
						then
							sox_needed=1
						fi
					;;
					*)
						# Truly unknown format: try
						# ffmpeg if available,
						# otherwise fall back to sox
						if (( disablevideo ))
						then
							decodeSox
						else
							extractAudio
							if (( ${destinationnormalize["$destination"]}))\
							|| (
							[ -n "${destinationfrequency["$destination"]}" ]\
							&& (( ${rate:-0} != ${destinationfrequency["$destination"]}))\
							) || (
							[ -n "${destinationchannels["$destination"]}" ]\
							&& (( ${channels:-0} != ${destinationchannels["$destination"]} ))
							)
							then
								sox_needed=1
							fi
						fi
					;;
				esac
			;;
		esac
		if ! (( copied ))
		then
			# Insert a decode task if one doesn't already exist for
			# this source file
			# keyed by $tmpfile so multiple destinations share a
			# single decode task
			if ! decodetaskid=$(
				Select tasks id <<<"key = $tmpfile"
			)
			then
				decodetaskid=$(
					Insert tasks <<-EOInsert
						key		$tmpfile
						source_file	$fileid
						$(
							for key in ${!commandline[@]}
							do
								echo "cmd_arg$key ${commandline[key]}"
							done
						)
						status		0
						cleanup		$tmpfile.wav
					EOInsert
				)
				progressSpin
			fi
			if (( sox_needed ))
			then
				# Insert a sox post-processing task chained
				# after the decode task
				decodeSox "$tempdir/$tmpfile.wav"
				if ! soxtaskid=$(
					Select tasks id <<<"key = $tmpfile"
				)
				then
					# Increment the decode task's
					# required_by counter so cleaner()
					# waits for all dependent tasks to
					# finish before cleaning up the
					# intermediate file
					parent_required=$(
						Select tasks required_by			\
							<<<"id = $decodetaskid"
					)
					Update tasks required_by $((++parent_required))	\
						<<<"id = $decodetaskid"
					soxtaskid=$(
						Insert tasks <<-EOInsert
							key		$tmpfile
							source_file	$fileid
							$(
								for key in ${!commandline[@]}
								do
									echo "cmd_arg$key ${commandline[key]}"
								done
							)
							requires	$decodetaskid
							status		0
							cleanup		$tmpfile.wav
						EOInsert
					)
					progressSpin
				fi
			fi
		fi
	fi
}
