fix: A/B test 16 (pageHeaderRenderer on playlist pages)
This commit is contained in:
parent
f3f2e1d3ca
commit
e65f14556f
17 changed files with 6435 additions and 182 deletions
|
|
@ -35,6 +35,7 @@ pub enum ABTest {
|
|||
MusicPlaylistTwoColumn = 13,
|
||||
CommentsFrameworkUpdate = 14,
|
||||
ChannelShortsLockup = 15,
|
||||
PlaylistPageHeader = 16,
|
||||
}
|
||||
|
||||
/// List of active A/B tests that are run when none is manually specified
|
||||
|
|
@ -112,6 +113,7 @@ pub async fn run_test(
|
|||
ABTest::MusicPlaylistTwoColumn => music_playlist_two_column(&query).await,
|
||||
ABTest::CommentsFrameworkUpdate => comments_framework_update(&query).await,
|
||||
ABTest::ChannelShortsLockup => channel_shorts_lockup(&query).await,
|
||||
ABTest::PlaylistPageHeader => playlist_page_header_renderer(&query).await,
|
||||
}
|
||||
.unwrap();
|
||||
pb.inc(1);
|
||||
|
|
@ -382,3 +384,20 @@ pub async fn channel_shorts_lockup(rp: &RustyPipeQuery) -> Result<bool> {
|
|||
.unwrap();
|
||||
Ok(res.contains("\"shortsLockupViewModel\""))
|
||||
}
|
||||
|
||||
pub async fn playlist_page_header_renderer(rp: &RustyPipeQuery) -> Result<bool> {
|
||||
let id = "VLPLZN_exA7d4RVmCQrG5VlWIjMOkMFZVVOc";
|
||||
let res = rp
|
||||
.raw(
|
||||
ClientType::Desktop,
|
||||
"browse",
|
||||
&QBrowse {
|
||||
context: rp.get_context(ClientType::Desktop, true, None).await,
|
||||
browse_id: id,
|
||||
params: None,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
Ok(res.contains("\"pageHeaderRenderer\""))
|
||||
}
|
||||
|
|
|
|||
75
codegen/src/collect_chan_prefixes.rs
Normal file
75
codegen/src/collect_chan_prefixes.rs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
use std::{collections::BTreeMap, fs::File, io::BufReader};
|
||||
|
||||
use path_macro::path;
|
||||
use rustypipe::{
|
||||
client::RustyPipe,
|
||||
param::{Language, LANGUAGES},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::util::{self, DICT_DIR};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct Entry {
|
||||
prefix: String,
|
||||
suffix: String,
|
||||
}
|
||||
|
||||
pub async fn collect_chan_prefixes() {
|
||||
let cname = "kiernanchrisman";
|
||||
let json_path = path!(*DICT_DIR / "chan_prefixes.json");
|
||||
let mut res = BTreeMap::new();
|
||||
|
||||
let rp = RustyPipe::new();
|
||||
|
||||
for lang in LANGUAGES {
|
||||
let playlist = rp
|
||||
.query()
|
||||
.lang(lang)
|
||||
.playlist("PLZN_exA7d4RVmCQrG5VlWIjMOkMFZVVOc")
|
||||
.await
|
||||
.unwrap();
|
||||
let n = playlist.channel.unwrap().name;
|
||||
let offset = n.find(cname).unwrap();
|
||||
let prefix = &n[..offset];
|
||||
let suffix = &n[(offset + cname.len())..];
|
||||
|
||||
res.insert(
|
||||
lang,
|
||||
Entry {
|
||||
prefix: prefix.to_owned(),
|
||||
suffix: suffix.to_owned(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let file = File::create(json_path).unwrap();
|
||||
serde_json::to_writer_pretty(file, &res).unwrap();
|
||||
}
|
||||
|
||||
pub fn write_samples_to_dict() {
|
||||
let json_path = path!(*DICT_DIR / "chan_prefixes.json");
|
||||
|
||||
let json_file = File::open(json_path).unwrap();
|
||||
let collected: BTreeMap<Language, Entry> =
|
||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||
let mut dict = util::read_dict();
|
||||
let langs = dict.keys().copied().collect::<Vec<_>>();
|
||||
|
||||
for lang in langs {
|
||||
let dict_entry = dict.entry(lang).or_default();
|
||||
|
||||
let e = collected.get(&lang).unwrap();
|
||||
dict_entry.chan_prefix = e.prefix.trim().to_owned();
|
||||
dict_entry.chan_suffix = e.suffix.trim().to_owned();
|
||||
|
||||
for lang in &dict_entry.equivalent {
|
||||
let ee = collected.get(lang).unwrap();
|
||||
if ee.prefix != e.prefix || ee.suffix != e.suffix {
|
||||
panic!("equivalent lang conflict, lang: {lang}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
util::write_dict(dict);
|
||||
}
|
||||
|
|
@ -85,6 +85,10 @@ pub(crate) struct Entry {
|
|||
///
|
||||
/// Format: Parsed text -> Album type
|
||||
pub album_types: phf::Map<&'static str, AlbumType>,
|
||||
/// Channel name prefix on playlist pages (e.g. `by`)
|
||||
pub chan_prefix: &'static str,
|
||||
/// Channel name suffix on playlist pages
|
||||
pub chan_suffix: &'static str,
|
||||
}
|
||||
"#;
|
||||
|
||||
|
|
@ -180,8 +184,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
.to_string()
|
||||
.replace('\n', "\n ");
|
||||
|
||||
write!(code_timeago_tokens, "{} => Entry {{\n timeago_tokens: {},\n date_order: {},\n months: {},\n timeago_nd_tokens: {},\n comma_decimal: {:?},\n number_tokens: {},\n number_nd_tokens: {},\n album_types: {},\n }},\n ",
|
||||
selector, code_ta_tokens, date_order, code_months, code_ta_nd_tokens, entry.comma_decimal, code_number_tokens, code_number_nd_tokens, code_album_types).unwrap();
|
||||
write!(code_timeago_tokens, "{} => Entry {{\n timeago_tokens: {},\n date_order: {},\n months: {},\n timeago_nd_tokens: {},\n comma_decimal: {:?},\n number_tokens: {},\n number_nd_tokens: {},\n album_types: {},\n chan_prefix: {:?},\n chan_suffix: {:?},\n }},\n ",
|
||||
selector, code_ta_tokens, date_order, code_months, code_ta_nd_tokens, entry.comma_decimal, code_number_tokens, code_number_nd_tokens, code_album_types, entry.chan_prefix, entry.chan_suffix).unwrap();
|
||||
}
|
||||
|
||||
code_timeago_tokens = code_timeago_tokens.trim_end().to_owned() + "\n }\n}\n";
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
mod abtest;
|
||||
mod collect_album_types;
|
||||
mod collect_chan_prefixes;
|
||||
mod collect_large_numbers;
|
||||
mod collect_playlist_dates;
|
||||
mod collect_video_dates;
|
||||
|
|
@ -29,10 +30,12 @@ enum Commands {
|
|||
CollectAlbumTypes,
|
||||
CollectVideoDurations,
|
||||
CollectVideoDates,
|
||||
CollectChanPrefixes,
|
||||
ParsePlaylistDates,
|
||||
ParseLargeNumbers,
|
||||
ParseAlbumTypes,
|
||||
ParseVideoDurations,
|
||||
ParseChanPrefixes,
|
||||
GenLocales,
|
||||
GenDict,
|
||||
DownloadTestfiles,
|
||||
|
|
@ -65,10 +68,14 @@ async fn main() {
|
|||
Commands::CollectVideoDates => {
|
||||
collect_video_dates::collect_video_dates(cli.concurrency).await;
|
||||
}
|
||||
Commands::CollectChanPrefixes => {
|
||||
collect_chan_prefixes::collect_chan_prefixes().await;
|
||||
}
|
||||
Commands::ParsePlaylistDates => collect_playlist_dates::write_samples_to_dict(),
|
||||
Commands::ParseLargeNumbers => collect_large_numbers::write_samples_to_dict(),
|
||||
Commands::ParseAlbumTypes => collect_album_types::write_samples_to_dict(),
|
||||
Commands::ParseVideoDurations => collect_video_durations::parse_video_durations(),
|
||||
Commands::ParseChanPrefixes => collect_chan_prefixes::write_samples_to_dict(),
|
||||
Commands::GenLocales => {
|
||||
gen_locales::generate_locales().await;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ pub struct DictEntry {
|
|||
///
|
||||
/// Format: Parsed text -> Album type
|
||||
pub album_types: BTreeMap<String, AlbumType>,
|
||||
/// Names of item types (Song, Video, Artist, Playlist)
|
||||
///
|
||||
/// Format: Parsed text -> Item type
|
||||
pub item_types: BTreeMap<String, ExtItemType>,
|
||||
/// Channel name prefix on playlist pages (e.g. `by`)
|
||||
pub chan_prefix: String,
|
||||
/// Channel name suffix on playlist pages
|
||||
pub chan_suffix: String,
|
||||
}
|
||||
|
||||
/// Parsed TimeAgo string, contains amount and time unit.
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ The data model for the video shelves did not change.
|
|||
- **Encountered on:** 1.05.2023
|
||||
- **Impact:** 🟢 Low
|
||||
- **Endpoint:** browse (trending videos)
|
||||
- **Status:** Frequent (99%)
|
||||
- **Status:** Stabilized
|
||||
|
||||
YouTube changed the header renderer type on the trending page to a `pageHeaderRenderer`.
|
||||
|
||||
|
|
@ -489,7 +489,7 @@ looks needlessly complex but contains the same parsing-relevant data as the old
|
|||
- **Encountered on:** 29.01.2024
|
||||
- **Impact:** 🟢 Low
|
||||
- **Endpoint:** browse
|
||||
- **Status:** Frequent (55%)
|
||||
- **Status:** Stabilized
|
||||
|
||||
YouTube introduced a new data model for channel headers, based on a
|
||||
`"pageHeaderRenderer"`. The new model comes with more needless complexity that needs to
|
||||
|
|
@ -598,7 +598,7 @@ be accomodated. There are also no mobile/TV header images available any more.
|
|||
- **Encountered on:** 29.02.2024
|
||||
- **Impact:** 🟢 Low
|
||||
- **Endpoint:** browse
|
||||
- **Status:** Discontinued (0%)
|
||||
- **Status:** Stabilized
|
||||
|
||||

|
||||
|
||||
|
|
@ -610,7 +610,7 @@ cover on the left side of the playlist content.
|
|||
- **Encountered on:** 31.01.2024
|
||||
- **Impact:** 🟢 Low
|
||||
- **Endpoint:** next
|
||||
- **Status:** Frequent (98%)
|
||||
- **Status:** Stabilized
|
||||
|
||||
YouTube changed the data model for YouTube comments, now putting the content into a
|
||||
seperate framework update object
|
||||
|
|
@ -754,7 +754,7 @@ seperate framework update object
|
|||
- **Encountered on:** 10.09.2024
|
||||
- **Impact:** 🟢 Low
|
||||
- **Endpoint:** browse
|
||||
- **Status:** Common
|
||||
- **Status:** Stabilized
|
||||
|
||||
YouTube changed the data model for the channel shorts tab
|
||||
|
||||
|
|
@ -787,3 +787,115 @@ YouTube changed the data model for the channel shorts tab
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
## [16] New playlist header renderer
|
||||
|
||||
- **Encountered on:** 11.10.2024
|
||||
- **Impact:** 🟢 Low
|
||||
- **Endpoint:** browse
|
||||
- **Status:** Common (99%)
|
||||
|
||||
```json
|
||||
{
|
||||
"pageHeaderRenderer": {
|
||||
"pageTitle": "LilyPichu",
|
||||
"content": {
|
||||
"pageHeaderViewModel": {
|
||||
"title": {
|
||||
"dynamicTextViewModel": {
|
||||
"text": {
|
||||
"content": "LilyPichu"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"contentMetadataViewModel": {
|
||||
"metadataRows": [
|
||||
{
|
||||
"metadataParts": [
|
||||
{
|
||||
"avatarStack": {
|
||||
"avatarStackViewModel": {
|
||||
"avatars": [
|
||||
{
|
||||
"avatarViewModel": {
|
||||
"image": {
|
||||
"sources": [
|
||||
{
|
||||
"url": "https://yt3.ggpht.com/ytc/AIdro_kcjhSY2e8WlYjQABOB65Za8n3QYycNHP9zXwxjKpBfOg=s48-c-k-c0x00ffffff-no-rj",
|
||||
"width": 48,
|
||||
"height": 48
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"text": {
|
||||
"content": "by Kevin Ramirez",
|
||||
"commandRuns": [
|
||||
{
|
||||
"startIndex": 0,
|
||||
"length": 16,
|
||||
"onTap": {
|
||||
"innertubeCommand": {
|
||||
"browseEndpoint": {
|
||||
"browseId": "UCai7BcI5lrXC2vdc3ySku8A",
|
||||
"canonicalBaseUrl": "/@XxthekevinramirezxX"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"metadataParts": [
|
||||
{
|
||||
"text": {
|
||||
"content": "Playlist"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"content": "10 videos"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"content": "856 views"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"actions": {},
|
||||
"description": {
|
||||
"descriptionPreviewViewModel": {
|
||||
"description": { "content": "Hello World" }
|
||||
}
|
||||
},
|
||||
"heroImage": {
|
||||
"contentPreviewImageViewModel": {
|
||||
"image": {
|
||||
"sources": [
|
||||
{
|
||||
"url": "https://i.ytimg.com/vi/DXuNJ267Vss/hqdefault.jpg?sqp=-oaymwEWCKgBEF5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLAHp6V96b70x4SWm9Pe6WEHnQhP6A",
|
||||
"width": 168,
|
||||
"height": 94
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -470,10 +470,10 @@ fn map_channel(
|
|||
)
|
||||
};
|
||||
let subscriber_count = sub_part.and_then(|t| {
|
||||
util::parse_large_numstr_or_warn::<u64>(&t.text, ctx.lang, &mut warnings)
|
||||
util::parse_large_numstr_or_warn::<u64>(t.as_str(), ctx.lang, &mut warnings)
|
||||
});
|
||||
let video_count =
|
||||
vc_part.and_then(|t| util::parse_numeric_or_warn(&t.text, &mut warnings));
|
||||
vc_part.and_then(|t| util::parse_numeric_or_warn(t.as_str(), &mut warnings));
|
||||
|
||||
Channel {
|
||||
id: metadata.external_id,
|
||||
|
|
@ -482,7 +482,7 @@ fn map_channel(
|
|||
md_rows
|
||||
.first()
|
||||
.and_then(|md| md.metadata_parts.get(1))
|
||||
.map(|txt| txt.text.to_owned())
|
||||
.map(|txt| txt.as_str().to_owned())
|
||||
.filter(|txt| util::CHANNEL_HANDLE_REGEX.is_match(txt))
|
||||
}),
|
||||
subscriber_count,
|
||||
|
|
@ -710,7 +710,7 @@ mod tests {
|
|||
#[case::livestreams("livestreams", "UC2DjFE7Xf11URZqWBigcVOQ")]
|
||||
#[case::pageheader("shorts_20240129_pageheader", "UCh8gHdtzO2tXd593_bjErWg")]
|
||||
#[case::pageheader2("videos_20240324_pageheader2", "UC2DjFE7Xf11URZqWBigcVOQ")]
|
||||
#[case::shorts2("shorts_20240910_lockup", "UCh8gHdtzO2tXd593_bjErWg")]
|
||||
#[case::lockup("shorts_20240910_lockup", "UCh8gHdtzO2tXd593_bjErWg")]
|
||||
fn map_channel_videos(#[case] name: &str, #[case] id: &str) {
|
||||
let json_path = path!(*TESTFILES / "channel" / format!("channel_{name}.json"));
|
||||
let json_file = File::open(json_path).unwrap();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
ChannelId, Playlist, VideoItem,
|
||||
},
|
||||
serializer::text::{TextComponent, TextComponents},
|
||||
util::{self, timeago, TryRemove},
|
||||
util::{self, dictionary, timeago, TryRemove},
|
||||
};
|
||||
|
||||
use super::{response, ClientType, MapRespCtx, MapResponse, MapResult, QBrowse, RustyPipeQuery};
|
||||
|
|
@ -98,46 +98,105 @@ impl MapResponse<Playlist> for response::Playlist {
|
|||
.playlist_sidebar_primary_info_renderer
|
||||
.description
|
||||
.filter(|d| !d.0.is_empty()),
|
||||
primary
|
||||
.playlist_sidebar_primary_info_renderer
|
||||
.thumbnail_renderer
|
||||
.playlist_video_thumbnail_renderer
|
||||
.thumbnail,
|
||||
Some(
|
||||
primary
|
||||
.playlist_sidebar_primary_info_renderer
|
||||
.thumbnail_renderer
|
||||
.playlist_video_thumbnail_renderer
|
||||
.thumbnail,
|
||||
),
|
||||
primary
|
||||
.playlist_sidebar_primary_info_renderer
|
||||
.stats
|
||||
.try_swap_remove(2),
|
||||
)
|
||||
}
|
||||
None => {
|
||||
let header_banner = header
|
||||
.playlist_header_renderer
|
||||
.playlist_header_banner
|
||||
.ok_or(ExtractionError::InvalidData(Cow::Borrowed(
|
||||
"no thumbnail found",
|
||||
)))?;
|
||||
|
||||
let mut byline = header.playlist_header_renderer.byline;
|
||||
let last_update_txt = byline
|
||||
.try_swap_remove(1)
|
||||
.map(|b| b.playlist_byline_renderer.text);
|
||||
|
||||
(
|
||||
None,
|
||||
header_banner.hero_playlist_thumbnail_renderer.thumbnail,
|
||||
last_update_txt,
|
||||
)
|
||||
}
|
||||
None => (None, None, None),
|
||||
};
|
||||
|
||||
let (name, playlist_id, channel, n_videos_txt, description2, thumbnails2, last_update_txt2) =
|
||||
match header {
|
||||
response::playlist::Header::PlaylistHeaderRenderer(header_renderer) => {
|
||||
let mut byline = header_renderer.byline;
|
||||
let last_update_txt = byline
|
||||
.try_swap_remove(1)
|
||||
.map(|b| b.playlist_byline_renderer.text);
|
||||
|
||||
(
|
||||
header_renderer.title,
|
||||
header_renderer.playlist_id,
|
||||
header_renderer
|
||||
.owner_text
|
||||
.and_then(|link| ChannelId::try_from(link).ok()),
|
||||
header_renderer.num_videos_text,
|
||||
header_renderer
|
||||
.description_text
|
||||
.map(|text| TextComponents(vec![TextComponent::new(text)])),
|
||||
header_renderer
|
||||
.playlist_header_banner
|
||||
.map(|b| b.hero_playlist_thumbnail_renderer.thumbnail),
|
||||
last_update_txt,
|
||||
)
|
||||
}
|
||||
response::playlist::Header::PageHeaderRenderer(content_renderer) => {
|
||||
let h = content_renderer.content.page_header_view_model;
|
||||
let rows = h.metadata.content_metadata_view_model.metadata_rows;
|
||||
let n_videos_txt = rows
|
||||
.get(1)
|
||||
.and_then(|r| r.metadata_parts.get(1))
|
||||
.map(|p| p.as_str().to_owned())
|
||||
.ok_or(ExtractionError::InvalidData("no video count".into()))?;
|
||||
let mut channel = rows
|
||||
.into_iter()
|
||||
.next()
|
||||
.and_then(|r| r.metadata_parts.into_iter().next())
|
||||
.and_then(|p| match p {
|
||||
response::MetadataPart::Text(_) => None,
|
||||
response::MetadataPart::AvatarStack {
|
||||
avatar_stack_view_model,
|
||||
} => ChannelId::try_from(avatar_stack_view_model.text).ok(),
|
||||
});
|
||||
// remove "by" prefix
|
||||
if let Some(c) = channel.as_mut() {
|
||||
let entry = dictionary::entry(ctx.lang);
|
||||
let n = c.name.strip_prefix(entry.chan_prefix).unwrap_or(&c.name);
|
||||
let n = n.strip_suffix(entry.chan_suffix).unwrap_or(n);
|
||||
c.name = n.trim().to_owned();
|
||||
}
|
||||
|
||||
let playlist_id = h
|
||||
.actions
|
||||
.flexible_actions_view_model
|
||||
.actions_rows
|
||||
.into_iter()
|
||||
.next()
|
||||
.and_then(|r| r.actions.into_iter().next())
|
||||
.and_then(|a| {
|
||||
a.button_view_model
|
||||
.on_tap
|
||||
.innertube_command
|
||||
.into_playlist_id()
|
||||
})
|
||||
.ok_or(ExtractionError::InvalidData("no playlist id".into()))?;
|
||||
(
|
||||
h.title.dynamic_text_view_model.text,
|
||||
playlist_id,
|
||||
channel,
|
||||
n_videos_txt,
|
||||
h.description.description_preview_view_model.description,
|
||||
h.hero_image.content_preview_image_view_model.image.into(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let n_videos = if mapper.ctoken.is_some() {
|
||||
util::parse_numeric(&header.playlist_header_renderer.num_videos_text)
|
||||
.map_err(|_| ExtractionError::InvalidData(Cow::Borrowed("no video count")))?
|
||||
util::parse_numeric(&n_videos_txt)
|
||||
.map_err(|_| ExtractionError::InvalidData("no video count".into()))?
|
||||
} else {
|
||||
mapper.items.len() as u64
|
||||
};
|
||||
|
||||
let playlist_id = header.playlist_header_renderer.playlist_id;
|
||||
if playlist_id != ctx.id {
|
||||
return Err(ExtractionError::WrongResult(format!(
|
||||
"got wrong playlist id {}, expected {}",
|
||||
|
|
@ -145,24 +204,19 @@ impl MapResponse<Playlist> for response::Playlist {
|
|||
)));
|
||||
}
|
||||
|
||||
let name = header.playlist_header_renderer.title;
|
||||
let description = description
|
||||
.or_else(|| {
|
||||
header
|
||||
.playlist_header_renderer
|
||||
.description_text
|
||||
.map(|text| TextComponents(vec![TextComponent::new(text)]))
|
||||
})
|
||||
.map(RichText::from);
|
||||
let channel = header
|
||||
.playlist_header_renderer
|
||||
.owner_text
|
||||
.and_then(|link| ChannelId::try_from(link).ok());
|
||||
|
||||
let last_update = last_update_txt.as_ref().and_then(|txt| {
|
||||
timeago::parse_textual_date_or_warn(ctx.lang, txt, &mut mapper.warnings)
|
||||
.map(OffsetDateTime::date)
|
||||
});
|
||||
let description = description.or(description2).map(RichText::from);
|
||||
let thumbnails = thumbnails
|
||||
.or(thumbnails2)
|
||||
.ok_or(ExtractionError::InvalidData(Cow::Borrowed(
|
||||
"no thumbnail found",
|
||||
)))?;
|
||||
let last_update = last_update_txt
|
||||
.as_deref()
|
||||
.or(last_update_txt2.as_deref())
|
||||
.and_then(|txt| {
|
||||
timeago::parse_textual_date_or_warn(ctx.lang, txt, &mut mapper.warnings)
|
||||
.map(OffsetDateTime::date)
|
||||
});
|
||||
|
||||
Ok(MapResult {
|
||||
c: Playlist {
|
||||
|
|
@ -207,6 +261,7 @@ mod tests {
|
|||
#[case::long("long", "PL5dDx681T4bR7ZF1IuWzOv1omlRbE7PiJ")]
|
||||
#[case::nomusic("nomusic", "PL1J-6JOckZtE_P9Xx8D3b2O6w0idhuKBe")]
|
||||
#[case::live("live", "UULVvqRdlKsE5Q8mf8YXbdIJLw")]
|
||||
#[case::pageheader("20241011_pageheader", "PLT2w2oBf1TZKyvY_M6JsASs73m-wjLzH5")]
|
||||
fn map_playlist_data(#[case] name: &str, #[case] id: &str) {
|
||||
let json_path = path!(*TESTFILES / "playlist" / format!("playlist_{name}.json"));
|
||||
let json_file = File::open(json_path).unwrap();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ use serde_with::{rust::deserialize_ignore_any, serde_as, DefaultOnError, VecSkip
|
|||
|
||||
use super::{
|
||||
video_item::YouTubeListRenderer, Alert, ChannelBadge, ContentRenderer, ContentsRenderer,
|
||||
ContinuationActionWrap, ImageView, ResponseContext, Thumbnails, TwoColumnBrowseResults,
|
||||
ContinuationActionWrap, ImageView, PageHeaderRendererContent, PhMetadataView, ResponseContext,
|
||||
Thumbnails, TwoColumnBrowseResults,
|
||||
};
|
||||
use crate::serializer::text::{AttributedText, Text, TextComponent};
|
||||
|
||||
|
|
@ -76,7 +77,7 @@ pub(crate) enum Header {
|
|||
C4TabbedHeaderRenderer(HeaderRenderer),
|
||||
/// Used for special channels like YouTube Music
|
||||
CarouselHeaderRenderer(ContentsRenderer<CarouselHeaderRendererItem>),
|
||||
PageHeaderRenderer(ContentRenderer<PageHeaderRenderer>),
|
||||
PageHeaderRenderer(ContentRenderer<PageHeaderRendererContent<PageHeaderRendererInner>>),
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
|
|
@ -114,12 +115,6 @@ pub(crate) enum CarouselHeaderRendererItem {
|
|||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PageHeaderRenderer {
|
||||
pub page_header_view_model: PageHeaderRendererInner,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
|
@ -225,38 +220,12 @@ pub(crate) struct PhAvatarView3 {
|
|||
pub avatar_view_model: ImageView,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhMetadataView {
|
||||
pub content_metadata_view_model: PhMetadataView2,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhMetadataView2 {
|
||||
pub metadata_rows: Vec<PhMetadataRow>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhMetadataRow {
|
||||
pub metadata_parts: Vec<TextWrap>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhBannerView {
|
||||
pub image_banner_view_model: ImageView,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct TextWrap {
|
||||
#[serde_as(deserialize_as = "Text")]
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct Metadata {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ use serde::{
|
|||
use serde_with::{serde_as, DisplayFromStr, VecSkipError};
|
||||
|
||||
use crate::error::ExtractionError;
|
||||
use crate::serializer::{text::Text, MapResult, VecSkipErrorWrap};
|
||||
use crate::serializer::text::{AttributedText, Text, TextComponent};
|
||||
use crate::serializer::{MapResult, VecSkipErrorWrap};
|
||||
|
||||
use self::video_item::YouTubeListRenderer;
|
||||
|
||||
|
|
@ -464,3 +465,61 @@ where
|
|||
deserializer.deserialize_seq(SeqVisitor(PhantomData::<T>))
|
||||
}
|
||||
}
|
||||
|
||||
// PAGE HEADER
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PageHeaderRendererContent<T> {
|
||||
pub page_header_view_model: T,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhMetadataView {
|
||||
pub content_metadata_view_model: PhMetadataView2,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhMetadataView2 {
|
||||
pub metadata_rows: Vec<PhMetadataRow>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhMetadataRow {
|
||||
#[serde_as(as = "VecSkipError<_>")]
|
||||
pub metadata_parts: Vec<MetadataPart>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) enum MetadataPart {
|
||||
Text(#[serde_as(deserialize_as = "AttributedText")] String),
|
||||
#[serde(rename_all = "camelCase")]
|
||||
AvatarStack {
|
||||
avatar_stack_view_model: AvatarStackViewModel,
|
||||
},
|
||||
}
|
||||
|
||||
impl MetadataPart {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
MetadataPart::Text(s) => s,
|
||||
MetadataPart::AvatarStack {
|
||||
avatar_stack_view_model,
|
||||
} => avatar_stack_view_model.text.as_str(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct AvatarStackViewModel {
|
||||
#[serde_as(deserialize_as = "AttributedText")]
|
||||
pub text: TextComponent,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use serde::Deserialize;
|
||||
use serde_with::{serde_as, DefaultOnError};
|
||||
use serde_with::{serde_as, DefaultOnError, VecSkipError};
|
||||
|
||||
use crate::serializer::text::{Text, TextComponent, TextComponents};
|
||||
use crate::serializer::text::{AttributedText, Text, TextComponent, TextComponents};
|
||||
|
||||
use super::{
|
||||
video_item::YouTubeListRenderer, Alert, ContentsRenderer, ResponseContext, SectionList, Tab,
|
||||
ThumbnailsWrap, TwoColumnBrowseResults,
|
||||
url_endpoint::NavigationEndpoint, video_item::YouTubeListRenderer, Alert, ContentRenderer,
|
||||
ContentsRenderer, ImageView, PageHeaderRendererContent, PhMetadataView, ResponseContext,
|
||||
SectionList, Tab, ThumbnailsWrap, TwoColumnBrowseResults,
|
||||
};
|
||||
|
||||
#[serde_as]
|
||||
|
|
@ -35,8 +36,9 @@ pub(crate) struct PlaylistVideoListRenderer {
|
|||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct Header {
|
||||
pub playlist_header_renderer: HeaderRenderer,
|
||||
pub(crate) enum Header {
|
||||
PlaylistHeaderRenderer(HeaderRenderer),
|
||||
PageHeaderRenderer(ContentRenderer<PageHeaderRendererContent<PageHeaderRendererInner>>),
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
|
|
@ -111,3 +113,85 @@ pub(crate) struct PlaylistThumbnailRenderer {
|
|||
#[serde(alias = "playlistCustomThumbnailRenderer")]
|
||||
pub playlist_video_thumbnail_renderer: ThumbnailsWrap,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PageHeaderRendererInner {
|
||||
pub title: PhTitleView,
|
||||
pub metadata: PhMetadataView,
|
||||
pub actions: PhActions,
|
||||
pub description: PhDescription,
|
||||
pub hero_image: PhHeroImage,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhDescription {
|
||||
pub description_preview_view_model: PhDescription2,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhDescription2 {
|
||||
#[serde_as(as = "Option<AttributedText>")]
|
||||
pub description: Option<TextComponents>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhHeroImage {
|
||||
pub content_preview_image_view_model: ImageView,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhTitleView {
|
||||
pub dynamic_text_view_model: PhTitleInner,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Default, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhTitleInner {
|
||||
#[serde_as(as = "AttributedText")]
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhActions {
|
||||
pub flexible_actions_view_model: PhActions2,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct PhActions2 {
|
||||
pub actions_rows: Vec<ActionsRow>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ActionsRow {
|
||||
#[serde_as(as = "VecSkipError<_>")]
|
||||
pub actions: Vec<ButtonAction>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ButtonAction {
|
||||
pub button_view_model: ButtonViewModel,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ButtonViewModel {
|
||||
pub on_tap: ActionOnTap,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct ActionOnTap {
|
||||
pub innertube_command: NavigationEndpoint,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ pub(crate) struct WatchEndpointConfig {
|
|||
#[derive(Default, Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
|
||||
pub(crate) enum MusicVideoType {
|
||||
#[default]
|
||||
#[serde(rename = "MUSIC_VIDEO_TYPE_OMV")]
|
||||
#[serde(rename = "MUSIC_VIDEO_TYPE_OMV", alias = "MUSIC_VIDEO_TYPE_UGC")]
|
||||
Video,
|
||||
#[serde(rename = "MUSIC_VIDEO_TYPE_ATV")]
|
||||
Track,
|
||||
|
|
@ -333,4 +333,26 @@ impl NavigationEndpoint {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_playlist_id(self) -> Option<String> {
|
||||
match self {
|
||||
NavigationEndpoint::Watch { watch_endpoint } => watch_endpoint.playlist_id,
|
||||
NavigationEndpoint::Browse {
|
||||
browse_endpoint,
|
||||
command_metadata,
|
||||
} => Some(browse_endpoint.browse_id).filter(|_| {
|
||||
browse_endpoint
|
||||
.browse_endpoint_context_supported_configs
|
||||
.map(|c| c.browse_endpoint_context_music_config.page_type == PageType::Playlist)
|
||||
.unwrap_or_default()
|
||||
|| command_metadata
|
||||
.map(|c| c.web_command_metadata.web_page_type == PageType::Playlist)
|
||||
.unwrap_or_default()
|
||||
}),
|
||||
NavigationEndpoint::Url { .. } => None,
|
||||
NavigationEndpoint::WatchPlaylist {
|
||||
watch_playlist_endpoint,
|
||||
} => Some(watch_playlist_endpoint.playlist_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,456 @@
|
|||
---
|
||||
source: src/client/playlist.rs
|
||||
expression: map_res.c
|
||||
---
|
||||
Playlist(
|
||||
id: "PLT2w2oBf1TZKyvY_M6JsASs73m-wjLzH5",
|
||||
name: "LilyPichu",
|
||||
videos: Paginator(
|
||||
count: Some(10),
|
||||
items: [
|
||||
VideoItem(
|
||||
id: "DXuNJ267Vss",
|
||||
name: "dreamy night ♫",
|
||||
duration: Some(246),
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/DXuNJ267Vss/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBQu39qIU8WKbC5KeXQ_a_Kmeq-Mw",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/DXuNJ267Vss/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLAFnmg4-mRI64nmz4R4GUGo720Jzw",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/DXuNJ267Vss/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLClxuSTfYdqfosJClOxA2osI934sw",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/DXuNJ267Vss/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCVR7qAVJNM3flwQ_ZYfPS3iujF1w",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelTag(
|
||||
id: "UCde_xnXu2lPBmRgAp_nq29A",
|
||||
name: "comfi beats",
|
||||
avatar: [],
|
||||
verification: None,
|
||||
subscriber_count: None,
|
||||
)),
|
||||
publish_date: "[date]",
|
||||
publish_date_txt: Some("4 years ago"),
|
||||
view_count: Some(15000000),
|
||||
is_live: false,
|
||||
is_short: false,
|
||||
is_upcoming: false,
|
||||
short_description: None,
|
||||
),
|
||||
VideoItem(
|
||||
id: "eutMcjJCVqc",
|
||||
name: "these days it\'s hard to find the words ♫",
|
||||
duration: Some(168),
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/eutMcjJCVqc/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLDc3Ycpb5YaNFeHu8Nf5smL25Z07A",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/eutMcjJCVqc/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLAScc3jmGa81fZ-rdds1pLhsyeHcA",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/eutMcjJCVqc/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCukgu31Ut9lp2E4t5BWlzit6JruA",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/eutMcjJCVqc/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBjeA0RixBcCP2w53Ke2H43HJ9j9w",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelTag(
|
||||
id: "UCde_xnXu2lPBmRgAp_nq29A",
|
||||
name: "comfi beats",
|
||||
avatar: [],
|
||||
verification: None,
|
||||
subscriber_count: None,
|
||||
)),
|
||||
publish_date: "[date]",
|
||||
publish_date_txt: Some("4 years ago"),
|
||||
view_count: Some(1200000),
|
||||
is_live: false,
|
||||
is_short: false,
|
||||
is_upcoming: false,
|
||||
short_description: None,
|
||||
),
|
||||
VideoItem(
|
||||
id: "B5eM3Q3wj0M",
|
||||
name: "a vision ♫",
|
||||
duration: Some(169),
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/B5eM3Q3wj0M/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBK3FpJmFmAlA7ALGjJDXrWC-jtfw",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/B5eM3Q3wj0M/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLCwzmil8fgPbrAd-ef4T3vzIzmlKg",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/B5eM3Q3wj0M/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBDU2ur1UisffVmAXAG8lXbT49x5Q",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/B5eM3Q3wj0M/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBy46YLhKfVL6Wj71RWd1Ru9C3Z0w",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelTag(
|
||||
id: "UCde_xnXu2lPBmRgAp_nq29A",
|
||||
name: "comfi beats",
|
||||
avatar: [],
|
||||
verification: None,
|
||||
subscriber_count: None,
|
||||
)),
|
||||
publish_date: "[date]",
|
||||
publish_date_txt: Some("4 years ago"),
|
||||
view_count: Some(843000),
|
||||
is_live: false,
|
||||
is_short: false,
|
||||
is_upcoming: false,
|
||||
short_description: None,
|
||||
),
|
||||
VideoItem(
|
||||
id: "MJedvm2TE8o",
|
||||
name: "a stormy night ♫",
|
||||
duration: Some(202),
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/MJedvm2TE8o/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBtulKIBStuPyBYbBqlE5B4-2xBaQ",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/MJedvm2TE8o/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLAEgWtwIZHLv5EKCZVIVibIkZLHlg",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/MJedvm2TE8o/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBSlJy1g4t2np6JK4hBst8b6PA2ew",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/MJedvm2TE8o/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLDkDGK867GRxs9b42P7hJkK6B2pRQ",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelTag(
|
||||
id: "UCde_xnXu2lPBmRgAp_nq29A",
|
||||
name: "comfi beats",
|
||||
avatar: [],
|
||||
verification: None,
|
||||
subscriber_count: None,
|
||||
)),
|
||||
publish_date: "[date]",
|
||||
publish_date_txt: Some("4 years ago"),
|
||||
view_count: Some(1300000),
|
||||
is_live: false,
|
||||
is_short: false,
|
||||
is_upcoming: false,
|
||||
short_description: None,
|
||||
),
|
||||
VideoItem(
|
||||
id: "HHKmS7c5ai4",
|
||||
name: "unknown waters ♫",
|
||||
duration: Some(116),
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/HHKmS7c5ai4/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLArqrLnSpTLA-1qj-yF6AmfrHOsTA",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/HHKmS7c5ai4/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLCOh-S60OM2Hhswihr3Glb1cM1AAg",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/HHKmS7c5ai4/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBEyk0qxSToWD_g9L3bTrtrsJjhsw",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/HHKmS7c5ai4/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLDG12RCxjnm4JHG9T8Ow_thj_ecxA",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelTag(
|
||||
id: "UCde_xnXu2lPBmRgAp_nq29A",
|
||||
name: "comfi beats",
|
||||
avatar: [],
|
||||
verification: None,
|
||||
subscriber_count: None,
|
||||
)),
|
||||
publish_date: "[date]",
|
||||
publish_date_txt: Some("4 years ago"),
|
||||
view_count: Some(707000),
|
||||
is_live: false,
|
||||
is_short: false,
|
||||
is_upcoming: false,
|
||||
short_description: None,
|
||||
),
|
||||
VideoItem(
|
||||
id: "zF32eh6PWPk",
|
||||
name: "wilting memories ♫",
|
||||
duration: Some(108),
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/zF32eh6PWPk/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLDr2_1EoZ50kzSgDKwJQaY6Pv3WJA",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/zF32eh6PWPk/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLC44h27mvgtl5QBA_ed1o4kXPieBA",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/zF32eh6PWPk/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLDm1iJNfB4KbVMoqPMKrWNHIBaBgg",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/zF32eh6PWPk/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLDCJEQasRwYLo-iK___zZ767PrCWQ",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelTag(
|
||||
id: "UCde_xnXu2lPBmRgAp_nq29A",
|
||||
name: "comfi beats",
|
||||
avatar: [],
|
||||
verification: None,
|
||||
subscriber_count: None,
|
||||
)),
|
||||
publish_date: "[date]",
|
||||
publish_date_txt: Some("4 years ago"),
|
||||
view_count: Some(797000),
|
||||
is_live: false,
|
||||
is_short: false,
|
||||
is_upcoming: false,
|
||||
short_description: None,
|
||||
),
|
||||
VideoItem(
|
||||
id: "hbz-8K-pxpY",
|
||||
name: "sunshine & butterflies ♫",
|
||||
duration: Some(185),
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/hbz-8K-pxpY/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLDMheaVKp1qI6AOcwrLl2K_U7EnAA",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/hbz-8K-pxpY/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLDSWaobRJuSVZFDf9aj1kHVx6WuXw",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/hbz-8K-pxpY/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLDi33fhhNwD8Rtf56eIrPZV0Wh8ZQ",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/hbz-8K-pxpY/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBt77gqVq8oLIUs7njZkvP2EvmTAw",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelTag(
|
||||
id: "UCde_xnXu2lPBmRgAp_nq29A",
|
||||
name: "comfi beats",
|
||||
avatar: [],
|
||||
verification: None,
|
||||
subscriber_count: None,
|
||||
)),
|
||||
publish_date: "[date]",
|
||||
publish_date_txt: Some("4 years ago"),
|
||||
view_count: Some(2500000),
|
||||
is_live: false,
|
||||
is_short: false,
|
||||
is_upcoming: false,
|
||||
short_description: None,
|
||||
),
|
||||
VideoItem(
|
||||
id: "A2zepLiuEJU",
|
||||
name: "foreverland ♫",
|
||||
duration: Some(146),
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/A2zepLiuEJU/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLAUpy0PRzet_xrPsGPj2Mw_ik5o0A",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/A2zepLiuEJU/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLCgYyZQkAGdE25F-zZ6AAHY5GuNjQ",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/A2zepLiuEJU/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBWFlbG5J4x8J3pxGC2k_P2O7lKmA",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/A2zepLiuEJU/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLD6N47yuLYe5m50AwYPX9Cos4RSVA",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelTag(
|
||||
id: "UCde_xnXu2lPBmRgAp_nq29A",
|
||||
name: "comfi beats",
|
||||
avatar: [],
|
||||
verification: None,
|
||||
subscriber_count: None,
|
||||
)),
|
||||
publish_date: "[date]",
|
||||
publish_date_txt: Some("4 years ago"),
|
||||
view_count: Some(983000),
|
||||
is_live: false,
|
||||
is_short: false,
|
||||
is_upcoming: false,
|
||||
short_description: None,
|
||||
),
|
||||
VideoItem(
|
||||
id: "5yaY7aG1Lpo",
|
||||
name: "dreamy nightmares ♫",
|
||||
duration: Some(197),
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/5yaY7aG1Lpo/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLB-5OLhj51LzsZswqPsGVPOKfkhFA",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/5yaY7aG1Lpo/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLDISujKyqhzBYW3SdgC5QTxv7i1KQ",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/5yaY7aG1Lpo/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLDBkkukABZ_d3rsEzewfiHimbM2PA",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/5yaY7aG1Lpo/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCnqJbFB4UvqIKUQq5xvVH6RQBm7A",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelTag(
|
||||
id: "UCde_xnXu2lPBmRgAp_nq29A",
|
||||
name: "comfi beats",
|
||||
avatar: [],
|
||||
verification: None,
|
||||
subscriber_count: None,
|
||||
)),
|
||||
publish_date: "[date]",
|
||||
publish_date_txt: Some("4 years ago"),
|
||||
view_count: Some(1100000),
|
||||
is_live: false,
|
||||
is_short: false,
|
||||
is_upcoming: false,
|
||||
short_description: None,
|
||||
),
|
||||
VideoItem(
|
||||
id: "WwXJrMhbi-s",
|
||||
name: "comfy vibes ♫",
|
||||
duration: Some(194),
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/WwXJrMhbi-s/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLByFfew80T9RbyU8-EiLyb6HRU4Ww",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/WwXJrMhbi-s/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLCcjh19GL-pWHpkpRD1ioCcyoZcrA",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/WwXJrMhbi-s/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCa7u5cp-4vH6mDG8HUOKyNTETgtQ",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/WwXJrMhbi-s/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLB-vP4BDBiu9PfU-F6DQ75iUsL4xQ",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelTag(
|
||||
id: "UCde_xnXu2lPBmRgAp_nq29A",
|
||||
name: "comfi beats",
|
||||
avatar: [],
|
||||
verification: None,
|
||||
subscriber_count: None,
|
||||
)),
|
||||
publish_date: "[date]",
|
||||
publish_date_txt: Some("4 years ago"),
|
||||
view_count: Some(1800000),
|
||||
is_live: false,
|
||||
is_short: false,
|
||||
is_upcoming: false,
|
||||
short_description: None,
|
||||
),
|
||||
],
|
||||
ctoken: None,
|
||||
endpoint: browse,
|
||||
),
|
||||
video_count: 10,
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/DXuNJ267Vss/hqdefault.jpg?sqp=-oaymwEWCKgBEF5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLAHp6V96b70x4SWm9Pe6WEHnQhP6A",
|
||||
width: 168,
|
||||
height: 94,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/DXuNJ267Vss/hqdefault.jpg?sqp=-oaymwEWCMQBEG5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLDPCehYWYW8HhToloH9MJWD_wKq1w",
|
||||
width: 196,
|
||||
height: 110,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/DXuNJ267Vss/hqdefault.jpg?sqp=-oaymwEXCPYBEIoBSFryq4qpAwkIARUAAIhCGAE=&rs=AOn4CLA7aSRV3Ymv8oEFYT7TUpwSZLPbCA",
|
||||
width: 246,
|
||||
height: 138,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/DXuNJ267Vss/hqdefault.jpg?sqp=-oaymwEXCNACELwBSFryq4qpAwkIARUAAIhCGAE=&rs=AOn4CLAYMzfwTTZbTbHcDUK9kIa450u_7g",
|
||||
width: 336,
|
||||
height: 188,
|
||||
),
|
||||
],
|
||||
description: None,
|
||||
channel: Some(ChannelId(
|
||||
id: "UCai7BcI5lrXC2vdc3ySku8A",
|
||||
name: "Kevin Ramirez",
|
||||
)),
|
||||
last_update: "[date]",
|
||||
last_update_txt: Some("Last updated on Oct 13, 2020"),
|
||||
visitor_data: Some("CgtQNE9Wb3N1MU1HSSic8Ka4BjIKCgJERRIEEgAgMA%3D%3D"),
|
||||
)
|
||||
|
|
@ -50,6 +50,10 @@ pub(crate) struct Entry {
|
|||
///
|
||||
/// Format: Parsed text -> Album type
|
||||
pub album_types: phf::Map<&'static str, AlbumType>,
|
||||
/// Channel name prefix on playlist pages (e.g. `by`)
|
||||
pub chan_prefix: &'static str,
|
||||
/// Channel name suffix on playlist pages
|
||||
pub chan_suffix: &'static str,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
|
@ -151,6 +155,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("enkelsnit", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "deur",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Am => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -252,6 +258,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("አልበም", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "በ",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Ar => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -355,6 +363,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("الكتب المسموعة", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "بواسطة",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::As => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -438,6 +448,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "ৰ দ\u{9cd}ব\u{9be}ৰ\u{9be}",
|
||||
},
|
||||
Language::Az => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -524,6 +536,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "by",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Be => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -640,6 +654,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("міні-альбом", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "ад",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Bg => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -725,6 +741,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("предаване", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "от",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Bn => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -816,6 +834,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("অ\u{9cd}য\u{9be}লব\u{9be}ম", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: ",",
|
||||
chan_suffix: "দ\u{9cd}ব\u{9be}র\u{9be}",
|
||||
},
|
||||
Language::Bs => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -926,6 +946,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "od",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Ca => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1023,6 +1045,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("audiollibre", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "de:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Cs => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1122,6 +1146,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("album", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "autor:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Da => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1218,6 +1244,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "af",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::De => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1299,6 +1327,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("hörspiel", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "von",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::El => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1399,6 +1429,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("άλμπουμ", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "από το χρήστη",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::En | Language::EnGb | Language::EnIn => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1511,6 +1543,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("audiobook", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "by",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Es => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1608,6 +1642,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "de",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::EsUs | Language::Es419 => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1706,6 +1742,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("álbum", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "de",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Et => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1806,6 +1844,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("album", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "kanalilt",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Eu => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1892,6 +1932,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("albuma", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "egilea:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Fa => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -1978,6 +2020,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("کتاب صوتی", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "توسط",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Fi => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -2066,6 +2110,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "tekijä:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Fil => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -2152,6 +2198,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "ni/ng",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Fr | Language::FrCa => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -2256,6 +2304,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("single", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "de",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Gl => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -2352,6 +2402,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("audiolibro", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "de",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Gu => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -2437,6 +2489,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("સિ\u{a82}ગલ", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "દ\u{acd}વારા",
|
||||
},
|
||||
Language::Hi => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -2526,6 +2580,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("एल\u{94d}\u{200d}बम", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "क\u{947} ज\u{93c}रिए",
|
||||
},
|
||||
Language::Hr => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -2635,6 +2691,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("singl", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "omogućio kanal",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Hu => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -2734,6 +2792,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("műsor", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "csatornától",
|
||||
},
|
||||
Language::Hy => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -2826,6 +2886,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ալբոմ", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "հեղինակ՝",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Id => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -2918,6 +2980,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("acara", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "oleh",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Is => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3023,6 +3087,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "eftir",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::It => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3125,6 +3191,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("programma", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "di",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Iw => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3233,6 +3301,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("סינגל", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "מאת",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Ja => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3300,6 +3370,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("表示", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "作成者:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Ka => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3392,6 +3464,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("სინგლი", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "-ის მიერ",
|
||||
},
|
||||
Language::Kk => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3485,6 +3559,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("альбом", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "қосқан",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Km => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3570,6 +3646,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ចម\u{17d2}រៀងទោល", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "ដោយ",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Kn => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3671,6 +3749,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ಆಲ\u{ccd}ಬಮ\u{ccd}", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "ಚಾನಲ\u{ccd}\u{200c}ನ\u{cbf}ಂದ",
|
||||
},
|
||||
Language::Ko => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3741,6 +3821,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("싱글", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "게시자:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Ky => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3829,6 +3911,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("чакан альбом", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "каналы аркылуу",
|
||||
},
|
||||
Language::Lo => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -3923,6 +4007,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ສະແດງ", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "ໂດຍ",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Lt => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4026,6 +4112,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("garsinė knyga", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "pridėjo",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Lv => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4132,6 +4220,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("pārraide", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "autors:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Mk => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4215,6 +4305,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("серија", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "од",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Ml => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4302,6 +4394,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ആല\u{d4d}\u{200d}\u{200c}ബം", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "മ\u{d41}ഖേന",
|
||||
},
|
||||
Language::Mn => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4379,6 +4473,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("цомог", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "сувгийн нэр:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Mr => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4481,6 +4577,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("शो", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "द\u{94d}वार\u{947}",
|
||||
},
|
||||
Language::Ms => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4570,6 +4668,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "oleh",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::My => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4663,6 +4763,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("အော\u{103a}ဒ\u{102e}ယ\u{102d}\u{102f}စာအ\u{102f}ပ\u{103a}", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "မ\u{103e}",
|
||||
},
|
||||
Language::Ne => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4750,6 +4852,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("अडियोब\u{941}क", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "द\u{94d}वारा",
|
||||
},
|
||||
Language::Nl => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4843,6 +4947,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "door",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::No => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -4946,6 +5052,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "av",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Or => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -5046,6 +5154,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "ଦ\u{b4d}ଵ\u{b3e}ର\u{b3e}",
|
||||
},
|
||||
Language::Pa => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -5135,6 +5245,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ਸ\u{a3c}\u{a4b}ਅ", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "ਵ\u{a71}ਲ\u{a4b}\u{a02}",
|
||||
},
|
||||
Language::Pl => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -5250,6 +5362,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("audiobook", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "autor:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Pt => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -5349,6 +5463,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("audiolivro", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "por",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::PtPt => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -5430,6 +5546,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("audiolivro", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "de",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Ro => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -5529,6 +5647,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("album", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "de",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Ru => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -5642,6 +5762,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("аудиошоу", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Si => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -5729,6 +5851,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ඇල\u{dca}බමය", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "ව\u{dd2}ස\u{dd2}න\u{dca}",
|
||||
},
|
||||
Language::Sk => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -5828,6 +5952,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("audiokniha", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "Autori:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Sl => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -5948,6 +6074,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "kanal",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Sq => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -6039,6 +6167,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("single", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "nga",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Sr => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -6127,6 +6257,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("серија", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "са канала",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::SrLatn => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -6215,6 +6347,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("serija", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "sa kanala",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Sv => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -6313,6 +6447,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("singel", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "från",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Sw => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -6400,6 +6536,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("kipindi", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "kutoka",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Ta => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -6503,6 +6641,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("ஆடியோ புத\u{bcd}தகம\u{bcd}", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "வழங\u{bcd}கியவர\u{bcd}:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Te => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -6603,6 +6743,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("స\u{c3f}ంగ\u{c3f}ల\u{c4d}", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "ఛ\u{c3e}న\u{c46}ల\u{c4d} ద\u{c4d}వ\u{c3e}ర\u{c3e}",
|
||||
},
|
||||
Language::Th => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -6704,6 +6846,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("อ\u{e31}ลบ\u{e31}\u{e49}ม", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "โดย",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Tr => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -6794,6 +6938,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("albüm", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "",
|
||||
chan_suffix: "tarafından",
|
||||
},
|
||||
Language::Uk => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -6911,6 +7057,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("аудіодрама", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "власник:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Ur => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -7006,6 +7154,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("شو", AlbumType::Show),
|
||||
],
|
||||
},
|
||||
chan_prefix: "منجانب",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Uz => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -7091,6 +7241,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("audiokitob", AlbumType::Audiobook),
|
||||
],
|
||||
},
|
||||
chan_prefix: "muallif:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::Vi => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -7159,6 +7311,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("đĩa nhạc", AlbumType::Album),
|
||||
],
|
||||
},
|
||||
chan_prefix: "của",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::ZhCn => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -7228,6 +7382,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("单曲", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "创建者:",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::ZhHk => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -7296,6 +7452,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("單曲", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "來自",
|
||||
chan_suffix: "",
|
||||
},
|
||||
Language::ZhTw => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -7363,6 +7521,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("單曲", AlbumType::Single),
|
||||
],
|
||||
},
|
||||
chan_prefix: "由",
|
||||
chan_suffix: "建立",
|
||||
},
|
||||
Language::Zu => Entry {
|
||||
timeago_tokens: ::phf::Map {
|
||||
|
|
@ -7467,6 +7627,8 @@ pub(crate) fn entry(lang: Language) -> Entry {
|
|||
("i-ep", AlbumType::Ep),
|
||||
],
|
||||
},
|
||||
chan_prefix: "ka-",
|
||||
chan_suffix: "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
85
testfiles/dict/chan_prefixes.json
Normal file
85
testfiles/dict/chan_prefixes.json
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
{
|
||||
"af": { "prefix": "deur ", "suffix": "" },
|
||||
"am": { "prefix": "በ", "suffix": "" },
|
||||
"ar": { "prefix": "بواسطة", "suffix": "" },
|
||||
"as": { "prefix": "", "suffix": "ৰ দ্বাৰা" },
|
||||
"az": { "prefix": "by ", "suffix": "" },
|
||||
"be": { "prefix": "ад ", "suffix": "" },
|
||||
"bg": { "prefix": "от ", "suffix": "" },
|
||||
"bn": { "prefix": ", ", "suffix": " দ্বারা" },
|
||||
"bs": { "prefix": "od ", "suffix": "" },
|
||||
"ca": { "prefix": "de: ", "suffix": "" },
|
||||
"cs": { "prefix": "autor: ", "suffix": "" },
|
||||
"da": { "prefix": "af ", "suffix": "" },
|
||||
"de": { "prefix": "von ", "suffix": "" },
|
||||
"el": { "prefix": "από το χρήστη ", "suffix": "" },
|
||||
"en": { "prefix": "by ", "suffix": "" },
|
||||
"en-GB": { "prefix": "by ", "suffix": "" },
|
||||
"en-IN": { "prefix": "by ", "suffix": "" },
|
||||
"es": { "prefix": "de ", "suffix": "" },
|
||||
"es-419": { "prefix": "de ", "suffix": "" },
|
||||
"es-US": { "prefix": "de ", "suffix": "" },
|
||||
"et": { "prefix": "kanalilt ", "suffix": "" },
|
||||
"eu": { "prefix": "egilea: ", "suffix": "" },
|
||||
"fa": { "prefix": "توسط ", "suffix": "" },
|
||||
"fi": { "prefix": "tekijä: ", "suffix": "" },
|
||||
"fil": { "prefix": "ni/ng ", "suffix": "" },
|
||||
"fr": { "prefix": "de ", "suffix": "" },
|
||||
"fr-CA": { "prefix": "de ", "suffix": "" },
|
||||
"gl": { "prefix": "de ", "suffix": "" },
|
||||
"gu": { "prefix": "", "suffix": " દ્વારા" },
|
||||
"hi": { "prefix": "", "suffix": " के ज़रिए" },
|
||||
"hr": { "prefix": "omogućio kanal ", "suffix": "" },
|
||||
"hu": { "prefix": "", "suffix": " csatornától" },
|
||||
"hy": { "prefix": "հեղինակ՝ ", "suffix": "" },
|
||||
"id": { "prefix": "oleh ", "suffix": "" },
|
||||
"is": { "prefix": "eftir ", "suffix": "" },
|
||||
"it": { "prefix": "di ", "suffix": "" },
|
||||
"iw": { "prefix": "מאת ", "suffix": "" },
|
||||
"ja": { "prefix": "作成者: ", "suffix": "" },
|
||||
"ka": { "prefix": "", "suffix": "-ის მიერ" },
|
||||
"kk": { "prefix": "қосқан ", "suffix": "" },
|
||||
"km": { "prefix": "ដោយ ", "suffix": "" },
|
||||
"kn": { "prefix": "", "suffix": " ಚಾನಲ್ನಿಂದ" },
|
||||
"ko": { "prefix": "게시자: ", "suffix": "" },
|
||||
"ky": { "prefix": "", "suffix": " каналы аркылуу" },
|
||||
"lo": { "prefix": "ໂດຍ ", "suffix": "" },
|
||||
"lt": { "prefix": "pridėjo ", "suffix": "" },
|
||||
"lv": { "prefix": "autors: ", "suffix": "" },
|
||||
"mk": { "prefix": "од ", "suffix": "" },
|
||||
"ml": { "prefix": "", "suffix": " മുഖേന" },
|
||||
"mn": { "prefix": "сувгийн нэр: ", "suffix": "" },
|
||||
"mr": { "prefix": "", "suffix": "द्वारे" },
|
||||
"ms": { "prefix": "oleh ", "suffix": "" },
|
||||
"my": { "prefix": "", "suffix": " မှ" },
|
||||
"ne": { "prefix": "", "suffix": " द्वारा" },
|
||||
"nl": { "prefix": "door ", "suffix": "" },
|
||||
"no": { "prefix": "av ", "suffix": "" },
|
||||
"or": { "prefix": "", "suffix": " ଦ୍ଵାରା" },
|
||||
"pa": { "prefix": "", "suffix": " ਵੱਲੋਂ" },
|
||||
"pl": { "prefix": "autor: ", "suffix": "" },
|
||||
"pt": { "prefix": "por ", "suffix": "" },
|
||||
"pt-PT": { "prefix": "de ", "suffix": "" },
|
||||
"ro": { "prefix": "de ", "suffix": "" },
|
||||
"ru": { "prefix": "", "suffix": "" },
|
||||
"si": { "prefix": "", "suffix": " විසින්" },
|
||||
"sk": { "prefix": "Autori: ", "suffix": "" },
|
||||
"sl": { "prefix": "kanal ", "suffix": "" },
|
||||
"sq": { "prefix": "nga ", "suffix": "" },
|
||||
"sr": { "prefix": "са канала ", "suffix": "" },
|
||||
"sr-Latn": { "prefix": "sa kanala ", "suffix": "" },
|
||||
"sv": { "prefix": "från ", "suffix": "" },
|
||||
"sw": { "prefix": "kutoka ", "suffix": "" },
|
||||
"ta": { "prefix": "வழங்கியவர்: ", "suffix": "" },
|
||||
"te": { "prefix": "", "suffix": " ఛానెల్ ద్వారా" },
|
||||
"th": { "prefix": "โดย ", "suffix": "" },
|
||||
"tr": { "prefix": "", "suffix": " tarafından" },
|
||||
"uk": { "prefix": "власник: ", "suffix": "" },
|
||||
"ur": { "prefix": "منجانب ", "suffix": "" },
|
||||
"uz": { "prefix": "muallif: ", "suffix": "" },
|
||||
"vi": { "prefix": "của ", "suffix": "" },
|
||||
"zh-CN": { "prefix": "创建者:", "suffix": "" },
|
||||
"zh-HK": { "prefix": "來自", "suffix": "" },
|
||||
"zh-TW": { "prefix": "由", "suffix": "建立" },
|
||||
"zu": { "prefix": "ka-", "suffix": "" }
|
||||
}
|
||||
|
|
@ -55,7 +55,9 @@
|
|||
"ep": "Ep",
|
||||
"drama": "Show",
|
||||
"enkelsnit": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "deur",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"am": {
|
||||
"equivalent": [],
|
||||
|
|
@ -117,7 +119,9 @@
|
|||
"የተራዘመ አልበም": "Ep",
|
||||
"ትዕይንት": "Show",
|
||||
"ነጠላ": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "በ",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"ar": {
|
||||
"equivalent": [],
|
||||
|
|
@ -180,7 +184,9 @@
|
|||
"ألبوم قصير": "Ep",
|
||||
"عرض": "Show",
|
||||
"أغنية منفردة": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "بواسطة",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"as": {
|
||||
"equivalent": [],
|
||||
|
|
@ -226,7 +232,9 @@
|
|||
"ep": "Ep",
|
||||
"শ্ব’": "Show",
|
||||
"একক": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "ৰ দ্বাৰা"
|
||||
},
|
||||
"az": {
|
||||
"equivalent": [],
|
||||
|
|
@ -275,7 +283,9 @@
|
|||
"ep": "Ep",
|
||||
"şou": "Show",
|
||||
"tək": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "by",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"be": {
|
||||
"equivalent": [],
|
||||
|
|
@ -349,7 +359,9 @@
|
|||
"міні-альбом": "Ep",
|
||||
"шоу": "Show",
|
||||
"сінгл": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "ад",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"bg": {
|
||||
"equivalent": [],
|
||||
|
|
@ -397,7 +409,9 @@
|
|||
"миниалбум": "Ep",
|
||||
"предаване": "Show",
|
||||
"сингъл": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "от",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"bn": {
|
||||
"equivalent": [],
|
||||
|
|
@ -450,7 +464,9 @@
|
|||
"ইপি": "Ep",
|
||||
"শো": "Show",
|
||||
"সিঙ্গেল": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": ",",
|
||||
"chan_suffix": "দ্বারা"
|
||||
},
|
||||
"bs": {
|
||||
"equivalent": [],
|
||||
|
|
@ -519,7 +535,9 @@
|
|||
"ep": "Ep",
|
||||
"serija": "Show",
|
||||
"singl": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "od",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"ca": {
|
||||
"equivalent": [],
|
||||
|
|
@ -577,7 +595,9 @@
|
|||
"ep": "Ep",
|
||||
"programa": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "de:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"cs": {
|
||||
"equivalent": [],
|
||||
|
|
@ -636,7 +656,9 @@
|
|||
"ep": "Ep",
|
||||
"zobrazit": "Show",
|
||||
"singl": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "autor:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"da": {
|
||||
"equivalent": [],
|
||||
|
|
@ -693,7 +715,9 @@
|
|||
"ep": "Ep",
|
||||
"lyddrama": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "af",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"de": {
|
||||
"equivalent": [],
|
||||
|
|
@ -737,7 +761,9 @@
|
|||
"ep": "Ep",
|
||||
"hörspiel": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "von",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"el": {
|
||||
"equivalent": [],
|
||||
|
|
@ -798,7 +824,9 @@
|
|||
"ep": "Ep",
|
||||
"εκπομπή": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "από το χρήστη",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"en": {
|
||||
"equivalent": [
|
||||
|
|
@ -872,7 +900,9 @@
|
|||
"ep": "Ep",
|
||||
"show": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "by",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"es": {
|
||||
"equivalent": [],
|
||||
|
|
@ -930,7 +960,9 @@
|
|||
"ep": "Ep",
|
||||
"audiodrama": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "de",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"es-US": {
|
||||
"equivalent": [
|
||||
|
|
@ -991,7 +1023,9 @@
|
|||
"ep": "Ep",
|
||||
"programa": "Show",
|
||||
"sencillo": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "de",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"et": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1052,7 +1086,9 @@
|
|||
"ep": "Ep",
|
||||
"sari": "Show",
|
||||
"singel": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "kanalilt",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"eu": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1101,7 +1137,9 @@
|
|||
"ep": "Ep",
|
||||
"saioa": "Show",
|
||||
"singlea": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "egilea:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"fa": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1150,7 +1188,9 @@
|
|||
"پخش فوقالعاده": "Ep",
|
||||
"نمایش": "Show",
|
||||
"تک آهنگ": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "توسط",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"fi": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1200,7 +1240,9 @@
|
|||
"ep": "Ep",
|
||||
"näytä": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "tekijä:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"fil": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1249,7 +1291,9 @@
|
|||
"ep": "Ep",
|
||||
"palabas": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "ni/ng",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"fr": {
|
||||
"equivalent": [
|
||||
|
|
@ -1315,7 +1359,9 @@
|
|||
"émission": "Show",
|
||||
"simple": "Single",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "de",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"gl": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1372,7 +1418,9 @@
|
|||
"ep": "Ep",
|
||||
"programa": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "de",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"gu": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1420,7 +1468,9 @@
|
|||
"ep": "Ep",
|
||||
"શો": "Show",
|
||||
"સિંગલ": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "દ્વારા"
|
||||
},
|
||||
"hi": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1472,7 +1522,9 @@
|
|||
"ईपी": "Ep",
|
||||
"शो": "Show",
|
||||
"सिंगल": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "के ज़रिए"
|
||||
},
|
||||
"hr": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1540,7 +1592,9 @@
|
|||
"ep": "Ep",
|
||||
"serija": "Show",
|
||||
"singl": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "omogućio kanal",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"hu": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1600,7 +1654,9 @@
|
|||
"ep": "Ep",
|
||||
"műsor": "Show",
|
||||
"kislemez": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "csatornától"
|
||||
},
|
||||
"hy": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1654,7 +1710,9 @@
|
|||
"ep": "Ep",
|
||||
"աուդիոդրամա": "Show",
|
||||
"սինգլ": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "հեղինակ՝",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"id": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1708,7 +1766,9 @@
|
|||
"ep": "Ep",
|
||||
"acara": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "oleh",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"is": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1773,7 +1833,9 @@
|
|||
"ep": "Ep",
|
||||
"þáttur": "Show",
|
||||
"smáskífa": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "eftir",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"it": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1835,7 +1897,9 @@
|
|||
"ep": "Ep",
|
||||
"programma": "Show",
|
||||
"singolo": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "di",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"iw": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1902,7 +1966,9 @@
|
|||
"מיני-אלבום": "Ep",
|
||||
"תסכית": "Show",
|
||||
"סינגל": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "מאת",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"ja": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1934,7 +2000,9 @@
|
|||
"ep": "Ep",
|
||||
"表示": "Show",
|
||||
"シングル": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "作成者:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"ka": {
|
||||
"equivalent": [],
|
||||
|
|
@ -1988,7 +2056,9 @@
|
|||
"მინი-ალბომი": "Ep",
|
||||
"ჩვენება": "Show",
|
||||
"სინგლი": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "-ის მიერ"
|
||||
},
|
||||
"kk": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2043,7 +2113,9 @@
|
|||
"ep": "Ep",
|
||||
"шоу": "Show",
|
||||
"сингл": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "қосқан",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"km": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2091,7 +2163,9 @@
|
|||
"ep": "Ep",
|
||||
"កម្មវិធីទូរទស្សន៍": "Show",
|
||||
"ចម្រៀងទោល": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "ដោយ",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"kn": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2152,7 +2226,9 @@
|
|||
"ep": "Ep",
|
||||
"ಶೋ": "Show",
|
||||
"ಒಂದೇ": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "ಚಾನಲ್ನಿಂದ"
|
||||
},
|
||||
"ko": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2187,7 +2263,9 @@
|
|||
"ep": "Ep",
|
||||
"표시": "Show",
|
||||
"싱글": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "게시자:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"ky": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2238,7 +2316,9 @@
|
|||
"чакан альбом": "Ep",
|
||||
"шоу": "Show",
|
||||
"сингл": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "каналы аркылуу"
|
||||
},
|
||||
"lo": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2294,7 +2374,9 @@
|
|||
"ep": "Ep",
|
||||
"ສະແດງ": "Show",
|
||||
"ຊິງເກິນ": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "ໂດຍ",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"lt": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2357,7 +2439,9 @@
|
|||
"mini albumas": "Ep",
|
||||
"serialas": "Show",
|
||||
"singlas": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "pridėjo",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"lv": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2423,7 +2507,9 @@
|
|||
"ep ieraksts": "Ep",
|
||||
"pārraide": "Show",
|
||||
"singls": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "autors:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"mk": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2469,7 +2555,9 @@
|
|||
"ep": "Ep",
|
||||
"серија": "Show",
|
||||
"сингл": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "од",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"ml": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2519,7 +2607,9 @@
|
|||
"ep": "Ep",
|
||||
"ഷോ": "Show",
|
||||
"സിംഗിൾ": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "മുഖേന"
|
||||
},
|
||||
"mn": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2560,7 +2650,9 @@
|
|||
"ep": "Ep",
|
||||
"жүжиг": "Show",
|
||||
"сингл": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "сувгийн нэр:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"mr": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2623,7 +2715,9 @@
|
|||
"भाग": "Ep",
|
||||
"शो": "Show",
|
||||
"सिंगल": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "द्वारे"
|
||||
},
|
||||
"ms": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2674,7 +2768,9 @@
|
|||
"ep": "Ep",
|
||||
"rancangan": "Show",
|
||||
"rekod single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "oleh",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"my": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2729,7 +2825,9 @@
|
|||
"ep": "Ep",
|
||||
"ရှိုး": "Show",
|
||||
"တစ်ကိုယ်တော်": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "မှ"
|
||||
},
|
||||
"ne": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2779,7 +2877,9 @@
|
|||
"ep": "Ep",
|
||||
"टिभी सो": "Show",
|
||||
"एकल एल्बम": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "द्वारा"
|
||||
},
|
||||
"nl": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2834,7 +2934,9 @@
|
|||
"ep": "Ep",
|
||||
"aflevering": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "door",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"no": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2898,7 +3000,9 @@
|
|||
"ep": "Ep",
|
||||
"hørespill": "Show",
|
||||
"singel": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "av",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"or": {
|
||||
"equivalent": [],
|
||||
|
|
@ -2959,7 +3063,9 @@
|
|||
"ep": "Ep",
|
||||
"ଶୋ": "Show",
|
||||
"ସିଙ୍ଗଲ୍": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "ଦ୍ଵାରା"
|
||||
},
|
||||
"pa": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3011,7 +3117,9 @@
|
|||
"ep": "Ep",
|
||||
"ਸ਼ੋਅ": "Show",
|
||||
"ਸਿੰਗਲ": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "ਵੱਲੋਂ"
|
||||
},
|
||||
"pl": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3084,7 +3192,9 @@
|
|||
"ep": "Ep",
|
||||
"słuchowisko": "Show",
|
||||
"singiel": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "autor:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"pt": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3144,7 +3254,9 @@
|
|||
"ep": "Ep",
|
||||
"programa": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "por",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"pt-PT": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3188,7 +3300,9 @@
|
|||
"ep": "Ep",
|
||||
"programa": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "de",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"ro": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3248,7 +3362,9 @@
|
|||
"ep": "Ep",
|
||||
"emisiune": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "de",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"ru": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3319,7 +3435,9 @@
|
|||
"ep": "Ep",
|
||||
"аудиошоу": "Show",
|
||||
"сингл": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"si": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3369,7 +3487,9 @@
|
|||
"දීවා": "Ep",
|
||||
"සංදර්ශනය": "Show",
|
||||
"තනි": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "විසින්"
|
||||
},
|
||||
"sk": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3428,7 +3548,9 @@
|
|||
"ep": "Ep",
|
||||
"relácia": "Show",
|
||||
"singel": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "Autori:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"sl": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3505,7 +3627,9 @@
|
|||
"ep": "Ep",
|
||||
"oddaja": "Show",
|
||||
"singel": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "kanal",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"sq": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3558,7 +3682,9 @@
|
|||
"ep": "Ep",
|
||||
"shfaq": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "nga",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"sr": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3608,7 +3734,9 @@
|
|||
"ep": "Ep",
|
||||
"серија": "Show",
|
||||
"сингл": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "са канала",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"sr-Latn": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3658,7 +3786,9 @@
|
|||
"ep": "Ep",
|
||||
"serija": "Show",
|
||||
"singl": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "sa kanala",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"sv": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3717,7 +3847,9 @@
|
|||
"ep": "Ep",
|
||||
"ljuddrama": "Show",
|
||||
"singel": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "från",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"sw": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3767,7 +3899,9 @@
|
|||
"ep": "Ep",
|
||||
"kipindi": "Show",
|
||||
"singo": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "kutoka",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"ta": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3830,7 +3964,9 @@
|
|||
"ep": "Ep",
|
||||
"ஆடியோ ஷோ": "Show",
|
||||
"சிங்கிள்": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "வழங்கியவர்:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"te": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3891,7 +4027,9 @@
|
|||
"ep": "Ep",
|
||||
"చూపించు": "Show",
|
||||
"సింగిల్": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "ఛానెల్ ద్వారా"
|
||||
},
|
||||
"th": {
|
||||
"equivalent": [],
|
||||
|
|
@ -3952,7 +4090,9 @@
|
|||
"ep": "Ep",
|
||||
"รายการ": "Show",
|
||||
"ซิงเกิล": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "โดย",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"tr": {
|
||||
"equivalent": [],
|
||||
|
|
@ -4004,7 +4144,9 @@
|
|||
"ep": "Ep",
|
||||
"program": "Show",
|
||||
"single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "",
|
||||
"chan_suffix": "tarafından"
|
||||
},
|
||||
"uk": {
|
||||
"equivalent": [],
|
||||
|
|
@ -4079,7 +4221,9 @@
|
|||
"мініальбом": "Ep",
|
||||
"аудіодрама": "Show",
|
||||
"сингл": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "власник:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"ur": {
|
||||
"equivalent": [],
|
||||
|
|
@ -4136,7 +4280,9 @@
|
|||
"ep": "Ep",
|
||||
"شو": "Show",
|
||||
"واحد": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "منجانب",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"uz": {
|
||||
"equivalent": [],
|
||||
|
|
@ -4184,7 +4330,9 @@
|
|||
"ep": "Ep",
|
||||
"shou": "Show",
|
||||
"singl": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "muallif:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"vi": {
|
||||
"equivalent": [],
|
||||
|
|
@ -4217,7 +4365,9 @@
|
|||
"đĩa nhạc mở rộng (ep)": "Ep",
|
||||
"chương trình": "Show",
|
||||
"đĩa đơn": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "của",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"zh-CN": {
|
||||
"equivalent": [],
|
||||
|
|
@ -4251,7 +4401,9 @@
|
|||
"迷你专辑": "Ep",
|
||||
"广播剧": "Show",
|
||||
"单曲": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "创建者:",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"zh-HK": {
|
||||
"equivalent": [],
|
||||
|
|
@ -4284,7 +4436,9 @@
|
|||
"ep": "Ep",
|
||||
"節目": "Show",
|
||||
"單曲": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "來自",
|
||||
"chan_suffix": ""
|
||||
},
|
||||
"zh-TW": {
|
||||
"equivalent": [],
|
||||
|
|
@ -4316,7 +4470,9 @@
|
|||
"ep": "Ep",
|
||||
"節目": "Show",
|
||||
"單曲": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "由",
|
||||
"chan_suffix": "建立"
|
||||
},
|
||||
"zu": {
|
||||
"equivalent": [],
|
||||
|
|
@ -4380,6 +4536,8 @@
|
|||
"i-ep": "Ep",
|
||||
"bonisa": "Show",
|
||||
"i-single": "Single"
|
||||
}
|
||||
},
|
||||
"chan_prefix": "ka-",
|
||||
"chan_suffix": ""
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4986
testfiles/playlist/playlist_20241011_pageheader.json
Normal file
4986
testfiles/playlist/playlist_20241011_pageheader.json
Normal file
File diff suppressed because it is too large
Load diff
Reference in a new issue