mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-18 23:05:26 +02:00
feat: Add custom date file format support
Signed-off-by: Myzel394 <50424412+Myzel394@users.noreply.github.com>
This commit is contained in:
parent
ee4529a9dc
commit
8fcd5ca487
@ -162,6 +162,7 @@ data class RecordingInformation(
|
|||||||
val folderPath: String,
|
val folderPath: String,
|
||||||
@Serializable(with = LocalDateTimeSerializer::class)
|
@Serializable(with = LocalDateTimeSerializer::class)
|
||||||
val recordingStart: LocalDateTime,
|
val recordingStart: LocalDateTime,
|
||||||
|
val batchesAmount: Int,
|
||||||
val maxDuration: Long,
|
val maxDuration: Long,
|
||||||
val intervalDuration: Long,
|
val intervalDuration: Long,
|
||||||
val fileExtension: String,
|
val fileExtension: String,
|
||||||
@ -176,6 +177,21 @@ data class RecordingInformation(
|
|||||||
.hasRecordingsAvailable()
|
.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 {
|
enum class Type {
|
||||||
AUDIO,
|
AUDIO,
|
||||||
VIDEO,
|
VIDEO,
|
||||||
|
@ -18,6 +18,7 @@ import androidx.annotation.RequiresApi
|
|||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import app.myzel394.alibi.db.AppSettings
|
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.MEDIA_RECORDINGS_PREFIX
|
||||||
import app.myzel394.alibi.ui.RECORDER_INTERNAL_SELECTED_VALUE
|
import app.myzel394.alibi.ui.RECORDER_INTERNAL_SELECTED_VALUE
|
||||||
import app.myzel394.alibi.ui.RECORDER_MEDIA_SELECTED_VALUE
|
import app.myzel394.alibi.ui.RECORDER_MEDIA_SELECTED_VALUE
|
||||||
@ -249,19 +250,22 @@ abstract class BatchesFolder(
|
|||||||
abstract fun cleanup()
|
abstract fun cleanup()
|
||||||
|
|
||||||
suspend fun concatenate(
|
suspend fun concatenate(
|
||||||
recordingStart: LocalDateTime,
|
recording: RecordingInformation,
|
||||||
extension: String,
|
filenameFormat: AppSettings.FilenameFormat,
|
||||||
disableCache: Boolean? = null,
|
disableCache: Boolean? = null,
|
||||||
onNextParameterTry: (String) -> Unit = {},
|
onNextParameterTry: (String) -> Unit = {},
|
||||||
durationPerBatchInMilliseconds: Long = 0,
|
|
||||||
onProgress: (Float?) -> Unit = {},
|
onProgress: (Float?) -> Unit = {},
|
||||||
): String {
|
): String {
|
||||||
val disableCache = disableCache ?: (type != BatchType.INTERNAL)
|
val disableCache = disableCache ?: (type != BatchType.INTERNAL)
|
||||||
|
|
||||||
if (!disableCache && checkIfOutputAlreadyExists(recordingStart, extension)) {
|
if (!disableCache && checkIfOutputAlreadyExists(
|
||||||
|
recording.recordingStart,
|
||||||
|
recording.fileExtension
|
||||||
|
)
|
||||||
|
) {
|
||||||
return getOutputFileForFFmpeg(
|
return getOutputFileForFFmpeg(
|
||||||
date = recordingStart,
|
date = recording.recordingStart,
|
||||||
extension = extension,
|
extension = recording.fileExtension,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,34 +275,12 @@ abstract class BatchesFolder(
|
|||||||
onProgress(null)
|
onProgress(null)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
val fullTime = recording.getFullDuration().toFloat();
|
||||||
val filePaths = getBatchesForFFmpeg()
|
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(
|
val outputFile = getOutputFileForFFmpeg(
|
||||||
date = recordingStart,
|
date = recording.getStartDateForFilename(filenameFormat),
|
||||||
extension = extension,
|
extension = recording.fileExtension,
|
||||||
)
|
)
|
||||||
|
|
||||||
concatenationFunction(
|
concatenationFunction(
|
||||||
@ -308,11 +290,7 @@ abstract class BatchesFolder(
|
|||||||
) { time ->
|
) { time ->
|
||||||
// The progressbar for the conversion is calculated based on the
|
// The progressbar for the conversion is calculated based on the
|
||||||
// current time of the conversion and the total time of the batches.
|
// current time of the conversion and the total time of the batches.
|
||||||
if (fullTime != null) {
|
onProgress(time / fullTime)
|
||||||
onProgress(time / fullTime!!)
|
|
||||||
} else {
|
|
||||||
onProgress(null)
|
|
||||||
}
|
|
||||||
}.await()
|
}.await()
|
||||||
return outputFile
|
return outputFile
|
||||||
} catch (e: MediaConverter.FFmpegException) {
|
} catch (e: MediaConverter.FFmpegException) {
|
||||||
|
@ -16,9 +16,7 @@ import app.myzel394.alibi.db.RecordingInformation
|
|||||||
import app.myzel394.alibi.enums.RecorderState
|
import app.myzel394.alibi.enums.RecorderState
|
||||||
import app.myzel394.alibi.helpers.AudioBatchesFolder
|
import app.myzel394.alibi.helpers.AudioBatchesFolder
|
||||||
import app.myzel394.alibi.helpers.BatchesFolder
|
import app.myzel394.alibi.helpers.BatchesFolder
|
||||||
import app.myzel394.alibi.ui.SUPPORTS_SCOPED_STORAGE
|
|
||||||
import app.myzel394.alibi.ui.utils.MicrophoneInfo
|
import app.myzel394.alibi.ui.utils.MicrophoneInfo
|
||||||
import java.lang.IllegalStateException
|
|
||||||
|
|
||||||
class AudioRecorderService :
|
class AudioRecorderService :
|
||||||
IntervalRecorderService<RecordingInformation, AudioBatchesFolder>() {
|
IntervalRecorderService<RecordingInformation, AudioBatchesFolder>() {
|
||||||
@ -304,12 +302,14 @@ class AudioRecorderService :
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ==== Settings ====
|
// ==== Settings ====
|
||||||
override fun getRecordingInformation() = RecordingInformation(
|
override fun getRecordingInformation() =
|
||||||
folderPath = batchesFolder.exportFolderForSettings(),
|
RecordingInformation(
|
||||||
recordingStart = recordingStart,
|
folderPath = batchesFolder.exportFolderForSettings(),
|
||||||
maxDuration = settings.maxDuration,
|
recordingStart = recordingStart,
|
||||||
fileExtension = settings.audioRecorderSettings.fileExtension,
|
maxDuration = settings.maxDuration,
|
||||||
intervalDuration = settings.intervalDuration,
|
batchesAmount = batchesFolder.getBatchesForFFmpeg().size,
|
||||||
type = RecordingInformation.Type.AUDIO,
|
fileExtension = settings.audioRecorderSettings.fileExtension,
|
||||||
)
|
intervalDuration = settings.intervalDuration,
|
||||||
|
type = RecordingInformation.Type.AUDIO,
|
||||||
|
)
|
||||||
}
|
}
|
@ -304,14 +304,16 @@ class VideoRecorderService :
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRecordingInformation(): RecordingInformation = RecordingInformation(
|
override fun getRecordingInformation() =
|
||||||
folderPath = batchesFolder.exportFolderForSettings(),
|
RecordingInformation(
|
||||||
recordingStart = recordingStart,
|
folderPath = batchesFolder.exportFolderForSettings(),
|
||||||
maxDuration = settings.maxDuration,
|
recordingStart = recordingStart,
|
||||||
fileExtension = settings.videoRecorderSettings.fileExtension,
|
maxDuration = settings.maxDuration,
|
||||||
intervalDuration = settings.intervalDuration,
|
batchesAmount = batchesFolder.getBatchesForFFmpeg().size,
|
||||||
type = RecordingInformation.Type.VIDEO,
|
fileExtension = settings.videoRecorderSettings.fileExtension,
|
||||||
)
|
intervalDuration = settings.intervalDuration,
|
||||||
|
type = RecordingInformation.Type.VIDEO,
|
||||||
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val CAMERA_CLOSE_TIMEOUT = 20000L
|
const val CAMERA_CLOSE_TIMEOUT = 20000L
|
||||||
|
@ -162,6 +162,7 @@ fun RecorderEventsHandler(
|
|||||||
// When recording is loaded from lastRecording
|
// When recording is loaded from lastRecording
|
||||||
?: settings.lastRecording
|
?: settings.lastRecording
|
||||||
?: throw Exception("No recording information available")
|
?: throw Exception("No recording information available")
|
||||||
|
|
||||||
val batchesFolder = when (recorder.javaClass) {
|
val batchesFolder = when (recorder.javaClass) {
|
||||||
AudioRecorderModel::class.java -> AudioBatchesFolder.importFromFolder(
|
AudioRecorderModel::class.java -> AudioBatchesFolder.importFromFolder(
|
||||||
recording.folderPath,
|
recording.folderPath,
|
||||||
@ -177,9 +178,8 @@ fun RecorderEventsHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
batchesFolder.concatenate(
|
batchesFolder.concatenate(
|
||||||
recording.recordingStart,
|
recording,
|
||||||
recording.fileExtension,
|
filenameFormat = settings.filenameFormat,
|
||||||
durationPerBatchInMilliseconds = settings.intervalDuration,
|
|
||||||
onProgress = { percentage ->
|
onProgress = { percentage ->
|
||||||
processingProgress = percentage
|
processingProgress = percentage
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user