feat: support multiple video selection

This commit is contained in:
2026-10-22 14:01:47 +02:00
parent acfb3be1e7
commit 2d30120072
12 changed files with 883 additions and 169 deletions
+55
View File
@@ -1394,3 +1394,58 @@ fn youtube_v1_reports_keep_canonical_urls_and_unknown_field_tolerance() {
assert!(state.poll_progress().unwrap());
assert!(state.is_watched(&video.id));
}
#[test]
fn player_launch_rejects_invalid_and_duplicate_batch_identities_before_creating_sessions() {
use crate::youtube::PlayerLaunch;
use std::ffi::OsStr;
let directory = TestDirectory::new();
let mut state = State::open(&directory.config()).unwrap();
for id in [
"",
"--help",
"jNQXAC9IVRw&list=other",
"日本語",
"miruro:opaque_Show-1:0",
"miruro:opaque_Show-1:01",
"miruro:opaque_Show-1:2147483648",
"miruro:../other:1",
"miruro:opaque_Show-1:1&ep=2",
"miruro-series:opaque_Show-1",
] {
let mut invalid_video = video();
invalid_video.id = id.into();
assert!(matches!(
PlayerLaunch::start(&[video(), invalid_video], OsStr::new("terebi"), &mut state),
Err(error) if error.kind() == io::ErrorKind::InvalidInput
));
}
for videos in [vec![], vec![video(), video()]] {
assert!(matches!(
PlayerLaunch::start(&videos, OsStr::new("terebi"), &mut state),
Err(error) if error.kind() == io::ErrorKind::InvalidInput
));
}
assert!(!state.sessions.exists());
assert!(state.streams.is_empty());
}
#[test]
fn progress_batch_prevalidates_snapshots_and_session_capacity() {
let directory = TestDirectory::new();
let mut state = State::open(&directory.config()).unwrap();
let mut invalid_video = miruro_video(2);
invalid_video.title = "invalid\nmetadata".into();
assert!(state.progress_files(&[video(), invalid_video]).is_err());
assert!(!state.sessions.exists());
assert!(state.streams.is_empty());
for _ in 0..MAX_STREAMS - 1 {
state
.streams
.push(ProgressStream::new(directory.0.join("unused.jsonl")));
}
assert!(state.progress_files(&[video(), miruro_video(2)]).is_err());
assert!(!state.sessions.exists());
assert_eq!(state.streams.len(), MAX_STREAMS - 1);
}