feat: add watch-later views and Terebi watched-state tracking
This commit is contained in:
+10
-6
@@ -1,12 +1,13 @@
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
io::{self, Read},
|
||||
path::Path,
|
||||
process::{Child, Command, Stdio},
|
||||
sync::mpsc::{self, Receiver, TryRecvError},
|
||||
thread,
|
||||
};
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const PAGE_SIZE: usize = 20;
|
||||
|
||||
@@ -16,7 +17,7 @@ pub struct Page {
|
||||
pub cutoff: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct Video {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
@@ -67,14 +68,14 @@ fn valid_channel_id(id: &str) -> bool {
|
||||
.all(|c| c.is_ascii_alphanumeric() || c == b'-' || c == b'_')
|
||||
}
|
||||
|
||||
fn valid_video_id(id: &str) -> bool {
|
||||
pub(crate) fn valid_video_id(id: &str) -> bool {
|
||||
id.len() == 11
|
||||
&& id
|
||||
.bytes()
|
||||
.all(|c| c.is_ascii_alphanumeric() || c == b'-' || c == b'_')
|
||||
}
|
||||
|
||||
fn validate_video(video: &mut Video) -> Result<(), String> {
|
||||
pub(crate) fn validate_video(video: &mut Video) -> Result<(), String> {
|
||||
if !valid_video_id(&video.id) {
|
||||
return Err("an invalid YouTube video ID".into());
|
||||
}
|
||||
@@ -463,19 +464,22 @@ pub struct PlayerLaunch {
|
||||
}
|
||||
|
||||
impl PlayerLaunch {
|
||||
pub fn start(id: &str, player: &OsStr) -> io::Result<Self> {
|
||||
pub fn start(id: &str, player: &OsStr, progress_file: &Path) -> io::Result<Self> {
|
||||
if !valid_video_id(id) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Invalid YouTube video ID",
|
||||
));
|
||||
}
|
||||
crate::watch_later::register_identity(progress_file, id)?;
|
||||
let mut player = isolated_command(player)
|
||||
.args([
|
||||
"--new-instance",
|
||||
"--url",
|
||||
&format!("https://www.youtube.com/watch?v={id}"),
|
||||
])
|
||||
.arg("--progress-file")
|
||||
.arg(progress_file)
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::piped())
|
||||
@@ -519,7 +523,7 @@ mod tests {
|
||||
fn player_launch_rejects_unsafe_video_ids_before_spawning() {
|
||||
for id in ["", "--help", "jNQXAC9IVRw&list=other", "日本語"] {
|
||||
assert!(matches!(
|
||||
PlayerLaunch::start(id, OsStr::new("terebi")),
|
||||
PlayerLaunch::start(id, OsStr::new("terebi"), Path::new("progress.jsonl")),
|
||||
Err(error) if error.kind() == io::ErrorKind::InvalidInput
|
||||
));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user