wip: async loading of both album sources

main
Tomáš Mládek 2023-10-01 12:56:13 +02:00
parent 5978ebb9b0
commit 68e4789461
7 changed files with 633 additions and 173 deletions

423
src-tauri/Cargo.lock generated
View File

@ -86,26 +86,6 @@ dependencies = [
"system-deps 6.1.1",
]
[[package]]
name = "audiotags"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f47bdf1acc4fa4113f8aa72bb3bfe62a61443c61d0d997b723ba61ce102c79b"
dependencies = [
"audiotags-dev-macro",
"id3",
"metaflac",
"mp4ameta",
"readme-rustdocifier",
"thiserror",
]
[[package]]
name = "audiotags-dev-macro"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b79298591161f312f06327df7963063ee07466be303dcc3084a44ec293cb36e"
[[package]]
name = "autocfg"
version = "1.1.0"
@ -439,30 +419,6 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.16"
@ -634,12 +590,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "embed-resource"
version = "2.3.0"
@ -650,7 +600,7 @@ dependencies = [
"rustc_version",
"toml 0.7.8",
"vswhom",
"winreg",
"winreg 0.51.0",
]
[[package]]
@ -825,6 +775,12 @@ dependencies = [
"syn 2.0.37",
]
[[package]]
name = "futures-sink"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
[[package]]
name = "futures-task"
version = "0.3.28"
@ -1151,6 +1107,25 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "h2"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap 1.9.3",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@ -1229,12 +1204,72 @@ dependencies = [
"itoa 1.0.9",
]
[[package]]
name = "http-body"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [
"bytes",
"http",
"pin-project-lite",
]
[[package]]
name = "http-range"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
[[package]]
name = "httparse"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]]
name = "httpdate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "0.14.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa 1.0.9",
"pin-project-lite",
"socket2 0.4.9",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]]
name = "iana-time-zone"
version = "0.1.57"
@ -1365,6 +1400,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "ipnet"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
[[package]]
name = "itoa"
version = "0.4.8"
@ -1497,10 +1538,8 @@ checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
name = "lissen"
version = "0.0.0"
dependencies = [
"anyhow",
"audiotags",
"id3",
"rayon",
"reqwest",
"serde",
"serde_json",
"tauri",
@ -1613,15 +1652,10 @@ dependencies = [
]
[[package]]
name = "metaflac"
version = "0.2.5"
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1470d3cc1bb0d692af5eb3afb594330b8ba09fd91c32c4e1c6322172a5ba750"
dependencies = [
"byteorder",
"hex",
"log",
]
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "miniz_oxide"
@ -1634,20 +1668,33 @@ dependencies = [
]
[[package]]
name = "mp4ameta"
version = "0.11.0"
name = "mio"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb23d62e8eb5299a3f79657c70ea9269eac8f6239a76952689bcd06a74057e81"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [
"lazy_static",
"mp4ameta_proc",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.48.0",
]
[[package]]
name = "mp4ameta_proc"
version = "0.6.0"
name = "native-tls"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07dcca13d1740c0a665f77104803360da0bdb3323ecce2e93fa2c959a6d52806"
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "ndk"
@ -1824,6 +1871,50 @@ dependencies = [
"windows-sys 0.42.0",
]
[[package]]
name = "openssl"
version = "0.10.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
dependencies = [
"bitflags 2.4.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "overload"
version = "0.1.1"
@ -2209,32 +2300,6 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
[[package]]
name = "rayon"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "readme-rustdocifier"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08ad765b21a08b1a8e5cdce052719188a23772bcbefb3c439f0baaf62c56ceac"
[[package]]
name = "redox_syscall"
version = "0.2.16"
@ -2308,6 +2373,43 @@ version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "reqwest"
version = "0.11.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
dependencies = [
"base64 0.21.4",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-native-tls",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"winreg 0.50.0",
]
[[package]]
name = "rfd"
version = "0.10.0"
@ -2387,6 +2489,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
@ -2399,6 +2510,29 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "selectors"
version = "0.22.0"
@ -2479,6 +2613,18 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa 1.0.9",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
version = "3.3.0"
@ -2587,6 +2733,26 @@ version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]]
name = "socket2"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "socket2"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
dependencies = [
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "soup2"
version = "0.2.1"
@ -3084,8 +3250,36 @@ checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
"num_cpus",
"pin-project-lite",
"socket2 0.5.4",
"windows-sys 0.48.0",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
"tracing",
]
[[package]]
@ -3131,6 +3325,12 @@ dependencies = [
"winnow",
]
[[package]]
name = "tower-service"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]]
name = "tracing"
version = "0.1.37"
@ -3202,6 +3402,12 @@ dependencies = [
"serde_json",
]
[[package]]
name = "try-lock"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "typenum"
version = "1.17.0"
@ -3268,6 +3474,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version-compare"
version = "0.0.11"
@ -3316,6 +3528,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
@ -3780,6 +4001,16 @@ dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "winreg"
version = "0.51.0"

