1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
/*
This file is part of jellything (https://codeberg.org/metamuffin/jellything)
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
use anyhow::Context;
use bincode::{Decode, Encode};
use jellybase::common::chrono::{format::Parsed, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct YVideo {
pub id: String,
pub title: String,
pub alt_title: Option<String>,
pub formats: Option<Vec<YFormat>>,
pub thumbnails: Option<Vec<YThumbnail>>,
pub thumbnail: Option<String>,
pub description: Option<String>,
pub channel_id: Option<String>,
pub duration: Option<f64>,
pub view_count: Option<usize>,
pub average_rating: Option<String>,
pub age_limit: Option<usize>,
pub webpage_url: String,
pub categories: Option<Vec<String>>,
pub tags: Option<Vec<String>>,
pub playable_in_embed: Option<bool>,
pub aspect_ratio: Option<f32>,
pub width: Option<i32>,
pub height: Option<i32>,
pub automatic_captions: Option<HashMap<String, Vec<YCaption>>>,
pub comment_count: Option<usize>,
pub chapters: Option<Vec<YChapter>>,
pub heatmap: Option<Vec<YHeatmapSample>>,
pub like_count: Option<usize>,
pub channel: Option<String>,
pub channel_follower_count: Option<usize>,
pub channel_is_verified: Option<bool>,
pub uploader: Option<String>,
pub uploader_id: Option<String>,
pub uploader_url: Option<String>,
pub upload_date: Option<String>,
pub availability: Option<String>, // "public" | "private" | "unlisted",
pub original_url: Option<String>,
pub webpage_url_basename: String,
pub webpage_url_domain: String,
pub extractor: String,
pub extractor_key: String,
pub playlist_count: Option<usize>,
pub playlist: Option<String>,
pub playlist_id: Option<String>,
pub playlist_title: Option<String>,
pub playlist_uploader: Option<String>,
pub playlist_uploader_id: Option<String>,
pub n_entries: Option<usize>,
pub playlist_index: Option<usize>,
pub display_id: Option<String>,
pub fulltitle: Option<String>,
pub duration_string: Option<String>,
pub is_live: Option<bool>,
pub was_live: Option<bool>,
pub epoch: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct YCaption {
pub url: Option<String>,
pub ext: String, //"vtt" | "json3" | "srv1" | "srv2" | "srv3" | "ttml",
pub protocol: Option<String>,
pub name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct YFormat {
pub format_id: String,
pub format_note: Option<String>,
pub ext: String,
pub protocol: String,
pub acodec: Option<String>,
pub vcodec: Option<String>,
pub url: Option<String>,
pub width: Option<u32>,
pub height: Option<u32>,
pub fps: Option<f64>,
pub columns: Option<u32>,
pub fragments: Option<Vec<YFragment>>,
pub resolution: Option<String>,
pub dynamic_range: Option<String>,
pub aspect_ratio: Option<f64>,
pub http_headers: HashMap<String, String>,
pub audio_ext: String,
pub video_ext: String,
pub vbr: Option<f64>,
pub abr: Option<f64>,
pub format: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct YFragment {
pub url: Option<String>,
pub duration: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct YThumbnail {
pub url: String,
pub preference: Option<i32>,
pub id: String,
pub height: Option<u32>,
pub width: Option<u32>,
pub resolution: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct YChapter {
pub start_time: f64,
pub end_time: f64,
pub title: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct YHeatmapSample {
pub start_time: f64,
pub end_time: f64,
pub value: f64,
}
pub fn parse_upload_date(d: &str) -> anyhow::Result<i64> {
let (year, month, day) = (&d[0..4], &d[4..6], &d[6..8]);
let (year, month, day) = (
year.parse().context("parsing year")?,
month.parse().context("parsing month")?,
day.parse().context("parsing day")?,
);
let mut p = Parsed::new();
p.year = Some(year);
p.month = Some(month);
p.day = Some(day);
p.hour_div_12 = Some(0);
p.hour_mod_12 = Some(0);
p.minute = Some(0);
p.second = Some(0);
Ok(p.to_datetime_with_timezone(&Utc)?.timestamp_millis())
}
|