From 17680cdf3b7456460e1a5cb56aa594173b3ca98a Mon Sep 17 00:00:00 2001 From: Maxim Date: Thu, 16 May 2024 20:47:24 +0400 Subject: [PATCH 1/6] Add support for heart languages (#195) * Add support for heart languages * replace # with javascript:void(0) to avoid some navigation bugs * use javascript:void(0) for href with empty url --- .../fetcher/di/DIModule.kt | 28 ++---- .../impl/repository/ChapterCatalogImpl.kt | 2 - .../impl/repository/StorageAccessImpl.kt | 92 ++++++++++--------- ...og.kt => UnfoldingWordLanguagesCatalog.kt} | 19 +++- .../fetcher/repository/FileAccessRequest.kt | 2 +- .../fetcher/repository/StorageAccess.kt | 3 +- .../fetcher/usecase/FetchBookViewData.kt | 50 ++++------ .../fetcher/usecase/FetchChapterViewData.kt | 28 ++---- .../fetcher/usecase/FetchLanguageViewData.kt | 32 +++---- .../fetcher/usecase/FetchProductViewData.kt | 21 +++-- .../fetcher/usecase/ProductFileExtension.kt | 1 + .../fetcher/usecase/ProductFileQuality.kt | 6 ++ .../usecase/RequestResourceContainer.kt | 2 +- .../fetcher/web/AppModule.kt | 4 +- .../fetcher/web/controllers/BookController.kt | 7 +- .../web/controllers/ChapterController.kt | 11 +-- .../web/controllers/LanguageController.kt | 6 +- .../web/controllers/ProductController.kt | 8 +- .../resources/templates/fragments/navbar.html | 14 +-- .../templates/fragments/productcard.html | 2 +- .../fetcher/LanguageCatalogsTest.kt | 5 +- .../fetcher/StorageAccessImplTest.kt | 23 +++-- ...AccessImpl_GetPathPrefixDir_TestCases.json | 4 +- 23 files changed, 170 insertions(+), 200 deletions(-) rename fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/{UnfoldingWordHeartLanguagesCatalog.kt => UnfoldingWordLanguagesCatalog.kt} (86%) create mode 100644 fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/ProductFileQuality.kt diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/di/DIModule.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/di/DIModule.kt index ef4dd5e8..26b2b997 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/di/DIModule.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/di/DIModule.kt @@ -2,23 +2,20 @@ package org.bibletranslationtools.fetcher.di import org.bibletranslationtools.fetcher.config.DevEnvironmentConfig import org.bibletranslationtools.fetcher.config.EnvironmentConfig -import org.bibletranslationtools.fetcher.impl.repository.AvailabilityCacheAccessor import org.bibletranslationtools.fetcher.impl.repository.BookCatalogImpl import org.bibletranslationtools.fetcher.impl.repository.BookRepositoryImpl import org.bibletranslationtools.fetcher.impl.repository.ChapterCatalogImpl -import org.bibletranslationtools.fetcher.impl.repository.ContentAvailabilityCacheBuilder import org.bibletranslationtools.fetcher.impl.repository.DirectoryProviderImpl +import org.bibletranslationtools.fetcher.impl.repository.LangType import org.bibletranslationtools.fetcher.impl.repository.LanguageRepositoryImpl -import org.bibletranslationtools.fetcher.impl.repository.PortGatewayLanguageCatalog import org.bibletranslationtools.fetcher.impl.repository.ProductCatalogImpl import org.bibletranslationtools.fetcher.impl.repository.RCRepositoryImpl import org.bibletranslationtools.fetcher.impl.repository.StorageAccessImpl -import org.bibletranslationtools.fetcher.impl.repository.UnfoldingWordHeartLanguagesCatalog +import org.bibletranslationtools.fetcher.impl.repository.UnfoldingWordLanguagesCatalog import org.bibletranslationtools.fetcher.io.LocalFileTransferClient import org.bibletranslationtools.fetcher.repository.BookCatalog import org.bibletranslationtools.fetcher.repository.BookRepository import org.bibletranslationtools.fetcher.repository.ChapterCatalog -import org.bibletranslationtools.fetcher.repository.ContentCacheAccessor import org.bibletranslationtools.fetcher.repository.DirectoryProvider import org.bibletranslationtools.fetcher.repository.LanguageCatalog import org.bibletranslationtools.fetcher.repository.LanguageRepository @@ -42,12 +39,13 @@ val appDependencyModule = module(createdAtStart = true) { single { StorageAccessImpl(get()) } single { ChapterCatalogImpl() } - single(named("GL")) { PortGatewayLanguageCatalog() } - single(named("HL")) { UnfoldingWordHeartLanguagesCatalog(get()) } + single(named(LangType.GL.name)) { UnfoldingWordLanguagesCatalog(get(), LangType.GL) } + single(named(LangType.HL.name)) { UnfoldingWordLanguagesCatalog(get(), LangType.HL) } + single(named(LangType.ALL.name)) { UnfoldingWordLanguagesCatalog(get(), LangType.ALL) } single { LanguageRepositoryImpl( - get(named("GL")), - get(named("HL")) + get(named(LangType.GL.name)), + get(named(LangType.HL.name)) ) } single { ProductCatalogImpl() } @@ -56,16 +54,4 @@ val appDependencyModule = module(createdAtStart = true) { single { RCRepositoryImpl(get()) } single { LocalFileTransferClient(get()) } - - single { - ContentAvailabilityCacheBuilder( - envConfig = get(), - languageCatalog = get(named("GL")), - productCatalog = get(), - chapterCatalog = get(), - bookRepository = get(), - storageAccess = get() - ) - } - single { AvailabilityCacheAccessor(get()) } } diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/ChapterCatalogImpl.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/ChapterCatalogImpl.kt index a8f4289d..eb347c47 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/ChapterCatalogImpl.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/ChapterCatalogImpl.kt @@ -3,8 +3,6 @@ package org.bibletranslationtools.fetcher.impl.repository import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.KotlinModule import com.fasterxml.jackson.module.kotlin.readValue -import io.ktor.client.request.get -import io.ktor.util.error import java.io.IOException import java.net.HttpURLConnection import java.net.URL diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/StorageAccessImpl.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/StorageAccessImpl.kt index 0af52be1..174da172 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/StorageAccessImpl.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/StorageAccessImpl.kt @@ -10,51 +10,32 @@ import org.bibletranslationtools.fetcher.data.Division import org.bibletranslationtools.fetcher.repository.DirectoryProvider import org.bibletranslationtools.fetcher.repository.FileAccessRequest import org.bibletranslationtools.fetcher.repository.StorageAccess +import org.bibletranslationtools.fetcher.usecase.ProductFileExtension +import org.bibletranslationtools.fetcher.usecase.resourceIdByLanguage import org.slf4j.LoggerFactory class StorageAccessImpl(private val directoryProvider: DirectoryProvider) : StorageAccess { companion object { - fun getPathPrefixDir( - languageCode: String, - resourceId: String, - fileExtension: String, - directoryProvider: DirectoryProvider, - bookSlug: String = "", - chapter: String = "" - ): File { - return getPathPrefixDir( - directoryProvider.getContentRoot(), - languageCode, - resourceId, - fileExtension, - bookSlug, - chapter - ) - } - fun getPathPrefixDir( root: File, languageCode: String, resourceId: String, - fileExtension: String, - bookSlug: String = "", - chapter: String = "" + fileExtension: String? = null, + bookSlug: String? = null, + chapter: String? = null ): File { - val trimmedChapter = chapter.trimStart('0') - - return when { - bookSlug.isNotEmpty() && trimmedChapter.isNotEmpty() -> - root.resolve( - "$languageCode/$resourceId/$bookSlug/$trimmedChapter/CONTENTS/$fileExtension" - ) - bookSlug.isNotEmpty() -> root.resolve( - "$languageCode/$resourceId/$bookSlug/CONTENTS/$fileExtension" - ) - else -> root.resolve( - "$languageCode/$resourceId/CONTENTS/$fileExtension" - ) - } + val trimmedChapter = chapter?.trimStart('0') + + val languagePart = languageCode + val resourcePart = "/$resourceId" + val bookPart = if (!bookSlug.isNullOrEmpty()) "/$bookSlug" else "" + val chapterPart = if (!trimmedChapter.isNullOrEmpty()) "/$trimmedChapter" else "" + val extensionPart = if (!fileExtension.isNullOrEmpty()) "/CONTENTS/$fileExtension" else "" + + return root.resolve( + "$languagePart$resourcePart$bookPart$chapterPart$extensionPart" + ) } fun getContentDir( @@ -85,20 +66,43 @@ class StorageAccessImpl(private val directoryProvider: DirectoryProvider) : Stor return directoryProvider.getContentRoot() } - override fun getLanguageCodes(): List { + override fun hasLanguageContent(languageCode: String): Boolean { val sourceFileRootDir = directoryProvider.getContentRoot() val dirs = sourceFileRootDir.listFiles(File::isDirectory) - return if (dirs.isNullOrEmpty()) listOf() else dirs.map { it.name } + return dirs?.any { it.name == languageCode } ?: false + } + + override fun hasProductContent(languageCode: String, fileExtensions: List): Boolean { + val resourceId = resourceIdByLanguage(languageCode) + val booksDir = getPathPrefixDir( + directoryProvider.getContentRoot(), + languageCode, + resourceId + ) + + return booksDir.listFiles(File::isDirectory)?.any { bookDir -> + val bookSlug = bookDir.name + fileExtensions.any { ext -> + val dir = getPathPrefixDir( + directoryProvider.getContentRoot(), + languageCode, + resourceId, + ext, + bookSlug + ) + dir.exists() + } + } ?: false } override fun getBookFile(request: FileAccessRequest): File? { val bookPrefixDir = getPathPrefixDir( + directoryProvider.getContentRoot(), languageCode = request.languageCode, resourceId = request.resourceId, bookSlug = request.bookSlug, - fileExtension = request.fileExtension, - directoryProvider = directoryProvider + fileExtension = request.fileExtension ) val grouping = getGrouping(request.fileExtension, Division.BOOK) @@ -126,12 +130,12 @@ class StorageAccessImpl(private val directoryProvider: DirectoryProvider) : Stor override fun getChapterFile(request: FileAccessRequest): File? { val chapterPrefixDir = getPathPrefixDir( + directoryProvider.getContentRoot(), languageCode = request.languageCode, resourceId = request.resourceId, bookSlug = request.bookSlug, fileExtension = request.fileExtension, - chapter = request.chapter, - directoryProvider = directoryProvider + chapter = request.chapter ) val grouping = getGrouping(request.fileExtension, Division.CHAPTER) @@ -188,11 +192,11 @@ class StorageAccessImpl(private val directoryProvider: DirectoryProvider) : Stor ): Boolean { for (ext in fileExtensionList) { val bookPrefixDir = getPathPrefixDir( + directoryProvider.getContentRoot(), languageCode = languageCode, resourceId = resourceId, bookSlug = bookSlug, - fileExtension = ext, - directoryProvider = directoryProvider + fileExtension = ext ) val walkBookDir = bookPrefixDir.walk() val grouping = getGrouping(ext, Division.BOOK) @@ -238,7 +242,7 @@ class StorageAccessImpl(private val directoryProvider: DirectoryProvider) : Stor private fun getGrouping(ext: String, division: Division): String { return when { - ext == "tr" -> "verse" + ext == ProductFileExtension.BTTR.fileType -> "verse" else -> division.name.toLowerCase() } } diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/UnfoldingWordHeartLanguagesCatalog.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/UnfoldingWordLanguagesCatalog.kt similarity index 86% rename from fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/UnfoldingWordHeartLanguagesCatalog.kt rename to fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/UnfoldingWordLanguagesCatalog.kt index de6dfa1f..0e73579d 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/UnfoldingWordHeartLanguagesCatalog.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/impl/repository/UnfoldingWordLanguagesCatalog.kt @@ -10,7 +10,6 @@ import java.io.IOException import java.net.HttpURLConnection import java.net.URL import org.bibletranslationtools.fetcher.data.Language -import org.bibletranslationtools.fetcher.di.ext.CommonKoinExt.get import org.bibletranslationtools.fetcher.repository.LanguageCatalog import org.slf4j.LoggerFactory @@ -18,8 +17,18 @@ private const val LANGUAGE_CODE_ID = "lc" private const val ANGLICIZED_NAME_ID = "ang" private const val LOCALIZED_NAME_ID = "ln" private const val IS_GATEWAY = "gw" +private const val DIRECTION = "ld" -class UnfoldingWordHeartLanguagesCatalog(envConfig: EnvironmentConfig) : LanguageCatalog { +enum class LangType { + GL, + HL, + ALL +} + +class UnfoldingWordLanguagesCatalog( + envConfig: EnvironmentConfig, + private val langType: LangType +) : LanguageCatalog { @JsonIgnoreProperties(ignoreUnknown = true) private data class UnfoldingWordHeartLanguage( @@ -45,7 +54,11 @@ class UnfoldingWordHeartLanguagesCatalog(envConfig: EnvironmentConfig) : Languag return languages .filter { - !it.isGateway + when (langType) { + LangType.GL -> it.isGateway + LangType.HL -> !it.isGateway + LangType.ALL -> true + } } .map { Language(it.code, it.anglicizedName, it.localizedName, isGateway = false) diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/repository/FileAccessRequest.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/repository/FileAccessRequest.kt index 07f0fb41..37d10d76 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/repository/FileAccessRequest.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/repository/FileAccessRequest.kt @@ -3,7 +3,7 @@ package org.bibletranslationtools.fetcher.repository data class FileAccessRequest( val languageCode: String, val resourceId: String, - val fileExtension: String, + val fileExtension: String = "", val bookSlug: String = "", val chapter: String = "", val mediaExtension: String = "", diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/repository/StorageAccess.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/repository/StorageAccess.kt index 44063f4c..c4538ed1 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/repository/StorageAccess.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/repository/StorageAccess.kt @@ -4,7 +4,8 @@ import java.io.File interface StorageAccess { fun getContentRoot(): File - fun getLanguageCodes(): List + fun hasLanguageContent(languageCode: String): Boolean + fun hasProductContent(languageCode: String, fileExtensions: List): Boolean fun getBookFile(request: FileAccessRequest): File? fun getChapterFile(request: FileAccessRequest): File? fun hasBookContent( diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchBookViewData.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchBookViewData.kt index dad1d167..6d6377e6 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchBookViewData.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchBookViewData.kt @@ -6,7 +6,6 @@ import org.bibletranslationtools.fetcher.data.ContainerExtensions import org.bibletranslationtools.fetcher.data.Language import org.bibletranslationtools.fetcher.data.Product import org.bibletranslationtools.fetcher.repository.BookRepository -import org.bibletranslationtools.fetcher.repository.ContentCacheAccessor import org.bibletranslationtools.fetcher.repository.FileAccessRequest import org.bibletranslationtools.fetcher.repository.StorageAccess import org.bibletranslationtools.fetcher.usecase.viewdata.BookViewData @@ -26,34 +25,26 @@ class FetchBookViewData( private val fileExtensionList = if (ContainerExtensions.isSupported(productExtension.fileType)) { - listOf("tr") + listOf(ProductFileExtension.BTTR.fileType) } else { - listOf("wav", "mp3") + listOf(ProductFileExtension.MP3.fileType, ProductFileExtension.WAV.fileType) } private val priorityList = listOf( - PriorityItem("mp3", "hi"), - PriorityItem("mp3", "low"), - PriorityItem("wav", "") + PriorityItem(ProductFileExtension.MP3.fileType, ProductFileQuality.HI.quality), + PriorityItem(ProductFileExtension.MP3.fileType, ProductFileQuality.LOW.quality), + PriorityItem(ProductFileExtension.WAV.fileType, "") ) - fun getViewDataList( - currentPath: String, - cacheAccessor: ContentCacheAccessor, - isGateway: Boolean = true - ): List { + fun getViewDataList(currentPath: String): List { val books = bookRepo.getBooks(resourceId = resourceId, languageCode = language.code) return books.map { book -> - book.availability = if (isGateway) { - cacheAccessor.isBookAvailable(book.slug, language.code, product.slug) - } else { - storage.hasBookContent( - language.code, - resourceId, - book.slug, - fileExtensionList - ) - } + book.availability = storage.hasBookContent( + language.code, + resourceId, + book.slug, + fileExtensionList + ) BookViewData( index = book.index, @@ -65,17 +56,9 @@ class FetchBookViewData( } } - fun getViewData( - bookSlug: String, - cacheAccessor: ContentCacheAccessor, - isGateway: Boolean = true - ): BookViewData? { + fun getViewData(bookSlug: String): BookViewData? { val book = bookRepo.getBook(bookSlug) - val url = if (isGateway) { - cacheAccessor.getBookUrl(bookSlug, language.code, product.slug) - } else { - getBookDownloadUrl(bookSlug) - } + val url = getBookDownloadUrl(bookSlug) return if (book != null) BookViewData( index = book.index, @@ -92,9 +75,10 @@ class FetchBookViewData( var url: String? = null for (priority in priorityList) { val fileAccessRequest = when (productExtension) { - ProductFileExtension.ORATURE -> return "#" + ProductFileExtension.ORATURE -> return "javascript:void(0)" ProductFileExtension.BTTR -> getBTTRFileAccessRequest(bookSlug, priority) ProductFileExtension.MP3 -> getMp3FileAccessRequest(bookSlug, priority) + else -> return "" } val bookFile = storage.getBookFile(fileAccessRequest) @@ -113,7 +97,7 @@ class FetchBookViewData( return FileAccessRequest( languageCode = language.code, resourceId = resourceId, - fileExtension = "tr", + fileExtension = ProductFileExtension.BTTR.fileType, bookSlug = bookSlug, mediaExtension = priorityItem.fileExtension, mediaQuality = priorityItem.mediaQuality diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchChapterViewData.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchChapterViewData.kt index f83e8b78..868a34b1 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchChapterViewData.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchChapterViewData.kt @@ -8,7 +8,6 @@ import org.bibletranslationtools.fetcher.data.Chapter import org.bibletranslationtools.fetcher.data.Language import org.bibletranslationtools.fetcher.data.Product import org.bibletranslationtools.fetcher.repository.ChapterCatalog -import org.bibletranslationtools.fetcher.repository.ContentCacheAccessor import org.bibletranslationtools.fetcher.repository.FileAccessRequest import org.bibletranslationtools.fetcher.repository.StorageAccess import org.bibletranslationtools.fetcher.usecase.viewdata.ChapterViewData @@ -27,9 +26,9 @@ class FetchChapterViewData( private data class PriorityItem(val fileExtension: String, val mediaQuality: String) private val priorityList = listOf( - PriorityItem("mp3", "hi"), - PriorityItem("mp3", "low"), - PriorityItem("wav", "") + PriorityItem(ProductFileExtension.MP3.fileType, ProductFileQuality.HI.quality), + PriorityItem(ProductFileExtension.MP3.fileType, ProductFileQuality.LOW.quality), + PriorityItem(ProductFileExtension.WAV.fileType, "") ) private val chapters: List = try { @@ -41,23 +40,8 @@ class FetchChapterViewData( throw ex } - fun getViewDataList( - contentCache: ContentCacheAccessor, - isGateway: Boolean - ): List { - return if (isGateway) { - chapters.map { - val requestUrl = contentCache.getChapterUrl( - number = it.number, - bookSlug = book.slug, - languageCode = language.code, - productSlug = product.slug - ) - ChapterViewData(it.number, url = requestUrl) - } - } else { - chaptersFromDirectory() - } + fun getViewDataList(): List { + return chaptersFromDirectory() } fun chaptersFromDirectory(): List { @@ -92,7 +76,7 @@ class FetchChapterViewData( return FileAccessRequest( languageCode = language.code, resourceId = resourceIdByLanguage(language.code), - fileExtension = "tr", + fileExtension = ProductFileExtension.BTTR.fileType, bookSlug = book.slug, chapter = chapterNumber.toString(), mediaExtension = priorityItem.fileExtension, diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchLanguageViewData.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchLanguageViewData.kt index 81c6799a..f4a3a589 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchLanguageViewData.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchLanguageViewData.kt @@ -1,29 +1,26 @@ package org.bibletranslationtools.fetcher.usecase import org.bibletranslationtools.fetcher.data.Language -import org.bibletranslationtools.fetcher.repository.ContentCacheAccessor import org.bibletranslationtools.fetcher.repository.LanguageRepository import org.bibletranslationtools.fetcher.repository.StorageAccess import org.bibletranslationtools.fetcher.usecase.viewdata.LanguageViewData class FetchLanguageViewData( private val languageRepo: LanguageRepository, - private val contentCache: ContentCacheAccessor, - storage: StorageAccess + private val storage: StorageAccess ) { companion object { const val DISPLAY_ITEMS_LIMIT = 30 private const val MATCHING_RESULT_TAKE = 20 } - private val languageCodesFromStorage = storage.getLanguageCodes() fun getViewDataList( currentPath: String ): List { - val languages = languageRepo.getGatewayLanguages() + val languages = languageRepo.getAll() - val listViewData = languages.map { - val available = contentCache.isLanguageAvailable(it.code) + val listViewData = languages.sortedBy { it.isGateway }.map { + val available = storage.hasLanguageContent(it.code) LanguageViewData( code = it.code, @@ -37,7 +34,12 @@ class FetchLanguageViewData( ) } - return listViewData.filter { it.url != null } + listViewData.filter { it.url == null } + val availableLanguages = listViewData.filter { it.url != null } + val unavailableLanguages = listViewData.filter { it.url == null } + + val allLanguages = availableLanguages + unavailableLanguages + + return allLanguages.take(DISPLAY_ITEMS_LIMIT) } fun filterLanguages( @@ -45,17 +47,13 @@ class FetchLanguageViewData( currentPath: String, currentIndex: Int = 0 ): List { - val result = getMatchingLanguages(query, languageRepo.getAll()) + val result = getMatchingLanguages(query, languageRepo.getAll().sortedBy { it.isGateway }) return result .drop(currentIndex) .take(DISPLAY_ITEMS_LIMIT) .map { - val available = if (it.isGateway) { - contentCache.isLanguageAvailable(it.code) - } else { - it.code in languageCodesFromStorage - } + val available = storage.hasLanguageContent(it.code) LanguageViewData( code = it.code, @@ -77,13 +75,13 @@ class FetchLanguageViewData( if (currentIndex < 0) return listOf() // load more (default) is only applied to HL - val languages = languageRepo.getHeartLanguages() + val languages = languageRepo.getAll().sortedBy { it.isGateway } return languages - .drop(currentIndex) + .drop(currentIndex + DISPLAY_ITEMS_LIMIT - 1) .take(DISPLAY_ITEMS_LIMIT) .map { - val available = it.code in languageCodesFromStorage + val available = storage.hasLanguageContent(it.code) LanguageViewData( code = it.code, anglicizedName = it.anglicizedName, diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchProductViewData.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchProductViewData.kt index a1346a51..26a784f4 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchProductViewData.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/FetchProductViewData.kt @@ -1,27 +1,30 @@ package org.bibletranslationtools.fetcher.usecase +import org.bibletranslationtools.fetcher.data.ContainerExtensions import org.bibletranslationtools.fetcher.data.Product -import org.bibletranslationtools.fetcher.repository.ContentCacheAccessor import org.bibletranslationtools.fetcher.repository.ProductCatalog +import org.bibletranslationtools.fetcher.repository.StorageAccess import org.bibletranslationtools.fetcher.usecase.viewdata.ProductViewData class FetchProductViewData( productCatalog: ProductCatalog, + private val storage: StorageAccess, private val languageCode: String ) { private val products: List = productCatalog.getAll() fun getListViewData( - currentPath: String, - cacheAccessor: ContentCacheAccessor, - isGateway: Boolean + currentPath: String ): List { return products.map { - val isAvailable = if (isGateway) { - cacheAccessor.isProductAvailable(it.slug, languageCode) - } else { - it.slug == ProductFileExtension.MP3.name.toLowerCase() - } + val productExtension = ProductFileExtension.getType(it.slug)!! + val fileExtensions = if (ContainerExtensions.isSupported(productExtension.fileType)) { + listOf(ProductFileExtension.BTTR.fileType) + } else { + listOf(ProductFileExtension.MP3.fileType, ProductFileExtension.WAV.fileType) + } + + val isAvailable = storage.hasProductContent(languageCode, fileExtensions) ProductViewData( slug = it.slug, diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/ProductFileExtension.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/ProductFileExtension.kt index dea97472..4cdda115 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/ProductFileExtension.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/ProductFileExtension.kt @@ -4,6 +4,7 @@ import java.lang.IllegalArgumentException enum class ProductFileExtension(val fileType: String) { MP3("mp3"), + WAV("wav"), BTTR("tr"), ORATURE("zip"); diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/ProductFileQuality.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/ProductFileQuality.kt new file mode 100644 index 00000000..4386111f --- /dev/null +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/ProductFileQuality.kt @@ -0,0 +1,6 @@ +package org.bibletranslationtools.fetcher.usecase + +enum class ProductFileQuality(val quality: String) { + HI("hi"), + LOW("low") +} \ No newline at end of file diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/RequestResourceContainer.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/RequestResourceContainer.kt index 2b3b8d5c..062dba94 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/RequestResourceContainer.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/usecase/RequestResourceContainer.kt @@ -247,7 +247,7 @@ class RequestResourceContainer( val mediaTypes = listOf(MediaType.MP3, MediaType.CUE) private val mediaQualityMap = mapOf( - MediaType.MP3.toString() to "hi", + MediaType.MP3.toString() to ProductFileQuality.HI.quality, MediaType.WAV.toString() to "", MediaType.CUE.toString() to "" ) diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/AppModule.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/AppModule.kt index a33f0a53..f7eb2427 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/AppModule.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/AppModule.kt @@ -49,7 +49,7 @@ fun Application.appModule() { modules(appDependencyModule) } install(Routing) { - scheduleCacheUpdate() + //scheduleCacheUpdate() routing { // Static contents declared here static("static") { @@ -86,7 +86,7 @@ private fun scheduleCacheUpdate() { val envConfig: EnvironmentConfig = get() val cacheAccessor: ContentCacheAccessor = get() - thread(start = true, isDaemon = true, name = "cache-update") { + thread(start = true, isDaemon = true, name = "cache-update") { val minutes = envConfig.CACHE_REFRESH_MINUTES.toLong() while (true) { Thread.sleep(MILLISECONDS_PER_MINUTE * minutes) diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/BookController.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/BookController.kt index 2f32f025..1406466b 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/BookController.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/BookController.kt @@ -11,12 +11,10 @@ import io.ktor.routing.route import org.bibletranslationtools.fetcher.config.EnvironmentConfig import org.bibletranslationtools.fetcher.di.ext.CommonKoinExt.get import org.bibletranslationtools.fetcher.repository.BookRepository -import org.bibletranslationtools.fetcher.repository.ContentCacheAccessor import org.bibletranslationtools.fetcher.repository.LanguageRepository import org.bibletranslationtools.fetcher.repository.ProductCatalog import org.bibletranslationtools.fetcher.repository.StorageAccess import org.bibletranslationtools.fetcher.usecase.FetchBookViewData -import org.bibletranslationtools.fetcher.usecase.resourceIdByLanguage import org.bibletranslationtools.fetcher.web.controllers.utils.GL_ROUTE import org.bibletranslationtools.fetcher.web.controllers.utils.LANGUAGE_PARAM_KEY import org.bibletranslationtools.fetcher.web.controllers.utils.PRODUCT_PARAM_KEY @@ -61,7 +59,6 @@ private fun booksView( params: UrlParameters, path: String ): ThymeleafContent { - val contentCache = get() val language = get().getLanguage(params.languageCode)!! val product = get().getProduct(params.productSlug)!! @@ -71,7 +68,7 @@ private fun booksView( get(), language, product - ).getViewDataList(path, contentCache, language.isGateway) + ).getViewDataList(path) return ThymeleafContent( template = "books", @@ -81,7 +78,7 @@ private fun booksView( "languagesNavUrl" to "/$GL_ROUTE", "fileTypesNavTitle" to product.titleKey, "fileTypesNavUrl" to "/$GL_ROUTE/${params.languageCode}", - "booksNavUrl" to "#" + "booksNavUrl" to "" ), locale = getPreferredLocale(contentLanguage, "books") ) diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/ChapterController.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/ChapterController.kt index 09ededce..41eed14a 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/ChapterController.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/ChapterController.kt @@ -14,7 +14,6 @@ import org.bibletranslationtools.fetcher.data.Deliverable import org.bibletranslationtools.fetcher.di.ext.CommonKoinExt.get import org.bibletranslationtools.fetcher.repository.BookRepository import org.bibletranslationtools.fetcher.repository.ChapterCatalog -import org.bibletranslationtools.fetcher.repository.ContentCacheAccessor import org.bibletranslationtools.fetcher.repository.LanguageRepository import org.bibletranslationtools.fetcher.repository.ProductCatalog import org.bibletranslationtools.fetcher.repository.ResourceContainerRepository @@ -105,12 +104,8 @@ private fun Route.oratureChapters() { } } -private fun chaptersView( - paramObjects: Deliverable -): ThymeleafContent { - val isGateway = paramObjects.language.isGateway +private fun chaptersView(paramObjects: Deliverable): ThymeleafContent { val envConfig = get() - val contentCache = get() val storageAccess = get() val bookViewData: BookViewData? = FetchBookViewData( @@ -119,7 +114,7 @@ private fun chaptersView( storageAccess, paramObjects.language, paramObjects.product - ).getViewData(paramObjects.book.slug, contentCache, isGateway) + ).getViewData(paramObjects.book.slug) val chapterViewDataList: List? = try { FetchChapterViewData( @@ -129,7 +124,7 @@ private fun chaptersView( paramObjects.language, paramObjects.product, paramObjects.book - ).getViewDataList(contentCache, isGateway) + ).getViewDataList() } catch (ex: ClientRequestException) { return errorPage( "internal_error", diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/LanguageController.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/LanguageController.kt index 7b90bed4..f9737077 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/LanguageController.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/LanguageController.kt @@ -11,7 +11,6 @@ import io.ktor.routing.get import io.ktor.routing.route import java.lang.NumberFormatException import org.bibletranslationtools.fetcher.di.ext.CommonKoinExt.get -import org.bibletranslationtools.fetcher.repository.ContentCacheAccessor import org.bibletranslationtools.fetcher.repository.LanguageRepository import org.bibletranslationtools.fetcher.repository.StorageAccess import org.bibletranslationtools.fetcher.usecase.FetchLanguageViewData @@ -86,7 +85,6 @@ private fun languagesView( ): ThymeleafContent { val languageList = FetchLanguageViewData( get(), - get(), get() ).getViewDataList(path) @@ -94,7 +92,7 @@ private fun languagesView( template = "languages", model = mapOf( "languageList" to languageList, - "languagesNavUrl" to "#", + "languagesNavUrl" to "", "gatewayCount" to languageList.size ), locale = getPreferredLocale(contentLanguage, "languages") @@ -108,7 +106,6 @@ private fun filterLanguages( ): ThymeleafContent { val resultLanguages = FetchLanguageViewData( get(), - get(), get() ).filterLanguages(query, currentPath, currentIndex) @@ -129,7 +126,6 @@ private fun loadMore( ): ThymeleafContent { val moreLanguages = FetchLanguageViewData( get(), - get(), get() ).loadMoreLanguages(path, currentIndex) diff --git a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/ProductController.kt b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/ProductController.kt index 4c8b9021..708b7cc3 100644 --- a/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/ProductController.kt +++ b/fetcher-web/src/main/kotlin/org/bibletranslationtools/fetcher/web/controllers/ProductController.kt @@ -9,9 +9,9 @@ import io.ktor.routing.Routing import io.ktor.routing.get import io.ktor.routing.route import org.bibletranslationtools.fetcher.di.ext.CommonKoinExt.get -import org.bibletranslationtools.fetcher.repository.ContentCacheAccessor import org.bibletranslationtools.fetcher.repository.LanguageRepository import org.bibletranslationtools.fetcher.repository.ProductCatalog +import org.bibletranslationtools.fetcher.repository.StorageAccess import org.bibletranslationtools.fetcher.usecase.FetchProductViewData import org.bibletranslationtools.fetcher.web.controllers.utils.GL_ROUTE import org.bibletranslationtools.fetcher.web.controllers.utils.LANGUAGE_PARAM_KEY @@ -54,12 +54,12 @@ private fun productsView( path: String ): ThymeleafContent { val language = get().getLanguage(languageCode)!! - val contentCache = get() val productList = FetchProductViewData( get(), + get(), language.code - ).getListViewData(path, contentCache, language.isGateway) + ).getListViewData(path) return ThymeleafContent( template = "products", @@ -67,7 +67,7 @@ private fun productsView( "productList" to productList, "languagesNavTitle" to language.localizedName, "languagesNavUrl" to "/$GL_ROUTE", - "fileTypesNavUrl" to "#" + "fileTypesNavUrl" to "" ), locale = getPreferredLocale(contentLanguage, "products") ) diff --git a/fetcher-web/src/main/resources/templates/fragments/navbar.html b/fetcher-web/src/main/resources/templates/fragments/navbar.html index 5fca9d00..5ed32557 100644 --- a/fetcher-web/src/main/resources/templates/fragments/navbar.html +++ b/fetcher-web/src/main/resources/templates/fragments/navbar.html @@ -5,25 +5,25 @@
-

አማርኛ

Amharic

diff --git a/fetcher-web/src/test/kotlin/org/bibletranslationtools/fetcher/ContentAvailabilityCacheTest.kt b/fetcher-web/src/test/kotlin/org/bibletranslationtools/fetcher/ContentAvailabilityCacheTest.kt index 179799bc..2e7d3ba9 100644 --- a/fetcher-web/src/test/kotlin/org/bibletranslationtools/fetcher/ContentAvailabilityCacheTest.kt +++ b/fetcher-web/src/test/kotlin/org/bibletranslationtools/fetcher/ContentAvailabilityCacheTest.kt @@ -2,7 +2,6 @@ package org.bibletranslationtools.fetcher import com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable import java.io.File -import java.io.FileNotFoundException import org.bibletranslationtools.fetcher.config.EnvironmentConfig import org.bibletranslationtools.fetcher.data.Chapter import org.bibletranslationtools.fetcher.data.Language @@ -15,13 +14,11 @@ import org.bibletranslationtools.fetcher.impl.repository.StorageAccessImpl import org.bibletranslationtools.fetcher.repository.ChapterCatalog import org.bibletranslationtools.fetcher.repository.DirectoryProvider import org.bibletranslationtools.fetcher.repository.LanguageCatalog -import org.bibletranslationtools.fetcher.repository.ResourceContainerRepository import org.bibletranslationtools.fetcher.repository.StorageAccess -import org.bibletranslationtools.fetcher.usecase.RequestResourceContainer +import org.bibletranslationtools.fetcher.impl.repository.RequestResourceContainerImpl import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Assert.assertTrue -import org.junit.Assert.fail import org.junit.Test import org.mockito.ArgumentMatchers.anyString import org.mockito.Mockito.`when` @@ -87,14 +84,14 @@ class ContentAvailabilityCacheTest { private fun CreateResourcesForBuildingCache(tempDir: File) { var chapterPath: File - if (RequestResourceContainer.mediaTypes.contains(MediaType.WAV)) { + if (RequestResourceContainerImpl.mediaTypes.contains(MediaType.WAV)) { chapterPath = tempDir.resolve( "en/ulb/2pe/$chapterNumber/CONTENTS/wav/chapter" ).apply { mkdirs() } chapterPath.resolve("en_ulb_2pe_c$chapterNumber.wav").createNewFile() } - if (RequestResourceContainer.mediaTypes.contains(MediaType.MP3)) { + if (RequestResourceContainerImpl.mediaTypes.contains(MediaType.MP3)) { chapterPath = tempDir.resolve( "en/ulb/2pe/$chapterNumber/CONTENTS/mp3/hi/chapter" ).apply { mkdirs() } From 5defc370a32a7e4238c74c6d3f50eda0f8e2759e Mon Sep 17 00:00:00 2001 From: Tony <34975907+AnonymousWalker@users.noreply.github.com> Date: Fri, 24 May 2024 10:58:00 -0400 Subject: [PATCH 6/6] Create pull_request_template.md (#203) * Create pull_request_template.md * Rename to PULL_REQUEST_TEMPLATE.md * Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..fde12b1d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,6 @@ +## Please include a summary of your changes. + + +## Before merging: +* [ ] If this PR targets dev branch, do a Squash-merge. +* [ ] If the target branch is prod, do a Regular merge.