song bridge

Seto Elkahfi committed Aug 2, 2024 at 00:08 UTC 92ba30ad32975a76f3acdb5c1a4709a48e85b2a8
9 files changed +138 -8
frontend/splitfire-desktop/app/_src/lib/tauriHandler.ts
+1
@@ -20,4 +20,5 @@ export const TAURI_ACCOUNT_REGISTER = 'account_register'
20 // Contents
21 export const TAURI_CONTENT_CAROUSEL = 'content_carousel'
22 export const TAURI_CONTENT_READY_TO_PLAY = 'content_ready_to_play'
23 +export const TAURI_CONTENT_SONG_BRIDGE_DETAIL = 'content_song_bridge_detail'
24
frontend/splitfire-desktop/app/split/page.tsx
+21
@@ -1,10 +1,31 @@
1 "use client";
2
3 import { useSearchParams } from "next/navigation";
4 +import { useLogger } from "../_src/lib/logger";
5 +import { useEffect } from "react";
6 +import { invoke } from "@tauri-apps/api";
7 +import { TAURI_CONTENT_SONG_BRIDGE_DETAIL } from "../_src/lib/tauriHandler";
8
9 export default function Page() {
10 + const log = useLogger("Play");
11 const searchParams = useSearchParams();
12 const songProviderId = searchParams.get("songProviderId");
13 +
14 + useEffect(() => {
15 + log.debug("Play page loaded.");
16 + async function fetchData() {
17 + try {
18 + const rest = await invoke(TAURI_CONTENT_SONG_BRIDGE_DETAIL, { songProviderId });
19 + log.debug("PreparePlayerResponse", rest);
20 +
21 + } catch (error) {
22 + log.error(error);
23 + }
24 + }
25 + fetchData();
26 + // eslint-disable-next-line react-hooks/exhaustive-deps
27 + }, []);
28 +
29 return (
30 <div className="prose prose-sm prose-invert max-w-none">
31 <div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
frontend/splitfire-desktop/src-tauri/Cargo.lock
+20
@@ -115,6 +115,7 @@ dependencies = [
115 "tauri-build",
116 "tauri-plugin-log",
117 "tauri-plugin-store",
118 + "uri-template-system",
119 "url-builder",
120 ]
121
@@ -4154,6 +4155,25 @@ version = "1.11.0"
4155 source = "registry+https://github.com/rust-lang/crates.io-index"
4156 checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
4157
4158 +[[package]]
4159 +name = "uri-template-system"
4160 +version = "0.1.0"
4161 +source = "registry+https://github.com/rust-lang/crates.io-index"
4162 +checksum = "50ce47b579c9b300dd1540e30578b33854f86e7072d7ff505016705609261ca9"
4163 +dependencies = [
4164 + "uri-template-system-core",
4165 +]
4166 +
4167 +[[package]]
4168 +name = "uri-template-system-core"
4169 +version = "0.1.5"
4170 +source = "registry+https://github.com/rust-lang/crates.io-index"
4171 +checksum = "26f254395af92efc86d9a0bb0a614dc76865c8a4ea0d71ba66ccd134d7f831fb"
4172 +dependencies = [
4173 + "fnv",
4174 + "thiserror",
4175 +]
4176 +
4177 [[package]]
4178 name = "url"
4179 version = "2.5.0"
frontend/splitfire-desktop/src-tauri/Cargo.toml
+1
@@ -31,6 +31,7 @@ tauri = { version = "1.7.1", features = [] }
31 tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1", features = ["colored"] }
32 tauri-plugin-store = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
33 url-builder = "0.1.1"
34 +uri-template-system = "=0.1.0"
35
36 [features]
37 # by default Tauri runs in production mode
frontend/splitfire-desktop/src-tauri/src/command/constants.rs
+1
@@ -29,6 +29,7 @@ pub const PATH_CAROUSEL: &str = "api/v1/carousel";
29 pub const PATH_READY_TO_PLAY: &str = "api/v1/ready-to-play";
30 pub const PATH_SEARCH: &str = "api/v1//search";
31 pub const PATH_TOP_VOTES: &str = "api/v1/top-votes";
32 +pub const PATH_SONG_BRIDGE_DETAIL: &str = "api/v1/song-bridge/{providerId}/detail";
33
34 pub fn base_url_builder() -> URLBuilder {
35 let mut url_builder = URLBuilder::new();
frontend/splitfire-desktop/src-tauri/src/main.rs
+4 -2
@@ -23,8 +23,9 @@ use app::{
23 account_logout, account_register,
24 },
25 content::{
26 - __cmd__content_carousel, __cmd__content_ready_to_play, content_carousel,
27 - content_ready_to_play,
26 + __cmd__content_carousel, __cmd__content_ready_to_play,
27 + __cmd__content_song_bridge_detail, content_carousel, content_ready_to_play,
28 + content_song_bridge_detail,
29 },
30 },
31 sfai_home_dir_path,
@@ -76,6 +77,7 @@ fn main() {
77 player_recording_length,
78 content_carousel,
79 content_ready_to_play,
80 + content_song_bridge_detail,
81 ])
82 .run(tauri::generate_context!())
83 .expect("Error while running tauri application.");
frontend/splitfire-desktop/src-tauri/src/models/content.rs
+43 -2
@@ -20,7 +20,7 @@ pub struct CarouselResponse {
20 #[derive(Serialize, Deserialize)]
21 #[derive(Debug)]
22 pub struct SongProvider {
23 - pub id: i32,
23 + pub id: i32, // API response code
24 pub name: String,
25 pub provider_id: String,
26 pub provider_type: ProviderType,
@@ -35,4 +35,45 @@ pub enum ProviderType {
35 Youtube,
36 #[serde(rename = "spotify")]
37 Spotify,
38 -}
\ No newline at end of file
38 +}
39 +
40 +#[derive(Serialize)]
41 +#[derive(Debug)]
42 +pub struct ContentSongBridgeResponse {
43 + pub code: TauriResponse,
44 + pub message: String,
45 + pub song_provider: Option<SongProvider>,
46 + pub votes: Vec<SongProviderVote>
47 +}
48 +
49 +#[derive(Serialize, Deserialize)]
50 +#[derive(Debug)]
51 +pub struct SongBridgeResponse {
52 + pub code: i32, // API response code
53 + pub message: String,
54 + pub error: Option<String>,
55 + pub song_provider: Option<SongProvider>,
56 + pub votes: Vec<SongProviderVote>
57 +}
58 +
59 +#[derive(Serialize, Deserialize)]
60 +#[derive(Debug)]
61 +pub struct SongProviderVote {
62 + pub id: i32,
63 + pub user_id: i32,
64 + pub song_provider_id: i32,
65 + pub vote_type: VoteType,
66 + pub voter_username_or_id: String,
67 + pub voter_gravatar: String,
68 + pub created_at: String,
69 + pub updated_at: String
70 +}
71 +
72 +#[derive(Serialize, Deserialize)]
73 +#[derive(Debug)]
74 +pub enum VoteType {
75 + #[serde(rename = "up")]
76 + UP,
77 + #[serde(rename = "down")]
78 + DOWN
79 +}
frontend/splitfire-desktop/src-tauri/src/models/player.rs
+2 -2
@@ -1,6 +1,6 @@
1 use std::fmt::Display;
2 use serde::{Deserialize, Serialize};
3 -use serde_repr::Serialize_repr;
3 +use serde_repr::{Deserialize_repr, Serialize_repr};
4
5
6 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
@@ -49,7 +49,7 @@ pub struct AudioFileResponse {
49 pub audio_file: AudioFile,
50 }
51
52 -#[derive(Serialize_repr)]
52 +#[derive(Serialize_repr, Deserialize_repr)]
53 #[repr(u8)]
54 #[derive(Debug)]
55 pub enum TauriResponse {
frontend/splitfire-desktop/src-tauri/src/rest/content.rs
+45 -2
@@ -1,7 +1,7 @@
1 use crate::{
2 - command::constants::{base_url_builder, PATH_CAROUSEL, PATH_READY_TO_PLAY},
2 + command::constants::{base_url_builder, PATH_CAROUSEL, PATH_READY_TO_PLAY, PATH_SONG_BRIDGE_DETAIL},
3 models::{
4 - content::{CarouselResponse, ContentCarouselResponse},
4 + content::{CarouselResponse, ContentCarouselResponse, ContentSongBridgeResponse, SongBridgeResponse},
5 player::TauriResponse,
6 },
7 };
@@ -83,6 +83,49 @@ pub async fn content_ready_to_play() -> ContentCarouselResponse {
83 }
84 }
85
86 +#[tauri::command]
87 +pub async fn content_song_bridge_detail(song_provider_id: String) -> ContentSongBridgeResponse {
88 + debug!("Song provider id: {:?}", song_provider_id);
89 + let response: Result<reqwest::Response, reqwest::Error> = Client::new()
90 + .get(content_url_builder(PATH_SONG_BRIDGE_DETAIL))
91 + .send()
92 + .await;
93 +
94 + let response = match response {
95 + Ok(response) => response,
96 + Err(e) => {
97 + error!("Failed to get response: {:?}", e);
98 + return ContentSongBridgeResponse {
99 + code: TauriResponse::Error,
100 + message: e.to_string(),
101 + song_provider: None,
102 + votes: vec![],
103 + };
104 + }
105 + };
106 +
107 + let res: SongBridgeResponse= match response.json().await {
108 + Ok(json) => json,
109 + Err(e) => {
110 + error!("Failed to parse response: {:?}", e);
111 + return ContentSongBridgeResponse {
112 + code: TauriResponse::Error,
113 + message: e.to_string(),
114 + song_provider: None,
115 + votes: vec![],
116 + };
117 + }
118 + };
119 +
120 + debug!("Song bridge detail: {:?}", res);
121 + ContentSongBridgeResponse {
122 + code: TauriResponse::Success,
123 + message: res.message,
124 + song_provider: res.song_provider,
125 + votes: res.votes,
126 + }
127 +}
128 +
129 fn content_url_builder(path: &str) -> String {
130 let mut url_builder = base_url_builder();
131 url_builder.add_route(path);