mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
84 lines
2.1 KiB
Rust
84 lines
2.1 KiB
Rust
use std::{mem, time::{Duration, Instant}};
|
|
|
|
use anyhow::Result;
|
|
use futures::{StreamExt, stream::FuturesUnordered};
|
|
use hashbrown::HashSet;
|
|
use tokio::sync::oneshot;
|
|
use yazi_fs::{File, FsScheme, provider::{Provider, local::Local}};
|
|
use yazi_macro::succ;
|
|
use yazi_parser::mgr::{DownloadOpt, OpenOpt};
|
|
use yazi_proxy::MgrProxy;
|
|
use yazi_shared::{data::Data, url::{UrlCow, UrlLike}};
|
|
use yazi_vfs::VfsFile;
|
|
|
|
use crate::{Actor, Ctx};
|
|
|
|
pub struct Download;
|
|
|
|
impl Actor for Download {
|
|
type Options = DownloadOpt;
|
|
|
|
const NAME: &str = "download";
|
|
|
|
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
|
|
let cwd = cx.cwd().clone();
|
|
let scheduler = cx.tasks.scheduler.clone();
|
|
|
|
tokio::spawn(async move {
|
|
Self::prepare(&opt.urls).await;
|
|
|
|
let mut wg1 = FuturesUnordered::new();
|
|
for url in opt.urls {
|
|
let (tx, rx) = oneshot::channel();
|
|
scheduler.file_download(url.to_owned(), Some(tx));
|
|
wg1.push(async move { (rx.await == Ok(false), url) });
|
|
}
|
|
|
|
let mut wg2 = vec![];
|
|
let mut urls = Vec::with_capacity(wg1.len());
|
|
let mut files = Vec::with_capacity(wg1.len());
|
|
let mut instant = Instant::now();
|
|
while let Some((success, url)) = wg1.next().await {
|
|
if !success {
|
|
continue;
|
|
}
|
|
|
|
let Ok(f) = File::new(&url).await else { continue };
|
|
urls.push(url);
|
|
files.push(f);
|
|
|
|
if instant.elapsed() >= Duration::from_secs(1) {
|
|
wg2.push(scheduler.fetch_mimetype(mem::take(&mut files)));
|
|
instant = Instant::now();
|
|
}
|
|
}
|
|
|
|
if !files.is_empty() {
|
|
wg2.push(scheduler.fetch_mimetype(files));
|
|
}
|
|
if futures::future::join_all(wg2).await.into_iter().any(|b| !b) {
|
|
return;
|
|
}
|
|
if opt.open && !urls.is_empty() {
|
|
MgrProxy::open(OpenOpt {
|
|
cwd: Some(cwd.into()),
|
|
targets: urls,
|
|
interactive: false,
|
|
hovered: false,
|
|
});
|
|
}
|
|
});
|
|
|
|
succ!();
|
|
}
|
|
}
|
|
|
|
impl Download {
|
|
async fn prepare(urls: &[UrlCow<'_>]) {
|
|
let roots: HashSet<_> = urls.iter().filter_map(|u| u.scheme().cache()).collect();
|
|
for mut root in roots {
|
|
root.push("%lock");
|
|
Local::regular(&root).create_dir_all().await.ok();
|
|
}
|
|
}
|
|
}
|