diff --git a/app/build.gradle b/app/build.gradle index ffb88ec2..234b2006 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -126,8 +126,8 @@ android { buildConfig true } defaultConfig { - versionCode 3020211 - versionName "6.0.11" + versionCode 3020212 + versionName "6.0.12" applicationId "ac.mdiq.podcini.R" def commit = "" diff --git a/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadRequestCreator.kt b/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadRequestCreator.kt index 074dc9e8..e53701bd 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadRequestCreator.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadRequestCreator.kt @@ -82,7 +82,7 @@ object DownloadRequestCreator { private fun getMediafilePath(media: EpisodeMedia): String { val item = media.episode ?: return "" - Logd(TAG, "item managed: ${item?.isManaged()}") + Logd(TAG, "item managed: ${item.isManaged()}") val title = item.feed?.title?:return "" val mediaPath = (MEDIA_DOWNLOADPATH + FileNameGenerator.generateFileName(title)) return UserPreferences.getDataFolder(mediaPath).toString() + "/" diff --git a/app/src/main/kotlin/ac/mdiq/podcini/preferences/fragments/ImportExportPreferencesFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/preferences/fragments/ImportExportPreferencesFragment.kt index 980d10f8..d5ec329c 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/preferences/fragments/ImportExportPreferencesFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/preferences/fragments/ImportExportPreferencesFragment.kt @@ -8,6 +8,7 @@ import ac.mdiq.podcini.net.sync.model.EpisodeAction import ac.mdiq.podcini.net.sync.model.EpisodeAction.Companion.readFromJsonObject import ac.mdiq.podcini.net.sync.model.SyncServiceException import ac.mdiq.podcini.preferences.ExportWriter +import ac.mdiq.podcini.preferences.OpmlTransporter.* import ac.mdiq.podcini.preferences.UserPreferences.getDataFolder import ac.mdiq.podcini.storage.database.Episodes.getEpisodeByGuidOrUrl import ac.mdiq.podcini.storage.database.Episodes.getEpisodes @@ -15,12 +16,11 @@ import ac.mdiq.podcini.storage.database.Feeds.getFeedList import ac.mdiq.podcini.storage.database.RealmDB.realm import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk import ac.mdiq.podcini.storage.model.Episode -import ac.mdiq.podcini.storage.model.Feed -import ac.mdiq.podcini.preferences.OpmlTransporter.* -import ac.mdiq.podcini.storage.database.Episodes.getEpisodeByTitle import ac.mdiq.podcini.storage.model.EpisodeFilter -import ac.mdiq.podcini.storage.utils.EpisodeUtil.hasAlmostEnded import ac.mdiq.podcini.storage.model.EpisodeSortOrder +import ac.mdiq.podcini.storage.model.Feed +import ac.mdiq.podcini.storage.utils.EpisodeUtil.hasAlmostEnded +import ac.mdiq.podcini.storage.utils.FileNameGenerator.generateFileName import ac.mdiq.podcini.ui.activity.OpmlImportActivity import ac.mdiq.podcini.ui.activity.PreferenceActivity import ac.mdiq.podcini.util.Logd @@ -709,6 +709,9 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { object MediaFilesTransporter { private val TAG: String = MediaFilesTransporter::class.simpleName ?: "Anonymous" + var feed: Feed? = null + val nameFeedMap: MutableMap = mutableMapOf() + val nameEpisodeMap: MutableMap = mutableMapOf() @Throws(IOException::class) fun exportToDocument(uri: Uri, context: Context) { try { @@ -753,6 +756,13 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { private fun copyRecursive(context: Context, srcFile: DocumentFile, srcRootDir: DocumentFile, destRootDir: File) { val relativePath = srcFile.uri.path?.substring(srcRootDir.uri.path!!.length+1) ?: return if (srcFile.isDirectory) { + Logd(TAG, "copyRecursive folder title: $relativePath") + feed = nameFeedMap[relativePath] ?: return + Logd(TAG, "copyRecursive found feed: ${feed?.title}") + nameEpisodeMap.clear() + feed!!.episodes.forEach { e -> + if (!e.title.isNullOrEmpty()) nameEpisodeMap[generateFileName(e.title!!)] = e + } val destFile = File(destRootDir, relativePath) if (!destFile.exists()) destFile.mkdirs() srcFile.listFiles().forEach { file -> @@ -763,13 +773,18 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { if (nameParts.size < 3) return val ext = nameParts[nameParts.size-1] val title = nameParts.dropLast(2).joinToString(".") - Logd(TAG, "copyRecursive title: $title") - val episode = getEpisodeByTitle(title) ?: return + Logd(TAG, "copyRecursive file title: $title") + val episode = nameEpisodeMap[title] ?: return + Logd(TAG, "copyRecursive found episode: ${episode.title}") val destName = "$title.${episode.id}.$ext" val destFile = File(destRootDir, destName) if (!destFile.exists()) { + Logd(TAG, "copyRecursive copying file to: ${destFile.absolutePath}") copyFile(srcFile, destFile, context) - upsertBlk(episode) { it.media?.setfileUrlOrNull(destFile.name)} + upsertBlk(episode) { + it.media?.fileUrl = destFile.absolutePath + it.media?.setIsDownloaded() + } } } } @@ -798,13 +813,24 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { val exportedDir = DocumentFile.fromTreeUri(context, uri) ?: throw IOException("Backup directory is not valid") if (exportedDir.name?.contains("Podcini-MediaFiles") != true) return val mediaDir = context.getExternalFilesDir("media") ?: return - exportedDir.listFiles().forEach { file -> - copyRecursive(context, file, exportedDir, mediaDir) + val fileList = exportedDir.listFiles() + if (fileList.isNotEmpty()) { + val feeds = getFeedList() + feeds.forEach { f -> + if (!f.title.isNullOrEmpty()) nameFeedMap[generateFileName(f.title!!)] = f + } + fileList.forEach { file -> + copyRecursive(context, file, exportedDir, mediaDir) + } } } catch (e: IOException) { Log.e(TAG, Log.getStackTraceString(e)) throw e - } finally { } + } finally { + nameFeedMap.clear() + nameEpisodeMap.clear() + feed = null + } } } diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/utils/FileNameGenerator.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/utils/FileNameGenerator.kt index 406d6d8d..b6489b9b 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/storage/utils/FileNameGenerator.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/utils/FileNameGenerator.kt @@ -24,7 +24,7 @@ object FileNameGenerator { */ @JvmStatic fun generateFileName(string: String): String { - var string = StringUtils.stripAccents(string) + val string = StringUtils.stripAccents(string) val buf = StringBuilder() for (c in string) { if (Character.isSpaceChar(c) && (buf.isEmpty() || Character.isSpaceChar(buf[buf.length - 1]))) continue diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt index 3406e0b0..afa81718 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/FeedEpisodesFragment.kt @@ -618,6 +618,9 @@ import java.util.concurrent.Semaphore } else episodes.addAll(feed_.episodes) val sortOrder = fromCode(feed_.preferences?.sortOrderCode?:0) if (sortOrder != null) getPermutor(sortOrder).reorder(episodes) +// episodes.forEach { +// Logd(TAG, "Episode: ${it.title} ${it.media?.downloaded} ${it.media?.fileUrl}") +// } if (onInit) { var hasNonMediaItems = false for (item in episodes) { diff --git a/app/src/main/res/xml/preferences_import_export.xml b/app/src/main/res/xml/preferences_import_export.xml index 18aa644d..3822b50a 100644 --- a/app/src/main/res/xml/preferences_import_export.xml +++ b/app/src/main/res/xml/preferences_import_export.xml @@ -22,11 +22,11 @@ search:keywords="@string/import_export_search_keywords" android:title="@string/media_files_export_label" android:summary="@string/media_files_export_summary"/> - - - - - + diff --git a/changelog.md b/changelog.md index 4219d43e..43fd9c05 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,9 @@ +# 6.0.12 + +* re-enabled import of downloaded media files, which can be used to migrate from 5.5.4. Media files imported are restricted to existing feeds and episodes. +* importing media files is only allowed from a directory with name containing "Podcini-MediaFiles" +* if you have imported some media files exported from 5.5.4 using version 6.0.10, these files are junk. You can opt for clearing storage or re-installing version 6, or you can ignore them for now as I plan to provide media file management functionality in the near future. + # 6.0.11 * This is a minor release of subtraction: import of downloaded media files is temporarily disabled as it's more complicated than I thought. Imported file names from earlier versions aren't easily recognizable. diff --git a/fastlane/metadata/android/en-US/changelogs/3020212.txt b/fastlane/metadata/android/en-US/changelogs/3020212.txt new file mode 100644 index 00000000..41c2abaf --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/3020212.txt @@ -0,0 +1,6 @@ + +Version 6.0.12 brings several changes: + +* re-enabled import of downloaded media files, which can be used to migrate from 5.5.4. Media files imported are restricted to existing feeds and episodes. +* importing media files is only allowed from a directory with name containing "Podcini-MediaFiles" +* if you have imported some media files exported from 5.5.4 using version 6.0.10, these files are junk. You can opt for clearing storage or re-installing version 6, or you can ignore them for now as I plan to provide media file management functionality in the near future. diff --git a/migrationTo6.md b/migrationTo6.md index 4e5fed3e..2d4ab96a 100644 --- a/migrationTo6.md +++ b/migrationTo6.md @@ -13,15 +13,13 @@ the following can be imported to it from Settings -> Import/Export: * preferences files * OPML file * json file of episodes progress -* downloaded media files (5.5.4 only, but currently not enabled for import) +* downloaded media files (5.5.4 only) An OPML file should be imported before importing episodes progress, but you can always re-do any of the above These files can be best exported in version 5.5.4 (or 5.5.3, or 5.5.2) in Settings -> Import/Export -Then your subscriptions, listening progress, favorites, and app preferences will be updated. - -Unfortunately, media files will need to be separately downloaded. +Then your subscriptions, listening progress, favorites, downloaded media files, and app preferences will be updated. * Note you can also export the progress from version 5.5.2 if you don't have 5.5.3, the difference is only that 5.5.3 includes the info about how far out an episode has been played, which can be useful when looking at statistics. Without that info, you can get similar (albeit not exactly the same) results by "Include marked played" in the filter of the statistics view.