mirror of
https://codeberg.org/simonrepp/hyper8.git
synced 2026-08-14 13:45:27 +02:00
Support enabling/disabling download buttons for videos (disabled by default)
This commit is contained in:
@@ -37,12 +37,13 @@ Content in a collection currently appears in the following order on the built si
|
||||
|
||||
## The collection.eno manifest
|
||||
|
||||
> All options at a glance: [description](#description), [embedding](#embedding), [link](#link), [offline](#offline), [title](#title), [unlisted](#unlisted), [video_order](#video_order)
|
||||
> All options at a glance: [description](#description), [download](#download), [embedding](#embedding), [link](#link), [offline](#offline), [title](#title), [unlisted](#unlisted), [video_order](#video_order)
|
||||
|
||||
Manifest for tagging and configuring a collection.
|
||||
|
||||
```eno
|
||||
title: Soothing clips
|
||||
download: enabled
|
||||
offline
|
||||
video_order: sort_number_desc
|
||||
unlisted
|
||||
@@ -70,6 +71,25 @@ additionally use markdown-style inline links such as `[Example](https://example.
|
||||
the text of a link (Note that no other markdown syntax is supported inside `description` though).
|
||||
Any number of empty lines in the description field separates paragraphs in the text.
|
||||
|
||||
## <a name="download"></a> `download`
|
||||
|
||||
This opt-in setting enables download buttons on video pages, openly inviting
|
||||
and allowing visitors to conveniently choose and download a specific version
|
||||
of a video to their computer.
|
||||
|
||||
```eno
|
||||
download: enabled
|
||||
```
|
||||
|
||||
Note that the absence of a download button (i.e. the default setting of this
|
||||
option) does not mean that it is not possible to download your videos - this
|
||||
is always easily possible for anyone with some technical knowledge. Enabling
|
||||
download buttons however is an invitation to your visitors that you want them
|
||||
to be easily able to do so, and inversely, not enabling it - as on every
|
||||
other website - simply implies that you do not openly invite downloads, and
|
||||
visitors will have to research or inquire about your video's license before
|
||||
making any use of it beyond watching it on your site.
|
||||
|
||||
## <a name="embedding"></a> `embedding`
|
||||
|
||||
This allows visitors/you to copy embed codes (html) that they/you can use to
|
||||
|
||||
@@ -30,7 +30,7 @@ sequential playback.
|
||||
|
||||
## The playlist.eno manifest
|
||||
|
||||
> All options at a glance: [banner](#banner), [description](#description), [embedding](#embedding), [link](#link), [offline](#offline), [order](#order), [title](#title), [unlisted](#unlisted)
|
||||
> All options at a glance: [banner](#banner), [description](#description), [download](#download), [embedding](#embedding), [link](#link), [offline](#offline), [order](#order), [title](#title), [unlisted](#unlisted)
|
||||
|
||||
Manifest for tagging and configuring a playlist.
|
||||
|
||||
@@ -39,6 +39,7 @@ banner:
|
||||
description = Colorful flags in the wind
|
||||
file = my_poster.jpg
|
||||
|
||||
download: enabled
|
||||
embedding: enabled
|
||||
offline
|
||||
order: release_date_asc
|
||||
@@ -78,6 +79,25 @@ additionally use markdown-style inline links such as `[Example](https://example.
|
||||
the text of a link (Note that no other markdown syntax is supported inside `description` though).
|
||||
Any number of empty lines in the description field separates paragraphs in the text.
|
||||
|
||||
## <a name="download"></a> `download`
|
||||
|
||||
This opt-in setting enables download buttons on video pages, openly inviting
|
||||
and allowing visitors to conveniently choose and download a specific version
|
||||
of a video to their computer.
|
||||
|
||||
```eno
|
||||
download: enabled
|
||||
```
|
||||
|
||||
Note that the absence of a download button (i.e. the default setting of this
|
||||
option) does not mean that it is not possible to download your videos - this
|
||||
is always easily possible for anyone with some technical knowledge. Enabling
|
||||
download buttons however is an invitation to your visitors that you want them
|
||||
to be easily able to do so, and inversely, not enabling it - as on every
|
||||
other website - simply implies that you do not openly invite downloads, and
|
||||
visitors will have to research or inquire about your video's license before
|
||||
making any use of it beyond watching it on your site.
|
||||
|
||||
## <a name="embedding"></a> `embedding`
|
||||
|
||||
This allows visitors/you to copy embed codes (html) that they/you can use to
|
||||
|
||||
@@ -39,7 +39,7 @@ subtitles while `fr.vtt` would indicate french subtitles.
|
||||
|
||||
## The video.eno manifest
|
||||
|
||||
> All options at a glance: [description](#description), [embedding](#embedding), [link](#link), [offline](#offline), [poster](#poster), [release_date](#release_date), [sort_number](#sort_number), [title](#title), [unlisted](#unlisted)
|
||||
> All options at a glance: [description](#description), [download](#download), [embedding](#embedding), [link](#link), [offline](#offline), [poster](#poster), [release_date](#release_date), [sort_number](#sort_number), [title](#title), [unlisted](#unlisted)
|
||||
|
||||
Manifest for tagging and configuring a video, which can be placed inside the
|
||||
video directory. A video directory can be identified as a video directory
|
||||
@@ -51,6 +51,7 @@ poster:
|
||||
description = Confused looking people in an office
|
||||
file = episode_1.jpg
|
||||
|
||||
download: enabled
|
||||
offline
|
||||
release_date: 2024-02-12
|
||||
sort_number: 1
|
||||
@@ -79,6 +80,25 @@ additionally use markdown-style inline links such as `[Example](https://example.
|
||||
the text of a link (Note that no other markdown syntax is supported inside `description` though).
|
||||
Any number of empty lines in the description field separates paragraphs in the text.
|
||||
|
||||
## <a name="download"></a> `download`
|
||||
|
||||
This opt-in setting enables a download button on the video page, openly inviting
|
||||
and allowing visitors to conveniently choose and download a specific version
|
||||
of the video to their computer.
|
||||
|
||||
```eno
|
||||
download: enabled
|
||||
```
|
||||
|
||||
Note that the absence of a download button (i.e. the default setting of this
|
||||
option) does not mean that it is not possible to download your video - this
|
||||
is always easily possible for anyone with some technical knowledge. Enabling
|
||||
the download button however is an invitation to your visitors that you want them
|
||||
to be easily able to do so, and inversely, not enabling it - as on every
|
||||
other website - simply implies that you do not openly invite downloading, and
|
||||
visitors will have to research or inquire about your video's license before
|
||||
making any use of it beyond watching it on your site.
|
||||
|
||||
## <a name="embedding"></a> `embedding`
|
||||
|
||||
This allows visitors/you to copy embed codes (html) that they/you can use to
|
||||
|
||||
+12
-4
@@ -35,16 +35,17 @@ use video::video_html;
|
||||
|
||||
/// Some options need to be evaluated in the context of the entire site tree
|
||||
/// before they are applied at the individual node level. This includes
|
||||
/// embedding, where the option is inherited down the tree but potentially
|
||||
/// overriden at the node level, as well as the unlisted option, which
|
||||
/// unconditionally applies to all descendants of a site tree branch whose
|
||||
/// (in)direct parent node is marked as unlisted.
|
||||
/// embedding and download, where the option is inherited down the tree but
|
||||
/// potentially overriden at the node level, as well as the unlisted option,
|
||||
/// which unconditionally applies to all descendants of a site tree branch
|
||||
/// whose(in)direct parent node is marked as unlisted.
|
||||
///
|
||||
/// MergeOptions represents these options, and at the node level we only
|
||||
/// consider the options on this struct (after we have merged in the options
|
||||
/// from the node level beforehand of course).
|
||||
#[derive(Clone)]
|
||||
struct MergedOptions {
|
||||
pub download: bool,
|
||||
pub embedding: bool,
|
||||
pub unlisted: bool
|
||||
}
|
||||
@@ -52,36 +53,43 @@ struct MergedOptions {
|
||||
impl MergedOptions {
|
||||
pub fn default() -> MergedOptions {
|
||||
MergedOptions {
|
||||
download: false,
|
||||
embedding: false,
|
||||
unlisted: false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn merge_collection_options(&self, collection: &Collection) -> MergedOptions {
|
||||
let download = collection.download.unwrap_or(self.download);
|
||||
let embedding = collection.embedding.unwrap_or(self.embedding);
|
||||
let unlisted = self.unlisted || collection.unlisted;
|
||||
|
||||
MergedOptions {
|
||||
download,
|
||||
embedding,
|
||||
unlisted
|
||||
}
|
||||
}
|
||||
|
||||
pub fn merge_playlist_options(&self, playlist: &Playlist) -> MergedOptions {
|
||||
let download = playlist.download.unwrap_or(self.download);
|
||||
let embedding = playlist.embedding.unwrap_or(self.embedding);
|
||||
let unlisted = self.unlisted || playlist.unlisted;
|
||||
|
||||
MergedOptions {
|
||||
download,
|
||||
embedding,
|
||||
unlisted
|
||||
}
|
||||
}
|
||||
|
||||
pub fn merge_video_options(&self, video: &Video) -> MergedOptions {
|
||||
let download = video.download.unwrap_or(self.download);
|
||||
let embedding = video.embedding.unwrap_or(self.embedding);
|
||||
let unlisted = self.unlisted || video.unlisted;
|
||||
|
||||
MergedOptions {
|
||||
download,
|
||||
embedding,
|
||||
unlisted
|
||||
}
|
||||
|
||||
+4
-1
@@ -38,7 +38,10 @@ pub fn video_html(
|
||||
};
|
||||
let e_title = html_escape_outside_attribute(title);
|
||||
|
||||
let r_downloads = downloads(site, video);
|
||||
let r_downloads = match merged_options.download {
|
||||
true => downloads(site, video),
|
||||
false => String::new()
|
||||
};
|
||||
|
||||
let next_video = if video.unlisted {
|
||||
None
|
||||
|
||||
@@ -32,6 +32,7 @@ use crate::util::checked_remove_dir_all;
|
||||
const COLLECTION_OPTIONS: &[&str] = &[
|
||||
"banner",
|
||||
"description",
|
||||
"download",
|
||||
"embedding",
|
||||
"link",
|
||||
"offline",
|
||||
@@ -44,6 +45,7 @@ const COLLECTION_OPTIONS: &[&str] = &[
|
||||
pub struct Collection {
|
||||
pub banner: Option<Banner>,
|
||||
pub description: Option<String>,
|
||||
pub download: Option<bool>,
|
||||
pub embedding: Option<bool>,
|
||||
pub errors: Vec<String>,
|
||||
pub links: Vec<Link>,
|
||||
@@ -141,6 +143,33 @@ impl Collection {
|
||||
self.errors.push(error);
|
||||
}
|
||||
}
|
||||
"download" => 'download: {
|
||||
if let Ok(field) = element.as_field() {
|
||||
if let Ok(result) = field.value() {
|
||||
if let Some(value) = result {
|
||||
match value {
|
||||
"enabled" => {
|
||||
self.download = Some(true);
|
||||
}
|
||||
"disabled" => {
|
||||
self.download = Some(false);
|
||||
}
|
||||
other => {
|
||||
let message = format!("The download option only supports the value 'enabled' or 'disabled'. The given value '{other}' was not recognized.");
|
||||
let error = element_error(element, manifest_path, &message);
|
||||
self.errors.push(error);
|
||||
}
|
||||
}
|
||||
|
||||
break 'download;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let message = "download needs to be provided as a field with the value 'enabled' or 'disabled', e.g.: 'download: enabled'";
|
||||
let error = element_error(element, manifest_path, message);
|
||||
self.errors.push(error);
|
||||
}
|
||||
"embedding" => 'embedding: {
|
||||
if let Ok(field) = element.as_field() {
|
||||
if let Ok(result) = field.value() {
|
||||
@@ -598,6 +627,7 @@ impl Collection {
|
||||
Collection {
|
||||
banner: None,
|
||||
description: None,
|
||||
download: None,
|
||||
embedding: None,
|
||||
errors: Vec::new(),
|
||||
links: Vec::new(),
|
||||
@@ -1003,6 +1033,10 @@ impl Collection {
|
||||
eno.push_str(&format!("file = {}\n", banner.file_name));
|
||||
}
|
||||
|
||||
if let Some(download) = self.download {
|
||||
eno.push_str(&format!("download: {}\n", if download { "enabled" } else { "disabled" }));
|
||||
}
|
||||
|
||||
if let Some(embedding) = self.embedding {
|
||||
eno.push_str(&format!("embedding: {}\n", if embedding { "enabled" } else { "disabled" }));
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ pub enum CollectionFormFeedback<'a> {
|
||||
Site(endpoints::site::SiteFormFeedback),
|
||||
Update {
|
||||
description: &'a str,
|
||||
download: Option<bool>,
|
||||
embedding: Option<bool>,
|
||||
offline: bool,
|
||||
title: Field,
|
||||
@@ -145,10 +146,16 @@ pub fn edit_page(
|
||||
let mut input_offline = Checkbox::new("offline", translations.offline);
|
||||
let mut input_title = Input::text("title", translations.title);
|
||||
let mut input_unlisted = Checkbox::new("unlisted", translations.unlisted);
|
||||
let mut select_download = Select::new("download", translations.download);
|
||||
let mut select_embedding = Select::new("embedding", translations.embedding);
|
||||
let mut select_video_order = Select::new("video_order", translations.video_order);
|
||||
let mut textarea_description = Textarea::markdown_subset(language, "description", translations.description);
|
||||
|
||||
// TODO: Dynamically determine and additionally display what the default or inherited value is here.
|
||||
select_download.option("", translations.inherit);
|
||||
select_download.option("enabled", translations.enabled);
|
||||
select_download.option("disabled", translations.disabled);
|
||||
|
||||
// TODO: Dynamically determine and additionally display what the default or inherited value is here.
|
||||
select_embedding.option("", translations.inherit);
|
||||
select_embedding.option("enabled", translations.enabled);
|
||||
@@ -167,12 +174,19 @@ pub fn edit_page(
|
||||
|
||||
let feedback_update = if let CollectionFormFeedback::Update {
|
||||
description,
|
||||
download,
|
||||
embedding,
|
||||
offline,
|
||||
title,
|
||||
unlisted,
|
||||
video_order
|
||||
} = &form_feedback {
|
||||
let download_value = match download {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
None => ""
|
||||
};
|
||||
|
||||
let embedding_value = match embedding {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
@@ -182,12 +196,19 @@ pub fn edit_page(
|
||||
input_offline.checked(*offline);
|
||||
input_title.validated_value(title);
|
||||
input_unlisted.checked(*unlisted);
|
||||
select_download.selected(download_value);
|
||||
select_embedding.selected(embedding_value);
|
||||
select_video_order.selected(video_order);
|
||||
textarea_description.value(description);
|
||||
|
||||
format!(r#"<span class="feedback">{t_not_saved}</span>"#)
|
||||
} else {
|
||||
let download = match collection.download {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
None => ""
|
||||
};
|
||||
|
||||
let embedding = match collection.embedding {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
@@ -197,6 +218,7 @@ pub fn edit_page(
|
||||
input_offline.checked(collection.offline);
|
||||
input_title.value_option(&collection.title);
|
||||
input_unlisted.checked(collection.unlisted);
|
||||
select_download.selected(download);
|
||||
select_embedding.selected(embedding);
|
||||
select_video_order.selected(collection.video_order.key());
|
||||
textarea_description.value_option(&collection.description);
|
||||
@@ -432,7 +454,10 @@ pub fn edit_page(
|
||||
{input_title}
|
||||
{textarea_description}
|
||||
{select_video_order}
|
||||
{select_embedding}
|
||||
<div class="form_split even">
|
||||
{select_download}
|
||||
{select_embedding}
|
||||
</div>
|
||||
{input_offline}
|
||||
{input_unlisted_conditionally_hidden}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ use super::CollectionFormFeedback;
|
||||
#[derive(Deserialize)]
|
||||
pub struct UpdateForm {
|
||||
description: String,
|
||||
download: String,
|
||||
embedding: String,
|
||||
offline: Option<String>,
|
||||
title: String,
|
||||
@@ -32,6 +33,12 @@ pub async fn update(
|
||||
|
||||
let description_trimmed = form.description.trim();
|
||||
|
||||
let download = match form.download.as_str() {
|
||||
"disabled" => Some(false),
|
||||
"enabled" => Some(true),
|
||||
_ => None
|
||||
};
|
||||
|
||||
let embedding = match form.embedding.as_str() {
|
||||
"disabled" => Some(false),
|
||||
"enabled" => Some(true),
|
||||
@@ -47,6 +54,7 @@ pub async fn update(
|
||||
if true {
|
||||
let mutation = |collection_mut: &mut Collection| {
|
||||
collection_mut.description = if description_trimmed.is_empty() { None } else { Some(description_trimmed.to_owned()) };
|
||||
collection_mut.download = download;
|
||||
collection_mut.embedding = embedding;
|
||||
collection_mut.offline = offline;
|
||||
collection_mut.title = if title_trimmed.is_empty() { None } else { Some(title_trimmed.to_owned()) };
|
||||
@@ -72,6 +80,7 @@ pub async fn update(
|
||||
|
||||
let form_feedback = CollectionFormFeedback::Update {
|
||||
description: description_trimmed,
|
||||
download,
|
||||
embedding,
|
||||
offline,
|
||||
title: Field::valid(title_trimmed),
|
||||
|
||||
@@ -53,6 +53,7 @@ pub enum PlaylistFormFeedback<'a> {
|
||||
Site(endpoints::site::SiteFormFeedback),
|
||||
Update {
|
||||
description: &'a str,
|
||||
download: Option<bool>,
|
||||
embedding: Option<bool>,
|
||||
offline: bool,
|
||||
order: &'a str,
|
||||
@@ -135,10 +136,16 @@ pub fn edit_page(
|
||||
let mut input_offline = Checkbox::new("offline", translations.offline);
|
||||
let mut input_title = Input::text("title", translations.title);
|
||||
let mut input_unlisted = Checkbox::new("unlisted", translations.unlisted);
|
||||
let mut select_download = Select::new("download", translations.download);
|
||||
let mut select_embedding = Select::new("embedding", translations.embedding);
|
||||
let mut select_order = Select::new("order", translations.order);
|
||||
let mut textarea_description = Textarea::markdown_subset(language, "description", translations.description);
|
||||
|
||||
// TODO: Dynamically determine and additionally display what the default or inherited value is here.
|
||||
select_download.option("", translations.inherit);
|
||||
select_download.option("enabled", translations.enabled);
|
||||
select_download.option("disabled", translations.disabled);
|
||||
|
||||
// TODO: Dynamically determine and additionally display what the default or inherited value is here.
|
||||
select_embedding.option("", translations.inherit);
|
||||
select_embedding.option("enabled", translations.enabled);
|
||||
@@ -156,12 +163,19 @@ pub fn edit_page(
|
||||
|
||||
let feedback_update = if let Some(PlaylistFormFeedback::Update {
|
||||
description,
|
||||
download,
|
||||
embedding,
|
||||
offline,
|
||||
order,
|
||||
title,
|
||||
unlisted
|
||||
}) = &form_feedback {
|
||||
let download_value = match download {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
None => ""
|
||||
};
|
||||
|
||||
let embedding_value = match embedding {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
@@ -171,12 +185,19 @@ pub fn edit_page(
|
||||
input_offline.checked(*offline);
|
||||
input_title.validated_value(title);
|
||||
input_unlisted.checked(*unlisted);
|
||||
select_download.selected(download_value);
|
||||
select_embedding.selected(embedding_value);
|
||||
select_order.selected(order);
|
||||
textarea_description.value(description);
|
||||
|
||||
format!(r#"<span class="feedback">{t_not_saved}</span>"#)
|
||||
} else {
|
||||
let download = match playlist.download {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
None => ""
|
||||
};
|
||||
|
||||
let embedding = match playlist.embedding {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
@@ -186,6 +207,7 @@ pub fn edit_page(
|
||||
input_offline.checked(playlist.offline);
|
||||
input_title.value_option(&playlist.title);
|
||||
input_unlisted.checked(playlist.unlisted);
|
||||
select_download.selected(download);
|
||||
select_embedding.selected(embedding);
|
||||
select_order.selected(playlist.order.key());
|
||||
textarea_description.value_option(&playlist.description);
|
||||
@@ -338,7 +360,10 @@ pub fn edit_page(
|
||||
{input_title}
|
||||
{textarea_description}
|
||||
{select_order}
|
||||
{select_embedding}
|
||||
<div class="form_split even">
|
||||
{select_download}
|
||||
{select_embedding}
|
||||
</div>
|
||||
{input_offline}
|
||||
{input_unlisted_conditionally_hidden}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ use super::PlaylistFormFeedback;
|
||||
#[derive(Deserialize)]
|
||||
pub struct PlaylistUpdateForm {
|
||||
description: String,
|
||||
download: String,
|
||||
embedding: String,
|
||||
offline: Option<String>,
|
||||
order: String,
|
||||
@@ -32,6 +33,12 @@ pub async fn update(
|
||||
|
||||
let description_trimmed = form.description.trim();
|
||||
|
||||
let download = match form.download.as_str() {
|
||||
"disabled" => Some(false),
|
||||
"enabled" => Some(true),
|
||||
_ => None
|
||||
};
|
||||
|
||||
let embedding = match form.embedding.as_str() {
|
||||
"disabled" => Some(false),
|
||||
"enabled" => Some(true),
|
||||
@@ -47,6 +54,7 @@ pub async fn update(
|
||||
if true {
|
||||
let mutation = |playlist_mut: &mut Playlist| {
|
||||
playlist_mut.description = if description_trimmed.is_empty() { None } else { Some(description_trimmed.to_owned()) };
|
||||
playlist_mut.download = download;
|
||||
playlist_mut.embedding = embedding;
|
||||
playlist_mut.offline = offline;
|
||||
playlist_mut.order = order;
|
||||
@@ -70,6 +78,7 @@ pub async fn update(
|
||||
|
||||
let form_feedback = PlaylistFormFeedback::Update {
|
||||
description: description_trimmed,
|
||||
download,
|
||||
embedding,
|
||||
offline,
|
||||
order: &form.order,
|
||||
|
||||
@@ -63,6 +63,7 @@ pub enum VideoFormFeedback<'a> {
|
||||
Site(endpoints::site::SiteFormFeedback),
|
||||
Update {
|
||||
description: &'a str,
|
||||
download: Option<bool>,
|
||||
embedding: Option<bool>,
|
||||
offline: bool,
|
||||
release_date: Field,
|
||||
@@ -417,9 +418,15 @@ pub fn edit_page(
|
||||
let mut input_sort_number = Input::number("sort_number", translations.sort_number);
|
||||
let mut input_title = Input::text("title", translations.title);
|
||||
let mut input_unlisted = Checkbox::new("unlisted", translations.unlisted);
|
||||
let mut select_download = Select::new("download", translations.download);
|
||||
let mut select_embedding = Select::new("embedding", translations.embedding);
|
||||
let mut textarea_description = Textarea::markdown_subset(language, "description", translations.description);
|
||||
|
||||
// TODO: Dynamically determine and additionally display what the default or inherited value is here.
|
||||
select_download.option("", translations.inherit);
|
||||
select_download.option("enabled", translations.enabled);
|
||||
select_download.option("disabled", translations.disabled);
|
||||
|
||||
// TODO: Dynamically determine and additionally display what the default or inherited value is here.
|
||||
select_embedding.option("", translations.inherit);
|
||||
select_embedding.option("enabled", translations.enabled);
|
||||
@@ -429,6 +436,7 @@ pub fn edit_page(
|
||||
|
||||
let feedback_update = if let Some(VideoFormFeedback::Update {
|
||||
description,
|
||||
download,
|
||||
embedding,
|
||||
offline,
|
||||
release_date,
|
||||
@@ -436,6 +444,12 @@ pub fn edit_page(
|
||||
title,
|
||||
unlisted
|
||||
}) = &form_feedback {
|
||||
let download_value = match download {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
None => ""
|
||||
};
|
||||
|
||||
let embedding_value = match embedding {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
@@ -447,11 +461,18 @@ pub fn edit_page(
|
||||
input_sort_number.validated_value(sort_number);
|
||||
input_title.validated_value(title);
|
||||
input_unlisted.checked(*unlisted);
|
||||
select_download.selected(download_value);
|
||||
select_embedding.selected(embedding_value);
|
||||
textarea_description.value(description);
|
||||
|
||||
format!(r#"<span class="feedback">{t_not_saved}</span>"#)
|
||||
} else {
|
||||
let download = match video.download {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
None => ""
|
||||
};
|
||||
|
||||
let embedding = match video.embedding {
|
||||
Some(true) => "enabled",
|
||||
Some(false) => "disabled",
|
||||
@@ -465,6 +486,7 @@ pub fn edit_page(
|
||||
input_sort_number.value_option(&sort_number);
|
||||
input_title.value_option(&video.title);
|
||||
input_unlisted.checked(video.unlisted);
|
||||
select_download.selected(download);
|
||||
select_embedding.selected(embedding);
|
||||
textarea_description.value_option(&video.description);
|
||||
|
||||
@@ -573,7 +595,10 @@ pub fn edit_page(
|
||||
{input_release_date}
|
||||
{input_sort_number}
|
||||
</div>
|
||||
{select_embedding}
|
||||
<div class="form_split even">
|
||||
{select_download}
|
||||
{select_embedding}
|
||||
</div>
|
||||
{input_offline}
|
||||
{input_unlisted_conditionally_hidden}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ use super::VideoFormFeedback;
|
||||
#[derive(Deserialize)]
|
||||
pub struct VideoUpdateForm {
|
||||
description: String,
|
||||
download: String,
|
||||
embedding: String,
|
||||
offline: Option<String>,
|
||||
release_date: String,
|
||||
@@ -34,6 +35,12 @@ pub async fn update(
|
||||
|
||||
let description_trimmed = form.description.trim();
|
||||
|
||||
let download = match form.download.as_str() {
|
||||
"disabled" => Some(false),
|
||||
"enabled" => Some(true),
|
||||
_ => None
|
||||
};
|
||||
|
||||
let embedding = match form.embedding.as_str() {
|
||||
"disabled" => Some(false),
|
||||
"enabled" => Some(true),
|
||||
@@ -74,6 +81,7 @@ pub async fn update(
|
||||
|
||||
let form_feedback = VideoFormFeedback::Update {
|
||||
description: description_trimmed,
|
||||
download,
|
||||
embedding,
|
||||
offline,
|
||||
release_date: Field::validated(release_date_trimmed, release_date.and_then(|release_date| release_date.err())),
|
||||
@@ -88,6 +96,7 @@ pub async fn update(
|
||||
} else {
|
||||
let mutation = |video_mut: &mut Video| {
|
||||
video_mut.description = if description_trimmed.is_empty() { None } else { Some(description_trimmed.to_owned()) };
|
||||
video_mut.download = download;
|
||||
video_mut.embedding = embedding;
|
||||
video_mut.offline = offline;
|
||||
video_mut.release_date = release_date.and_then(|release_date| release_date.ok());
|
||||
|
||||
@@ -30,6 +30,7 @@ use crate::util::checked_remove_dir_all;
|
||||
const PLAYLIST_OPTIONS: &[&str] = &[
|
||||
"banner",
|
||||
"description",
|
||||
"download",
|
||||
"embedding",
|
||||
"link",
|
||||
"offline",
|
||||
@@ -42,6 +43,7 @@ const PLAYLIST_OPTIONS: &[&str] = &[
|
||||
pub struct Playlist {
|
||||
pub banner: Option<Banner>,
|
||||
pub description: Option<String>,
|
||||
pub download: Option<bool>,
|
||||
pub embedding: Option<bool>,
|
||||
pub errors: Vec<String>,
|
||||
pub links: Vec<Link>,
|
||||
@@ -146,6 +148,33 @@ impl Playlist {
|
||||
self.errors.push(error);
|
||||
}
|
||||
}
|
||||
"download" => 'download: {
|
||||
if let Ok(field) = element.as_field() {
|
||||
if let Ok(result) = field.value() {
|
||||
if let Some(value) = result {
|
||||
match value {
|
||||
"enabled" => {
|
||||
self.download = Some(true);
|
||||
}
|
||||
"disabled" => {
|
||||
self.download = Some(false);
|
||||
}
|
||||
other => {
|
||||
let message = format!("The download option only supports the value 'enabled' or 'disabled'. The given value '{other}' was not recognized.");
|
||||
let error = element_error(element, manifest_path, &message);
|
||||
self.errors.push(error);
|
||||
}
|
||||
}
|
||||
|
||||
break 'download;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let message = "download needs to be provided as a field with the value 'enabled' or 'disabled', e.g.: 'download: enabled'";
|
||||
let error = element_error(element, manifest_path, message);
|
||||
self.errors.push(error);
|
||||
}
|
||||
"embedding" => 'embedding: {
|
||||
if let Ok(field) = element.as_field() {
|
||||
if let Ok(result) = field.value() {
|
||||
@@ -418,6 +447,7 @@ impl Playlist {
|
||||
Playlist {
|
||||
banner: None,
|
||||
description: None,
|
||||
download: None,
|
||||
embedding: None,
|
||||
errors: Vec::new(),
|
||||
links: Vec::new(),
|
||||
@@ -630,6 +660,10 @@ impl Playlist {
|
||||
eno.push_str(&format!("file = {}\n", banner.file_name));
|
||||
}
|
||||
|
||||
if let Some(download) = self.download {
|
||||
eno.push_str(&format!("download: {}\n", if download { "enabled" } else { "disabled" }));
|
||||
}
|
||||
|
||||
if let Some(embedding) = self.embedding {
|
||||
eno.push_str(&format!("embedding: {}\n", if embedding { "enabled" } else { "disabled" }));
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ use crate::util::{checked_remove_dir_all, hash};
|
||||
|
||||
const VIDEO_OPTIONS: &[&str] = &[
|
||||
"description",
|
||||
"download",
|
||||
"embedding",
|
||||
"link",
|
||||
"offline",
|
||||
@@ -42,6 +43,7 @@ const VIDEO_OPTIONS: &[&str] = &[
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Video {
|
||||
pub description: Option<String>,
|
||||
pub download: Option<bool>,
|
||||
pub embedding: Option<bool>,
|
||||
pub errors: Vec<String>,
|
||||
pub links: Vec<Link>,
|
||||
@@ -122,6 +124,33 @@ impl Video {
|
||||
self.errors.push(error);
|
||||
}
|
||||
}
|
||||
"download" => 'download: {
|
||||
if let Ok(field) = element.as_field() {
|
||||
if let Ok(result) = field.value() {
|
||||
if let Some(value) = result {
|
||||
match value {
|
||||
"enabled" => {
|
||||
self.download = Some(true);
|
||||
}
|
||||
"disabled" => {
|
||||
self.download = Some(false);
|
||||
}
|
||||
other => {
|
||||
let message = format!("The download option only supports the value 'enabled' or 'disabled'. The given value '{other}' was not recognized.");
|
||||
let error = element_error(element, manifest_path, &message);
|
||||
self.errors.push(error);
|
||||
}
|
||||
}
|
||||
|
||||
break 'download;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let message = "download needs to be provided as a field with the value 'enabled' or 'disabled', e.g.: 'download: enabled'";
|
||||
let error = element_error(element, manifest_path, message);
|
||||
self.errors.push(error);
|
||||
}
|
||||
"embedding" => 'embedding: {
|
||||
if let Ok(field) = element.as_field() {
|
||||
if let Ok(result) = field.value() {
|
||||
@@ -570,6 +599,7 @@ impl Video {
|
||||
pub fn new(path: String) -> Video {
|
||||
Video {
|
||||
description: None,
|
||||
download: None,
|
||||
embedding: None,
|
||||
errors: Vec::new(),
|
||||
links: Vec::new(),
|
||||
@@ -725,6 +755,10 @@ impl Video {
|
||||
eno.push_str(&link.to_eno());
|
||||
}
|
||||
|
||||
if let Some(download) = self.download {
|
||||
eno.push_str(&format!("download: {}\n", if download { "enabled" } else { "disabled" }));
|
||||
}
|
||||
|
||||
if let Some(embedding) = self.embedding {
|
||||
eno.push_str(&format!("embedding: {}\n", if embedding { "enabled" } else { "disabled" }));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user