SyncedFolderUtils.kt 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Nextcloud Android client application
  3. *
  4. * @author Andy Scherzinger
  5. * Copyright (C) 2020 Andy Scherzinger
  6. * Copyright (C) 2022 Álvaro Brey
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. package com.owncloud.android.utils
  22. import com.owncloud.android.datamodel.MediaFolder
  23. import com.owncloud.android.datamodel.MediaFolderType
  24. import com.owncloud.android.datamodel.SyncedFolder
  25. import java.io.File
  26. /**
  27. * Utility class with methods for processing synced folders.
  28. */
  29. object SyncedFolderUtils {
  30. private val DISQUALIFIED_MEDIA_DETECTION_SOURCE = listOf(
  31. "cover.jpg",
  32. "cover.jpeg",
  33. "folder.jpg",
  34. "folder.jpeg"
  35. )
  36. private val DISQUALIFIED_MEDIA_DETECTION_FILE_SET: Set<String> = DISQUALIFIED_MEDIA_DETECTION_SOURCE.toSet()
  37. private val AUTO_QUALIFYING_FOLDER_TYPE_SET: Set<MediaFolderType> = setOf(MediaFolderType.CUSTOM)
  38. private const val THUMBNAIL_FOLDER_PREFIX = ".thumbnail"
  39. private const val THUMBNAIL_DATA_FILE_PREFIX = ".thumbdata"
  40. private const val SINGLE_FILE = 1
  41. /**
  42. * analyzes a given media folder if its content qualifies for the folder to be handled as a media folder.
  43. *
  44. * @param mediaFolder media folder to analyse
  45. * @return `true` if it qualifies as a media folder else `false`
  46. */
  47. fun isQualifyingMediaFolder(mediaFolder: MediaFolder?): Boolean {
  48. return when {
  49. mediaFolder == null -> false
  50. AUTO_QUALIFYING_FOLDER_TYPE_SET.contains(mediaFolder.type) -> true
  51. !isQualifiedFolder(mediaFolder.absolutePath) -> false
  52. else -> {
  53. when {
  54. mediaFolder.numberOfFiles < SINGLE_FILE -> false
  55. // music album (just one cover-art image)
  56. mediaFolder.type == MediaFolderType.IMAGE -> containsQualifiedImages(
  57. mediaFolder.filePaths.map { File(it) }
  58. )
  59. else -> true
  60. }
  61. }
  62. }
  63. }
  64. /**
  65. * analyzes a given synced folder if its content qualifies for the folder to be handled as a media folder.
  66. *
  67. * @param syncedFolder synced folder to analyse
  68. * @return `true` if it qualifies as a media folder else `false`
  69. */
  70. fun isQualifyingMediaFolder(syncedFolder: SyncedFolder?): Boolean {
  71. if (syncedFolder == null) {
  72. return false
  73. }
  74. return isQualifyingMediaFolder(syncedFolder.localPath, syncedFolder.type)
  75. }
  76. /**
  77. * analyzes a given folder based on a path-string and type if its content qualifies for the folder to be handled as
  78. * a media folder.
  79. *
  80. * @param folderPath String representation for a folder
  81. * @param folderType type of the folder
  82. * @return `true` if it qualifies as a media folder else `false`
  83. */
  84. fun isQualifyingMediaFolder(folderPath: String?, folderType: MediaFolderType): Boolean {
  85. return when {
  86. AUTO_QUALIFYING_FOLDER_TYPE_SET.contains(folderType) -> true
  87. !isQualifiedFolder(folderPath) -> false
  88. folderPath == null -> false
  89. else -> {
  90. val files: List<File> = getFileList(File(folderPath))
  91. when {
  92. // no files
  93. files.size < SINGLE_FILE -> false
  94. // music album (just one cover-art image)
  95. folderType == MediaFolderType.IMAGE -> containsQualifiedImages(files)
  96. else -> true
  97. }
  98. }
  99. }
  100. }
  101. /**
  102. * check if folder is qualified for auto upload.
  103. *
  104. * @param folderPath the folder's path string
  105. * @return code>true if folder qualifies for auto upload else `false`
  106. */
  107. @JvmStatic
  108. fun isQualifiedFolder(folderPath: String?): Boolean {
  109. if (folderPath == null) {
  110. return false
  111. }
  112. val folder = File(folderPath)
  113. // check if folder starts with thumbnail prefix
  114. return folder.isDirectory && !folder.name.startsWith(THUMBNAIL_FOLDER_PREFIX)
  115. }
  116. /**
  117. * check if given list of files contains images that qualify as auto upload relevant files.
  118. *
  119. * @param files list of files
  120. * @return `true` if at least one files qualifies as auto upload relevant else `false`
  121. */
  122. private fun containsQualifiedImages(files: List<File>): Boolean {
  123. return files.any { isFileNameQualifiedForAutoUpload(it.name) && MimeTypeUtil.isImage(it) }
  124. }
  125. /**
  126. * check if given file is auto upload relevant files.
  127. *
  128. * @param fileName file name to be checked
  129. * @return `true` if the file qualifies as auto upload relevant else `false`
  130. */
  131. @JvmStatic
  132. fun isFileNameQualifiedForAutoUpload(fileName: String?): Boolean {
  133. return when {
  134. fileName != null -> {
  135. !DISQUALIFIED_MEDIA_DETECTION_FILE_SET.contains(fileName.lowercase()) &&
  136. !fileName.startsWith(THUMBNAIL_DATA_FILE_PREFIX)
  137. }
  138. else -> false
  139. }
  140. }
  141. /**
  142. * return list of files for given folder.
  143. *
  144. * @param localFolder folder to scan
  145. * @return sorted list of folder of given folder
  146. */
  147. fun getFileList(localFolder: File): List<File> {
  148. val files: Array<File> = localFolder.listFiles { pathname: File -> !pathname.isDirectory } ?: return emptyList()
  149. return files
  150. .map { Pair(it, it.lastModified()) }
  151. .sortedBy { it.second }
  152. .map { it.first }
  153. }
  154. }