Skip to main content

bbdown_core/
models.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
4#[serde(rename_all = "snake_case")]
5pub enum ResolvedContent {
6    Video(VideoMetadata),
7    Season(SeasonResolution),
8}
9
10#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
11pub struct SeasonResolution {
12    pub season: SeasonMetadata,
13    pub selected_episodes: Vec<EpisodeMetadata>,
14}
15
16#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
17pub struct VideoMetadata {
18    pub aid: u64,
19    pub bvid: Option<String>,
20    pub title: String,
21    pub description: String,
22    pub cover_url: Option<String>,
23    pub pub_time: Option<i64>,
24    pub owner: Option<Owner>,
25    pub tags: Vec<Tag>,
26    pub pages: Vec<PageMetadata>,
27}
28
29#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
30pub struct Owner {
31    pub mid: u64,
32    pub name: String,
33}
34
35#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
36pub struct PageMetadata {
37    pub index: u32,
38    pub aid: u64,
39    pub cid: u64,
40    pub epid: Option<u64>,
41    pub title: String,
42    pub duration_seconds: Option<u32>,
43}
44
45#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
46pub struct Tag {
47    pub id: u64,
48    pub name: String,
49}
50
51#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
52pub struct SeasonMetadata {
53    pub season_id: Option<u64>,
54    pub media_id: Option<u64>,
55    pub title: String,
56    pub description: String,
57    pub cover_url: Option<String>,
58    pub main_episode_count: usize,
59    pub areas: Vec<String>,
60    pub tags: Vec<String>,
61    pub episodes: Vec<EpisodeMetadata>,
62}
63
64#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
65pub struct EpisodeMetadata {
66    pub index: u32,
67    pub aid: u64,
68    pub bvid: Option<String>,
69    pub cid: u64,
70    pub epid: u64,
71    pub title: String,
72    pub long_title: Option<String>,
73    pub pub_time: Option<i64>,
74}
75
76#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
77pub struct DownloadPlan {
78    pub title: String,
79    pub entries: Vec<DownloadEntry>,
80}
81
82#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
83pub struct DownloadEntry {
84    pub index: u32,
85    pub aid: u64,
86    pub bvid: Option<String>,
87    pub cid: u64,
88    pub epid: Option<u64>,
89    pub title: String,
90    pub source: StreamSource,
91    pub streams: StreamSet,
92    #[serde(default, skip_serializing_if = "StreamDiagnostics::is_empty")]
93    pub diagnostics: StreamDiagnostics,
94    pub subtitles: Vec<SubtitleTrack>,
95    pub danmaku: DanmakuTrack,
96}
97
98#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
99#[serde(rename_all = "snake_case")]
100pub enum StreamSource {
101    NormalWeb,
102    PgcWeb,
103    PgcProxy,
104    IntlWeb,
105}
106
107#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
108pub struct StreamDiagnostics {
109    pub attempts: Vec<StreamResolverAttempt>,
110}
111
112impl StreamDiagnostics {
113    #[must_use]
114    pub fn is_empty(&self) -> bool {
115        self.attempts.is_empty()
116    }
117}
118
119#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
120pub struct StreamResolverAttempt {
121    pub source: StreamSource,
122    pub outcome: StreamResolverOutcome,
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub area: Option<String>,
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub endpoint: Option<String>,
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub message: Option<String>,
129}
130
131#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
132#[serde(rename_all = "snake_case")]
133pub enum StreamResolverOutcome {
134    Succeeded,
135    Failed,
136    Skipped,
137}
138
139#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
140#[non_exhaustive]
141pub struct StreamSet {
142    pub videos: Vec<MediaStream>,
143    pub audios: Vec<MediaStream>,
144    pub flv_segments: Vec<FlvSegment>,
145    pub accept_quality: Vec<u32>,
146    #[serde(default)]
147    pub qualities: Vec<StreamQuality>,
148    pub duration_seconds: Option<u32>,
149}
150
151#[non_exhaustive]
152#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
153pub struct StreamQuality {
154    pub id: u32,
155    pub description: Option<String>,
156}
157
158#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
159pub struct MediaStream {
160    pub id: u32,
161    pub base_url: String,
162    pub backup_urls: Vec<String>,
163    pub codecs: Option<String>,
164    pub bandwidth: Option<u64>,
165    pub width: Option<u32>,
166    pub height: Option<u32>,
167    pub frame_rate: Option<String>,
168    pub mime_type: Option<String>,
169    pub size: Option<u64>,
170}
171
172#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
173pub struct FlvSegment {
174    pub order: u32,
175    pub url: String,
176    pub backup_urls: Vec<String>,
177    pub size: Option<u64>,
178    pub length_ms: Option<u64>,
179}
180
181#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
182pub struct SubtitleTrack {
183    pub language: String,
184    pub language_doc: Option<String>,
185    pub url: String,
186    pub format: SubtitleFormat,
187}
188
189#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
190#[serde(rename_all = "snake_case")]
191pub enum SubtitleFormat {
192    Json,
193    Ass,
194    Unknown,
195}
196
197#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
198pub struct DanmakuTrack {
199    pub cid: u64,
200    pub xml_url: String,
201}