mirror of
https://github.com/Dangoware/dango-music-player.git
synced 2025-04-19 10:02:53 -05:00
Grabbing songs from the backend almost works + other minor changes
This commit is contained in:
parent
ba01bb4a7c
commit
efca53b4bd
10 changed files with 484 additions and 60 deletions
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
use kushi::{Queue, QueueItemType};
|
use kushi::{Queue, QueueItemType};
|
||||||
use kushi::{QueueError, QueueItem};
|
use kushi::{QueueError, QueueItem};
|
||||||
|
use serde::Serialize;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
@ -74,9 +75,10 @@ pub enum PlayerCommand {
|
||||||
SetVolume(f64),
|
SetVolume(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum PlayerResponse {
|
pub enum PlayerResponse {
|
||||||
Empty,
|
Empty,
|
||||||
|
NowPlaying(Song)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum LibraryCommand {
|
pub enum LibraryCommand {
|
||||||
|
@ -270,7 +272,8 @@ impl<'c, P: Player + Send + Sync> Controller<'c, P> {
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
};
|
};
|
||||||
player.write().unwrap().enqueue_next(uri).unwrap();
|
player.write().unwrap().enqueue_next(uri).unwrap();
|
||||||
player_mail.send(PlayerResponse::Empty).await.unwrap();
|
let QueueItemType::Single(x) = item.item else { panic!("This is temporary, handle queueItemTypes at some point")};
|
||||||
|
player_mail.send(PlayerResponse::NowPlaying(x.song.clone())).await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PlayerCommand::PrevSong => {
|
PlayerCommand::PrevSong => {
|
||||||
|
@ -328,14 +331,11 @@ impl<'c, P: Player + Send + Sync> Controller<'c, P> {
|
||||||
let x = inner_lib_mail.recv().await.unwrap();
|
let x = inner_lib_mail.recv().await.unwrap();
|
||||||
}
|
}
|
||||||
LibraryCommand::AllSongs => {
|
LibraryCommand::AllSongs => {
|
||||||
println!("got command");
|
|
||||||
inner_lib_mail
|
inner_lib_mail
|
||||||
.send(InnerLibraryCommand::AllSongs)
|
.send(InnerLibraryCommand::AllSongs)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("sent");
|
|
||||||
let x = inner_lib_mail.recv().await.unwrap();
|
let x = inner_lib_mail.recv().await.unwrap();
|
||||||
println!("recieved");
|
|
||||||
if let InnerLibraryResponse::AllSongs(songs) = x {
|
if let InnerLibraryResponse::AllSongs(songs) = x {
|
||||||
lib_mail.send(LibraryResponse::AllSongs(songs.clone())).await.unwrap();
|
lib_mail.send(LibraryResponse::AllSongs(songs.clone())).await.unwrap();
|
||||||
} else {
|
} else {
|
||||||
|
@ -497,3 +497,4 @@ mod test_super {
|
||||||
a.join().unwrap();
|
a.join().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::cmp::Ordering;
|
||||||
// Various std things
|
// Various std things
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::io::Read;
|
||||||
use std::ops::ControlFlow::{Break, Continue};
|
use std::ops::ControlFlow::{Break, Continue};
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
|
@ -473,6 +474,24 @@ impl Song {
|
||||||
None => Err("No valid URIs for this song".into()),
|
None => Err("No valid URIs for this song".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn album_art(&self, i: usize) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
match self.album_art[i] {
|
||||||
|
AlbumArt::Embedded(j) => {
|
||||||
|
let file = lofty::read_from_path(self.primary_uri()?.0.path())?;
|
||||||
|
if file.contains_tag_type(TagType::Id3v2) {
|
||||||
|
Ok(file.tag(TagType::Id3v2).unwrap().pictures()[j].data().to_vec())
|
||||||
|
} else {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AlbumArt::External(ref path) => {
|
||||||
|
let mut buf = vec![];
|
||||||
|
std::fs::File::open(path.path())?.read_to_end(&mut buf)?;
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
|
224
package-lock.json
generated
224
package-lock.json
generated
|
@ -8,8 +8,12 @@
|
||||||
"name": "dango-music-player",
|
"name": "dango-music-player",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@jprochazk/cbor": "github:jprochazk/cbor",
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
"@tauri-apps/plugin-shell": "^2",
|
"@tauri-apps/plugin-shell": "^2",
|
||||||
|
"cbor": "github:jprochazk/cbor",
|
||||||
|
"cbor-x": "^1.6.0",
|
||||||
|
"node-fetch": "^3.3.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
|
@ -19,7 +23,7 @@
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^5.3.1"
|
"vite": "^5.4.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
|
@ -289,6 +293,78 @@
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@cbor-extract/cbor-extract-darwin-arm64": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@cbor-extract/cbor-extract-darwin-x64": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@cbor-extract/cbor-extract-linux-arm": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@cbor-extract/cbor-extract-linux-arm64": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@cbor-extract/cbor-extract-linux-x64": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@cbor-extract/cbor-extract-win32-x64": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.21.5",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||||
|
@ -657,6 +733,10 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@jprochazk/cbor": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "git+ssh://git@github.com/jprochazk/cbor.git#4824b43c60f8a1c38fd8ef3d51d1f24e30a55743"
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.5",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||||
|
@ -1287,6 +1367,40 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/cbor": {
|
||||||
|
"name": "@jprochazk/cbor",
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "git+ssh://git@github.com/jprochazk/cbor.git#4824b43c60f8a1c38fd8ef3d51d1f24e30a55743"
|
||||||
|
},
|
||||||
|
"node_modules/cbor-extract": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cbor-extract/-/cbor-extract-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"node-gyp-build-optional-packages": "5.1.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"download-cbor-prebuilds": "bin/download-prebuilds.js"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@cbor-extract/cbor-extract-darwin-arm64": "2.2.0",
|
||||||
|
"@cbor-extract/cbor-extract-darwin-x64": "2.2.0",
|
||||||
|
"@cbor-extract/cbor-extract-linux-arm": "2.2.0",
|
||||||
|
"@cbor-extract/cbor-extract-linux-arm64": "2.2.0",
|
||||||
|
"@cbor-extract/cbor-extract-linux-x64": "2.2.0",
|
||||||
|
"@cbor-extract/cbor-extract-win32-x64": "2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cbor-x": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cbor-x/-/cbor-x-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==",
|
||||||
|
"optionalDependencies": {
|
||||||
|
"cbor-extract": "^2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/convert-source-map": {
|
"node_modules/convert-source-map": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||||
|
@ -1299,6 +1413,14 @@
|
||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/data-uri-to-buffer": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.7",
|
"version": "4.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||||
|
@ -1316,6 +1438,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/detect-libc": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.65",
|
"version": "1.5.65",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.65.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.65.tgz",
|
||||||
|
@ -1369,6 +1500,39 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fetch-blob": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/jimmywarting"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "paypal",
|
||||||
|
"url": "https://paypal.me/jimmywarting"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"node-domexception": "^1.0.0",
|
||||||
|
"web-streams-polyfill": "^3.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20 || >= 14.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/formdata-polyfill": {
|
||||||
|
"version": "4.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||||
|
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||||
|
"dependencies": {
|
||||||
|
"fetch-blob": "^3.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.20.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
@ -1474,6 +1638,55 @@
|
||||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-domexception": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/jimmywarting"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://paypal.me/jimmywarting"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-fetch": {
|
||||||
|
"version": "3.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||||
|
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||||
|
"dependencies": {
|
||||||
|
"data-uri-to-buffer": "^4.0.0",
|
||||||
|
"fetch-blob": "^3.1.4",
|
||||||
|
"formdata-polyfill": "^4.0.10"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/node-fetch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp-build-optional-packages": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"detect-libc": "^2.0.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-gyp-build-optional-packages": "bin.js",
|
||||||
|
"node-gyp-build-optional-packages-optional": "optional.js",
|
||||||
|
"node-gyp-build-optional-packages-test": "build-test.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.18",
|
"version": "2.0.18",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
|
||||||
|
@ -1657,6 +1870,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
|
||||||
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
|
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.21.3",
|
"esbuild": "^0.21.3",
|
||||||
"postcss": "^8.4.43",
|
"postcss": "^8.4.43",
|
||||||
|
@ -1711,6 +1925,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/web-streams-polyfill": {
|
||||||
|
"version": "3.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||||
|
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
|
|
|
@ -25,6 +25,6 @@
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^5.3.1"
|
"vite": "^5.4.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,17 +18,19 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
tauri-build = { version = "2", features = [] }
|
tauri-build = { version = "2", features = [] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tauri = { version = "2", features = ["unstable"] }
|
dmp-core = { path = "../dmp-core" }
|
||||||
|
tauri = { version = "2", features = [ "protocol-asset", "unstable"] }
|
||||||
tauri-plugin-shell = "2"
|
tauri-plugin-shell = "2"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
dmp-core = { path = "../dmp-core" }
|
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
crossbeam = "0.8.4"
|
crossbeam = "0.8.4"
|
||||||
directories = "5.0.1"
|
directories = "5.0.1"
|
||||||
uuid = { version = "1.11.0", features = ["v4"] }
|
uuid = { version = "1.11.0", features = ["v4"] }
|
||||||
ciborium = "0.2.2"
|
ciborium = "0.2.2"
|
||||||
mime = "0.3.17"
|
mime = "0.3.17"
|
||||||
|
file-format = "0.26.0"
|
||||||
|
chrono = { version = "0.4.38", features = ["serde"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "custom-protocol" ]
|
default = [ "custom-protocol" ]
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use std::{fs, path::PathBuf, str::FromStr, thread::spawn};
|
use std::{fs, io::Read, path::PathBuf, str::FromStr, thread::spawn, time::Duration};
|
||||||
|
|
||||||
use crossbeam::channel::{unbounded, Receiver, Sender};
|
use crossbeam::channel::{unbounded, Receiver, Sender};
|
||||||
use dmp_core::{config::{Config, ConfigLibrary}, music_controller::controller::{Controller, ControllerHandle}, music_player::gstreamer::GStreamer, music_storage::library::MusicLibrary};
|
use dmp_core::{config::{Config, ConfigLibrary}, music_controller::controller::{Controller, ControllerHandle}, music_player::gstreamer::GStreamer, music_storage::library::{AlbumArt, MusicLibrary}};
|
||||||
use tauri::{Manager, State, WebviewWindowBuilder, Wry};
|
use tauri::{http::Response, Manager, State, Url, WebviewWindowBuilder, Wry};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
use wrappers::ArtworkRx;
|
||||||
|
|
||||||
use crate::wrappers::{get_library, play, pause, prev, set_volume, get_song, next};
|
use crate::wrappers::{get_library, play, pause, prev, set_volume, get_song, next};
|
||||||
|
|
||||||
|
@ -12,13 +13,14 @@ pub mod wrappers;
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
let (rx, tx) = unbounded::<Config>();
|
let (rx, tx) = unbounded::<Config>();
|
||||||
let (lib_rx, lib_tx) = unbounded::<PathBuf>();
|
let (lib_rx, lib_tx) = unbounded::<Option<PathBuf>>();
|
||||||
let (handle_rx, handle_tx) = unbounded::<ControllerHandle>();
|
let (handle_rx, handle_tx) = unbounded::<ControllerHandle>();
|
||||||
|
let (art_rx, art_tx) = unbounded::<Vec<u8>>();
|
||||||
|
|
||||||
let t1 = spawn(move || {
|
let controller_thread = spawn(move || {
|
||||||
let mut config = { tx.recv().unwrap() } ;
|
let mut config = { tx.recv().unwrap() } ;
|
||||||
let scan_path = { lib_tx.recv().unwrap() };
|
let scan_path = { lib_tx.recv().unwrap() };
|
||||||
let save_path = config.libraries.library_folder.join("library.dlib");
|
let save_path = dbg!(config.libraries.library_folder.join("library.dlib"));
|
||||||
|
|
||||||
let mut library = MusicLibrary::init(
|
let mut library = MusicLibrary::init(
|
||||||
save_path.clone(),
|
save_path.clone(),
|
||||||
|
@ -28,19 +30,25 @@ pub fn run() {
|
||||||
Uuid::new_v4()
|
Uuid::new_v4()
|
||||||
}
|
}
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
|
let scan_path = scan_path.unwrap_or_else(|| config.libraries.get_default().unwrap().scan_folders.as_ref().unwrap()[0].clone());
|
||||||
library.scan_folder(&scan_path).unwrap();
|
library.scan_folder(&scan_path).unwrap();
|
||||||
|
|
||||||
config.push_library( ConfigLibrary::new(save_path, String::from("Library"), Some(vec![scan_path.clone()])));
|
if config.libraries.get_default().is_err() {
|
||||||
// config.write_file().unwrap();
|
config.push_library( ConfigLibrary::new(save_path, String::from("Library"), Some(vec![scan_path.clone()])));
|
||||||
|
}
|
||||||
|
if library.library.is_empty() {
|
||||||
|
println!("library is empty");
|
||||||
|
} else {
|
||||||
|
config.write_file().unwrap();
|
||||||
|
}
|
||||||
|
println!("scan_path: {}", scan_path.display());
|
||||||
|
|
||||||
let (handle, input) = ControllerHandle::new(
|
let (handle, input) = ControllerHandle::new(
|
||||||
library,
|
library,
|
||||||
std::sync::Arc::new(std::sync::RwLock::new(config))
|
std::sync::Arc::new(std::sync::RwLock::new(config))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
handle_rx.send(handle).unwrap();
|
handle_rx.send(handle).unwrap();
|
||||||
|
|
||||||
let controller = futures::executor::block_on(Controller::<GStreamer>::start(input)).unwrap();
|
let controller = futures::executor::block_on(Controller::<GStreamer>::start(input)).unwrap();
|
||||||
|
@ -59,10 +67,25 @@ pub fn run() {
|
||||||
next,
|
next,
|
||||||
prev,
|
prev,
|
||||||
get_song,
|
get_song,
|
||||||
|
lib_already_created,
|
||||||
|
|
||||||
]).manage(ConfigRx(rx))
|
]).manage(ConfigRx(rx))
|
||||||
.manage(LibRx(lib_rx))
|
.manage(LibRx(lib_rx))
|
||||||
.manage(HandleTx(handle_tx))
|
.manage(HandleTx(handle_tx))
|
||||||
|
.manage(ArtworkRx(art_rx))
|
||||||
|
.register_asynchronous_uri_scheme_protocol("asset", move |_, req, res| {
|
||||||
|
dbg!(req);
|
||||||
|
let buf = art_tx.recv().unwrap_or_else(|_| Vec::new());
|
||||||
|
res.respond(
|
||||||
|
Response::builder()
|
||||||
|
.header("Origin", "*")
|
||||||
|
.header("Content-Length", buf.len())
|
||||||
|
.status(200)
|
||||||
|
.body(buf)
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
println!("res sent")
|
||||||
|
})
|
||||||
.build(tauri::generate_context!())
|
.build(tauri::generate_context!())
|
||||||
.expect("error while building tauri application");
|
.expect("error while building tauri application");
|
||||||
|
|
||||||
|
@ -73,19 +96,21 @@ pub fn run() {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
});
|
});
|
||||||
t1.join().unwrap();
|
// controller_thread.join().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ConfigRx(Sender<Config>);
|
struct ConfigRx(Sender<Config>);
|
||||||
|
|
||||||
struct LibRx(Sender<PathBuf>);
|
struct LibRx(Sender<Option<PathBuf>>);
|
||||||
struct HandleTx(Receiver<ControllerHandle>);
|
struct HandleTx(Receiver<ControllerHandle>);
|
||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn get_config(state: State<'_, ConfigRx>) -> Result<Config, String> {
|
async fn get_config(state: State<'_, ConfigRx>) -> Result<Config, String> {
|
||||||
if let Some(dir) = directories::ProjectDirs::from("", "Dangoware", "dmp") {
|
if let Some(dir) = directories::ProjectDirs::from("", "Dangoware", "dmp") {
|
||||||
let path = dir.config_dir();
|
let path = dir.config_dir();
|
||||||
fs::create_dir(path).or_else(|err| {
|
// dbg!(&path);
|
||||||
|
fs::create_dir_all(path).or_else(|err| {
|
||||||
if err.kind() == std::io::ErrorKind::AlreadyExists {
|
if err.kind() == std::io::ErrorKind::AlreadyExists {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
@ -139,7 +164,7 @@ async fn create_library(
|
||||||
path: String
|
path: String
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
println!("{path}");
|
println!("{path}");
|
||||||
let path = PathBuf::from(path);
|
let path = PathBuf::from(path.trim().trim_matches('"'));
|
||||||
|
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
panic!("Path {} does not exist!", path.display())
|
panic!("Path {} does not exist!", path.display())
|
||||||
|
@ -147,9 +172,17 @@ async fn create_library(
|
||||||
panic!("Path {} is not a directory!", path.display())
|
panic!("Path {} is not a directory!", path.display())
|
||||||
}
|
}
|
||||||
|
|
||||||
lib_rx.inner().0.send(path).unwrap();
|
lib_rx.inner().0.send(Some(path)).unwrap();
|
||||||
app.manage(handle_tx.inner().0.recv().unwrap());
|
app.manage(handle_tx.inner().0.recv().unwrap());
|
||||||
|
|
||||||
window.close().unwrap();
|
window.close().unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn lib_already_created(app: tauri::AppHandle<Wry>, lib_rx: State<'_, LibRx>, handle_tx: State<'_, HandleTx>) -> Result<(), String> {
|
||||||
|
println!("lib already created");
|
||||||
|
lib_rx.inner().0.send(None);
|
||||||
|
app.manage(handle_tx.inner().0.recv().unwrap());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
use dmp_core::{music_controller::controller::{ControllerHandle, LibraryCommand, LibraryResponse, PlayerResponse}, music_storage::library::Song};
|
use std::collections::BTreeMap;
|
||||||
use tauri::{ipc::Response, State};
|
|
||||||
|
use chrono::{DateTime, Utc, serde::ts_milliseconds_option};
|
||||||
|
use crossbeam::channel::Sender;
|
||||||
|
use dmp_core::{music_controller::controller::{ControllerHandle, LibraryCommand, LibraryResponse, PlayerResponse}, music_storage::library::{BannedType, Song, URI}};
|
||||||
|
use serde::Serialize;
|
||||||
|
use tauri::{ipc::Response, AppHandle, Emitter, State, Wry};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
pub struct ArtworkRx(pub Sender<Vec<u8>>);
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn play(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
pub async fn play(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
||||||
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::Play).await.unwrap();
|
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::Play).await.unwrap();
|
||||||
|
@ -21,7 +28,8 @@ pub async fn pause(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), Strin
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn set_volume(ctrl_handle: State<'_, ControllerHandle>, volume: f64) -> Result<(), String> {
|
pub async fn set_volume(ctrl_handle: State<'_, ControllerHandle>, volume: String) -> Result<(), String> {
|
||||||
|
let volume = volume.parse::<f64>().unwrap() / 1000.0;
|
||||||
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::SetVolume(volume)).await.unwrap();
|
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::SetVolume(volume)).await.unwrap();
|
||||||
let PlayerResponse::Empty = ctrl_handle.player_mail.recv().await.unwrap() else {
|
let PlayerResponse::Empty = ctrl_handle.player_mail.recv().await.unwrap() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -36,11 +44,14 @@ pub async fn get_volume(ctrl_handle: State<'_, ControllerHandle>) -> Result<(),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn next(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
pub async fn next(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>, art_rx: State<'_, ArtworkRx>) -> Result<(), String> {
|
||||||
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::NextSong).await.unwrap();
|
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::NextSong).await.unwrap();
|
||||||
let PlayerResponse::Empty = ctrl_handle.player_mail.recv().await.unwrap() else {
|
let PlayerResponse::NowPlaying(song) = ctrl_handle.player_mail.recv().await.unwrap() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
let _song = _Song::from(&song);
|
||||||
|
art_rx.0.send(song.album_art(0).unwrap()).unwrap();
|
||||||
|
app.emit("now_playing_change", _song).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,16 +70,48 @@ pub async fn now_playing(ctrl_handle: State<'_, ControllerHandle>) -> Result<(),
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Grab Album art from custom protocol
|
||||||
|
#[derive(Serialize, Debug, Clone)]
|
||||||
|
pub struct _Song {
|
||||||
|
pub location: Vec<URI>,
|
||||||
|
pub uuid: Uuid,
|
||||||
|
pub plays: i32,
|
||||||
|
pub format: Option<String>,
|
||||||
|
pub duration: String,
|
||||||
|
#[serde(with = "ts_milliseconds_option")]
|
||||||
|
pub last_played: Option<DateTime<Utc>>,
|
||||||
|
#[serde(with = "ts_milliseconds_option")]
|
||||||
|
pub date_added: Option<DateTime<Utc>>,
|
||||||
|
#[serde(with = "ts_milliseconds_option")]
|
||||||
|
pub date_modified: Option<DateTime<Utc>>,
|
||||||
|
pub tags: BTreeMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Song> for _Song {
|
||||||
|
fn from(value: &Song) -> Self {
|
||||||
|
_Song {
|
||||||
|
location: value.location.clone(),
|
||||||
|
uuid: value.uuid.clone(),
|
||||||
|
plays: value.plays.clone(),
|
||||||
|
duration: value.duration.as_secs().to_string(),
|
||||||
|
format: value.format.map(|format| format.to_string()),
|
||||||
|
last_played: value.last_played,
|
||||||
|
date_added: value.date_added,
|
||||||
|
date_modified: value.date_modified,
|
||||||
|
tags: value.tags.iter().map(|(k, v)| (k.to_string(), v.clone())).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_library(ctrl_handle: State<'_, ControllerHandle>) -> Result<Response, String> {
|
pub async fn get_library(ctrl_handle: State<'_, ControllerHandle>) -> Result<Vec<_Song>, String> {
|
||||||
println!("getting songs");
|
|
||||||
ctrl_handle.lib_mail.send(LibraryCommand::AllSongs).await.unwrap();
|
ctrl_handle.lib_mail.send(LibraryCommand::AllSongs).await.unwrap();
|
||||||
let LibraryResponse::AllSongs(songs) = ctrl_handle.lib_mail.recv().await.unwrap() else { unreachable!("It has been reached") };
|
let LibraryResponse::AllSongs(songs) = ctrl_handle.lib_mail.recv().await.unwrap() else { unreachable!("It has been reached") };
|
||||||
println!("got songs");
|
|
||||||
|
|
||||||
let mut buf = vec![];
|
let _songs = songs.iter().map(|song| _Song::from(song)).collect::<Vec<_>>();
|
||||||
ciborium::into_writer(&songs, &mut buf);
|
|
||||||
Ok(Response::new(buf))
|
Ok(_songs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
@ -78,3 +121,10 @@ pub async fn get_song(ctrl_handle: State<'_, ControllerHandle>) -> Result<(), St
|
||||||
println!("got songs");
|
println!("got songs");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
pub struct NowPlaying {
|
||||||
|
title: String,
|
||||||
|
artist: String,
|
||||||
|
album: String,
|
||||||
|
}
|
|
@ -18,7 +18,11 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"security": {
|
"security": {
|
||||||
"csp": null
|
"assetProtocol": {
|
||||||
|
"enable": true,
|
||||||
|
"scope": { "allow": ["asset://localhost*"] }
|
||||||
|
},
|
||||||
|
"csp": "default-src 'self'; img-src 'self'; asset: asset://localhost/*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bundle": {
|
"bundle": {
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
.mainView {
|
.mainView {
|
||||||
background-color: #f5eab2;
|
background-color: #f5eab2;
|
||||||
height: 91.5%;
|
height: 91.5%;
|
||||||
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
#playBar {
|
#playBar {
|
||||||
|
@ -71,3 +72,9 @@
|
||||||
background-color: burlywood;
|
background-color: burlywood;
|
||||||
height: 50%;
|
height: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.song {
|
||||||
|
display: flex;
|
||||||
|
justify-content: left;
|
||||||
|
gap: 1%;
|
||||||
|
}
|
132
src/App.tsx
132
src/App.tsx
|
@ -1,29 +1,40 @@
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import reactLogo from "./assets/react.svg";
|
import { convertFileSrc, invoke } from "@tauri-apps/api/core";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import { Config, Song } from "./types";
|
import { Config } from "./types";
|
||||||
|
import { EventEmitter } from "@tauri-apps/plugin-shell";
|
||||||
import { decode, encode } from 'cbor-x';
|
import { listen } from "@tauri-apps/api/event";
|
||||||
import CBOR from "cbor";
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const library = useState<JSX.Element[]>();
|
||||||
|
const [artwork, setArtwork] = useState<JSX.Element>(<></>);
|
||||||
|
const [nowPlaying, setNowPlaying] = useState<JSX.Element>(<NowPlaying title="blank" album="blank" artist="blank" artwork={ artwork }/>);
|
||||||
|
|
||||||
|
listen<any>("now_playing_change", (event) => {
|
||||||
|
console.log(event.payload);
|
||||||
|
|
||||||
|
setNowPlaying( <NowPlaying
|
||||||
|
title={ event.payload.tags.TrackTitle }
|
||||||
|
album={ event.payload.tags.AlbumTitle }
|
||||||
|
artist={ event.payload.tags["DISPLAY ARTIST"]}
|
||||||
|
artwork={ artwork } />)
|
||||||
|
setArtwork( <img src="asset://localhost" id="nowPlayingArtwork" /> )
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getConfig();
|
getConfig();
|
||||||
invoke('set_volume', { volume: 0.04 }).then( () => {} )
|
invoke('set_volume', { volume: "1" }).then( () => {} )
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="container">
|
<main className="container">
|
||||||
<div className="leftSide">
|
<div className="leftSide">
|
||||||
<PlaylistHead />
|
<PlaylistHead />
|
||||||
<MainView />
|
<MainView lib_ref={ library } />
|
||||||
<PlayBar />
|
<PlayBar />
|
||||||
</div>
|
</div>
|
||||||
<div className="rightSide">
|
<div className="rightSide">
|
||||||
<NowPlaying />
|
{ nowPlaying }
|
||||||
<Queue />
|
<Queue />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -38,6 +49,9 @@ function getConfig(): any {
|
||||||
let config = _config as Config;
|
let config = _config as Config;
|
||||||
if (config.libraries.libraries.length == 0) {
|
if (config.libraries.libraries.length == 0) {
|
||||||
newWindow()
|
newWindow()
|
||||||
|
} else {
|
||||||
|
console.log("else");
|
||||||
|
invoke('lib_already_created').then(() => {})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -60,17 +74,78 @@ function PlaylistHead() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function MainView() {
|
interface MainViewProps {
|
||||||
|
lib_ref: [JSX.Element[] | undefined, React.Dispatch<React.SetStateAction<JSX.Element[] | undefined>>],
|
||||||
|
}
|
||||||
|
|
||||||
|
function MainView({ lib_ref }: MainViewProps) {
|
||||||
|
const [library, setLibrary] = lib_ref;
|
||||||
|
// useEffect(() => {
|
||||||
|
// console.log(lib_ref);
|
||||||
|
// console.log(typeof lib_ref);
|
||||||
|
// if (typeof lib_ref.current !== "undefined") {
|
||||||
|
|
||||||
|
// setLibrary(lib_ref.current.map((song) => {
|
||||||
|
// <Song
|
||||||
|
// location={ song.location }
|
||||||
|
// uuid={ song.uuid }
|
||||||
|
// plays={ song.plays }
|
||||||
|
// duration={ song.duration }
|
||||||
|
// tags={ song.tags }
|
||||||
|
// />
|
||||||
|
// }))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }, [lib_ref])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mainView">
|
<div className="mainView">
|
||||||
main view
|
main view
|
||||||
<button onClick={ () => invoke('get_library').then((bytes) => {
|
<button onClick={ (e) => {
|
||||||
console.log(bytes);
|
e.preventDefault();
|
||||||
let arr = new Uint8Array(bytes as ArrayBuffer);
|
|
||||||
let a: any = CBOR.decode(arr);
|
|
||||||
console.log(a);
|
|
||||||
|
|
||||||
}) }>get library</button>
|
invoke('get_library').then((lib) => {
|
||||||
|
setLibrary([...(lib as any[]).map((song) => {
|
||||||
|
console.log(song);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Song
|
||||||
|
key={ song.uuid }
|
||||||
|
location={ song.location }
|
||||||
|
uuid={ song.uuid }
|
||||||
|
plays={ song.plays }
|
||||||
|
duration={ song.duration }
|
||||||
|
tags={ song.tags }
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})])
|
||||||
|
})} }>get library</button>
|
||||||
|
<div>{ library }</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SongProps {
|
||||||
|
location: any,
|
||||||
|
uuid: string,
|
||||||
|
plays: number,
|
||||||
|
format?: string,
|
||||||
|
duration: string,
|
||||||
|
last_played?: string,
|
||||||
|
date_added?: string,
|
||||||
|
date_modified?: string,
|
||||||
|
tags: any
|
||||||
|
}
|
||||||
|
|
||||||
|
function Song(props: SongProps) {
|
||||||
|
console.log(props.tags);
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="song">
|
||||||
|
<p className="title">{ props.tags.TrackTitle }</p>
|
||||||
|
<p className="album">{ props.tags.Album }</p>
|
||||||
|
<p className="artist">{ props.tags.AlbumArtist }</p>
|
||||||
|
<p className="duration">{ props.duration }</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -95,20 +170,31 @@ function PlayBar() {
|
||||||
}
|
}
|
||||||
}}>{ playing }</button>
|
}}>{ playing }</button>
|
||||||
<button onClick={ () => invoke('next').then(() => {}) }>next</button>
|
<button onClick={ () => invoke('next').then(() => {}) }>next</button>
|
||||||
<input type="range" name="volume" id="volumeSlider" />
|
<input type="range" name="volume" id="volumeSlider" onChange={ (volume) => {
|
||||||
|
invoke('set_volume', { volume: volume.target.value }).then(() => {})
|
||||||
|
}} />
|
||||||
</div>
|
</div>
|
||||||
<input type="range" name="seek" id="seekBar" />
|
<input type="range" name="seek" id="seekBar" />
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function NowPlaying() {
|
interface NowPlayingProps {
|
||||||
|
title: string,
|
||||||
|
artist: string,
|
||||||
|
album: string,
|
||||||
|
artwork: JSX.Element
|
||||||
|
}
|
||||||
|
|
||||||
|
function NowPlaying({ title, artist, album, artwork }: NowPlayingProps) {
|
||||||
|
console.log(convertFileSrc("abc"));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="nowPlaying">
|
<section className="nowPlaying">
|
||||||
<img id="nowPlayingArtwork" src="https://images.genius.com/22648cfc4f618884df6d6082962b34d2.1000x1000x1.png" />
|
{ artwork }
|
||||||
<h2>やけにインザレイン</h2>
|
<h2>{ title }</h2>
|
||||||
<p>t+pazolite; 小林私</p>
|
<p>{ artist }</p>
|
||||||
<p>Heartache Debug</p>
|
<p>{ album }</p>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue