fixed downloading enqueing in web-ui view

This commit is contained in:
euzu
2023-11-07 16:28:23 +01:00
parent be922351e6
commit a01fbe83ea
7 changed files with 48 additions and 28 deletions
+4 -4
View File
@@ -1,6 +1,6 @@
import ApiService, {DefaultApiService} from "./api-service";
import {Observable, throwError} from "rxjs";
import {FileDownloadInfo, FileDownloadRequest, FileDownloadResponse} from "../model/file-download";
import {FileDownloadInfo, FileDownloadRequest} from "../model/file-download";
import {first} from "rxjs/operators";
//const FILE_API_PATH = 'file';
@@ -8,14 +8,14 @@ const FILE_DOWNLOAD_API_PATH = 'file/download';
const FILE_DOWNLOAD_INFO_API_PATH =FILE_DOWNLOAD_API_PATH + '/info';
export default interface FileApiService extends ApiService {
download(req: FileDownloadRequest): Observable<FileDownloadResponse>;
download(req: FileDownloadRequest): Observable<FileDownloadInfo>;
getDownloadInfo(): Observable<FileDownloadInfo>;
}
export class DefaultFileApiService extends DefaultApiService implements FileApiService {
download(req: FileDownloadRequest): Observable<FileDownloadResponse> {
download(req: FileDownloadRequest): Observable<FileDownloadInfo> {
if (req.url) {
return this.post<FileDownloadResponse>(FILE_DOWNLOAD_API_PATH, req);
return this.post<FileDownloadInfo>(FILE_DOWNLOAD_API_PATH, req);
}
return throwError(() => new Error('Invalid arguments'));
}
@@ -73,7 +73,16 @@ export default function FileDownload(props: FileDownloadProps) {
}, []);
useEffect(() => {
const sub = services.file().subscribeDownloadNotification(() => startPoll());
const sub = services.file().subscribeDownloadNotification((info: FileDownloadInfo) => {
setDownloads((downloads: any) => {
if (!downloads[info.uuid]) {
downloads[info.uuid] = info;
return {...downloads};
}
return downloads;
});
startPoll();
});
return () => sub.unsubscribe();
}, [services, startPoll])
@@ -8,7 +8,7 @@ import {useSnackbar} from "notistack";
import {getIconByName} from "../../icons/icons";
import {useServices} from "../../provider/service-provider";
import ServerConfig from "../../model/server-config";
import {FileDownloadResponse} from "../../model/file-download";
import {FileDownloadInfo} from "../../model/file-download";
const VALID_VIDEO_FILES = ['mkv', 'mp4', 'avi'];
@@ -97,7 +97,7 @@ export default function PlaylistTree(props: PlaylistTreeProps) {
url: item.header.url,
filename: filename + '.' + ext
}).pipe(first()).subscribe({
next: (_: FileDownloadResponse) => {},
next: (_: FileDownloadInfo) => {},
error: _ => enqueueSnackbar("Download failed!", {variant: 'error'}),
complete: noop,
});
-4
View File
@@ -3,10 +3,6 @@ export interface FileDownloadRequest {
filename: string;
}
export interface FileDownloadResponse {
success: boolean;
}
export interface DownloadErrorInfo {
uuid: string;
filename: string;
+7 -7
View File
@@ -1,12 +1,12 @@
import {PlaylistItem, PlaylistGroup} from "../model/playlist";
import FileSaver from "file-saver";
import {Observer, Observable, Subject, Subscription, tap} from "rxjs";
import {Observable, Subject, Subscription, tap} from "rxjs";
import FileApiService, {DefaultFileApiService} from "../api/file-api-service";
import {FileDownloadInfo, FileDownloadRequest, FileDownloadResponse} from "../model/file-download";
import {FileDownloadInfo, FileDownloadRequest} from "../model/file-download";
export default class FileService {
private downloadNotification = new Subject<boolean>();
private downloadNotification = new Subject<FileDownloadInfo>();
constructor(private fileApiService: FileApiService = new DefaultFileApiService()) {
}
@@ -14,8 +14,8 @@ export default class FileService {
return this.downloadNotification.subscribe(observer as any);
}
private notifyDownload() {
this.downloadNotification.next(true);
private notifyDownload(info: FileDownloadInfo) {
this.downloadNotification.next(info);
}
save(playlist: PlaylistGroup[]) {
@@ -30,8 +30,8 @@ export default class FileService {
FileSaver.saveAs(blob, "playlist.m3u");
}
download(req: FileDownloadRequest): Observable<FileDownloadResponse> {
return this.fileApiService.download(req).pipe(tap((result) => result?.success && this.notifyDownload() ));
download(req: FileDownloadRequest): Observable<FileDownloadInfo> {
return this.fileApiService.download(req).pipe(tap((result) => this.notifyDownload(result) ));
}
getDownloadInfo(): Observable<FileDownloadInfo> {
+15 -5
View File
@@ -55,15 +55,25 @@ impl FileDownload {
Ok(url) => {
let filename_re = download_cfg._re_filename.as_ref().unwrap();
let tmp_filename = filename_re.replace_all(&unidecode(req_filename)
.replace(' ', "_"), "").to_string();
let filname_path = Path::new(&tmp_filename);
let file_stem = filname_path.file_stem().and_then(OsStr::to_str).unwrap_or("");
let file_ext = filname_path.extension().and_then(OsStr::to_str).unwrap_or("");
.replace(' ', "_"), "")
.replace("__", "_")
.replace("_-_", "-").to_string();
let filename_path = Path::new(&tmp_filename);
let file_stem = filename_path.file_stem().and_then(OsStr::to_str).unwrap_or("").trim_matches(FILENAME_TRIM_PATTERNS);
let file_ext = filename_path.extension().and_then(OsStr::to_str).unwrap_or("");
let filename = format!("{}.{}", file_stem.trim_matches(FILENAME_TRIM_PATTERNS), file_ext);
let mut filename = format!("{}.{}", file_stem, file_ext);
let file_dir = get_download_directory(download_cfg, file_stem);
let mut file_path: PathBuf = file_dir.clone();
file_path.push(&filename);
let mut x: usize = 1;
while file_path.is_file() {
filename = format!("{}_{}.{}", file_stem, x, file_ext);
file_path = file_dir.clone();
file_path.push(&filename);
x += 1;
}
file_path.to_str()?;
Some(FileDownload {
+10 -5
View File
@@ -4,7 +4,7 @@ use std::io::{ErrorKind, Write};
use std::ops::Deref;
use std::sync::{Arc, RwLock};
use actix_web::{HttpResponse, web};
use serde_json::{json};
use serde_json::{json, Value};
use crate::api::api_model::{AppState, DownloadErrorInfo, DownloadQueue, FileDownload, FileDownloadRequest};
use crate::model::config::{VideoDownloadConfig};
use crate::utils::{bytes_to_megabytes, get_request_headers};
@@ -93,6 +93,12 @@ fn run_download_queue(download_cfg: &VideoDownloadConfig, download_queue: Arc<Do
Ok(())
}
macro_rules! download_info_response {
($file_download:expr, $errors:expr) => {
HttpResponse::Ok().json(json!({"uuid": $file_download.uuid, "filename": $file_download.filename, "filesize": $file_download.size, "errors": $errors}))
}
}
pub(crate) async fn queue_download_file(
req: web::Json<FileDownloadRequest>,
_app_state: web::Data<AppState>,
@@ -103,7 +109,7 @@ pub(crate) async fn queue_download_file(
}
match FileDownload::new(req.url.as_str(), req.filename.as_str(), download_cfg) {
Some(file_download) => {
let file_name = file_download.filename.to_owned();
let response = download_info_response!(file_download, Value::Null);
_app_state.downloads.queue.lock().unwrap().push(file_download);
if _app_state.downloads.active.read().unwrap().is_none() {
match run_download_queue(download_cfg, Arc::clone(&_app_state.downloads)) {
@@ -111,7 +117,7 @@ pub(crate) async fn queue_download_file(
Err(err) => return HttpResponse::InternalServerError().json(json!({"error": err})),
}
}
HttpResponse::Ok().json(json!({"success": file_name}))
response
}
None => HttpResponse::BadRequest().json(json!({"error": "Invalid Arguments"})),
}
@@ -120,7 +126,6 @@ pub(crate) async fn queue_download_file(
}
}
pub(crate) async fn download_file_info(
_app_state: web::Data<AppState>,
) -> HttpResponse {
@@ -133,6 +138,6 @@ pub(crate) async fn download_file_info(
match &*_app_state.downloads.active.read().unwrap() {
None => HttpResponse::Ok().json(json!({"finished": true, "errors": errors})),
Some(file_download) =>
HttpResponse::Ok().json(json!({"uuid": file_download.uuid, "filename": file_download.filename, "filesize": file_download.size, "errors": errors}))
download_info_response!(file_download, errors)
}
}