fix ig thumbnail
This commit is contained in:
1
src-tauri/Cargo.lock
generated
1
src-tauri/Cargo.lock
generated
@@ -3974,6 +3974,7 @@ name = "stream-capture"
|
|||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"base64 0.22.1",
|
||||||
"chrono",
|
"chrono",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"regex",
|
"regex",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ tauri-plugin-dialog = "2"
|
|||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
reqwest = { version = "0.12", features = ["json", "rustls-tls", "stream"] }
|
reqwest = { version = "0.12", features = ["json", "rustls-tls", "stream"] }
|
||||||
|
base64 = "0.22"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
|||||||
@@ -49,6 +49,28 @@ pub fn get_ffmpeg_version(app: AppHandle) -> Result<String, String> {
|
|||||||
binary_manager::get_ffmpeg_version(&app).map_err(|e| e.to_string())
|
binary_manager::get_ffmpeg_version(&app).map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn fetch_image(url: String) -> Result<String, String> {
|
||||||
|
use base64::{Engine as _, engine::general_purpose};
|
||||||
|
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let res = client.get(&url)
|
||||||
|
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
let bytes = res.bytes().await.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
// Convert to base64
|
||||||
|
let b64 = general_purpose::STANDARD.encode(&bytes);
|
||||||
|
|
||||||
|
// Simple heuristic for mime type
|
||||||
|
let mime = if url.to_lowercase().ends_with(".png") { "image/png" } else { "image/jpeg" };
|
||||||
|
|
||||||
|
Ok(format!("data:{};base64,{}", mime, b64))
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn fetch_metadata(app: AppHandle, url: String, parse_mix_playlist: bool) -> Result<downloader::MetadataResult, String> {
|
pub async fn fetch_metadata(app: AppHandle, url: String, parse_mix_playlist: bool) -> Result<downloader::MetadataResult, String> {
|
||||||
downloader::fetch_metadata(&app, &url, parse_mix_playlist).await.map_err(|e| e.to_string())
|
downloader::fetch_metadata(&app, &url, parse_mix_playlist).await.map_err(|e| e.to_string())
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ pub fn run() {
|
|||||||
commands::get_ytdlp_version,
|
commands::get_ytdlp_version,
|
||||||
commands::get_quickjs_version,
|
commands::get_quickjs_version,
|
||||||
commands::get_ffmpeg_version,
|
commands::get_ffmpeg_version,
|
||||||
|
commands::fetch_image,
|
||||||
commands::fetch_metadata,
|
commands::fetch_metadata,
|
||||||
commands::start_download,
|
commands::start_download,
|
||||||
commands::get_settings,
|
commands::get_settings,
|
||||||
|
|||||||
@@ -61,6 +61,38 @@ watch(() => analysisStore.options.is_audio_only, () => {
|
|||||||
analysisStore.options.output_format = 'original'
|
analysisStore.options.output_format = 'original'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
async function processThumbnail(url: string | undefined): Promise<string | undefined> {
|
||||||
|
if (!url) return undefined;
|
||||||
|
// Check if it's an Instagram URL or similar that needs proxying
|
||||||
|
if (url.includes('instagram.com') || url.includes('fbcdn.net') || url.includes('cdninstagram.com')) {
|
||||||
|
try {
|
||||||
|
return await invoke<string>('fetch_image', { url });
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Thumbnail fetch failed, falling back to URL', e);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processMetadataThumbnails(metadata: any) {
|
||||||
|
if (!metadata) return;
|
||||||
|
|
||||||
|
// Process single video thumbnail
|
||||||
|
if (metadata.thumbnail) {
|
||||||
|
metadata.thumbnail = await processThumbnail(metadata.thumbnail);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process playlist entries
|
||||||
|
if (metadata.entries && Array.isArray(metadata.entries)) {
|
||||||
|
await Promise.all(metadata.entries.map(async (entry: any) => {
|
||||||
|
if (entry.thumbnail) {
|
||||||
|
entry.thumbnail = await processThumbnail(entry.thumbnail);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function analyze() {
|
async function analyze() {
|
||||||
if (!analysisStore.url) return
|
if (!analysisStore.url) return
|
||||||
analysisStore.loading = true
|
analysisStore.loading = true
|
||||||
@@ -122,6 +154,9 @@ async function analyze() {
|
|||||||
throw new Error("所有链接解析失败或均为播放列表。");
|
throw new Error("所有链接解析失败或均为播放列表。");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process thumbnails for batch results
|
||||||
|
await Promise.all(results.map(r => processMetadataThumbnails(r)));
|
||||||
|
|
||||||
// Construct synthetic playlist
|
// Construct synthetic playlist
|
||||||
analysisStore.metadata = {
|
analysisStore.metadata = {
|
||||||
id: 'batch_download_' + Date.now(),
|
id: 'batch_download_' + Date.now(),
|
||||||
@@ -155,6 +190,8 @@ async function analyze() {
|
|||||||
|
|
||||||
const res = await invoke<any>('fetch_metadata', { url: urlToScan, parseMixPlaylist: parseMix })
|
const res = await invoke<any>('fetch_metadata', { url: urlToScan, parseMixPlaylist: parseMix })
|
||||||
|
|
||||||
|
await processMetadataThumbnails(res);
|
||||||
|
|
||||||
// Initialize selected state for playlist entries
|
// Initialize selected state for playlist entries
|
||||||
if (res.entries) {
|
if (res.entries) {
|
||||||
res.entries = res.entries.map((e: any) => ({ ...e, selected: true }))
|
res.entries = res.entries.map((e: any) => ({ ...e, selected: true }))
|
||||||
|
|||||||
Reference in New Issue
Block a user