Skip to content

Commit

Permalink
Merge branch 'dev' into dh-dark-mode
Browse files Browse the repository at this point in the history
  • Loading branch information
darrellcolehill committed Jun 6, 2024
2 parents 10f215e + 9eb5a9d commit 5976346
Show file tree
Hide file tree
Showing 33 changed files with 428 additions and 36 deletions.
2 changes: 1 addition & 1 deletion common/audio/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
group = 'org.wycliffeassociates.otter.common'
version = '0.4.2'
version = '0.4.3'

dependencies {
testImplementation "junit:junit:$junitVer"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class WavFile private constructor() : AudioFormatStrategy {
val metadataSize = totalDataLength - nonMetadataSize
val bytes = ByteArray(metadataSize)
file.inputStream().use {
val metadataStart = headerSize + totalAudioLength
val metadataStart = headerSize + wordAlign(totalAudioLength)
it.skip(metadataStart.toLong())
it.read(bytes)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class CueChunkTest {
}
val os = WavOutputStream(wav)
os.use {
os.write(ByteArray(writeSize))
os.write(ByteArray(wordAlign(writeSize)))
}
val validator = WavFile(file, WavMetadata(listOf(CueChunk())))
val resultMetadata = validator.metadata
Expand Down
2 changes: 2 additions & 0 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ dependencies {
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitRxJava2Ver"

implementation "org.apache.tika:tika-core:$tikaVer"

implementation "org.bibletranslationtools:kotlin-scripture-burrito:$kotlinscriptureburritoVer"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.wycliffeassociates.otter.common.data

interface IAppInfo {
val appName: String
val appVersion: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ import org.wycliffeassociates.otter.common.domain.project.exporter.ExportOptions
import org.wycliffeassociates.otter.common.domain.project.exporter.ExportResult
import org.wycliffeassociates.otter.common.domain.project.exporter.ProjectExporterCallback
import org.wycliffeassociates.otter.common.domain.audio.WAV_TO_MP3_COMPRESSED_RATE
import org.wycliffeassociates.otter.common.domain.content.FileNamer
import org.wycliffeassociates.otter.common.domain.resourcecontainer.RcConstants
import org.wycliffeassociates.otter.common.domain.resourcecontainer.burrito.ScriptureBurritoUtils
import org.wycliffeassociates.otter.common.io.zip.IFileWriter
import org.wycliffeassociates.otter.common.persistence.IDirectoryProvider
import org.wycliffeassociates.otter.common.utils.mapNotNull
Expand All @@ -43,11 +45,18 @@ import org.wycliffeassociates.resourcecontainer.entity.Media
import org.wycliffeassociates.resourcecontainer.entity.MediaManifest
import org.wycliffeassociates.resourcecontainer.entity.MediaProject
import java.io.File
import java.nio.file.Files
import java.util.*
import java.util.regex.Pattern
import javax.inject.Inject
import kotlin.io.path.deleteIfExists
import kotlin.io.path.inputStream
import kotlin.io.path.outputStream
import kotlin.io.path.readText

class SourceProjectExporter @Inject constructor(
directoryProvider: IDirectoryProvider
directoryProvider: IDirectoryProvider,
val burritoUtils: ScriptureBurritoUtils
) : RCProjectExporter(directoryProvider) {
@Inject
lateinit var audioExporter: AudioExporter
Expand Down Expand Up @@ -88,7 +97,7 @@ class SourceProjectExporter @Inject constructor(
override fun estimateExportSize(workbook: Workbook, chapterFilter: List<Int>): Long {
return workbook.target.chapters
.filter { it.sort in chapterFilter }
.mapNotNull {it.getSelectedTake()?.file }
.mapNotNull { it.getSelectedTake()?.file }
.reduce(0L) { size, nextFile ->
when (AudioFileFormat.of(nextFile.extension)) {
AudioFileFormat.MP3 -> size + nextFile.length()
Expand All @@ -108,23 +117,27 @@ class SourceProjectExporter @Inject constructor(
): Single<ExportResult> {
val fileWriter = directoryProvider.newFileWriter(exportFile)

return exportSelectedTakes(workbook, fileWriter, contributors, options?.chapters)
.andThen(
Single.fromCallable {
callback?.onNotifyProgress(80.0, "finishingUp")
return exportSelectedTakes(
workbook,
fileWriter,
contributors,
options?.chapters
).map { takes ->
callback?.onNotifyProgress(80.0, "finishingUp")

fileWriter.close() // must close before changing file extension or NoSuchFileException
buildSourceProjectMetadata(
exportFile,
workbook.source.resourceMetadata.path,
workbook
)
// change extension app-specific format
val exportedFile = restoreFileExtension(exportFile, OratureFileFormat.ORATURE.extension)
callback?.onNotifySuccess(workbook.target.toCollection(), exportedFile)
ExportResult.SUCCESS
}
fileWriter.close() // must close before changing file extension or NoSuchFileException
buildSourceProjectMetadata(
exportFile,
workbook.source.resourceMetadata.path,
workbook,
takes
)
// change extension app-specific format
val exportedFile = restoreFileExtension(exportFile, OratureFileFormat.ORATURE.extension)
callback?.onNotifySuccess(workbook.target.toCollection(), exportedFile)
ExportResult.SUCCESS
}

.doOnError {
logger.error("Error while exporting project as source.", it)
fileWriter.close()
Expand All @@ -138,7 +151,7 @@ class SourceProjectExporter @Inject constructor(
fileWriter: IFileWriter,
contributors: List<Contributor>,
chapterFilter: List<Int>? = null
): Completable {
): Single<Map<Int, List<File>>> {
val tempExportDir = directoryProvider.tempDirectory
.resolve("export${Date().time}")
.apply { mkdirs() }
Expand All @@ -161,19 +174,40 @@ class SourceProjectExporter @Inject constructor(
)
Pair(take, exportPath)
}
.flatMapCompletable { (take, exportPath) ->
exportTake(take!!, exportPath, license, contributors)
}.andThen {
.map { (take, exportPath) ->
exportTake(take!!, exportPath, license, contributors).blockingAwait()
take
}
.collectInto(mutableListOf<Take>()) { takes, take ->
takes.add(take)
}
.map {
// include the .cue files associated with takes within the same directory
fileWriter.copyDirectory(tempExportDir, RcConstants.SOURCE_MEDIA_DIR)
it.onComplete()
gatherAudioFilesByChapter(tempExportDir)
}
.subscribeOn(Schedulers.io())
.doOnError {
logger.error("Error while copying takes to export file", it)
}
}

private fun gatherAudioFilesByChapter(dir: File): Map<Int, List<File>> {
val map = mutableMapOf<Int, List<File>>()
dir.listFiles()?.forEach { audioFile ->
val chapterPattern = Regex("""_c(\d+)""")

val chapterNumber = chapterPattern.find(audioFile.name)!!.groupValues[1].toInt()

if (map.containsKey(chapterNumber)) {
(map[chapterNumber]!! as MutableList).add(audioFile)
} else {
map[chapterNumber] = mutableListOf(audioFile)
}
}
return map
}

private fun exportTake(
take: Take,
exportPath: File,
Expand All @@ -197,7 +231,8 @@ class SourceProjectExporter @Inject constructor(
private fun buildSourceProjectMetadata(
exportFile: File,
sourceRCFile: File,
workbook: Workbook
workbook: Workbook,
takes: Map<Int, List<File>>
) {
try {
ResourceContainer.load(exportFile).use { rc ->
Expand All @@ -209,6 +244,22 @@ class SourceProjectExporter @Inject constructor(
)

rc.write()

val tempFile = Files.createTempFile(
directoryProvider.tempDirectory.toPath(),
"out_burrito",
"json"
)
burritoUtils.writeBurritoManifest(
workbook,
takes,
rc,
tempFile.outputStream()
)
rc.accessor.write("metadata.json") {
tempFile.inputStream().transferTo(it)
}
tempFile.deleteIfExists()
}
} catch (e: Exception) {
logger.error("Error while updating project manifest.", e)
Expand All @@ -222,8 +273,10 @@ class SourceProjectExporter @Inject constructor(
exportRC.manifest.projects = projects

// copy source text
sourceRC.accessor
.getInputStreams(".", "usfm").forEach { fileName, inputStream ->
sourceRC
.accessor
.getInputStreams(".", "usfm")
.forEach { (fileName, inputStream) ->
inputStream.use { ins ->
exportRC.accessor.write(fileName) {
it.buffered().use { out ->
Expand Down
Loading

0 comments on commit 5976346

Please sign in to comment.