View File

@ -1,26 +1,24 @@
[package]
name = "lissen"
version = "0.0.0"
description = "A Tauri App"
authors = ["you"]
license = ""
repository = ""
description = "A Tauri App"
edition = "2021"
license = ""
name = "lissen"
repository = ""
version = "0.0.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { version = "1.4", features = [] }
tauri-build = {version = "1.4", features = [] }
[dependencies]
tauri = { version = "1.4", features = [ "dialog-open", "shell-open"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
id3 = "1.8.0"
rayon = "1.8.0"
reqwest = {version = "0.11.20", features = ["json"] }
serde = {version = "1.0", features = ["derive"] }
serde_json = "1.0"
tauri = {version = "1.4", features = ["dialog-open", "shell-open"] }
walkdir = "2.4.0"
anyhow = "1.0.75"
audiotags = "0.4.1"
[features]
# this feature is used for production builds or when `devPath` points to the filesystem

View File

@ -1,12 +1,13 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use id3::{Tag, TagLike};
use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use tauri::Manager;
use walkdir::WalkDir;
#[derive(Debug, Serialize, PartialEq, Eq, Hash)]
pub struct Album {
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)]
pub struct LocalAlbum {
pub name: String,
pub artist: String,
pub year: i32,
@ -14,15 +15,16 @@ pub struct Album {
}
#[tauri::command]
async fn get_local_albums(dirpath: String) -> Result<Vec<Album>, String> {
async fn get_local_albums(
dirpath: String,
app_handle: tauri::AppHandle,
) -> Result<Vec<LocalAlbum>, String> {
let mut result = HashSet::new();
for entry in WalkDir::new(dirpath) {
let entry = entry.map_err(|e| e.to_string())?;
println!("{}", entry.path().display());
for entry in WalkDir::new(dirpath).into_iter().filter_map(|e| e.ok()) {
if entry.file_type().is_file() {
let path = entry.path();
if let Ok(tag) = Tag::read_from_path(path) {
let album = Album {
let album = LocalAlbum {
name: tag.album().unwrap_or("").to_string(),
artist: tag.artist().unwrap_or("").to_string(),
year: tag.year().unwrap_or(0),
@ -32,19 +34,124 @@ async fn get_local_albums(dirpath: String) -> Result<Vec<Album>, String> {
.map(|ext| ext == "flac" || ext == "wav")
.unwrap_or(false),
};
result.insert(album);
let json_local_album = serde_json::to_value(&album).unwrap();
let new = result.insert(album);
if new {
app_handle
.emit_all("new_local_album", json_local_album)
.unwrap();
}
}
}
}
Ok(result.into_iter().collect())
}
#[derive(Debug, Serialize, PartialEq, Eq, Hash)]
pub struct ScrobbledAlbum {
pub name: String,
pub artist: String,
pub playcount: u64,
}
#[derive(Debug, Deserialize)]
pub enum Period {
Overall,
Week,
Month,
ThreeMonths,
SixMonths,
Year,
}
impl ToString for Period {
fn to_string(&self) -> String {
match self {
Period::Overall => "overall",
Period::Week => "7day",
Period::Month => "1month",
Period::ThreeMonths => "3month",
Period::SixMonths => "6month",
Period::Year => "12month",
}
.to_string()
}
}
#[tauri::command]
async fn get_top_scrobbled_albums(
user: String,
period: Period,
limit: u64,
api_key: Option<String>,
app_handle: tauri::AppHandle,
) -> Result<Vec<ScrobbledAlbum>, String> {
let api_key = api_key
.or_else(|| option_env!("LASTFM_API_KEY").map(|s| s.to_string()))
.ok_or("No API key supplied.")?;
let period = period.to_string();
let page_size = 50;
let mut final_result = Vec::new();
let mut page = 1;
while final_result.len() < limit as usize {
let url = format!(
"https://ws.audioscrobbler.com/2.0/?method=user.gettopalbums&user={user}&api_key={api_key}&period={period}&limit={page_size}&page={page}&format=json");
println!("Fetching {}", url);
let resp = reqwest::get(&url)
.await
.map_err(|e| e.to_string())?
.json::<serde_json::Value>()
.await
.map_err(|e| e.to_string())?;
let albums = resp["topalbums"]["album"]
.as_array()
.ok_or("no albums found")?;
let mut result = Vec::new();
for album in albums {
let name = album["name"].as_str().ok_or("no album name")?.to_string();
let artist = album["artist"]["name"]
.as_str()
.ok_or("no artist name")?
.to_string();
let playcount = album["playcount"]
.as_str()
.ok_or("no playcount")?
.parse()
.map_err(|_| "failed to parse playcount")?;
result.push(ScrobbledAlbum {
name,
artist,
playcount,
});
}
app_handle
.emit_all(
"new_scrobbled_albums",
serde_json::to_value(&result).unwrap(),
)
.unwrap();
final_result.extend(result);
page += 1;
}
Ok(final_result)
}
fn main() {
// https://github.com/tauri-apps/tauri/issues/5143#issuecomment-1311815517
std::env::set_var("WEBKIT_DISABLE_COMPOSITING_MODE", "1");
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![get_local_albums])
.invoke_handler(tauri::generate_handler![
get_top_scrobbled_albums,
get_local_albums
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@ -1,39 +1,172 @@
<script lang="ts">
import Greet from './lib/Greet.svelte'
import { invoke } from "@tauri-apps/api/tauri";
import { open } from "@tauri-apps/api/dialog";
import { listen } from "@tauri-apps/api/event";
import { onMount } from "svelte";
import { period, username } from "./stores";
interface ScrobbledAlbum {
name: string;
artist: string;
playcount: number;
}
let scrobbledAlbums: ScrobbledAlbum[] = [];
let loadingScrobbledAlbums = false;
interface LocalAlbum {
name: string;
artist: string;
year: number;
lossless: boolean;
}
let localAlbums: LocalAlbum[] = [];
let loadingLocalAlbums = false;
onMount(() => {
listen("new_local_album", (event) => {
const album = event.payload as LocalAlbum;
localAlbums = [...localAlbums, album];
});
listen("new_scrobbled_albums", (event) => {
const newAlbums = event.payload as ScrobbledAlbum[];
scrobbledAlbums = [...scrobbledAlbums, ...newAlbums];
});
});
async function loadScrobbles() {
if (loadingScrobbledAlbums) {
return;
}
scrobbledAlbums = [];
loadingScrobbledAlbums = true;
try {
await invoke("get_top_scrobbled_albums", {
user: $username,
period: $period,
limit: 200,
});
} catch (e) {
handleError(e);
}
loadingScrobbledAlbums = false;
}
async function loadLocal() {
const selected = await open({
directory: true,
});
if (typeof selected === "string" && selected.length > 0) {
localAlbums = [];
loadingLocalAlbums = true;
try {
await invoke("get_local_albums", {
dirpath: selected,
});
} catch (e) {
handleError(e);
}
loadingLocalAlbums = false;
}
}
function handleError(e: unknown) {
console.error(e);
alert(e);
}
</script>
<main class="container">
<h1>Welcome to Tauri!</h1>
<main>
<div class="main">
<div class="scrobbles">
<div class="input">
<label>
Username:
<input type="text" bind:value={$username} />
</label>
<label>
Period:
<select bind:value={$period}>
<option value="Week">7 days</option>
<option value="Month">1 month</option>
<option value="ThreeMonths">3 months</option>
<option value="SixMonths">6 months</option>
<option value="Year">Year</option>
<option value="Overall">Overall</option>
</select>
</label>
<div class="row">
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo vite" alt="Vite Logo" />
</a>
<a href="https://tauri.app" target="_blank">
<img src="/tauri.svg" class="logo tauri" alt="Tauri Logo" />
</a>
<a href="https://svelte.dev" target="_blank">
<img src="/svelte.svg" class="logo svelte" alt="Svelte Logo" />
</a>
<button on:click={loadScrobbles}>Load scrobbles</button>
</div>
<div class="display">
<div class="label">Scrobbled albums: {scrobbledAlbums.length}</div>
<div class="albums">
{#each scrobbledAlbums as album}
<div class="album">
<div class="name">{album.name}</div>
<div class="artist">{album.artist}</div>
<div class="playcount">Played: {album.playcount}</div>
</div>
{/each}
</div>
</div>
</div>
<div class="local">
<div class="input">
<button on:click={loadLocal}>Load local albums</button>
</div>
<div class="albums">
{#each localAlbums as album}
<div class="album">
<div class="name">{album.name}</div>
<div class="artist">{album.artist}</div>
<div class="year">{album.year}</div>
<div class="lossless">{album.lossless}</div>
</div>
{/each}
</div>
</div>
</div>
<p>
Click on the Tauri, Vite, and Svelte logos to learn more.
</p>
<div class="row">
<Greet />
</div>
</main>
<style>
.logo.vite:hover {
filter: drop-shadow(0 0 2em #747bff);
main {
display: flex;
flex-direction: column;
align-items: center;
}
.main {
display: flex;
width: 100vw;
}
.main > * {
flex-basis: 50%;
}
.albums {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin: 1rem;
}
.album {
display: flex;
flex-direction: column;
border: 1px solid white;
border-radius: 2px;
padding: 0.5rem;
}
.album {
& .name {
font-weight: bold;
}
.logo.svelte:hover {
filter: drop-shadow(0 0 2em #ff3e00);
& .artist {
font-size: 0.8em;
}
</style>
}
</style>

View File

@ -1,27 +0,0 @@
<script lang="ts">
import { invoke } from "@tauri-apps/api/tauri";
import { open } from "@tauri-apps/api/dialog";
let name = "";
let greetMsg = "";
async function greet() {
const selected = await open({
directory: true,
});
if (typeof selected === "string" && selected.length > 0) {
const res = await invoke("get_local_albums", {
dirpath: selected,
});
console.log({ res });
}
greetMsg = selected.toString();
}
</script>
<div>
<form class="row" on:submit|preventDefault={greet}>
<button type="submit">Load</button>
</form>
<p>{greetMsg}</p>
</div>

17
src/stores.ts Normal file
View File

@ -0,0 +1,17 @@
import { writable } from "svelte/store";
export const username = writable(localStorage.getItem("username"));
username.subscribe((value) => (localStorage.username = value));
export type Period =
| "Overall"
| "Week"
| "Month"
| "ThreeMonths"
| "SixMonths"
| "Year";
export const period = writable<Period>(
(localStorage.getItem("period") as Period) || "Overall"
);
period.subscribe((value) => (localStorage.period = value));

View File

@ -54,6 +54,7 @@ h1 {
}
input,
select,
button {
border-radius: 8px;
border: 1px solid transparent;