Получите разрешение на чтение для URI на Android из файла Playlist без FilePickerAndroid

Форум для тех, кто программирует под Android
Anonymous
Получите разрешение на чтение для URI на Android из файла Playlist без FilePicker

Сообщение Anonymous »

Моя цель - прочитать файл плейлиста (M3U) и запрашивать/прочитать метаданные для каждого файла. Однако я как бы застрял в разрешении. Остальное должно быть «автоматическим» < /p>
Во-первых, я прошу разрешение на чтение для файла плейлиста, выполнив: < /p>
val filePickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenDocument(),
onResult = { uri: Uri? ->
context.contentResolver.takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)

context.contentResolver.openInputStream(it)?.use { inputStream -> // readfile}

// ADD OPTION 1 OR 2 HERE

}

< /code>
У меня есть два варианта; fun scanMediaStore(): MutableList {
val mediaFiles: MutableList = mutableListOf()

val projection = arrayOf(
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.ALBUM_ID,
)
val selectionArgs = arrayOf("%.mp3", "%.m4a")
val selection = selectionArgs.joinToString(" OR ") {
"${MediaStore.Audio.Media.DATA} LIKE ?"
}

val sortOrder = null

fun queryMediaStore(uri: Uri) {
Log.d("Scanning", "queryMediaStore: $uri")
app.contentResolver.query(
uri,
projection,
selection,
selectionArgs,
sortOrder
)?.use { cursor ->
while (cursor.moveToNext()) {
val getOrThrow: (String) -> Int = { columnName ->
cursor.getColumnIndexOrThrow(columnName)
}

val mediaID: Int = cursor.getInt(getOrThrow(MediaStore.Audio.Media._ID))
val name: String = cursor.getString(getOrThrow(MediaStore.Audio.Media.TITLE))
val path: String = cursor.getString(getOrThrow(MediaStore.Audio.Media.DATA))
val artist: String = cursor.getString(getOrThrow(MediaStore.Audio.Media.ARTIST))
val duration: Int = cursor.getInt(getOrThrow(MediaStore.Audio.Media.DURATION))

Log.d("MediaFiles", "Found: $path")
mediaFiles.add(...)
}
}
}

queryMediaStore(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)
queryMediaStore(MediaStore.Audio.Media.INTERNAL_CONTENT_URI)

return mediaFiles
}

for path in playlist:
MatchAgainst(path, scanMediaStore()) // pseudo code; matches paths/names against already scanned files

< /code>
или лучший вариант (который борется за работу)fun getMediaIDFor(path: String) : int {
???
}

fun getMetaDataAndAdd(path: String) : int {
???
}

// pseudo code
for path in playlist:
itemID = getMediaIDFor(path)
if (itemID not in scanMediaStore()) {
getMetaDataAndAdd(itemID/path)
}

< /code>
Для тех, кто заинтересован в том, что я специально говорит о M3U, сгенерированном Samsungmusic, и файлы обычно содержат относительные пути к файлу. (Итак, "../../..../sdcardid/foo/bar/song.mp3")
Что я пробовал:
непосредственно чтение FilePaths (ошибка разрешения)
Query uri (ursired yrrish-k prety-ktride" lang-kt-ktide "// Uri is built with

val playlistDocId = DocumentsContract.getDocumentId(it)
val basePath = playlistDocId.substringBeforeLast("/")
val baseUri = DocumentsContract.buildDocumentUri("com.android.externalstorage.documents", basePath)
var resolvedUri = resolveRelativeUri(baseUri, path) // where path is the relative path from the playlist file

fun resolveRelativeUri(baseUri: Uri, relativePath: String): Uri {
val baseDocId = DocumentsContract.getDocumentId(baseUri)
val baseParts = baseDocId.split(":", limit = 2)
val storageRoot = baseParts[0]
val baseDir = baseParts.getOrNull(1) ?: ""

val normalizedPath = File("/$baseDir", relativePath).normalize().path.removePrefix("/")
val resolvedDocId = "$storageRoot:$normalizedPath"

return DocumentsContract.buildDocumentUri(
"com.android.externalstorage.documents",
resolvedDocId
)
}

fun resolveRelativeUri(baseUri: Uri, relativePath: String): Uri {
val baseDocId = DocumentsContract.getDocumentId(baseUri)
val baseParts = baseDocId.split(":", limit = 2)
val storageRoot = baseParts[0]
val baseDir = baseParts.getOrNull(1) ?: ""

val normalizedPath = File("/$baseDir", relativePath).normalize().path.removePrefix("/")
val resolvedDocId = "$storageRoot:$normalizedPath"

return DocumentsContract.buildDocumentUri(
"com.android.externalstorage.documents",
resolvedDocId
)
}

suspend fun getSongFromUri(uri: Uri): ...? = withContext(Dispatchers.IO) {
Log.d("ViewModel", "Trying to read $uri")
val projection = arrayOf(
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DURATION
)

app.contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
if (cursor.moveToFirst()) {
val id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID))
val title =
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE))
val path =
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA))
val artist =
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST))
val duration =
cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION))

return@withContext ...
}
}
return@withContext null
}

< /code>
его JetPack Compose
Target API - Android 10+; Тем не менее, обратная совместимость приветствуется.
Любая помощь ценится.

Подробнее здесь: https://stackoverflow.com/questions/796 ... filepicker

Вернуться в «Android»