use crate::common::database::DatabaseRow;
use crate::common::fastresume::Fastresume;
use crate::config::Config;
use rusqlite::Connection;
use serde_rusqlite::from_rows;
use std::error::Error;
use std::fs;
use std::path::Path;
pub fn to_fastresume(db: &Connection, config: &Config) -> Result<(), Box<dyn Error>> {
println!("DB -> fastresume: creating fastresume files...");
let mut num_torrents_dumped = 0;
let dir_path = config
.output_directory
.as_deref()
.map(Path::new)
.unwrap_or_else(|| Path::new("qbfrt_dump"));
fs::create_dir_all(dir_path)?;
if config.verbose {
println!("DB -> fastresume: output directory: {:?}", dir_path);
}
let mut search_stmt = db.prepare("SELECT * FROM torrents")?;
let all_torrents = from_rows::<DatabaseRow>(search_stmt.query([])?);
for torrent in all_torrents {
let torrent = match torrent {
Ok(torrent) => torrent,
Err(err) => {
eprintln!("DB -> fastresume: Skipping item due to error: {err}");
continue;
}
};
let bencoded_resume_data = torrent.libtorrent_resume_data.as_slice();
let mut resume_data =
serde_bencode::from_bytes::<Fastresume>(bencoded_resume_data).unwrap();
resume_data.qbt_category = Some(torrent.category.unwrap_or_default().into_bytes());
resume_data.qbt_content_layout = Some(torrent.content_layout.into_bytes());
resume_data.qbt_first_last_piece_priority = Some(torrent.has_outer_pieces_priority);
resume_data.qbt_inactive_seeding_time_limit = Some(torrent.inactive_seeding_time_limit);
resume_data.qbt_name = Some(torrent.name.unwrap_or_default());
resume_data.qbt_ratio_limit = Some(torrent.ratio_limit);
resume_data.qbt_seed_status = Some(torrent.has_seed_status);
resume_data.qbt_seeding_time_limit = Some(torrent.seeding_time_limit);
resume_data.qbt_share_limit_action = Some(torrent.share_limit_action.unwrap_or_default());
resume_data.qbt_stop_condition = Some(torrent.stop_condition);
if torrent.target_save_path.is_some() {
resume_data.qbt_download_path = Some(torrent.download_path.unwrap_or_default());
resume_data.qbt_save_path = Some(torrent.target_save_path.unwrap_or_default());
}
match torrent.tags {
Some(tags) => {
let tags: Vec<String> = tags.split(',').map(|s| s.to_string()).collect();
resume_data.qbt_tags = Some(tags);
}
None => resume_data.qbt_tags = Some(vec![]),
}
let new_resume_data = serde_bencode::to_bytes(&resume_data)?;
let fastresume_file = dir_path.join(format!("{}.fastresume", torrent.torrent_id));
let torrent_file = dir_path.join(format!("{}.torrent", torrent.torrent_id));
fs::write(fastresume_file, new_resume_data)?;
fs::write(torrent_file, torrent.metadata.as_slice())?;
if config.verbose {
println!(
"DB -> fastresume: fastresume created for {}",
torrent.torrent_id
);
}
num_torrents_dumped += 1;
}
match num_torrents_dumped {
0 => println!("DB -> fastresume: no torrents were dumped"),
1 => println!("DB -> fastresume: 1 torrent was dumped"),
_ => println!(
"DB -> fastresume: {} torrents were dumped",
num_torrents_dumped
),
}
Ok(())
}