fix: file export in web

This commit is contained in:
Xinrea
2025-04-30 21:33:09 +08:00
parent 4d3e069a81
commit 32b7e9c3c2
8 changed files with 60 additions and 25 deletions

View File

@@ -1,6 +1,8 @@
# Generated by Cargo
# will have compiled files and executables
/target/
cache
output
tmps
clips
data

View File

@@ -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 }

View File

@@ -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"

View File

@@ -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 {

View File

@@ -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<RecorderList, ()> {
@@ -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,

View File

@@ -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<State>,
Json(params): Json<ExportDanmuRequest>,
) -> Result<Json<ApiResponse<String>>, ApiError> {
let result = export_danmu(state.0, params.options).await?;
Ok(Json(ApiResponse::success(result)))
}
async fn handler_hls(
state: axum::extract::State<State>,
Path(uri): Path<String>,
@@ -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))

View File

@@ -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();
}
}
</script>

View File

@@ -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();
}
}
</script>