diff --git a/Cargo.lock b/Cargo.lock index b3ae4ed..78f4e15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1380,7 +1380,7 @@ dependencies = [ [[package]] name = "rqbit" -version = "1.1.0" +version = "1.1.1" dependencies = [ "anyhow", "clap", diff --git a/crates/librqbit/src/chunk_tracker.rs b/crates/librqbit/src/chunk_tracker.rs index 7dbdebe..b02d358 100644 --- a/crates/librqbit/src/chunk_tracker.rs +++ b/crates/librqbit/src/chunk_tracker.rs @@ -20,6 +20,8 @@ pub struct ChunkTracker { have: BF, lengths: Lengths, + + priority_piece_ids: Vec, } // TODO: this should be redone from "have" pieces, not from "needed" pieces. @@ -55,11 +57,20 @@ pub enum ChunkMarkingResult { impl ChunkTracker { pub fn new(needed_pieces: BF, have_pieces: BF, lengths: Lengths) -> Self { + // TODO: ideally this needs to be a list based on needed files, e.g. + // last needed piece for each file. But let's keep simple for now. + let last_needed_piece_id = needed_pieces.iter_ones().rev().next(); + + // The last pieces first. Often important information is stored in the last piece. + // E.g. if it's a video file, than the last piece often contains some index, or just + // players look into it, and it's better be there. + let priority_piece_ids = last_needed_piece_id.into_iter().collect(); Self { chunk_status: compute_chunk_status(&lengths, &needed_pieces), needed_pieces, lengths, have: have_pieces, + priority_piece_ids, } } pub fn get_needed_pieces(&self) -> &BF { @@ -73,15 +84,15 @@ impl ChunkTracker { } pub fn iter_needed_pieces(&self) -> impl Iterator + '_ { - // Try the last piece first. Often important information is stored in the last piece. - // Then sequentially one by one. This is not super sophisticated but sometimes helps. - let last_piece_id = self.lengths.last_piece_id().get() as usize; - self.needed_pieces - .get(last_piece_id..) - .unwrap() - .iter_ones() - .map(move |n| n + last_piece_id) - .chain(self.needed_pieces.get(..last_piece_id).unwrap().iter_ones()) + self.priority_piece_ids + .iter() + .copied() + .filter(move |piece_id| self.needed_pieces[*piece_id]) + .chain( + self.needed_pieces + .iter_ones() + .filter(move |id| !self.priority_piece_ids.contains(id)), + ) } // None if wrong chunk diff --git a/crates/librqbit/src/torrent_manager.rs b/crates/librqbit/src/torrent_manager.rs index 7e35c1d..8a6965c 100644 --- a/crates/librqbit/src/torrent_manager.rs +++ b/crates/librqbit/src/torrent_manager.rs @@ -214,9 +214,19 @@ impl TorrentManager { ); spawner.spawn_block_in_place(|| { - for (file, (name, length)) in - files.iter().zip(info.iter_filenames_and_lengths().unwrap()) + for (idx, (file, (name, length))) in files + .iter() + .zip(info.iter_filenames_and_lengths().unwrap()) + .enumerate() { + if options + .only_files + .as_ref() + .map(|v| !v.contains(&idx)) + .unwrap_or(false) + { + continue; + } let now = Instant::now(); if let Err(err) = ensure_file_length(&mut file.lock(), length) { warn!( diff --git a/crates/rqbit/Cargo.toml b/crates/rqbit/Cargo.toml index edd0199..2b0e56d 100644 --- a/crates/rqbit/Cargo.toml +++ b/crates/rqbit/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rqbit" description = "A bittorent client" -version = "1.1.0" +version = "1.1.1" authors = ["Igor Katson "] edition = "2018"