mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-08-05 19:59:51 +00:00
feat: integrate Uniffi for audio metadata reading and writing with Lofty library
This commit is contained in:
parent
abeae2144c
commit
a09a7c8976
12
.github/workflows/spotube-release-binary.yml
vendored
12
.github/workflows/spotube-release-binary.yml
vendored
@ -112,6 +112,9 @@ jobs:
|
||||
distribution: temurin
|
||||
java-version: 21
|
||||
|
||||
- name: Set up Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
@ -170,6 +173,9 @@ jobs:
|
||||
distribution: temurin
|
||||
java-version: 21
|
||||
|
||||
- name: Set up Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
@ -231,6 +237,9 @@ jobs:
|
||||
distribution: temurin
|
||||
java-version: 21
|
||||
|
||||
- name: Set up Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
@ -268,6 +277,9 @@ jobs:
|
||||
distribution: temurin
|
||||
java-version: 21
|
||||
|
||||
- name: Set up Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -113,3 +113,5 @@ android/app/.cxx
|
||||
/package.json
|
||||
/package-lock.json
|
||||
/bun.lock
|
||||
|
||||
**/target/
|
||||
@ -30,4 +30,6 @@ plugins {
|
||||
alias(libs.plugins.zipline.gradle.plugin) apply false
|
||||
alias(libs.plugins.spotubeGradle) apply false
|
||||
alias(libs.plugins.vlcjBundler) apply false
|
||||
alias(libs.plugins.uniffi) apply false
|
||||
alias(libs.plugins.cargo) apply false
|
||||
}
|
||||
723
composeApp/Cargo.lock
generated
Normal file
723
composeApp/Cargo.lock
generated
Normal file
@ -0,0 +1,723 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "basic-toml"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-platform"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.19.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "compose-app"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lofty",
|
||||
"uniffi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs-err"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47"
|
||||
dependencies = [
|
||||
"log",
|
||||
"plain",
|
||||
"scroll",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||
|
||||
[[package]]
|
||||
name = "lofty"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dec4feeff6c7d75093278133a06e827d7af6d2bfe20b0f331f9d10338a5ec7ca"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"data-encoding",
|
||||
"flate2",
|
||||
"lofty_attr",
|
||||
"log",
|
||||
"ogg_pager",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lofty_attr"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "458ace39169e4b83c4f77ae3d42d5d1d11c422feef590219a97c973d3b524557"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ogg_pager"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d36b1d6964c3ac92b7aea701057e02b6b91143d70d83b20abf75a231a3c0216"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "plain"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
|
||||
dependencies = [
|
||||
"scroll_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll_derive"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||
|
||||
[[package]]
|
||||
name = "smawk"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8e2fb0f499abb4d162f2bedad68f5ef91a1682b5a03596ddb67efd37768d100"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
|
||||
dependencies = [
|
||||
"smawk",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "uniffi"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3291800a6b06569f7d3e15bdb6dc235e0f0c8bd3eb07177f430057feb076415f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_metadata",
|
||||
"uniffi_bindgen",
|
||||
"uniffi_core",
|
||||
"uniffi_macros",
|
||||
"uniffi_pipeline",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_bindgen"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a04b99fa7796eaaa7b87976a0dbdd1178dc1ee702ea00aca2642003aef9b669e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama",
|
||||
"camino",
|
||||
"cargo_metadata",
|
||||
"fs-err",
|
||||
"glob",
|
||||
"goblin",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"tempfile",
|
||||
"textwrap",
|
||||
"toml",
|
||||
"uniffi_internal_macros",
|
||||
"uniffi_meta",
|
||||
"uniffi_pipeline",
|
||||
"uniffi_udl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_core"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f38a9a27529ccff732f8efddb831b65b1e07f7dea3fd4cacd4a35a8c4b253b98"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"once_cell",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_internal_macros"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09acd2ce09c777dd65ee97c251d33c8a972afc04873f1e3b21eb3492ade16933"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_macros"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5596f178c4f7aafa1a501c4e0b96236a96bc2ef92bdb453d83e609dad0040152"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"fs-err",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn",
|
||||
"toml",
|
||||
"uniffi_meta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_meta"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beadc1f460eb2e209263c49c4f5b19e9a02e00a3b2b393f78ad10d766346ecff"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"siphasher",
|
||||
"uniffi_internal_macros",
|
||||
"uniffi_pipeline",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_pipeline"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd76b3ac8a2d964ca9fce7df21c755afb4c77b054a85ad7a029ad179cc5abb8a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"tempfile",
|
||||
"uniffi_internal_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_udl"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4319cf905911d70d5b97ce0f46f101619a22e9a189c8c46d797a9955e9233716"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"textwrap",
|
||||
"uniffi_meta",
|
||||
"weedle2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weedle2"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
||||
12
composeApp/Cargo.toml
Normal file
12
composeApp/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "compose-app"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
uniffi = "0.29.4"
|
||||
lofty = "0.24.0"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "staticlib"]
|
||||
path = "src/commonMain/rust/lib.rs"
|
||||
@ -15,6 +15,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import gobley.gradle.GobleyHost
|
||||
import gobley.gradle.cargo.dsl.jvm
|
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||
import org.jetbrains.compose.reload.gradle.ComposeHotRun
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
@ -30,6 +32,9 @@ plugins {
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
alias(libs.plugins.zipline.gradle.plugin)
|
||||
alias(libs.plugins.vlcjBundler)
|
||||
alias(libs.plugins.uniffi)
|
||||
alias(libs.plugins.cargo)
|
||||
kotlin("plugin.atomicfu") version libs.versions.kotlin
|
||||
}
|
||||
|
||||
vlcjBundler {
|
||||
@ -334,3 +339,9 @@ tasks.withType<ComposeHotRun>().configureEach {
|
||||
project.layout.buildDirectory.dir("compose/tmp/prepareAppResources").get()
|
||||
)
|
||||
}
|
||||
|
||||
cargo {
|
||||
builds.jvm {
|
||||
embedRustLibrary = (rustTarget == GobleyHost.current.rustTarget)
|
||||
}
|
||||
}
|
||||
@ -392,25 +392,42 @@ class DownloadManager(
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyMetadata(item: DownloadItem, filename: String, downloadDir: Path) {
|
||||
private suspend fun applyMetadata(item: DownloadItem, filename: String, downloadDir: Path) {
|
||||
val filePath = downloadDir / filename.toPath()
|
||||
if (!fileSystem.exists(filePath)) return
|
||||
|
||||
// TODO: Write metadata/audio tags to the downloaded file.
|
||||
// This is the dedicated placeholder for metadata tagging.
|
||||
// Implementation should use a platform-specific audio tagging library
|
||||
// to write ID3 tags (MP3), MP4 atoms (M4A/AAC), Vorbis comments (OGG/FLAC), etc.
|
||||
//
|
||||
// Tags to write from the track metadata:
|
||||
// - Title: item.title
|
||||
// - Artist: item.artists
|
||||
// - Album: item.album
|
||||
// - Track number: item.track?.trackNumber
|
||||
// - Disc number: item.track?.discNumber
|
||||
// - Duration: item.track?.durationMs
|
||||
// - Album art: item.track?.thumbnails (download and embed)
|
||||
// - ISRC: item.track?.isrcCode
|
||||
// - External URI: item.track?.externalUri
|
||||
val track = item.track ?: return
|
||||
|
||||
val coverBytes = try {
|
||||
val thumbnail = track.thumbnails?.maxByOrNull { it.width * it.height }
|
||||
if (thumbnail != null) {
|
||||
val response = httpClient.get(thumbnail.url)
|
||||
val channel = response.bodyAsChannel()
|
||||
val packet = channel.readRemaining()
|
||||
val bytes = packet.readByteArray()
|
||||
packet.close()
|
||||
bytes
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.w(e) { "Failed to download cover art for ${item.title}" }
|
||||
null
|
||||
}
|
||||
|
||||
try {
|
||||
uniffi.compose_app.writeAudioMetadata(
|
||||
filePath = filePath.toString(),
|
||||
title = item.title,
|
||||
artists = item.artists,
|
||||
album = item.album,
|
||||
trackNumber = track.trackNumber,
|
||||
discNumber = track.discNumber,
|
||||
coverBytes = coverBytes,
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
logger.w(e) { "Failed to write audio metadata for ${item.title}" }
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveDownloadDir(): Path {
|
||||
|
||||
160
composeApp/src/commonMain/rust/lib.rs
Normal file
160
composeApp/src/commonMain/rust/lib.rs
Normal file
@ -0,0 +1,160 @@
|
||||
use lofty::config::WriteOptions;
|
||||
use lofty::file::{AudioFile, FileType, TaggedFileExt};
|
||||
use lofty::picture::Picture;
|
||||
use lofty::probe::Probe;
|
||||
use lofty::tag::{Accessor, Tag, TagExt};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(uniffi::Record)]
|
||||
pub struct AudioMetadata {
|
||||
pub title: Option<String>,
|
||||
pub artists: Vec<String>,
|
||||
pub album: Option<String>,
|
||||
pub duration_ms: i64,
|
||||
pub track_number: Option<u32>,
|
||||
pub disc_number: Option<u32>,
|
||||
pub cover_bytes: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, uniffi::Error)]
|
||||
pub enum AudioTagError {
|
||||
FileNotFound,
|
||||
ReadError { reason: String },
|
||||
WriteError { reason: String },
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AudioTagError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AudioTagError::FileNotFound => write!(f, "File not found"),
|
||||
AudioTagError::ReadError { reason } => write!(f, "Read error: {}", reason),
|
||||
AudioTagError::WriteError { reason } => write!(f, "Write error: {}", reason),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
fn read_audio_metadata(file_path: String) -> Result<AudioMetadata, AudioTagError> {
|
||||
let path = Path::new(&file_path);
|
||||
if !path.exists() {
|
||||
return Err(AudioTagError::FileNotFound);
|
||||
}
|
||||
|
||||
let tagged_file = Probe::open(path)
|
||||
.map_err(|e| AudioTagError::ReadError { reason: e.to_string() })?
|
||||
.read()
|
||||
.map_err(|e| AudioTagError::ReadError { reason: e.to_string() })?;
|
||||
|
||||
let duration = tagged_file.properties().duration();
|
||||
let duration_ms = duration.as_millis() as i64;
|
||||
|
||||
let tag = tagged_file.primary_tag().or_else(|| tagged_file.first_tag());
|
||||
|
||||
let mut title = None;
|
||||
let mut artists = Vec::new();
|
||||
let mut album = None;
|
||||
let mut track_number = None;
|
||||
let mut disc_number = None;
|
||||
let mut cover_bytes = None;
|
||||
|
||||
if let Some(tag) = tag {
|
||||
title = tag.title().map(|s| s.to_string());
|
||||
|
||||
if let Some(artist) = tag.artist() {
|
||||
artists = artist
|
||||
.split(';')
|
||||
.map(|s| s.trim().to_string())
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect();
|
||||
}
|
||||
|
||||
album = tag.album().map(|s| s.to_string());
|
||||
track_number = tag.track();
|
||||
disc_number = tag.disk();
|
||||
|
||||
if let Some(pic) = tag.pictures().first() {
|
||||
cover_bytes = Some(pic.data().to_vec());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(AudioMetadata {
|
||||
title,
|
||||
artists,
|
||||
album,
|
||||
duration_ms,
|
||||
track_number,
|
||||
disc_number,
|
||||
cover_bytes,
|
||||
})
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
fn write_audio_metadata(
|
||||
file_path: String,
|
||||
title: String,
|
||||
artists: String,
|
||||
album: Option<String>,
|
||||
track_number: Option<i32>,
|
||||
disc_number: Option<i32>,
|
||||
cover_bytes: Option<Vec<u8>>,
|
||||
) -> Result<(), AudioTagError> {
|
||||
let path = Path::new(&file_path);
|
||||
if !path.exists() {
|
||||
return Err(AudioTagError::FileNotFound);
|
||||
}
|
||||
|
||||
let mut tagged_file = Probe::open(path)
|
||||
.map_err(|e| AudioTagError::ReadError { reason: e.to_string() })?
|
||||
.read()
|
||||
.map_err(|e| AudioTagError::ReadError { reason: e.to_string() })?;
|
||||
|
||||
let file_type = tagged_file.file_type();
|
||||
|
||||
if tagged_file.primary_tag().is_none() && tagged_file.first_tag().is_none() {
|
||||
let new_tag = match file_type {
|
||||
FileType::Mpeg => Tag::new(lofty::tag::TagType::Id3v2),
|
||||
FileType::Mp4 => Tag::new(lofty::tag::TagType::Mp4Ilst),
|
||||
FileType::Flac => Tag::new(lofty::tag::TagType::VorbisComments),
|
||||
FileType::Opus | FileType::Vorbis => Tag::new(lofty::tag::TagType::VorbisComments),
|
||||
_ => Tag::new(lofty::tag::TagType::Id3v2),
|
||||
};
|
||||
tagged_file.insert_tag(new_tag);
|
||||
}
|
||||
|
||||
let tag = if tagged_file.primary_tag().is_some() {
|
||||
tagged_file.primary_tag_mut().unwrap()
|
||||
} else if tagged_file.first_tag().is_some() {
|
||||
tagged_file.first_tag_mut().unwrap()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
tag.set_title(title);
|
||||
tag.set_artist(artists);
|
||||
|
||||
if let Some(album_name) = album {
|
||||
tag.set_album(album_name);
|
||||
}
|
||||
|
||||
if let Some(num) = track_number {
|
||||
tag.set_track(num as u32);
|
||||
}
|
||||
|
||||
if let Some(num) = disc_number {
|
||||
tag.set_disk(num as u32);
|
||||
}
|
||||
|
||||
if let Some(bytes) = cover_bytes {
|
||||
if !bytes.is_empty() {
|
||||
let picture = Picture::unchecked(bytes).build();
|
||||
tag.push_picture(picture);
|
||||
}
|
||||
}
|
||||
|
||||
tag.save_to_path(path, WriteOptions::default())
|
||||
.map_err(|e| AudioTagError::WriteError { reason: e.to_string() })?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
uniffi::setup_scaffolding!();
|
||||
@ -54,16 +54,23 @@ class JvmLocalMediaDiscoveryService : LocalMediaDiscoveryService {
|
||||
if (scanned.incrementAndGet() > MAX_FILES_PER_SCAN) return@forEach
|
||||
val parent = filePath.parent?.absolutePathString() ?: return@forEach
|
||||
val trackPath = filePath.toAbsolutePath().toString()
|
||||
println("Debug: Found track path = $trackPath")
|
||||
|
||||
val metadata = try {
|
||||
uniffi.compose_app.readAudioMetadata(trackPath)
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
val track = LocalMediaTrack(
|
||||
path = trackPath,
|
||||
name = filePath.nameWithoutExtension.ifBlank {
|
||||
name = metadata?.title?.takeIf { it.isNotBlank() }
|
||||
?: filePath.nameWithoutExtension.ifBlank {
|
||||
filePath.fileName.toString()
|
||||
},
|
||||
artists = emptyList(),
|
||||
durationMs = 0L,
|
||||
album = null,
|
||||
coverBytes = null,
|
||||
artists = metadata?.artists?.takeIf { it.isNotEmpty() } ?: emptyList(),
|
||||
durationMs = metadata?.durationMs ?: 0L,
|
||||
album = metadata?.album,
|
||||
coverBytes = metadata?.coverBytes,
|
||||
)
|
||||
folders.getOrPut(parent) { mutableListOf() }.add(track)
|
||||
}
|
||||
|
||||
@ -72,6 +72,8 @@ spotube-gradle = "0.1.0"
|
||||
cryptography = "0.6.0"
|
||||
reorderable = "3.1.0"
|
||||
vlcjBundler = "0.1.0"
|
||||
uniffi = "0.3.7"
|
||||
kotlinx-atomicfu = "0.33.0"
|
||||
|
||||
[libraries]
|
||||
appdirs = { module = "net.harawata:appdirs", version.ref = "appdirs" }
|
||||
@ -175,3 +177,6 @@ zipline-gradle-plugin = { id = "app.cash.zipline", version.ref = "ziplineVersion
|
||||
mavenPublish = { id = "maven-publish" }
|
||||
spotubeGradle = { id = "dev.krtirtho.spotube.gradle-plugin", version.ref = "spotube-gradle" }
|
||||
vlcjBundler = { id = "dev.krtirtho.vlcj-bundler.gradle-plugin", version.ref = "vlcjBundler" }
|
||||
kotlinxAtomicFu = { id = "org.jetbrains.kotlinx.atomicfu", version.ref = "kotlinx-atomicfu" }
|
||||
uniffi = { id = "dev.gobley.uniffi", version.ref = "uniffi" }
|
||||
cargo = { id = "dev.gobley.cargo", version.ref = "uniffi" }
|
||||
Loading…
Reference in New Issue
Block a user