diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore index ed93ad8..ec7f039 100644 --- a/src-tauri/.gitignore +++ b/src-tauri/.gitignore @@ -1,6 +1,8 @@ # Generated by Cargo # will have compiled files and executables /target/ +cache +output tmps clips data diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index fd82630..421425c 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -54,6 +54,7 @@ url = "2.5.4" custom-protocol = ["tauri/custom-protocol"] cuda = ["whisper-rs/cuda"] headless = [] +default = ["headless"] [target.'cfg(windows)'.dependencies] whisper-rs = { version = "0.14.2", default-features = false } diff --git a/src-tauri/config.example.toml b/src-tauri/config.example.toml index dbb3537..fcd9313 100644 --- a/src-tauri/config.example.toml +++ b/src-tauri/config.example.toml @@ -5,7 +5,7 @@ live_end_notify = true clip_notify = true post_notify = true auto_subtitle = false -whisper_model = "" +whisper_model = "./whisper_model.bin" whisper_prompt = "这是一段中文 你们好" clip_name_format = "[{room_id}][{live_id}][{title}][{created_at}].mp4" diff --git a/src-tauri/src/config.rs b/src-tauri/src/config.rs index c35e470..0a190dd 100644 --- a/src-tauri/src/config.rs +++ b/src-tauri/src/config.rs @@ -38,7 +38,7 @@ fn default_auto_subtitle() -> bool { } fn default_whisper_model() -> String { - "".to_string() + "whisper_model.bin".to_string() } fn default_whisper_prompt() -> String { diff --git a/src-tauri/src/handlers/recorder.rs b/src-tauri/src/handlers/recorder.rs index 2aa1a3d..fe2edc3 100644 --- a/src-tauri/src/handlers/recorder.rs +++ b/src-tauri/src/handlers/recorder.rs @@ -1,3 +1,4 @@ +use crate::danmu2ass; use crate::database::record::RecordRow; use crate::database::recorder::RecorderRow; use crate::recorder::danmu::DanmuEntry; @@ -7,10 +8,11 @@ use crate::recorder_manager::RecorderList; use crate::state::State; use crate::state_type; +#[cfg(not(feature = "headless"))] +use auri::State as TauriState; + use serde::Deserialize; use serde::Serialize; -#[cfg(not(feature = "headless"))] -use {crate::danmu2ass, tauri::State as TauriState}; #[cfg_attr(not(feature = "headless"), tauri::command)] pub async fn get_recorder_list(state: state_type!()) -> Result { @@ -158,6 +160,7 @@ pub async fn get_danmu_record( } #[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ExportDanmuOptions { platform: String, room_id: u64, @@ -167,8 +170,7 @@ pub struct ExportDanmuOptions { ass: bool, } -#[cfg(not(feature = "headless"))] -#[tauri::command] +#[cfg_attr(not(feature = "headless"), tauri::command)] pub async fn export_danmu( state: state_type!(), options: ExportDanmuOptions, diff --git a/src-tauri/src/http_server.rs b/src-tauri/src/http_server.rs index caf8660..cb45ca9 100644 --- a/src-tauri/src/http_server.rs +++ b/src-tauri/src/http_server.rs @@ -17,10 +17,10 @@ use crate::{ }, message::{delete_message, get_messages, read_message}, recorder::{ - add_recorder, delete_archive, fetch_hls, force_start, force_stop, get_archive, - get_archives, get_danmu_record, get_recent_record, get_recorder_list, get_room_info, - get_today_record_count, get_total_length, remove_recorder, send_danmaku, - set_auto_start, + add_recorder, delete_archive, export_danmu, fetch_hls, force_start, force_stop, + get_archive, get_archives, get_danmu_record, get_recent_record, get_recorder_list, + get_room_info, get_today_record_count, get_total_length, remove_recorder, send_danmaku, + set_auto_start, ExportDanmuOptions, }, utils::{get_disk_info, DiskInfo}, video::{ @@ -43,9 +43,9 @@ use crate::{ recorder_manager::{ClipRangeParams, RecorderList}, state::State, }; -use axum::response::sse; +use axum::{extract::Query, response::sse}; use axum::{ - extract::{Json, Path, Query}, + extract::{Json, Path}, http::StatusCode, response::{IntoResponse, Sse}, routing::{get, post}, @@ -834,6 +834,20 @@ async fn handler_fetch( Ok((status, response_headers, body)) } +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +struct ExportDanmuRequest { + options: ExportDanmuOptions, +} + +async fn handler_export_danmu( + state: axum::extract::State, + Json(params): Json, +) -> Result>, ApiError> { + let result = export_danmu(state.0, params.options).await?; + Ok(Json(ApiResponse::success(result))) +} + async fn handler_hls( state: axum::extract::State, Path(uri): Path, @@ -1138,6 +1152,7 @@ pub async fn start_api_server(state: State) { "/api/encode_video_subtitle", post(handler_encode_video_subtitle), ) + .route("/api/export_danmu", post(handler_export_danmu)) // Utils commands .route("/api/get_disk_info", post(handler_get_disk_info)) .route("/api/fetch", post(handler_fetch)) diff --git a/src/lib/MarkerPanel.svelte b/src/lib/MarkerPanel.svelte index b026b67..bd53314 100644 --- a/src/lib/MarkerPanel.svelte +++ b/src/lib/MarkerPanel.svelte @@ -8,7 +8,7 @@ import type { Marker } from "./interface"; import { createEventDispatcher } from "svelte"; import { Tooltip } from "flowbite-svelte"; - import { invoke } from "../lib/invoker"; + import { invoke, TAURI_ENV } from "../lib/invoker"; import { save } from "@tauri-apps/plugin-dialog"; import type { RecordItem } from "./db"; const dispatch = createEventDispatcher(); @@ -47,12 +47,19 @@ .split(" ")[0] .replaceAll("/", "-")}]${archive.title}.txt`; console.log("export to file", file_name); - const path = await save({ - title: "导出标记列表", - defaultPath: file_name, - }); - if (!path) return; - await invoke("export_to_file", { fileName: path, content: r }); + if (TAURI_ENV) { + const path = await save({ + title: "导出标记列表", + defaultPath: file_name, + }); + if (!path) return; + await invoke("export_to_file", { fileName: path, content: r }); + } else { + const a = document.createElement("a"); + a.href = "data:text/plain;charset=utf-8," + encodeURIComponent(r); + a.download = file_name; + a.click(); + } } diff --git a/src/lib/Player.svelte b/src/lib/Player.svelte index a1b838d..8e157a9 100644 --- a/src/lib/Player.svelte +++ b/src/lib/Player.svelte @@ -814,12 +814,20 @@ })) as string; let file_name = `danmu_${room_id}_${live_id}.${ass ? "ass" : "txt"}`; - const path = await save({ - title: "导出弹幕", - defaultPath: file_name, - }); - if (!path) return; - await invoke("export_to_file", { fileName: path, content: assContent }); + if (TAURI_ENV) { + const path = await save({ + title: "导出弹幕", + defaultPath: file_name, + }); + if (!path) return; + await invoke("export_to_file", { fileName: path, content: assContent }); + } else { + const a = document.createElement("a"); + a.href = + "data:text/plain;charset=utf-8," + encodeURIComponent(assContent); + a.download = file_name; + a.click(); + } }