add media links like struct to weights cover images

This commit is contained in:
Brandon Thomas committed 2024-09-18 23:30:32 -04:00
1 parent 5c5fd10d60
commit c4e4d8e12b
14 files changed
+162 -36

No files matched your search

@@ -0,0 +1,84 @@
use crate::http_server::common_responses::media_links::{MediaDomain, MediaLinks};
use buckets::public::media_files::bucket_file_path::MediaFileBucketPath;
use url::Url;
use utoipa::ToSchema;
// TODO(bt,2024-09-18): Consolidate thumbnail builder code and vars
// TODO(bt,2024-09-05): Worth reducing the quality at all?
const QUALITY : u8 = 95;
/// Cover image links can only be jpg, png, etc. No videos.
#[derive(Clone, Serialize, ToSchema)]
pub struct CoverImageLinks {
/// Primary link to the cover image via the CDN.
pub cdn_url: Url,
/// Template to construct thumbnail URLs.
/// Replace the string `{WIDTH}` with the desired width.
/// Only relevant for image media files. (Video media files instead have
/// video previews, which, in turn, have their own thumbnail templates.)
pub thumbnail_template: String,
}
impl CoverImageLinks {
pub fn from_media_path(
domain: MediaDomain,
bucket_path: &MediaFileBucketPath,
) -> Option<Self> {
let rooted_path = bucket_path.get_full_object_path_str();
Self::from_rooted_path(domain, rooted_path)
}
pub fn from_maybe_media_path(
domain: MediaDomain,
bucket_path: Option<&MediaFileBucketPath>,
) -> Option<Self> {
match bucket_path {
None => None,
Some(bucket_path) => Self::from_media_path(domain, bucket_path),
}
}
pub fn from_parts(
domain: MediaDomain,
maybe_cover_image_public_bucket_path: Option<&str>,
maybe_cover_image_public_bucket_prefix: Option<&str>,
maybe_cover_image_public_bucket_extension: Option<&str>,
) -> Option<Self> {
let bucket_path= match maybe_cover_image_public_bucket_path {
None => return None,
Some(path) => path,
};
let bucket_path = MediaFileBucketPath::from_object_hash(
bucket_path,
maybe_cover_image_public_bucket_prefix,
maybe_cover_image_public_bucket_extension
);
Self::from_media_path(domain, &bucket_path)
}
pub fn from_rooted_path(
domain: MediaDomain,
rooted_path: &str,
) -> Option<Self> {
if !rooted_path.ends_with(".jpg")
&& !rooted_path.ends_with(".png")
&& !rooted_path.ends_with(".gif") {
return None;
}
let mut cdn_url = domain.new_cdn_url();
cdn_url.set_path(rooted_path);
Some(Self {
cdn_url,
thumbnail_template: thumbnail_template(domain, rooted_path),
})
}
}
fn thumbnail_template(media_domain: MediaDomain, rooted_path: &str) -> String {
let host = media_domain.cdn_url_str();
format!("{host}/cdn-cgi/image/width={{WIDTH}},quality={QUALITY}{rooted_path}")
}
@@ -0,0 +1 @@
pub mod cover_image_links;
@@ -54,6 +54,7 @@ pub struct MediaLinks {
/// Video preview images (still and animated gif) for mp4 video files.
/// These are only set for video media files.
/// These are not set for "cover images" that are gif or webms, but rather video files.
pub maybe_video_previews: Option<VideoPreviews>,
}
@@ -1,3 +1,4 @@
pub mod media;
pub mod media_file_cover_image_details;
pub mod media_file_origin_details;
pub mod media_file_social_meta_lite;
@@ -1,24 +1,30 @@
use url::Url;
use utoipa::ToSchema;
use buckets::public::media_files::bucket_file_path::MediaFileBucketPath;
use tokens::tokens::model_weights::ModelWeightToken;
use crate::http_server::common_responses::media::cover_image_links::CoverImageLinks;
use crate::http_server::common_responses::media_links::MediaDomain;
use crate::http_server::web_utils::bucket_urls::bucket_url_from_media_path::bucket_url_from_media_path;
use crate::util::placeholder_images::cover_images::default_cover_image_color_from_token::default_cover_image_color_from_token;
use crate::util::placeholder_images::cover_images::default_cover_image_from_token::default_cover_image_from_token;
use buckets::public::media_files::bucket_file_path::MediaFileBucketPath;
use tokens::tokens::model_weights::ModelWeightToken;
/// Everything we need to create a cover image.
/// Cover images are small descriptive images that can be set for any model.
/// If a cover image is set, this is the path to the asset.
#[derive(Clone, Serialize, ToSchema)]
pub struct WeightsCoverImageDetails {
/// If a cover image is set, this is the path to the asset.
#[deprecated(note="This field doesn't point to the full URL. Use maybe_cover_image_public_bucket_url instead.")]
/// DEPRECATED. If a cover image is set, this is the path to the asset.
#[deprecated(note="Deprecated. Use `maybe_cdn_url` and `maybe_thumbnail_template` instead.")]
pub maybe_cover_image_public_bucket_path: Option<String>,
/// If a cover image is set, this is the URL to the asset.
/// DEPRECATED. If a cover image is set, this is the URL to the asset.
#[deprecated(note="Deprecated. Use `maybe_cdn_url` and `maybe_thumbnail_template` instead.")]
pub maybe_cover_image_public_bucket_url: Option<Url>,
/// Links to the cover image (CDN direct link, thumbnail template)
pub maybe_links: Option<CoverImageLinks>,
/// For items without a cover image, we can use one of our own.
pub default_cover: WeightsDefaultCoverInfo,
}
@@ -35,6 +41,7 @@ pub struct WeightsDefaultCoverInfo {
impl WeightsCoverImageDetails {
pub fn from_optional_db_fields(
domain: MediaDomain,
model_weight_token: &ModelWeightToken,
maybe_cover_image_public_bucket_path: Option<&str>,
maybe_cover_image_public_bucket_prefix: Option<&str>,
@@ -61,9 +68,13 @@ impl WeightsCoverImageDetails {
let image_index = default_cover_image_from_token(model_weight_token);
let maybe_links = CoverImageLinks::from_maybe_media_path(
domain, maybe_bucket_path.as_ref());
Self {
maybe_cover_image_public_bucket_path,
maybe_cover_image_public_bucket_url,
maybe_links,
default_cover: WeightsDefaultCoverInfo::from_token(model_weight_token),
}
}
@@ -80,19 +91,21 @@ impl WeightsDefaultCoverInfo {
#[cfg(test)]
mod tests {
use url::Url;
use tokens::tokens::model_weights::ModelWeightToken;
use crate::http_server::common_responses::media_links::MediaDomain;
use crate::http_server::common_responses::weights_cover_image_details::WeightsCoverImageDetails;
use tokens::tokens::model_weights::ModelWeightToken;
use url::Url;
#[test]
fn test_from_optional_db_fields() {
let domain = MediaDomain::Storyteller;
let token = ModelWeightToken::new_from_str("weight_token");
let maybe_public_bucket_hash = Some("bucket_hash");
let maybe_prefix = Some("image_");
let maybe_extension= Some(".png");
let cover_image = WeightsCoverImageDetails::from_optional_db_fields(
domain,
&token,
maybe_public_bucket_hash,
maybe_prefix,
@@ -6,14 +6,21 @@
use std::fmt;
use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::{Path, Query};
use actix_web::{web, HttpRequest, HttpResponse};
use chrono::{DateTime, Utc};
use log::warn;
use utoipa::{IntoParams, ToSchema};
use crate::http_server::common_responses::media_links::MediaLinks;
use crate::http_server::common_responses::pagination_page::PaginationPage;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::state::server_state::ServerState;
use buckets::public::media_files::bucket_file_path::MediaFileBucketPath;
use enums::by_table::media_files::media_file_type::MediaFileType;
use enums::by_table::model_weights::weights_category::WeightsCategory;
@@ -22,13 +29,6 @@ use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEnti
use enums_public::by_table::model_weights::public_weights_types::PublicWeightsType;
use mysql_queries::queries::users::user_bookmarks::list_user_bookmarks::{list_user_bookmarks_by_maybe_entity_type, ListUserBookmarksForUserArgs};
use tokens::tokens::user_bookmarks::UserBookmarkToken;
use crate::http_server::common_responses::media_links::MediaLinks;
use crate::http_server::common_responses::pagination_page::PaginationPage;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::state::server_state::ServerState;
#[derive(Deserialize, ToSchema)]
pub struct ListUserBookmarksPathInfo {
@@ -1,10 +1,10 @@
use std::fmt;
use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::Path;
use actix_web::{web, HttpRequest, HttpResponse};
use chrono::{DateTime, Utc};
use log::warn;
use utoipa::ToSchema;
@@ -21,6 +21,7 @@ use tokens::tokens::model_weights::ModelWeightToken;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::common_responses::weights_cover_image_details::WeightsCoverImageDetails;
use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain;
use crate::state::server_state::ServerState;
use crate::util::title_to_url_slug::title_to_url_slug;
@@ -171,7 +172,10 @@ pub async fn get_weight_handler(
}
}
let media_domain = get_media_domain(&http_request);
let cover_image_details = WeightsCoverImageDetails::from_optional_db_fields(
media_domain,
&weight.token,
weight.maybe_cover_image_public_bucket_hash.as_deref(),
weight.maybe_cover_image_public_bucket_prefix.as_deref(),
@@ -229,4 +233,4 @@ pub async fn get_weight_handler(
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
}
@@ -1,8 +1,8 @@
use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::{web, HttpRequest, HttpResponse};
use chrono::{DateTime, Utc};
use log::warn;
use rand::Rng;
@@ -23,6 +23,7 @@ use crate::http_server::common_responses::pagination_cursors::PaginationCursors;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::common_responses::weights_cover_image_details::WeightsCoverImageDetails;
use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain;
use crate::state::server_state::ServerState;
use crate::util::title_to_url_slug::title_to_url_slug;
@@ -215,12 +216,15 @@ pub async fn list_available_weights_handler(
let random_float = rng.gen_range(0.0..1.0);
let random_bool = random_float >= 0.5;
let media_domain = get_media_domain(&http_request);
// generate parse a response
let response = ListAvailableWeightsSuccessResponse {
success: true,
results: weights_page.weights.into_iter()
.map(|weight| {
let cover_image_details = WeightsCoverImageDetails::from_optional_db_fields(
media_domain,
&weight.token,
weight.maybe_cover_image_public_bucket_hash.as_deref(),
weight.maybe_cover_image_public_bucket_prefix.as_deref(),
@@ -1,9 +1,9 @@
use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::Query;
use actix_web::{web, HttpRequest, HttpResponse};
use chrono::{DateTime, Utc};
use log::{debug, error, warn};
use r2d2_redis::redis::Commands;
@@ -22,6 +22,7 @@ use tokens::tokens::model_weights::ModelWeightToken;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::common_responses::weights_cover_image_details::WeightsCoverImageDetails;
use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain;
use crate::http_server::endpoints::media_files::helpers::get_scoped_media_classes::get_scoped_media_classes;
use crate::http_server::endpoints::media_files::list::list_featured_media_files_handler::ListFeaturedMediaFilesError;
use crate::http_server::endpoints::media_files::list::list_media_files_handler::{ListMediaFilesError, ListMediaFilesQueryParams};
@@ -223,11 +224,14 @@ pub async fn list_featured_weights_handler(
None
};
let media_domain = get_media_domain(&http_request);
let response = ListFeaturedWeightsSuccessResponse {
success: true,
results: results_page.records.into_iter()
.map(|w| {
let cover_image_details = WeightsCoverImageDetails::from_optional_db_fields(
media_domain,
&w.token,
w.maybe_cover_image_public_bucket_hash.as_deref(),
w.maybe_cover_image_public_bucket_prefix.as_deref(),
@@ -1,8 +1,8 @@
use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::{web, HttpRequest, HttpResponse};
use chrono::{DateTime, Utc};
use log::{debug, error, warn};
use r2d2_redis::redis::Commands;
@@ -18,6 +18,7 @@ use tokens::tokens::model_weights::ModelWeightToken;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::common_responses::weights_cover_image_details::WeightsCoverImageDetails;
use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain;
use crate::state::server_state::ServerState;
use crate::util::title_to_url_slug::title_to_url_slug;
@@ -138,11 +139,14 @@ pub async fn list_pinned_weights_handler(
};
}
let media_domain = get_media_domain(&http_request);
let response = ListPinnedWeightsSuccessResponse {
success: true,
results: weights.into_iter()
.map(|w| {
let cover_image_details = WeightsCoverImageDetails::from_optional_db_fields(
media_domain,
&w.token,
w.maybe_cover_image_public_bucket_hash.as_deref(),
w.maybe_cover_image_public_bucket_prefix.as_deref(),
@@ -1,10 +1,10 @@
use std::fmt;
use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::{Path, Query};
use actix_web::{web, HttpRequest, HttpResponse};
use chrono::{DateTime, Utc};
use log::warn;
use utoipa::{IntoParams, ToSchema};
@@ -22,6 +22,7 @@ use crate::http_server::common_responses::pagination_page::PaginationPage;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::common_responses::weights_cover_image_details::WeightsCoverImageDetails;
use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain;
use crate::state::server_state::ServerState;
use crate::util::title_to_url_slug::title_to_url_slug;
@@ -194,9 +195,12 @@ pub async fn list_weights_by_user_handler(
}
};
let media_domain = get_media_domain(&http_request);
let weights: Vec<Weight> = results_page.records.into_iter().map(|weight| {
let cover_image_details = WeightsCoverImageDetails::from_optional_db_fields(
media_domain,
&weight.token,
weight.maybe_cover_image_public_bucket_hash.as_deref(),
weight.maybe_cover_image_public_bucket_prefix.as_deref(),
@@ -25,9 +25,10 @@ use crate::state::server_state::ServerState;
)
)]
pub async fn search_model_weights_http_get_handler(
_http_request: HttpRequest,
http_request: HttpRequest,
request: Query<SearchModelWeightsRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<Json<SearchModelWeightsSuccessResponse>, SearchModelWeightsError>
server_state: web::Data<Arc<ServerState>>
) -> Result<Json<SearchModelWeightsSuccessResponse>, SearchModelWeightsError>
{
search_model_weights_impl(request.0, server_state).await
search_model_weights_impl(http_request, request.0, server_state).await
}
@@ -27,9 +27,9 @@ use crate::state::server_state::ServerState;
)
)]
pub async fn search_model_weights_http_post_handler(
_http_request: HttpRequest,
http_request: HttpRequest,
request: Json<SearchModelWeightsRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<Json<SearchModelWeightsSuccessResponse>, SearchModelWeightsError>
{
search_model_weights_impl(request.0, server_state).await
search_model_weights_impl(http_request, request.0, server_state).await
}
@@ -7,14 +7,21 @@ use std::collections::HashSet;
use std::fmt;
use std::sync::Arc;
use actix_web::{HttpResponse, web};
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::Json;
use actix_web::{web, HttpRequest, HttpResponse};
use chrono::{DateTime, Utc};
use log::error;
use utoipa::ToSchema;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::common_responses::weights_cover_image_details::WeightsCoverImageDetails;
use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::state::server_state::ServerState;
use crate::util::title_to_url_slug::title_to_url_slug;
use buckets::public::media_files::bucket_file_path::MediaFileBucketPath;
use elasticsearch_schema::searches::search_model_weights::{search_model_weights, SearchArgs};
use enums::by_table::model_weights::weights_category::WeightsCategory;
@@ -24,13 +31,6 @@ use enums_public::by_table::model_weights::public_weights_types::PublicWeightsTy
use primitives::numerics::i32_to_u32_zero_clamped::i32_to_u32_zero_clamped;
use tokens::tokens::model_weights::ModelWeightToken;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::common_responses::weights_cover_image_details::WeightsCoverImageDetails;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::state::server_state::ServerState;
use crate::util::title_to_url_slug::title_to_url_slug;
#[derive(Deserialize, ToSchema)]
pub struct SearchModelWeightsRequest {
pub search_term: String,
@@ -113,8 +113,10 @@ impl fmt::Display for SearchModelWeightsError {
}
pub async fn search_model_weights_impl(
http_request: HttpRequest,
request: SearchModelWeightsRequest,
server_state: web::Data<Arc<ServerState>>) -> Result<Json<SearchModelWeightsSuccessResponse>, SearchModelWeightsError>
server_state: web::Data<Arc<ServerState>>
) -> Result<Json<SearchModelWeightsSuccessResponse>, SearchModelWeightsError>
{
let maybe_weights_categories = request.weight_category
.map(|weight_category| {
@@ -144,9 +146,12 @@ pub async fn search_model_weights_impl(
SearchModelWeightsError::ServerError
})?;
let media_domain = get_media_domain(&http_request);
let results = results.into_iter()
.map(|result| {
let cover_image_details = WeightsCoverImageDetails::from_optional_db_fields(
media_domain,
&result.token,
result.maybe_cover_image_public_bucket_hash.as_deref(),
result.maybe_cover_image_public_bucket_prefix.as_deref(),