fork featured media files -> pinned media files

This commit is contained in:
Brandon Thomas committed 2024-05-05 02:44:49 -04:00
1 parent 1a482657d3
commit 7b8439e2a6
4 files changed
+255

No files matched your search

@@ -59,6 +59,7 @@ use crate::http_server::endpoints::media_files::list::list_featured_media_files_
use crate::http_server::endpoints::media_files::list::list_media_files_by_batch_token_handler::*;
use crate::http_server::endpoints::media_files::list::list_media_files_for_user_handler::*;
use crate::http_server::endpoints::media_files::list::list_media_files_handler::*;
use crate::http_server::endpoints::media_files::list::list_pinned_media_files_handler::*;
use crate::http_server::endpoints::media_files::upload::upload_audio_media_file_handler::*;
use crate::http_server::endpoints::media_files::upload::upload_engine_asset::upload_engine_asset_media_file_handler::*;
use crate::http_server::endpoints::media_files::upload::upload_error::MediaFileUploadError;
@@ -117,6 +118,7 @@ use crate::http_server::web_utils::response_success_helpers::*;
crate::http_server::endpoints::media_files::list::list_media_files_by_batch_token_handler::list_media_files_by_batch_token_handler,
crate::http_server::endpoints::media_files::list::list_media_files_for_user_handler::list_media_files_for_user_handler,
crate::http_server::endpoints::media_files::list::list_media_files_handler::list_media_files_handler,
crate::http_server::endpoints::media_files::list::list_pinned_media_files_handler::list_pinned_media_files_handler,
crate::http_server::endpoints::media_files::upload::upload_audio_media_file_handler::upload_audio_media_file_handler,
crate::http_server::endpoints::media_files::upload::upload_engine_asset::upload_engine_asset_media_file_handler::upload_engine_asset_media_file_handler,
crate::http_server::endpoints::media_files::upload::upload_generic::upload_media_file_handler::upload_media_file_handler,
@@ -305,6 +307,8 @@ use crate::http_server::web_utils::response_success_helpers::*;
ListMediaFilesForUserSuccessResponse,
ListMediaFilesQueryParams,
ListMediaFilesSuccessResponse,
ListPinnedMediaFilesError,
ListPinnedMediaFilesSuccessResponse,
ListSessionJobsError,
ListSessionJobsItem,
ListSessionJobsQueryParams,
@@ -337,6 +341,7 @@ use crate::http_server::web_utils::response_success_helpers::*;
MediaFileUploadError,
ModelWeightForList,
ModelWeightSearchResult,
PinnedMediaFile,
ProfileError,
RatingRow,
RenameMediaFileError,
@@ -0,0 +1,244 @@
use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use chrono::{DateTime, Utc};
use log::{debug, error, warn};
use r2d2_redis::redis::Commands;
use utoipa::ToSchema;
use buckets::public::media_files::bucket_file_path::MediaFileBucketPath;
use enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType;
use enums::by_table::media_files::media_file_class::MediaFileClass;
use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory;
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
use enums::by_table::media_files::media_file_type::MediaFileType;
use enums::no_table::style_transfer::style_transfer_name::StyleTransferName;
use mysql_queries::queries::media_files::get::batch_get_media_files_by_tokens::batch_get_media_files_by_tokens;
use tokens::tokens::media_files::MediaFileToken;
use users_component::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::common_responses::media_file_cover_image_details::{MediaFileCoverImageDetails, MediaFileDefaultCover};
use crate::http_server::common_responses::media_file_origin_details::MediaFileOriginDetails;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::server_state::ServerState;
#[derive(Serialize, ToSchema)]
pub struct ListPinnedMediaFilesSuccessResponse {
pub success: bool,
pub results: Vec<PinnedMediaFile>,
}
#[derive(Serialize, ToSchema)]
pub struct PinnedMediaFile {
pub token: MediaFileToken,
/// The coarse-grained class of media file: image, video, etc.
pub media_class: MediaFileClass,
/// Type of media will dictate which fields are populated and what
/// the frontend should display (eg. video player vs audio player).
/// This is closer in meaning to a "mime type".
pub media_type: MediaFileType,
/// If this is an engine/3D asset, this is the broad category (scene,
/// animation, etc.) of that object.
/// This can also be used for filtering in list/batch endpoints.
pub maybe_engine_category: Option<MediaFileEngineCategory>,
/// If this is an engine/3D asset for an animation or a rig that can
/// be animated with either (or both) skeletal or blend shape animations,
/// this describes the animation regime used or supported.
pub maybe_animation_type: Option<MediaFileAnimationType>,
/// URL to the media file
pub public_bucket_path: String,
/// Information about the cover image. Many media files do not require a cover image,
/// e.g. image files, video files with thumbnails, audio files, etc.
/// 3D files require them.
pub cover_image: MediaFileCoverImageDetails,
#[deprecated(note="Use MediaFileOriginDetails instead")]
pub origin_category: MediaFileOriginCategory,
#[deprecated(note="Use MediaFileOriginDetails instead")]
pub origin_product_category: MediaFileOriginProductCategory,
#[deprecated(note="Use MediaFileOriginDetails instead")]
pub maybe_origin_model_type: Option<MediaFileOriginModelType>,
#[deprecated(note="Use MediaFileOriginDetails instead")]
pub maybe_origin_model_token: Option<String>,
/// Details where the media file came from.
pub origin: MediaFileOriginDetails,
pub maybe_creator: Option<UserDetailsLight>,
/// The name or title of the media file (optional)
pub maybe_title: Option<String>,
/// Text transcripts for TTS, etc.
pub maybe_text_transcript: Option<String>,
/// For Comfy / Video Style Transfer jobs, this might include
/// the name of the selected style.
pub maybe_style_name: Option<StyleTransferName>,
/// Duration for audio and video files, if available.
/// Measured in milliseconds.
pub maybe_duration_millis: Option<u64>,
/// Statistics about the media file
pub stats: SimpleEntityStats,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
/// The key we store pinned media file tokens under
const REDIS_KEY : &str = "pinned_media_files_list";
#[derive(Debug, ToSchema)]
pub enum ListPinnedMediaFilesError {
NotAuthorized,
ServerError,
}
impl std::fmt::Display for ListPinnedMediaFilesError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl ResponseError for ListPinnedMediaFilesError {
fn status_code(&self) -> StatusCode {
match *self {
ListPinnedMediaFilesError::NotAuthorized => StatusCode::UNAUTHORIZED,
ListPinnedMediaFilesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
/// List media files that were pinned by the staff (paginated).
#[utoipa::path(
get,
tag = "Media Files",
path = "/v1/media_files/list_pinned",
responses(
(status = 200, description = "List Featured Media Files", body = ListPinnedMediaFilesSuccessResponse),
(status = 401, description = "Not authorized", body = ListPinnedMediaFilesError),
(status = 500, description = "Server error", body = ListPinnedMediaFilesError),
),
)]
pub async fn list_pinned_media_files_handler(
http_request: HttpRequest,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, impl ResponseError> {
let mut redis = server_state.redis_pool.get()
.map_err(|err| {
error!("Could not obtain redis: {err}");
ListPinnedMediaFilesError::ServerError
})?;
let token_list : Option<String> = redis.get(REDIS_KEY)
.map_err(|err| {
error!("Could not get redis result: {err}");
ListPinnedMediaFilesError::ServerError
})?;
let media_file_tokens = token_list
.unwrap_or_else(|| "".to_string())
.split(",")
.into_iter()
.map(|item| item.trim())
.filter(|item| !item.is_empty())
.map(|item| MediaFileToken::new_from_str(item))
.collect::<Vec<MediaFileToken>>();
debug!("Weight tokens from Redis: {:?}", media_file_tokens);
let mut media_files = Vec::new();
if !media_file_tokens.is_empty() {
let query_results =
batch_get_media_files_by_tokens(&server_state.mysql_pool, &media_file_tokens, false).await;
media_files = match query_results {
Ok(media_files) => media_files,
Err(e) => {
warn!("Query error: {:?}", e);
return Err(ListPinnedMediaFilesError::ServerError);
}
};
}
let response = ListPinnedMediaFilesSuccessResponse {
success: true,
results: media_files.into_iter()
.map(|m| {
let public_bucket_path = MediaFileBucketPath::from_object_hash(
&m.public_bucket_directory_hash,
m.maybe_public_bucket_prefix.as_deref(),
m.maybe_public_bucket_extension.as_deref())
.get_full_object_path_str()
.to_string();
PinnedMediaFile {
token: m.token.clone(),
media_class: m.media_class,
media_type: m.media_type,
maybe_engine_category: m.maybe_engine_category,
maybe_animation_type: m.maybe_animation_type,
public_bucket_path,
cover_image: MediaFileCoverImageDetails::from_optional_db_fields(
&m.token,
m.maybe_file_cover_image_public_bucket_hash.as_deref(),
m.maybe_file_cover_image_public_bucket_prefix.as_deref(),
m.maybe_file_cover_image_public_bucket_extension.as_deref(),
),
origin: MediaFileOriginDetails::from_db_fields_str(
m.origin_category,
m.origin_product_category,
m.maybe_origin_model_type,
m.maybe_origin_model_token.as_deref(),
m.maybe_origin_model_title.as_deref()),
origin_category: m.origin_category,
origin_product_category: m.origin_product_category,
maybe_origin_model_type: m.maybe_origin_model_type,
maybe_origin_model_token: m.maybe_origin_model_token,
maybe_creator: UserDetailsLight::from_optional_db_fields_owned(
m.maybe_creator_user_token,
m.maybe_creator_username,
m.maybe_creator_display_name,
m.maybe_creator_email_gravatar_hash
),
maybe_title: m.maybe_title,
maybe_text_transcript: m.maybe_text_transcript,
maybe_style_name: m.maybe_prompt_args
.as_ref()
.and_then(|args| args.style_name.as_ref())
.and_then(|style| style.to_style_name()),
maybe_duration_millis: m.maybe_duration_millis,
stats: SimpleEntityStats {
positive_rating_count: m.maybe_ratings_positive_count.unwrap_or(0),
bookmark_count: m.maybe_bookmark_count.unwrap_or(0),
},
created_at: m.created_at,
updated_at: m.updated_at,
}
}).collect::<Vec<_>>(),
};
let body = serde_json::to_string(&response)
.map_err(|e| ListPinnedMediaFilesError::ServerError)?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
@@ -3,3 +3,4 @@ pub mod list_featured_media_files_handler;
pub mod list_media_files_by_batch_token_handler;
pub mod list_media_files_for_user_handler;
pub mod list_media_files_handler;
pub mod list_pinned_media_files_handler;
@@ -14,6 +14,7 @@ use crate::http_server::endpoints::media_files::list::list_featured_media_files_
use crate::http_server::endpoints::media_files::list::list_media_files_handler::list_media_files_handler;
use crate::http_server::endpoints::media_files::list::list_media_files_by_batch_token_handler::list_media_files_by_batch_token_handler;
use crate::http_server::endpoints::media_files::list::list_media_files_for_user_handler::list_media_files_for_user_handler;
use crate::http_server::endpoints::media_files::list::list_pinned_media_files_handler::list_pinned_media_files_handler;
use crate::http_server::endpoints::media_files::upload::upload_audio_media_file_handler::upload_audio_media_file_handler;
use crate::http_server::endpoints::media_files::upload::upload_engine_asset::upload_engine_asset_media_file_handler::upload_engine_asset_media_file_handler;
use crate::http_server::endpoints::media_files::upload::upload_generic::upload_media_file_handler::upload_media_file_handler;
@@ -72,6 +73,10 @@ pub fn add_media_file_routes<T, B> (app: App<T>) -> App<T>
.route(web::get().to(list_featured_media_files_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(web::resource("/list_pinned")
.route(web::get().to(list_pinned_media_files_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(web::resource("/list/user/{username}")
.route(web::get().to(list_media_files_for_user_handler))
.route(web::head().to(|| HttpResponse::Ok()))