feat: Add custom date file format support

Signed-off-by: Myzel394 <50424412+Myzel394@users.noreply.github.com>
This commit is contained in:
Myzel394 2024-06-09 16:48:35 +02:00
parent ee4529a9dc
commit 8fcd5ca487
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
5 changed files with 53 additions and 57 deletions

View File

@ -162,6 +162,7 @@ data class RecordingInformation(
val folderPath: String,
@Serializable(with = LocalDateTimeSerializer::class)
val recordingStart: LocalDateTime,
val batchesAmount: Int,
val maxDuration: Long,
val intervalDuration: Long,
val fileExtension: String,
@ -176,6 +177,21 @@ data class RecordingInformation(
.hasRecordingsAvailable()
}
fun getStartDateForFilename(filenameFormat: AppSettings.FilenameFormat): LocalDateTime {
return when (filenameFormat) {
AppSettings.FilenameFormat.DATETIME_ABSOLUTE_START -> recordingStart
AppSettings.FilenameFormat.DATETIME_RELATIVE_START -> LocalDateTime.now().minusSeconds(
getFullDuration() / 1000
)
}
}
fun getFullDuration(): Long {
// This is not accurate, since the last batch may be shorter than the others
// but it's good enough
return intervalDuration * batchesAmount - (intervalDuration * 0.5).toLong()
}
enum class Type {
AUDIO,
VIDEO,

View File

@ -18,6 +18,7 @@ import androidx.annotation.RequiresApi
import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile
import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.db.RecordingInformation
import app.myzel394.alibi.ui.MEDIA_RECORDINGS_PREFIX
import app.myzel394.alibi.ui.RECORDER_INTERNAL_SELECTED_VALUE
import app.myzel394.alibi.ui.RECORDER_MEDIA_SELECTED_VALUE
@ -249,19 +250,22 @@ abstract class BatchesFolder(
abstract fun cleanup()
suspend fun concatenate(
recordingStart: LocalDateTime,
extension: String,
recording: RecordingInformation,
filenameFormat: AppSettings.FilenameFormat,
disableCache: Boolean? = null,
onNextParameterTry: (String) -> Unit = {},
durationPerBatchInMilliseconds: Long = 0,
onProgress: (Float?) -> Unit = {},
): String {
val disableCache = disableCache ?: (type != BatchType.INTERNAL)
if (!disableCache && checkIfOutputAlreadyExists(recordingStart, extension)) {
if (!disableCache && checkIfOutputAlreadyExists(
recording.recordingStart,
recording.fileExtension
)
) {
return getOutputFileForFFmpeg(
date = recordingStart,
extension = extension,
date = recording.recordingStart,
extension = recording.fileExtension,
)
}
@ -271,34 +275,12 @@ abstract class BatchesFolder(
onProgress(null)
try {
val fullTime = recording.getFullDuration().toFloat();
val filePaths = getBatchesForFFmpeg()
// Casting here to float so it doesn't need to redo it on every progress update
var fullTime: Float? = null
runCatching {
// `fullTime` is not accurate as the last batch might be shorter,
// but it's good enough for the progress bar
// Using the code below results in a nasty bug:
// since we use ffmpeg to extract the duration, the saf parameter is already
// "used up" and we can't use it again for the actual concatenation
// Since an accurate progress bar is less important than speed,
// we currently don't use this code
/*
val lastBatchTime = (FFprobeKit.execute(
"-i ${filePaths.last()} -show_entries format=duration -v quiet -of csv=\"p=0\"",
).output.toFloat() * 1000).toLong()
fullTime =
((durationPerBatchInMilliseconds * (filePaths.size - 1)) + lastBatchTime).toFloat()
*/
// We use an approximation for the duration of the batches
fullTime = (durationPerBatchInMilliseconds * filePaths.size).toFloat()
}
val outputFile = getOutputFileForFFmpeg(
date = recordingStart,
extension = extension,
date = recording.getStartDateForFilename(filenameFormat),
extension = recording.fileExtension,
)
concatenationFunction(
@ -308,11 +290,7 @@ abstract class BatchesFolder(
) { time ->
// The progressbar for the conversion is calculated based on the
// current time of the conversion and the total time of the batches.
if (fullTime != null) {
onProgress(time / fullTime!!)
} else {
onProgress(null)
}
onProgress(time / fullTime)
}.await()
return outputFile
} catch (e: MediaConverter.FFmpegException) {

View File

@ -16,9 +16,7 @@ import app.myzel394.alibi.db.RecordingInformation
import app.myzel394.alibi.enums.RecorderState
import app.myzel394.alibi.helpers.AudioBatchesFolder
import app.myzel394.alibi.helpers.BatchesFolder
import app.myzel394.alibi.ui.SUPPORTS_SCOPED_STORAGE
import app.myzel394.alibi.ui.utils.MicrophoneInfo
import java.lang.IllegalStateException
class AudioRecorderService :
IntervalRecorderService<RecordingInformation, AudioBatchesFolder>() {
@ -304,12 +302,14 @@ class AudioRecorderService :
}
// ==== Settings ====
override fun getRecordingInformation() = RecordingInformation(
folderPath = batchesFolder.exportFolderForSettings(),
recordingStart = recordingStart,
maxDuration = settings.maxDuration,
fileExtension = settings.audioRecorderSettings.fileExtension,
intervalDuration = settings.intervalDuration,
type = RecordingInformation.Type.AUDIO,
)
override fun getRecordingInformation() =
RecordingInformation(
folderPath = batchesFolder.exportFolderForSettings(),
recordingStart = recordingStart,
maxDuration = settings.maxDuration,
batchesAmount = batchesFolder.getBatchesForFFmpeg().size,
fileExtension = settings.audioRecorderSettings.fileExtension,
intervalDuration = settings.intervalDuration,
type = RecordingInformation.Type.AUDIO,
)
}

View File

@ -304,14 +304,16 @@ class VideoRecorderService :
this
}
override fun getRecordingInformation(): RecordingInformation = RecordingInformation(
folderPath = batchesFolder.exportFolderForSettings(),
recordingStart = recordingStart,
maxDuration = settings.maxDuration,
fileExtension = settings.videoRecorderSettings.fileExtension,
intervalDuration = settings.intervalDuration,
type = RecordingInformation.Type.VIDEO,
)
override fun getRecordingInformation() =
RecordingInformation(
folderPath = batchesFolder.exportFolderForSettings(),
recordingStart = recordingStart,
maxDuration = settings.maxDuration,
batchesAmount = batchesFolder.getBatchesForFFmpeg().size,
fileExtension = settings.videoRecorderSettings.fileExtension,
intervalDuration = settings.intervalDuration,
type = RecordingInformation.Type.VIDEO,
)
companion object {
const val CAMERA_CLOSE_TIMEOUT = 20000L

View File

@ -162,6 +162,7 @@ fun RecorderEventsHandler(
// When recording is loaded from lastRecording
?: settings.lastRecording
?: throw Exception("No recording information available")
val batchesFolder = when (recorder.javaClass) {
AudioRecorderModel::class.java -> AudioBatchesFolder.importFromFolder(
recording.folderPath,
@ -177,9 +178,8 @@ fun RecorderEventsHandler(
}
batchesFolder.concatenate(
recording.recordingStart,
recording.fileExtension,
durationPerBatchInMilliseconds = settings.intervalDuration,
recording,
filenameFormat = settings.filenameFormat,
onProgress = { percentage ->
processingProgress = percentage
}