Compare commits

..
Author SHA1 Message Date
Brandon Thomas 2929eae094 rate limiter 2026-06-19 10:42:50 -04:00
Brandon Thomas b47f9a522a video info handler 2026-06-19 10:40:49 -04:00
139 changed files with 294 additions and 5325 deletions
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\nINSERT INTO uploaded_videos\nSET\n token = ?,\n sha1_checksum = ?,\n filesize_bytes = ?,\n maybe_filename = ?,\n maybe_width = ?,\n maybe_height = ?,\n maybe_resolution = ?,\n maybe_detected_model_family = ?,\n maybe_detected_model_type = ?,\n maybe_report = ?,\n upload_ip_address = ?,\n created_at = NOW()\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 11
},
"nullable": []
},
"hash": "14e63e59f7d550181126151029bcd17d08278196ba0ee4d32450c2567b1da26e"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\nUPDATE uploaded_video_notes\nSET\n maybe_filename = ?,\n maybe_reported_model_type = ?,\n maybe_reported_model_name = ?,\n maybe_website = ?,\n maybe_other_website = ?,\n maybe_comments = ?,\n maybe_email_address = ?,\n can_share_report = ?,\n was_scammed = ?,\n maybe_comment_update_ip_address = ?,\n version = version + 1\nWHERE token = ?\nLIMIT 1\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 11
},
"nullable": []
},
"hash": "4036dfd9d4e9e77e557776468c14b75f49170de1e55a1b9b9e83446a0c356e74"
}
@@ -1,157 +0,0 @@
{
"db_name": "MySQL",
"query": "\nSELECT\n token as `token: UploadedVideoToken`,\n sha1_checksum,\n filesize_bytes as `filesize_bytes: u32`,\n maybe_width as `maybe_width: u32`,\n maybe_height as `maybe_height: u32`,\n maybe_resolution,\n maybe_detected_model_family as `maybe_detected_model_family: UploadedVideoDetectedModelFamily`,\n maybe_detected_model_type as `maybe_detected_model_type: UploadedVideoDetectedModelType`,\n maybe_report,\n upload_ip_address,\n maybe_updated_ip_address,\n created_at,\n updated_at\nFROM uploaded_videos\nWHERE sha1_checksum = ?\nLIMIT 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token: UploadedVideoToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 1,
"name": "sha1_checksum",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 2,
"name": "filesize_bytes: u32",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED | NO_DEFAULT_VALUE",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 3,
"name": "maybe_width: u32",
"type_info": {
"type": "Long",
"flags": "UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 4,
"name": "maybe_height: u32",
"type_info": {
"type": "Long",
"flags": "UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 5,
"name": "maybe_resolution",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 48
}
},
{
"ordinal": 6,
"name": "maybe_detected_model_family: UploadedVideoDetectedModelFamily",
"type_info": {
"type": "VarString",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 7,
"name": "maybe_detected_model_type: UploadedVideoDetectedModelType",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 8,
"name": "maybe_report",
"type_info": {
"type": "Blob",
"flags": "BLOB | BINARY",
"char_set": 224,
"max_size": 67108860
}
},
{
"ordinal": 9,
"name": "upload_ip_address",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 10,
"name": "maybe_updated_ip_address",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 11,
"name": "created_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 12,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
"char_set": 63,
"max_size": 19
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
true,
true,
true,
true,
true,
true,
false,
true,
false,
false
]
},
"hash": "408c893a0ced805de4c3c6cfdf0c6a4bcc93dd1eaf98382522eae46e72eb3aa5"
}
@@ -1,157 +0,0 @@
{
"db_name": "MySQL",
"query": "\nSELECT\n token as `token: UploadedVideoToken`,\n sha1_checksum,\n filesize_bytes as `filesize_bytes: u32`,\n maybe_width as `maybe_width: u32`,\n maybe_height as `maybe_height: u32`,\n maybe_resolution,\n maybe_detected_model_family as `maybe_detected_model_family: UploadedVideoDetectedModelFamily`,\n maybe_detected_model_type as `maybe_detected_model_type: UploadedVideoDetectedModelType`,\n maybe_report,\n upload_ip_address,\n maybe_updated_ip_address,\n created_at,\n updated_at\nFROM uploaded_videos\nWHERE token = ?\nLIMIT 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token: UploadedVideoToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 1,
"name": "sha1_checksum",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 2,
"name": "filesize_bytes: u32",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED | NO_DEFAULT_VALUE",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 3,
"name": "maybe_width: u32",
"type_info": {
"type": "Long",
"flags": "UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 4,
"name": "maybe_height: u32",
"type_info": {
"type": "Long",
"flags": "UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 5,
"name": "maybe_resolution",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 48
}
},
{
"ordinal": 6,
"name": "maybe_detected_model_family: UploadedVideoDetectedModelFamily",
"type_info": {
"type": "VarString",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 7,
"name": "maybe_detected_model_type: UploadedVideoDetectedModelType",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 8,
"name": "maybe_report",
"type_info": {
"type": "Blob",
"flags": "BLOB | BINARY",
"char_set": 224,
"max_size": 67108860
}
},
{
"ordinal": 9,
"name": "upload_ip_address",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 10,
"name": "maybe_updated_ip_address",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 11,
"name": "created_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 12,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
"char_set": 63,
"max_size": 19
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
true,
true,
true,
true,
true,
true,
false,
true,
false,
false
]
},
"hash": "73d70c5ee77f5059801d324610a80b3f52da3ddec2e89f63e8f41fc68ff0aaec"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\nINSERT INTO uploaded_video_notes\nSET\n token = ?,\n uploaded_video_token = ?,\n maybe_filename = ?,\n maybe_reported_model_type = ?,\n maybe_reported_model_name = ?,\n maybe_website = ?,\n maybe_other_website = ?,\n maybe_comments = ?,\n maybe_email_address = ?,\n can_share_report = ?,\n was_scammed = ?,\n comment_create_ip_address = ?,\n created_at = NOW()\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 12
},
"nullable": []
},
"hash": "b1f30a79864351a28a58cae43ee38ff12a8d64d9393b8f27590fe03b0ae3ab05"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\nUPDATE uploaded_videos\nSET\n maybe_filename = ?,\n maybe_width = ?,\n maybe_height = ?,\n maybe_resolution = ?,\n maybe_detected_model_family = ?,\n maybe_detected_model_type = ?,\n maybe_report = ?,\n maybe_updated_ip_address = ?,\n version = version + 1\nWHERE token = ?\nLIMIT 1\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 9
},
"nullable": []
},
"hash": "c6bbdc963e0d49ac55973a728d04b371967c20bfb9dd4bd75e4693dc7a114c99"
}
Generated
-18
View File
@@ -1730,14 +1730,6 @@ dependencies = [
"serde",
]
[[package]]
name = "bucket_client"
version = "0.0.1"
dependencies = [
"rust-s3",
"workspace-build-acceleration",
]
[[package]]
name = "bucket_paths"
version = "0.0.1"
@@ -11004,14 +10996,6 @@ dependencies = [
"digest 0.11.2",
]
[[package]]
name = "sha1_hash"
version = "0.0.1"
dependencies = [
"sha1 0.10.6",
"workspace-build-acceleration",
]
[[package]]
name = "sha1_smol"
version = "1.0.0"
@@ -11589,7 +11573,6 @@ dependencies = [
"billing_artcraft_component",
"billing_component",
"bootstrap",
"bucket_client",
"bucket_paths",
"bytes",
"chrono",
@@ -11661,7 +11644,6 @@ dependencies = [
"serde_derive",
"serde_json",
"server_environment",
"sha1_hash",
"shared_env_var_config",
"speculoos",
"sqlx",
-4
View File
@@ -10,7 +10,6 @@ members = [
"crates/api_clients/artcraft/artcraft_api_keys",
"crates/api_clients/artcraft/artcraft_client",
"crates/api_clients/artcraft/artcraft_router",
"crates/api_clients/bucket_client",
"crates/api_clients/cloud_storage",
"crates/api_clients/comet_api_client",
"crates/api_clients/datadog_client",
@@ -88,7 +87,6 @@ members = [
"crates/lib/pager",
"crates/lib/password",
"crates/lib/server_environment",
"crates/lib/sha1_hash",
"crates/lib/sqlx_mysql_helpers",
"crates/lib/storyteller_root",
"crates/lib/url_config",
@@ -240,7 +238,6 @@ artcraft_api_keys = { path = "crates/api_clients/artcraft/artcraft_api_keys" }
artcraft_client = { path = "crates/api_clients/artcraft/artcraft_client" }
artcraft_router = { path = "crates/api_clients/artcraft/artcraft_router" }
bootstrap = { path = "crates/lib/bootstrap" }
bucket_client = { path = "crates/api_clients/bucket_client" }
bucket_paths = { path = "crates/schema/buckets/bucket_paths" }
build_metadata = { path = "crates/lib/build_metadata" }
cloud_storage = { path = "crates/api_clients/cloud_storage" }
@@ -285,7 +282,6 @@ openai_sora_client = { path = "crates/api_clients/openai_sora_client" }
primitives = { path = "crates/lib/data/primitives" }
seedance2pro_client = { path = "crates/api_clients/seedance2pro_client" }
server_environment = { path = "crates/lib/server_environment" }
sha1_hash = { path = "crates/lib/sha1_hash" }
shared_service_components = { path = "crates/lib/shared_service_components" }
sqlite_tasks = { path = "crates/schema/database/sqlite_tasks" }
subprocess_common = { path = "crates/lib/deprecated/subprocess_common" }
@@ -1,5 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
DROP TABLE IF EXISTS uploaded_videos;
@@ -1,62 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
CREATE TABLE uploaded_videos (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
-- Effective "primary key" (used internally for lookups and as a foreign key).
token VARCHAR(32) NOT NULL,
-- ========== FILE ==========
-- SHA-1 checksum of the uploaded bytes (40 hex chars). De-dupes uploads.
sha1_checksum VARCHAR(40) NOT NULL,
-- Size of the uploaded file in bytes.
filesize_bytes INT(10) UNSIGNED NOT NULL,
-- Pixel dimensions, when they could be determined.
maybe_width INT(10) UNSIGNED DEFAULT NULL,
maybe_height INT(10) UNSIGNED DEFAULT NULL,
-- Resolution label (e.g. "1080p", "1920x1080"), when known.
maybe_resolution VARCHAR(12) DEFAULT NULL,
-- ========== DETECTION ==========
-- Detected provenance family (e.g. "seedance", "veo", "sora", "dreamina", "kling").
maybe_detected_model_family VARCHAR(32) DEFAULT NULL,
-- Detected model type / variant (e.g. "full", "fast", "mini").
maybe_detected_model_type VARCHAR(32) DEFAULT NULL,
-- Free-form report / analysis blob for this upload.
maybe_report MEDIUMTEXT DEFAULT NULL,
-- ========== IP ADDRESSES ==========
-- IP address that uploaded the video. Wide enough for IPv4/IPv6.
upload_ip_address VARCHAR(40) NOT NULL,
-- IP address that last updated the row. Wide enough for IPv4/IPv6.
maybe_updated_ip_address VARCHAR(40) DEFAULT NULL,
-- ========== VERSION ==========
-- Optimistic-concurrency "vector clock". Bump by 1 on every update — set in
-- the UPDATE statement (MySQL can't auto-increment a plain column via schema).
version INT(8) UNSIGNED NOT NULL DEFAULT 0,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
UNIQUE KEY (sha1_checksum),
KEY index_maybe_detected_model_family (maybe_detected_model_family)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -1,5 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
DROP TABLE IF EXISTS uploaded_video_notes;
@@ -1,69 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
CREATE TABLE uploaded_video_notes (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
-- Effective "primary key" (used internally for lookups and as a foreign key).
token VARCHAR(32) NOT NULL,
-- The uploaded video this note is about (FK to uploaded_videos.token).
uploaded_video_token VARCHAR(32) NOT NULL,
-- ========== SUBMISSION ==========
-- Original filename of the submitted clip, as provided by the user.
maybe_filename VARCHAR(512) DEFAULT NULL,
-- The model type the submitter claims this video is.
maybe_reported_model_type VARCHAR(32) DEFAULT NULL,
-- Free-form custom model name when the submitter's model isn't a known type.
maybe_reported_model_name VARCHAR(64) DEFAULT NULL,
-- The website / platform the video was obtained from.
maybe_website VARCHAR(32) DEFAULT NULL,
-- Free-form website when it isn't a known option.
maybe_other_website VARCHAR(128) DEFAULT NULL,
-- Free-form comments from the submitter.
maybe_comments VARCHAR(1024) DEFAULT NULL,
-- ========== CONTACT & FLAGS ==========
-- Optional email address for follow-up.
maybe_email_address VARCHAR(255) DEFAULT NULL,
-- Whether the submitter consents to us sharing the report.
can_share_report BOOLEAN NOT NULL DEFAULT FALSE,
-- Whether the submitter believes they were scammed.
was_scammed BOOLEAN NOT NULL DEFAULT FALSE,
-- ========== IP ADDRESSES ==========
-- IP address that submitted the note. Wide enough for IPv4/IPv6.
comment_create_ip_address VARCHAR(40) NOT NULL,
-- IP address that last updated the note. Wide enough for IPv4/IPv6.
maybe_comment_update_ip_address VARCHAR(40) DEFAULT NULL,
-- ========== VERSION ==========
-- Optimistic-concurrency "vector clock". Bump by 1 on every update — set in
-- the UPDATE statement (MySQL can't auto-increment a plain column via schema).
version INT(8) UNSIGNED NOT NULL DEFAULT 0,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
KEY fk_uploaded_video_token (uploaded_video_token)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -1,6 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE uploaded_videos
DROP COLUMN maybe_filename;
@@ -1,6 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE uploaded_videos
ADD COLUMN maybe_filename VARCHAR(512) DEFAULT NULL AFTER filesize_bytes;
@@ -1,69 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
CREATE TABLE uploaded_video_notes (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
-- Effective "primary key" (used internally for lookups and as a foreign key).
token VARCHAR(32) NOT NULL,
-- The uploaded video this note is about (FK to uploaded_videos.token).
uploaded_video_token VARCHAR(32) NOT NULL,
-- ========== SUBMISSION ==========
-- Original filename of the submitted clip, as provided by the user.
maybe_filename VARCHAR(512) DEFAULT NULL,
-- The model type the submitter claims this video is.
maybe_reported_model_type VARCHAR(32) DEFAULT NULL,
-- Free-form custom model name when the submitter's model isn't a known type.
maybe_reported_model_name VARCHAR(64) DEFAULT NULL,
-- The website / platform the video was obtained from.
maybe_website VARCHAR(32) DEFAULT NULL,
-- Free-form website when it isn't a known option.
maybe_other_website VARCHAR(128) DEFAULT NULL,
-- Free-form comments from the submitter.
maybe_comments VARCHAR(1024) DEFAULT NULL,
-- ========== CONTACT & FLAGS ==========
-- Optional email address for follow-up.
maybe_email_address VARCHAR(255) DEFAULT NULL,
-- Whether the submitter consents to us sharing the report.
can_share_report BOOLEAN NOT NULL DEFAULT FALSE,
-- Whether the submitter believes they were scammed.
was_scammed BOOLEAN NOT NULL DEFAULT FALSE,
-- ========== IP ADDRESSES ==========
-- IP address that submitted the note. Wide enough for IPv4/IPv6.
comment_create_ip_address VARCHAR(40) NOT NULL,
-- IP address that last updated the note. Wide enough for IPv4/IPv6.
maybe_comment_update_ip_address VARCHAR(40) DEFAULT NULL,
-- ========== VERSION ==========
-- Optimistic-concurrency "vector clock". Bump by 1 on every update — set in
-- the UPDATE statement (MySQL can't auto-increment a plain column via schema).
version INT(8) UNSIGNED NOT NULL DEFAULT 0,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
KEY fk_uploaded_video_token (uploaded_video_token)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -1,65 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
CREATE TABLE uploaded_videos (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
-- Effective "primary key" (used internally for lookups and as a foreign key).
token VARCHAR(32) NOT NULL,
-- ========== FILE ==========
-- SHA-1 checksum of the uploaded bytes (40 hex chars). De-dupes uploads.
sha1_checksum VARCHAR(40) NOT NULL,
-- Size of the uploaded file in bytes.
filesize_bytes INT(10) UNSIGNED NOT NULL,
-- Original filename of the uploaded clip, as provided by the user.
maybe_filename VARCHAR(512) DEFAULT NULL,
-- Pixel dimensions, when they could be determined.
maybe_width INT(10) UNSIGNED DEFAULT NULL,
maybe_height INT(10) UNSIGNED DEFAULT NULL,
-- Resolution label (e.g. "1080p", "1920x1080"), when known.
maybe_resolution VARCHAR(12) DEFAULT NULL,
-- ========== DETECTION ==========
-- Detected provenance family (e.g. "seedance", "veo", "sora", "dreamina", "kling").
maybe_detected_model_family VARCHAR(32) DEFAULT NULL,
-- Detected model type / variant (e.g. "full", "fast", "mini").
maybe_detected_model_type VARCHAR(32) DEFAULT NULL,
-- Free-form report / analysis blob for this upload.
maybe_report MEDIUMTEXT DEFAULT NULL,
-- ========== IP ADDRESSES ==========
-- IP address that uploaded the video. Wide enough for IPv4/IPv6.
upload_ip_address VARCHAR(40) NOT NULL,
-- IP address that last updated the row. Wide enough for IPv4/IPv6.
maybe_updated_ip_address VARCHAR(40) DEFAULT NULL,
-- ========== VERSION ==========
-- Optimistic-concurrency "vector clock". Bump by 1 on every update — set in
-- the UPDATE statement (MySQL can't auto-increment a plain column via schema).
version INT(8) UNSIGNED NOT NULL DEFAULT 0,
-- ========== TIMESTAMPS ==========
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- INDICES --
PRIMARY KEY (id),
UNIQUE KEY (token),
UNIQUE KEY (sha1_checksum),
KEY index_maybe_detected_model_family (maybe_detected_model_family)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -1,3 +1 @@
pub mod notes;
pub mod read_only;
pub mod upload;
@@ -1,60 +0,0 @@
//! Request/response types for `POST /v1/video_info/notes`.
//!
//! A note is user-submitted context about an uploaded video (what model they
//! believe it is, where it came from, free-form comments). Always tied to an
//! [`UploadedVideoToken`]; pass a [`UploadVideoNoteToken`] to update an existing
//! note instead of creating a new one.
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
use enums::by_table::uploaded_video_notes::uploaded_video_note_reported_model_type::UploadedVideoNoteReportedModelType;
use enums::by_table::uploaded_video_notes::uploaded_video_note_reported_website::UploadedVideoNoteReportedWebsite;
use tokens::tokens::uploaded_video_notes::UploadVideoNoteToken;
use tokens::tokens::uploaded_videos::UploadedVideoToken;
/// Request body for `POST /v1/video_info/notes`.
#[derive(Deserialize, ToSchema, Debug, Clone)]
pub struct VideoInfoNoteRequest {
/// The uploaded video this note is about. Required.
pub uploaded_video_token: UploadedVideoToken,
/// If present, update this existing note instead of creating a new one.
pub maybe_uploaded_video_note_token: Option<UploadVideoNoteToken>,
/// Original filename of the submitted clip.
pub maybe_filename: Option<String>,
/// The model type the submitter claims this video is (dropdown / enum).
pub maybe_reported_model_type: Option<UploadedVideoNoteReportedModelType>,
/// Free-form custom model name (trimmed; empty becomes absent).
pub maybe_reported_model_name: Option<String>,
/// The website / platform the video came from (dropdown / enum).
pub maybe_website: Option<UploadedVideoNoteReportedWebsite>,
/// Free-form website (trimmed; empty becomes absent).
pub maybe_other_website: Option<String>,
/// Free-form comments (trimmed; empty becomes absent).
pub maybe_comments: Option<String>,
/// Optional contact email (trimmed; empty becomes absent).
pub maybe_email_address: Option<String>,
/// Whether the submitter consents to us sharing the report. Defaults to false.
pub can_share_report: Option<bool>,
/// Whether the submitter believes they were scammed. Defaults to false.
pub was_scammed: Option<bool>,
}
/// Response body for `POST /v1/video_info/notes`.
#[derive(Serialize, Deserialize, ToSchema, Debug, Clone)]
pub struct VideoInfoNoteResponse {
pub success: bool,
/// The created or updated note's token (e.g. `uvnote_…`).
pub uploaded_video_note_token: UploadVideoNoteToken,
}
@@ -1,46 +0,0 @@
//! Response type for `POST /v1/video_info/upload`.
//!
//! Same detected provenance as the read-only endpoint, plus the persisted
//! [`UploadedVideoToken`] (used for follow-up requests, e.g. attaching a note).
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;
use tokens::tokens::uploaded_videos::UploadedVideoToken;
use crate::video_info::read_only::{
DreaminaVideoInfo, KlingVideoInfo, SeedanceVideoInfo, SoraVideoInfo, VeoVideoInfo,
VideoProvenanceKind,
};
/// Response for `POST /v1/video_info/upload`. Mirrors
/// [`crate::video_info::read_only::VideoInfoReadOnlyResponse`] and adds the
/// persisted record's token.
#[derive(Serialize, Deserialize, ToSchema, Debug, Clone)]
pub struct VideoInfoUploadResponse {
pub success: bool,
/// The persisted `uploaded_videos` record token (e.g. `uvt_…`).
pub uploaded_video_token: UploadedVideoToken,
/// Which provenance family was detected (if any).
pub kind: VideoProvenanceKind,
/// The container `©too` encoder tag, e.g. `"Lavf60.16.100"` or `"Google"`.
pub maybe_encoder: Option<String>,
/// Present when [`kind`](Self::kind) is [`VideoProvenanceKind::Seedance`].
pub maybe_seedance: Option<SeedanceVideoInfo>,
/// Present when [`kind`](Self::kind) is [`VideoProvenanceKind::Veo`].
pub maybe_veo: Option<VeoVideoInfo>,
/// Present when [`kind`](Self::kind) is [`VideoProvenanceKind::Sora`].
pub maybe_sora: Option<SoraVideoInfo>,
/// Present when [`kind`](Self::kind) is [`VideoProvenanceKind::Dreamina`].
pub maybe_dreamina: Option<DreaminaVideoInfo>,
/// Present when [`kind`](Self::kind) is [`VideoProvenanceKind::Kling`].
pub maybe_kling: Option<KlingVideoInfo>,
}
@@ -1,19 +0,0 @@
[package]
name = "bucket_client"
edition = "2024"
version = "0.0.1"
publish = false
[lib]
name = "bucket_client"
path = "src/lib.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
[dependencies]
# cargo-hakari workspace hack (faster compile times)
workspace-build-acceleration.workspace = true
# External
rust-s3.workspace = true
@@ -1,66 +0,0 @@
use s3::Bucket;
use crate::bucket_client_error::BucketClientError;
use crate::object_name::ObjectName;
/// Arguments for [`BucketClient::upload_file_bytes`].
pub struct UploadFileBytesArgs<'a, S: AsRef<str>> {
/// The destination object key (normalized via [`ObjectName`]).
pub object_name: S,
/// The raw bytes to upload.
pub bytes: &'a [u8],
/// Optional MIME type. Defaults to `application/octet-stream` when `None`.
pub content_type: Option<&'a str>,
}
/// A client for a single S3-compatible bucket. Cheap to clone. Build one with
/// [`crate::BucketClientBuilder`].
#[derive(Clone)]
pub struct BucketClient {
bucket: Bucket,
}
impl BucketClient {
/// Wrap a fully-configured `Bucket`. Internal — use
/// [`crate::BucketClientBuilder`] to construct a client.
pub(crate) fn from_bucket(bucket: Bucket) -> Self {
Self { bucket }
}
/// The name of the bucket this client targets.
pub fn bucket_name(&self) -> &str {
self.bucket.name.as_str()
}
/// Upload raw bytes to `object_name`, optionally with an explicit content type.
///
/// Returns [`BucketClientError::UploadFailed`] if the store responds with a
/// non-2xx status, or [`BucketClientError::S3Error`] on a transport/protocol
/// error.
pub async fn upload_file_bytes<S: AsRef<str>>(
&self,
args: UploadFileBytesArgs<'_, S>,
) -> Result<(), BucketClientError> {
let object_name = ObjectName::new(&args.object_name);
let response = match args.content_type {
Some(content_type) => {
self
.bucket
.put_object_with_content_type(object_name.as_str(), args.bytes, content_type)
.await?
}
None => self.bucket.put_object(object_name.as_str(), args.bytes).await?,
};
let status_code = response.status_code();
if !(200..300).contains(&status_code) {
return Err(BucketClientError::UploadFailed {
status_code,
message: String::from_utf8_lossy(response.bytes()).into_owned(),
});
}
Ok(())
}
}
@@ -1,119 +0,0 @@
use std::time::Duration;
use s3::creds::Credentials;
use s3::region::Region;
use s3::Bucket;
use crate::bucket_client::BucketClient;
use crate::bucket_client_error::BucketClientError;
/// Builder for [`BucketClient`].
///
/// `access_key`, `secret_key`, `region_name`, and `bucket_name` are required;
/// `endpoint` and `bucket_request_timeout` are optional.
///
/// - With an `endpoint` set, the bucket targets a custom S3-compatible host
/// (R2, GCS, MinIO, etc.) via `Region::Custom`, and uses path-style addressing
/// (subdomain-style for Google Cloud Storage).
/// - Without an `endpoint`, the `region_name` is parsed as an AWS region
/// (e.g. `"us-east-1"`), which determines the AWS endpoint automatically.
#[derive(Debug, Default, Clone)]
pub struct BucketClientBuilder {
access_key: Option<String>,
secret_key: Option<String>,
region_name: Option<String>,
bucket_name: Option<String>,
endpoint: Option<String>,
bucket_request_timeout: Option<Duration>,
}
impl BucketClientBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn access_key(mut self, access_key: impl Into<String>) -> Self {
self.access_key = Some(access_key.into());
self
}
pub fn secret_key(mut self, secret_key: impl Into<String>) -> Self {
self.secret_key = Some(secret_key.into());
self
}
pub fn region_name(mut self, region_name: impl Into<String>) -> Self {
self.region_name = Some(region_name.into());
self
}
pub fn bucket_name(mut self, bucket_name: impl Into<String>) -> Self {
self.bucket_name = Some(bucket_name.into());
self
}
/// Optional custom S3-compatible endpoint (e.g. an R2/GCS/MinIO URL). When
/// unset, an AWS endpoint is derived from `region_name`.
pub fn endpoint(mut self, endpoint: impl Into<String>) -> Self {
self.endpoint = Some(endpoint.into());
self
}
pub fn bucket_request_timeout(mut self, timeout: Duration) -> Self {
self.bucket_request_timeout = Some(timeout);
self
}
/// Validate the configuration and construct a [`BucketClient`].
pub fn build(self) -> Result<BucketClient, BucketClientError> {
let access_key = require(self.access_key, "access_key")?;
let secret_key = require(self.secret_key, "secret_key")?;
let region_name = require(self.region_name, "region_name")?;
let bucket_name = require(self.bucket_name, "bucket_name")?;
let credentials = Credentials {
access_key: Some(access_key),
secret_key: Some(secret_key),
security_token: None,
session_token: None,
expiration: None,
};
// A custom endpoint targets an S3-compatible host via `Region::Custom`;
// otherwise the region name is parsed as a standard AWS region.
let region = match self.endpoint.as_deref() {
Some(endpoint) => Region::Custom {
region: region_name.clone(),
endpoint: endpoint.to_string(),
},
None => region_name.parse().map_err(|err| {
BucketClientError::ClientBuilderSetupError(format!(
"invalid region {region_name:?}: {err:?}"
))
})?,
};
let mut bucket = Bucket::new(&bucket_name, region, credentials)?;
bucket.set_request_timeout(self.bucket_request_timeout);
// Addressing style only matters for custom endpoints: Google Cloud Storage
// needs subdomain (virtual-hosted) style; other S3-compatible stores use
// path style. AWS uses the crate default (virtual-hosted).
if let Some(endpoint) = self.endpoint.as_deref() {
if endpoint == "https://storage.googleapis.com" {
bucket.set_subdomain_style();
} else {
bucket.set_path_style();
}
}
Ok(BucketClient::from_bucket(*bucket))
}
}
/// Resolve a required builder field, or report which one was missing.
fn require(value: Option<String>, field: &str) -> Result<String, BucketClientError> {
value.ok_or_else(|| {
BucketClientError::ClientBuilderSetupError(format!("{field} is required"))
})
}
@@ -1,56 +0,0 @@
use std::fmt;
use std::io;
/// Errors produced by [`crate::BucketClient`] and [`crate::BucketClientBuilder`].
#[derive(Debug)]
pub enum BucketClientError {
/// An error surfaced by the underlying `rust-s3` client.
S3Error(s3::error::S3Error),
/// A local I/O error (e.g. while reading bytes to upload).
IoError(io::Error),
/// The builder was misconfigured — a required field was missing, or client
/// construction failed for a reason we can describe.
ClientBuilderSetupError(String),
/// The object store accepted the request but returned a non-success status.
UploadFailed { status_code: u16, message: String },
}
impl fmt::Display for BucketClientError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::S3Error(err) => write!(f, "S3 error: {}", err),
Self::IoError(err) => write!(f, "I/O error: {}", err),
Self::ClientBuilderSetupError(message) => {
write!(f, "bucket client setup error: {}", message)
}
Self::UploadFailed { status_code, message } => {
write!(f, "upload failed (HTTP {}): {}", status_code, message)
}
}
}
}
impl std::error::Error for BucketClientError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::S3Error(err) => Some(err),
Self::IoError(err) => Some(err),
_ => None,
}
}
}
impl From<s3::error::S3Error> for BucketClientError {
fn from(err: s3::error::S3Error) -> Self {
Self::S3Error(err)
}
}
impl From<io::Error> for BucketClientError {
fn from(err: io::Error) -> Self {
Self::IoError(err)
}
}
@@ -1,15 +0,0 @@
//! bucket_client
//!
//! A small, ergonomic client for S3-compatible object storage, built on the
//! `rust-s3` crate. Construct one with [`BucketClientBuilder`] and upload bytes
//! with [`BucketClient::upload_file_bytes`].
pub mod bucket_client;
pub mod bucket_client_builder;
pub mod bucket_client_error;
pub mod object_name;
pub use bucket_client::{BucketClient, UploadFileBytesArgs};
pub use bucket_client_builder::BucketClientBuilder;
pub use bucket_client_error::BucketClientError;
pub use object_name::ObjectName;
@@ -1,52 +0,0 @@
use std::fmt;
/// A normalized object key for the bucket.
///
/// Leading slashes are stripped: S3/R2 treat a leading `/` as an empty leading
/// path segment, which silently produces surprising keys (e.g. `/foo.mp4`
/// becomes an object literally named `/foo.mp4`). Normalizing here keeps stored
/// keys consistent regardless of how callers format the name.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ObjectName(String);
impl ObjectName {
/// Build a normalized object name from any string-like value.
pub fn new(raw: impl AsRef<str>) -> Self {
ObjectName(raw.as_ref().trim_start_matches('/').to_string())
}
/// The normalized key as a string slice.
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for ObjectName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl AsRef<str> for ObjectName {
fn as_ref(&self) -> &str {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn strips_leading_slashes() {
assert_eq!(ObjectName::new("/foo/bar.mp4").as_str(), "foo/bar.mp4");
assert_eq!(ObjectName::new("///a").as_str(), "a");
assert_eq!(ObjectName::new("already/clean.txt").as_str(), "already/clean.txt");
}
#[test]
fn accepts_string_and_str() {
assert_eq!(ObjectName::new(String::from("x.bin")).as_str(), "x.bin");
assert_eq!(ObjectName::new("x.bin").as_str(), "x.bin");
}
}
@@ -17,7 +17,7 @@ use tokio::io::AsyncReadExt;
use errors::AnyhowResult;
#[derive(Clone)]
pub struct LegacyBucketClient {
pub struct BucketClient {
bucket: Bucket,
/// If set, put all files under this root path.
optional_bucket_root: Option<String>,
@@ -25,21 +25,21 @@ pub struct LegacyBucketClient {
#[derive(Debug)]
pub enum LegacyBucketClientError {
pub enum BucketClientError {
ErrorWithCodeAndMessage { code: u16, message: String },
}
impl std::fmt::Display for LegacyBucketClientError {
impl std::fmt::Display for BucketClientError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
LegacyBucketClientError::ErrorWithCodeAndMessage { code, message } => write!(f, "Error {}: {}", code, message),
BucketClientError::ErrorWithCodeAndMessage { code, message } => write!(f, "Error {}: {}", code, message),
}
}
}
impl Error for LegacyBucketClientError {}
impl Error for BucketClientError {}
impl LegacyBucketClient {
impl BucketClient {
pub fn bucket_name(&self) -> String {
self.bucket.name().to_string()
}
+1 -1
View File
@@ -1,2 +1,2 @@
pub mod legacy_bucket_client;
pub mod bucket_client;
pub mod remote_file_manager;
@@ -4,7 +4,7 @@ use tokio::time::Duration;
use errors::AnyhowResult;
use crate::legacy_bucket_client::LegacyBucketClient;
use crate::bucket_client::BucketClient;
#[async_trait]
#[deprecated(note="this abstraction is too complicated, use another bucket client")]
@@ -106,13 +106,13 @@ impl BucketOrchestration {
}
#[deprecated(note="this abstraction is too complicated, use another bucket client")]
async fn get_bucket_with_visibility(&self, public: bool) -> AnyhowResult<LegacyBucketClient> {
async fn get_bucket_with_visibility(&self, public: bool) -> AnyhowResult<BucketClient> {
let bucket_timeout = easyenv::get_env_duration_seconds_or_default(
"BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 10));
let bucket_client = if public {
// use public bucket client
info!("Configuring public GCS bucket...");
LegacyBucketClient::create(
BucketClient::create(
&self.access_key,
&self.secret_key,
&self.region_name,
@@ -123,7 +123,7 @@ impl BucketOrchestration {
)?
} else {
info!("Configuring private GCS bucket...");
LegacyBucketClient::create(
BucketClient::create(
&self.access_key,
&self.secret_key,
&self.region_name,
@@ -20,7 +20,7 @@ pub struct RemoteCloudFileClient {
impl RemoteCloudFileClient {
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `LegacyBucketClient`")]
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `BucketClient`")]
pub async fn get_remote_cloud_file_client() -> AnyhowResult<Self> {
let bucket_orchestration = match BucketOrchestration::new_bucket_client_from_existing_env() {
Ok(client) => client,
@@ -34,7 +34,7 @@ impl RemoteCloudFileClient {
})
}
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `LegacyBucketClient`")]
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `BucketClient`")]
pub fn new(bucket_orchestration_client: Box<dyn BucketOrchestrationCore>) -> Self {
Self {
bucket_orchestration_client
@@ -42,7 +42,7 @@ impl RemoteCloudFileClient {
}
// Where the to_system_file_path is let sd_checkpoint_path = work_temp_dir.path().join("sd_checkpoint.safetensors"); path and file name and extension
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `LegacyBucketClient`")]
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `BucketClient`")]
pub async fn download_file(&self, remote_cloud_bucket_details:RemoteCloudBucketDetails, to_system_file_path:String) -> AnyhowResult<()> {
let file_descriptor = remote_cloud_bucket_details.file_descriptor_from_bucket_details();
let file_bucket_directory = FileBucketDirectory::from_existing_bucket_details(remote_cloud_bucket_details);
@@ -53,7 +53,7 @@ impl RemoteCloudFileClient {
Ok(())
}
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `LegacyBucketClient`")]
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `BucketClient`")]
pub async fn download_media_file(&self, media_file_path: &MediaFileBucketPath, to_system_file_path: String) -> AnyhowResult<()> {
const IS_PUBLIC: bool = true; // NB: Media files are always public
let full_remote_cloud_file_path = media_file_path.get_full_object_path_str().to_string();
@@ -63,7 +63,7 @@ impl RemoteCloudFileClient {
}
// return error or success with meta data.
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `LegacyBucketClient`")]
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `BucketClient`")]
pub async fn upload_file(&self, file_descriptor:Box<dyn FileDescriptor>, from_system_file_path:&str) -> AnyhowResult<FileMetaData> {
// get file meta data
@@ -99,7 +99,7 @@ impl RemoteCloudFileClient {
}
// Retrieve the metadata from the file
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `LegacyBucketClient`")]
#[deprecated(note="DO NOT USE THIS AWFUL CLOUD BUCKET CLIENT. These abstractions are complicated. See `BucketClient`")]
pub fn get_file_meta_data(system_file_path:&str) -> AnyhowResult<FileMetaData> {
let file_size_bytes = file_size(system_file_path.clone())?;
let sha256_checksum = sha256_hash_file(system_file_path.clone())?;
@@ -2,12 +2,12 @@ use std::time::Duration;
use log::info;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use errors::AnyhowResult;
pub struct BucketClients {
pub public: LegacyBucketClient,
pub private: LegacyBucketClient,
pub public: BucketClient,
pub private: BucketClient,
}
pub fn get_bucket_clients() -> AnyhowResult<BucketClients> {
@@ -25,7 +25,7 @@ pub fn get_bucket_clients() -> AnyhowResult<BucketClients> {
info!("Configuring public GCS bucket...");
let public_bucket_client = LegacyBucketClient::create(
let public_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -37,7 +37,7 @@ pub fn get_bucket_clients() -> AnyhowResult<BucketClients> {
info!("Configuring private GCS bucket...");
let private_bucket_client = LegacyBucketClient::create(
let private_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -2,7 +2,7 @@ use log::info;
use sqlx::{MySql, Pool};
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
use enums::by_table::media_uploads::media_upload_type::MediaUploadType;
use enums::by_table::zs_voices::encoding_type::ZsVoiceEncodingType;
@@ -128,7 +128,7 @@ async fn create_voice_records(
Ok((voice_token, dataset_token))
}
async fn seed_file_to_bucket(wav_file: &str, bucket_client: &LegacyBucketClient) -> AnyhowResult<MediaFileBucketPath> {
async fn seed_file_to_bucket(wav_file: &str, bucket_client: &BucketClient) -> AnyhowResult<MediaFileBucketPath> {
info!("Uploading wav file {} ...", wav_file);
let public_upload_path = MediaFileBucketPath::generate_new(
@@ -4,7 +4,7 @@ use log::info;
use sqlx::mysql::MySqlPoolOptions;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use shared_env_var_config::logging::DEFAULT_RUST_LOG;
use shared_env_var_config::mysql::env_get_mysql_connection_string_or_default;
use enums::by_table::media_files::media_file_type::MediaFileType;
@@ -48,7 +48,7 @@ pub async fn main() -> AnyhowResult<()> {
info!("Configuring GCS bucket...");
let public_bucket_client = LegacyBucketClient::create(
let public_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -1,14 +1,14 @@
use sqlx::{MySql, Pool};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
pub struct Deps {
pub mysql_development : Pool<MySql>,
pub mysql_production : Pool<MySql>,
pub bucket_development_public: LegacyBucketClient,
pub bucket_development_private: LegacyBucketClient,
pub bucket_development_public: BucketClient,
pub bucket_development_private: BucketClient,
pub bucket_production_public: LegacyBucketClient,
pub bucket_production_private: LegacyBucketClient,
pub bucket_production_public: BucketClient,
pub bucket_production_private: BucketClient,
}
@@ -9,7 +9,7 @@ use log::info;
use sqlx::{MySql, Pool};
use sqlx::mysql::MySqlPoolOptions;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use shared_env_var_config::logging::DEFAULT_RUST_LOG;
use errors::AnyhowResult;
@@ -68,7 +68,7 @@ async fn get_mysql(env_var_name: &str) -> AnyhowResult<Pool<MySql>> {
Ok(pool)
}
pub fn get_bucket_client(env_var_suffix: &str) -> AnyhowResult<LegacyBucketClient> {
pub fn get_bucket_client(env_var_suffix: &str) -> AnyhowResult<BucketClient> {
let env_var_suffix = env_var_suffix.to_uppercase();
let access_key = easyenv::get_env_string_required(&format!("ACCESS_KEY_{env_var_suffix}"))?;
let secret_key = easyenv::get_env_string_required(&format!("SECRET_KEY_{env_var_suffix}"))?;
@@ -84,7 +84,7 @@ pub fn get_bucket_client(env_var_suffix: &str) -> AnyhowResult<LegacyBucketClien
info!("Configuring GCS bucket {env_var_suffix} ...");
Ok(LegacyBucketClient::create(
Ok(BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -6,7 +6,6 @@ pub (crate) mod artcraft_website;
pub (crate) mod development_only;
pub (crate) mod fakeyou;
pub (crate) mod legacy;
pub (crate) mod realseedance;
pub (crate) mod storyteller;
pub (crate) mod storyteller_board;
pub (crate) mod storyteller_render;
@@ -1,14 +0,0 @@
use actix_cors::Cors;
use crate::util::netlify_branch_domain_matches::netlify_branch_domain_matches;
/// CORS for the "Is That Real Seedance?" website (video-info-website).
pub fn add_realseedance(cors: Cors, _is_production: bool) -> Cors {
cors
// Actual domain
.allowed_origin("https://realseedance.com")
.allowed_origin("https://www.realseedance.com")
// Netlify project (bare domain + branch / deploy-preview subdomains)
.allowed_origin_fn(|origin, _req_head| {
netlify_branch_domain_matches(origin, "real-seedance.netlify.app")
})
}
-25
View File
@@ -9,7 +9,6 @@ use crate::configs::artcraft_website::add_artcraft_website;
use crate::configs::development_only::add_development_only;
use crate::configs::fakeyou::{add_fakeyou, add_fakeyou_dev_proxy};
use crate::configs::legacy::{add_legacy_storyteller_stream, add_legacy_trumped, add_legacy_vocodes, add_power_stream};
use crate::configs::realseedance::add_realseedance;
use crate::configs::storyteller::{add_storyteller, add_storyteller_dev_proxy};
use crate::configs::storyteller_board::add_storyteller_board;
use crate::configs::storyteller_render::add_storyteller_render;
@@ -53,7 +52,6 @@ fn do_build_cors_config(is_production: bool) -> Cors {
cors = add_artcraft_webapp(cors, is_production);
cors = add_artcraft_website(cors, is_production);
cors = add_artcraft_admin_dashboard(cors, is_production);
cors = add_realseedance(cors, is_production);
// Legacy
cors = add_legacy_trumped(cors, is_production);
@@ -119,9 +117,6 @@ mod tests {
"https://artcraft.ai",
"https://www.artcraft.ai",
"https://artcraft-dashboard.netlify.app",
"https://realseedance.com",
"https://www.realseedance.com",
"https://real-seedance.netlify.app",
];
for origin in origins {
assert_origin_ok(&production_cors, origin).await;
@@ -186,26 +181,6 @@ mod tests {
assert_origin_invalid(&development_cors, "https://staging.fakeyou.com").await;
}
#[actix_rt::test]
async fn test_realseedance_production() {
let production_cors = build_cors_config(ServerEnvironment::Production);
// Valid origins
assert_origin_ok(&production_cors, "https://realseedance.com").await;
assert_origin_ok(&production_cors, "https://www.realseedance.com").await;
assert_origin_ok(&production_cors, "https://real-seedance.netlify.app").await;
// Netlify deploy-preview / branch subdomain
assert_origin_ok(
&production_cors,
"https://deploy-preview-12--real-seedance.netlify.app",
)
.await;
// Invalid origins
assert_origin_invalid(&production_cors, "https://realseedance.fake.com").await;
assert_origin_invalid(&production_cors, "https://realseedance.netlify.app").await;
}
#[actix_rt::test]
async fn test_storyteller_production() {
let production_cors = build_cors_config(ServerEnvironment::Production);
-19
View File
@@ -1,19 +0,0 @@
[package]
name = "sha1_hash"
edition = "2024"
version = "0.0.1"
publish = false
[lib]
name = "sha1_hash"
path = "src/lib.rs"
[package.metadata.cargo-udeps.ignore]
normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
# External
sha1 = "0.10"
-17
View File
@@ -1,17 +0,0 @@
use std::fmt;
/// Errors produced while computing a SHA-1 hash.
#[derive(Debug)]
pub enum Sha1HashError {
/// The SHA-1 digest wasn't the expected 20 bytes. This should be unreachable
/// for a well-behaved SHA-1 implementation; it exists as a defensive guard.
UnexpectedDigestLength(usize),
}
impl fmt::Display for Sha1HashError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::error::Error for Sha1HashError {}
-11
View File
@@ -1,11 +0,0 @@
//! sha1_hash
//!
//! SHA-1 hashing utilities. The primary entry point is
//! [`sha1_hash_bytes_as_crockford`], which hashes bytes with SHA-1 and returns
//! the 20-byte digest as a lowercase Crockford base32 string (32 chars).
pub mod error;
pub mod sha1_hash_bytes_as_crockford;
pub use error::Sha1HashError;
pub use sha1_hash_bytes_as_crockford::sha1_hash_bytes_as_crockford;
@@ -1,74 +0,0 @@
use sha1::{Digest, Sha1};
use crate::error::Sha1HashError;
/// Lowercase Crockford base32 alphabet (excludes I, L, O, U). Matches the casing
/// used by the `tokens` crate's Crockford generators.
const CROCKFORD_LOWERCASE: &[u8] = b"0123456789abcdefghjkmnpqrstvwxyz";
/// The byte length of a SHA-1 digest.
const SHA1_DIGEST_LEN: usize = 20;
/// SHA-1 hash `bytes` and return the 20-byte digest encoded as a lowercase
/// Crockford base32 string (32 characters, no padding — 160 bits / 5).
pub fn sha1_hash_bytes_as_crockford(bytes: &[u8]) -> Result<String, Sha1HashError> {
let mut hasher = Sha1::new();
hasher.update(bytes);
let digest = hasher.finalize();
if digest.len() != SHA1_DIGEST_LEN {
return Err(Sha1HashError::UnexpectedDigestLength(digest.len()));
}
Ok(encode_crockford_lower(&digest))
}
/// Encode bytes as lowercase Crockford base32, reading 5 bits at a time.
fn encode_crockford_lower(data: &[u8]) -> String {
let mut out = String::with_capacity(data.len() * 8 / 5 + 1);
let mut buffer: u32 = 0;
let mut bits: u32 = 0;
for &byte in data {
buffer = (buffer << 8) | byte as u32;
bits += 8;
while bits >= 5 {
bits -= 5;
let index = ((buffer >> bits) & 0x1f) as usize;
out.push(CROCKFORD_LOWERCASE[index] as char);
}
}
if bits > 0 {
let index = ((buffer << (5 - bits)) & 0x1f) as usize;
out.push(CROCKFORD_LOWERCASE[index] as char);
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_input_is_32_crockford_chars() {
// SHA-1("") = da39a3ee5e6b4b0d3255bfef95601890afd80709
let out = sha1_hash_bytes_as_crockford(&[]).unwrap();
assert_eq!(out.len(), 32);
assert!(out.bytes().all(|b| CROCKFORD_LOWERCASE.contains(&b)));
}
#[test]
fn deterministic_and_distinct() {
let a = sha1_hash_bytes_as_crockford(b"hello").unwrap();
let b = sha1_hash_bytes_as_crockford(b"hello").unwrap();
let c = sha1_hash_bytes_as_crockford(b"world").unwrap();
assert_eq!(a, b);
assert_ne!(a, c);
assert_eq!(a.len(), 32);
}
#[test]
fn encodes_known_bytes() {
// 20 zero bytes → 32 '0' chars.
assert_eq!(encode_crockford_lower(&[0u8; 20]), "0".repeat(32));
}
}
@@ -37,8 +37,6 @@ pub mod trending_model_analytics;
pub mod tts;
pub mod twitch;
pub mod unsubscribe_reason;
pub mod uploaded_video_notes;
pub mod uploaded_videos;
pub mod user_impersonation_requests;
pub mod user_referral_codes;
pub mod user_referrals;
@@ -1,79 +0,0 @@
use std::marker::PhantomData;
use sqlx::{Executor, MySql};
use enums::by_table::uploaded_video_notes::uploaded_video_note_reported_model_type::UploadedVideoNoteReportedModelType;
use enums::by_table::uploaded_video_notes::uploaded_video_note_reported_website::UploadedVideoNoteReportedWebsite;
use tokens::tokens::uploaded_video_notes::UploadVideoNoteToken;
use tokens::tokens::uploaded_videos::UploadedVideoToken;
pub struct InsertUploadedVideoNoteArgs<'e, 'c, E>
where
E: 'e + Executor<'c, Database = MySql>,
{
pub uploaded_video_token: &'e UploadedVideoToken,
pub maybe_filename: Option<&'e str>,
pub maybe_reported_model_type: Option<UploadedVideoNoteReportedModelType>,
pub maybe_reported_model_name: Option<&'e str>,
pub maybe_website: Option<UploadedVideoNoteReportedWebsite>,
pub maybe_other_website: Option<&'e str>,
pub maybe_comments: Option<&'e str>,
pub maybe_email_address: Option<&'e str>,
pub can_share_report: bool,
pub was_scammed: bool,
pub comment_create_ip_address: &'e str,
pub mysql_executor: E,
pub phantom: PhantomData<&'c E>,
}
/// Insert a new `uploaded_video_notes` record. The `UploadVideoNoteToken` is
/// minted here (in the data-access layer, not the handler) and returned.
/// `created_at` is set to `NOW()`.
pub async fn insert_uploaded_video_note<'e, 'c: 'e, E>(
args: InsertUploadedVideoNoteArgs<'e, 'c, E>,
) -> Result<UploadVideoNoteToken, sqlx::Error>
where
E: 'e + Executor<'c, Database = MySql>,
{
let token = UploadVideoNoteToken::generate();
sqlx::query!(
r#"
INSERT INTO uploaded_video_notes
SET
token = ?,
uploaded_video_token = ?,
maybe_filename = ?,
maybe_reported_model_type = ?,
maybe_reported_model_name = ?,
maybe_website = ?,
maybe_other_website = ?,
maybe_comments = ?,
maybe_email_address = ?,
can_share_report = ?,
was_scammed = ?,
comment_create_ip_address = ?,
created_at = NOW()
"#,
token.as_str(),
args.uploaded_video_token.as_str(),
args.maybe_filename,
args.maybe_reported_model_type.map(|model_type| model_type.to_str()),
args.maybe_reported_model_name,
args.maybe_website.map(|website| website.to_str()),
args.maybe_other_website,
args.maybe_comments,
args.maybe_email_address,
args.can_share_report,
args.was_scammed,
args.comment_create_ip_address,
)
.execute(args.mysql_executor)
.await?;
Ok(token)
}
@@ -1,2 +0,0 @@
pub mod insert_uploaded_video_note;
pub mod update_uploaded_video_note;
@@ -1,77 +0,0 @@
use std::marker::PhantomData;
use sqlx::{Executor, MySql};
use enums::by_table::uploaded_video_notes::uploaded_video_note_reported_model_type::UploadedVideoNoteReportedModelType;
use enums::by_table::uploaded_video_notes::uploaded_video_note_reported_website::UploadedVideoNoteReportedWebsite;
use tokens::tokens::uploaded_video_notes::UploadVideoNoteToken;
pub struct UpdateUploadedVideoNoteArgs<'e, 'c, E>
where
E: 'e + Executor<'c, Database = MySql>,
{
pub token: &'e UploadVideoNoteToken,
pub maybe_filename: Option<&'e str>,
pub maybe_reported_model_type: Option<UploadedVideoNoteReportedModelType>,
pub maybe_reported_model_name: Option<&'e str>,
pub maybe_website: Option<UploadedVideoNoteReportedWebsite>,
pub maybe_other_website: Option<&'e str>,
pub maybe_comments: Option<&'e str>,
pub maybe_email_address: Option<&'e str>,
pub can_share_report: bool,
pub was_scammed: bool,
/// IP address of the request making the update; stamped on `maybe_comment_update_ip_address`.
pub maybe_comment_update_ip_address: Option<&'e str>,
pub mysql_executor: E,
pub phantom: PhantomData<&'c E>,
}
/// Update the mutable fields of an `uploaded_video_notes` record by `token`. The
/// `version` vector clock is incremented by 1, and `updated_at` is refreshed via
/// the column's `ON UPDATE` clause. Returns the number of rows affected (0 if no
/// row matched).
pub async fn update_uploaded_video_note<'e, 'c: 'e, E>(
args: UpdateUploadedVideoNoteArgs<'e, 'c, E>,
) -> Result<u64, sqlx::Error>
where
E: 'e + Executor<'c, Database = MySql>,
{
let result = sqlx::query!(
r#"
UPDATE uploaded_video_notes
SET
maybe_filename = ?,
maybe_reported_model_type = ?,
maybe_reported_model_name = ?,
maybe_website = ?,
maybe_other_website = ?,
maybe_comments = ?,
maybe_email_address = ?,
can_share_report = ?,
was_scammed = ?,
maybe_comment_update_ip_address = ?,
version = version + 1
WHERE token = ?
LIMIT 1
"#,
args.maybe_filename,
args.maybe_reported_model_type.map(|model_type| model_type.to_str()),
args.maybe_reported_model_name,
args.maybe_website.map(|website| website.to_str()),
args.maybe_other_website,
args.maybe_comments,
args.maybe_email_address,
args.can_share_report,
args.was_scammed,
args.maybe_comment_update_ip_address,
args.token.as_str(),
)
.execute(args.mysql_executor)
.await?;
Ok(result.rows_affected())
}
@@ -1,68 +0,0 @@
use std::marker::PhantomData;
use sqlx::{Executor, MySql};
use enums::by_table::uploaded_videos::uploaded_video_detected_model_family::UploadedVideoDetectedModelFamily;
use enums::by_table::uploaded_videos::uploaded_video_detected_model_type::UploadedVideoDetectedModelType;
use tokens::tokens::uploaded_videos::UploadedVideoToken;
use crate::queries::uploaded_videos::uploaded_video_row::UploadedVideoRow;
pub struct GetUploadedVideoBySha1ChecksumArgs<'e, 'c, E>
where
E: 'e + Executor<'c, Database = MySql>,
{
pub sha1_checksum: &'e str,
pub mysql_executor: E,
pub phantom: PhantomData<&'c E>,
}
/// Look up an `uploaded_videos` record by its `sha1_checksum`. `Ok(None)` if no
/// row matches. Useful for de-duplicating re-uploads of the same bytes.
pub async fn get_uploaded_video_by_sha1_checksum<'e, 'c: 'e, E>(
args: GetUploadedVideoBySha1ChecksumArgs<'e, 'c, E>,
) -> Result<Option<UploadedVideoRow>, sqlx::Error>
where
E: 'e + Executor<'c, Database = MySql>,
{
let result = sqlx::query!(
r#"
SELECT
token as `token: UploadedVideoToken`,
sha1_checksum,
filesize_bytes as `filesize_bytes: u32`,
maybe_width as `maybe_width: u32`,
maybe_height as `maybe_height: u32`,
maybe_resolution,
maybe_detected_model_family as `maybe_detected_model_family: UploadedVideoDetectedModelFamily`,
maybe_detected_model_type as `maybe_detected_model_type: UploadedVideoDetectedModelType`,
maybe_report,
upload_ip_address,
maybe_updated_ip_address,
created_at,
updated_at
FROM uploaded_videos
WHERE sha1_checksum = ?
LIMIT 1
"#,
args.sha1_checksum,
)
.fetch_optional(args.mysql_executor)
.await?;
Ok(result.map(|r| UploadedVideoRow {
token: r.token,
sha1_checksum: r.sha1_checksum,
filesize_bytes: r.filesize_bytes,
maybe_width: r.maybe_width,
maybe_height: r.maybe_height,
maybe_resolution: r.maybe_resolution,
maybe_detected_model_family: r.maybe_detected_model_family,
maybe_detected_model_type: r.maybe_detected_model_type,
maybe_report: r.maybe_report,
upload_ip_address: r.upload_ip_address,
maybe_updated_ip_address: r.maybe_updated_ip_address,
created_at: r.created_at,
updated_at: r.updated_at,
}))
}
@@ -1,67 +0,0 @@
use std::marker::PhantomData;
use sqlx::{Executor, MySql};
use enums::by_table::uploaded_videos::uploaded_video_detected_model_family::UploadedVideoDetectedModelFamily;
use enums::by_table::uploaded_videos::uploaded_video_detected_model_type::UploadedVideoDetectedModelType;
use tokens::tokens::uploaded_videos::UploadedVideoToken;
use crate::queries::uploaded_videos::uploaded_video_row::UploadedVideoRow;
pub struct GetUploadedVideoByTokenArgs<'e, 'c, E>
where
E: 'e + Executor<'c, Database = MySql>,
{
pub token: &'e UploadedVideoToken,
pub mysql_executor: E,
pub phantom: PhantomData<&'c E>,
}
/// Look up an `uploaded_videos` record by its `token`. `Ok(None)` if no row matches.
pub async fn get_uploaded_video_by_token<'e, 'c: 'e, E>(
args: GetUploadedVideoByTokenArgs<'e, 'c, E>,
) -> Result<Option<UploadedVideoRow>, sqlx::Error>
where
E: 'e + Executor<'c, Database = MySql>,
{
let result = sqlx::query!(
r#"
SELECT
token as `token: UploadedVideoToken`,
sha1_checksum,
filesize_bytes as `filesize_bytes: u32`,
maybe_width as `maybe_width: u32`,
maybe_height as `maybe_height: u32`,
maybe_resolution,
maybe_detected_model_family as `maybe_detected_model_family: UploadedVideoDetectedModelFamily`,
maybe_detected_model_type as `maybe_detected_model_type: UploadedVideoDetectedModelType`,
maybe_report,
upload_ip_address,
maybe_updated_ip_address,
created_at,
updated_at
FROM uploaded_videos
WHERE token = ?
LIMIT 1
"#,
args.token.as_str(),
)
.fetch_optional(args.mysql_executor)
.await?;
Ok(result.map(|r| UploadedVideoRow {
token: r.token,
sha1_checksum: r.sha1_checksum,
filesize_bytes: r.filesize_bytes,
maybe_width: r.maybe_width,
maybe_height: r.maybe_height,
maybe_resolution: r.maybe_resolution,
maybe_detected_model_family: r.maybe_detected_model_family,
maybe_detected_model_type: r.maybe_detected_model_type,
maybe_report: r.maybe_report,
upload_ip_address: r.upload_ip_address,
maybe_updated_ip_address: r.maybe_updated_ip_address,
created_at: r.created_at,
updated_at: r.updated_at,
}))
}
@@ -1,75 +0,0 @@
use std::marker::PhantomData;
use sqlx::{Executor, MySql};
use enums::by_table::uploaded_videos::uploaded_video_detected_model_family::UploadedVideoDetectedModelFamily;
use enums::by_table::uploaded_videos::uploaded_video_detected_model_type::UploadedVideoDetectedModelType;
use tokens::tokens::uploaded_videos::UploadedVideoToken;
pub struct InsertUploadedVideoArgs<'e, 'c, E>
where
E: 'e + Executor<'c, Database = MySql>,
{
pub sha1_checksum: &'e str,
pub filesize_bytes: u32,
pub maybe_filename: Option<&'e str>,
pub maybe_width: Option<u32>,
pub maybe_height: Option<u32>,
pub maybe_resolution: Option<&'e str>,
pub maybe_detected_model_family: Option<UploadedVideoDetectedModelFamily>,
pub maybe_detected_model_type: Option<UploadedVideoDetectedModelType>,
pub maybe_report: Option<&'e str>,
pub upload_ip_address: &'e str,
pub mysql_executor: E,
pub phantom: PhantomData<&'c E>,
}
/// Insert a new `uploaded_videos` record. The `UploadedVideoToken` is minted
/// here (in the data-access layer, not the handler) and returned. `created_at`
/// is set to `NOW()`.
pub async fn insert_uploaded_video<'e, 'c: 'e, E>(
args: InsertUploadedVideoArgs<'e, 'c, E>,
) -> Result<UploadedVideoToken, sqlx::Error>
where
E: 'e + Executor<'c, Database = MySql>,
{
let token = UploadedVideoToken::generate();
sqlx::query!(
r#"
INSERT INTO uploaded_videos
SET
token = ?,
sha1_checksum = ?,
filesize_bytes = ?,
maybe_filename = ?,
maybe_width = ?,
maybe_height = ?,
maybe_resolution = ?,
maybe_detected_model_family = ?,
maybe_detected_model_type = ?,
maybe_report = ?,
upload_ip_address = ?,
created_at = NOW()
"#,
token.as_str(),
args.sha1_checksum,
args.filesize_bytes,
args.maybe_filename,
args.maybe_width,
args.maybe_height,
args.maybe_resolution,
args.maybe_detected_model_family.map(|family| family.to_str()),
args.maybe_detected_model_type.map(|model_type| model_type.to_str()),
args.maybe_report,
args.upload_ip_address,
)
.execute(args.mysql_executor)
.await?;
Ok(token)
}
@@ -1,5 +0,0 @@
pub mod get_uploaded_video_by_sha1_checksum;
pub mod get_uploaded_video_by_token;
pub mod insert_uploaded_video;
pub mod update_uploaded_video;
pub mod uploaded_video_row;
@@ -1,72 +0,0 @@
use std::marker::PhantomData;
use sqlx::{Executor, MySql};
use enums::by_table::uploaded_videos::uploaded_video_detected_model_family::UploadedVideoDetectedModelFamily;
use enums::by_table::uploaded_videos::uploaded_video_detected_model_type::UploadedVideoDetectedModelType;
use tokens::tokens::uploaded_videos::UploadedVideoToken;
pub struct UpdateUploadedVideoArgs<'e, 'c, E>
where
E: 'e + Executor<'c, Database = MySql>,
{
pub token: &'e UploadedVideoToken,
pub maybe_filename: Option<&'e str>,
pub maybe_width: Option<u32>,
pub maybe_height: Option<u32>,
pub maybe_resolution: Option<&'e str>,
pub maybe_detected_model_family: Option<UploadedVideoDetectedModelFamily>,
pub maybe_detected_model_type: Option<UploadedVideoDetectedModelType>,
pub maybe_report: Option<&'e str>,
/// IP address of the request making the update; stamped on `maybe_updated_ip_address`.
pub maybe_updated_ip_address: Option<&'e str>,
pub mysql_executor: E,
pub phantom: PhantomData<&'c E>,
}
/// Update the mutable fields of an `uploaded_videos` record by `token`
/// (dimensions, detection, report, updater IP). The `version` vector clock is
/// incremented by 1, and `updated_at` is refreshed via the column's `ON UPDATE`
/// clause. Returns the number of rows affected (0 if no row matched).
pub async fn update_uploaded_video<'e, 'c: 'e, E>(
args: UpdateUploadedVideoArgs<'e, 'c, E>,
) -> Result<u64, sqlx::Error>
where
E: 'e + Executor<'c, Database = MySql>,
{
let result = sqlx::query!(
r#"
UPDATE uploaded_videos
SET
maybe_filename = ?,
maybe_width = ?,
maybe_height = ?,
maybe_resolution = ?,
maybe_detected_model_family = ?,
maybe_detected_model_type = ?,
maybe_report = ?,
maybe_updated_ip_address = ?,
version = version + 1
WHERE token = ?
LIMIT 1
"#,
args.maybe_filename,
args.maybe_width,
args.maybe_height,
args.maybe_resolution,
args.maybe_detected_model_family.map(|family| family.to_str()),
args.maybe_detected_model_type.map(|model_type| model_type.to_str()),
args.maybe_report,
args.maybe_updated_ip_address,
args.token.as_str(),
)
.execute(args.mysql_executor)
.await?;
Ok(result.rows_affected())
}
@@ -1,28 +0,0 @@
use chrono::{DateTime, Utc};
use enums::by_table::uploaded_videos::uploaded_video_detected_model_family::UploadedVideoDetectedModelFamily;
use enums::by_table::uploaded_videos::uploaded_video_detected_model_type::UploadedVideoDetectedModelType;
use tokens::tokens::uploaded_videos::UploadedVideoToken;
/// A materialized `uploaded_videos` row (minus the internal `id`).
#[derive(Debug, Clone)]
pub struct UploadedVideoRow {
pub token: UploadedVideoToken,
pub sha1_checksum: String,
pub filesize_bytes: u32,
pub maybe_width: Option<u32>,
pub maybe_height: Option<u32>,
pub maybe_resolution: Option<String>,
pub maybe_detected_model_family: Option<UploadedVideoDetectedModelFamily>,
pub maybe_detected_model_type: Option<UploadedVideoDetectedModelType>,
pub maybe_report: Option<String>,
pub upload_ip_address: String,
pub maybe_updated_ip_address: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
@@ -21,8 +21,6 @@ pub mod staff_audit_logs;
pub mod tag_uses;
pub mod trending_model_analytics;
pub mod tts_models;
pub mod uploaded_video_notes;
pub mod uploaded_videos;
pub mod usages;
pub mod user_bookmarks;
pub mod user_ratings;
@@ -1,2 +0,0 @@
pub mod uploaded_video_note_reported_model_type;
pub mod uploaded_video_note_reported_website;
@@ -1,253 +0,0 @@
use std::collections::BTreeSet;
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
use utoipa::ToSchema;
/// Used in the `uploaded_video_notes` table in a `VARCHAR(32)` field.
///
/// The model the note's submitter claims the video is. The variant set mirrors
/// [`crate::common::generation::common_video_model::CommonVideoModel`].
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
pub enum UploadedVideoNoteReportedModelType {
#[serde(rename = "grok_video")]
GrokVideo,
#[serde(rename = "grok_imagine_video")]
GrokImagineVideo,
#[serde(rename = "grok_imagine_video_1p5")]
GrokImagineVideo1p5,
#[serde(rename = "kling_1p6_pro")]
Kling16Pro,
#[serde(rename = "kling_2p1_pro")]
Kling21Pro,
#[serde(rename = "kling_2p1_master")]
Kling21Master,
#[serde(rename = "kling_2p5_turbo_pro")]
Kling2p5TurboPro,
#[serde(rename = "kling_2p6_pro")]
Kling2p6Pro,
#[serde(rename = "kling_3p0_standard")]
Kling3p0Standard,
#[serde(rename = "kling_3p0_pro")]
Kling3p0Pro,
#[serde(rename = "happy_horse_1p0")]
HappyHorse1p0,
#[serde(rename = "seedance_1p0_lite")]
Seedance10Lite,
#[serde(rename = "seedance_1p5_pro")]
Seedance1p5Pro,
// `preview_model` is a retired alias that collapses onto Seedance 2.0.
#[serde(rename = "seedance_2p0", alias = "preview_model")]
Seedance2p0,
// `preview_model_fast` is a retired alias that collapses onto Seedance 2.0 Fast.
#[serde(rename = "seedance_2p0_fast", alias = "preview_model_fast")]
Seedance2p0Fast,
#[serde(rename = "seedance_2p0_bp")]
Seedance2p0BytePlus,
#[serde(rename = "seedance_2p0_bp_fast")]
Seedance2p0BytePlusFast,
#[serde(rename = "seedance_2p0_u")]
Seedance2p0Ultra,
#[serde(rename = "seedance_2p0_u_fast")]
Seedance2p0UltraFast,
#[serde(rename = "seedance_2p0_bpu")]
Seedance2p0BytePlusUltra,
#[serde(rename = "seedance_2p0_bpu_fast")]
Seedance2p0BytePlusUltraFast,
#[serde(rename = "sora_2")]
Sora2,
#[serde(rename = "sora_2_pro")]
Sora2Pro,
#[serde(rename = "veo_2")]
Veo2,
#[serde(rename = "veo_3")]
Veo3,
#[serde(rename = "veo_3_fast")]
Veo3Fast,
#[serde(rename = "veo_3p1")]
Veo3p1,
#[serde(rename = "veo_3p1_fast")]
Veo3p1Fast,
}
impl_enum_display_and_debug_using_to_str!(UploadedVideoNoteReportedModelType);
impl_mysql_enum_coders!(UploadedVideoNoteReportedModelType);
impl_mysql_from_row!(UploadedVideoNoteReportedModelType);
impl UploadedVideoNoteReportedModelType {
pub fn to_str(&self) -> &'static str {
match self {
Self::GrokVideo => "grok_video",
Self::GrokImagineVideo => "grok_imagine_video",
Self::GrokImagineVideo1p5 => "grok_imagine_video_1p5",
Self::Kling16Pro => "kling_1p6_pro",
Self::Kling21Pro => "kling_2p1_pro",
Self::Kling21Master => "kling_2p1_master",
Self::Kling2p5TurboPro => "kling_2p5_turbo_pro",
Self::Kling2p6Pro => "kling_2p6_pro",
Self::Kling3p0Standard => "kling_3p0_standard",
Self::Kling3p0Pro => "kling_3p0_pro",
Self::HappyHorse1p0 => "happy_horse_1p0",
Self::Seedance10Lite => "seedance_1p0_lite",
Self::Seedance1p5Pro => "seedance_1p5_pro",
Self::Seedance2p0 => "seedance_2p0",
Self::Seedance2p0Fast => "seedance_2p0_fast",
Self::Seedance2p0BytePlus => "seedance_2p0_bp",
Self::Seedance2p0BytePlusFast => "seedance_2p0_bp_fast",
Self::Seedance2p0Ultra => "seedance_2p0_u",
Self::Seedance2p0UltraFast => "seedance_2p0_u_fast",
Self::Seedance2p0BytePlusUltra => "seedance_2p0_bpu",
Self::Seedance2p0BytePlusUltraFast => "seedance_2p0_bpu_fast",
Self::Sora2 => "sora_2",
Self::Sora2Pro => "sora_2_pro",
Self::Veo2 => "veo_2",
Self::Veo3 => "veo_3",
Self::Veo3Fast => "veo_3_fast",
Self::Veo3p1 => "veo_3p1",
Self::Veo3p1Fast => "veo_3p1_fast",
}
}
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"grok_video" => Ok(Self::GrokVideo),
"grok_imagine_video" => Ok(Self::GrokImagineVideo),
"grok_imagine_video_1p5" => Ok(Self::GrokImagineVideo1p5),
"kling_1p6_pro" => Ok(Self::Kling16Pro),
"kling_2p1_pro" => Ok(Self::Kling21Pro),
"kling_2p1_master" => Ok(Self::Kling21Master),
"kling_2p5_turbo_pro" => Ok(Self::Kling2p5TurboPro),
"kling_2p6_pro" => Ok(Self::Kling2p6Pro),
"kling_3p0_standard" => Ok(Self::Kling3p0Standard),
"kling_3p0_pro" => Ok(Self::Kling3p0Pro),
"happy_horse_1p0" => Ok(Self::HappyHorse1p0),
"seedance_1p0_lite" => Ok(Self::Seedance10Lite),
"seedance_1p5_pro" => Ok(Self::Seedance1p5Pro),
"seedance_2p0" => Ok(Self::Seedance2p0),
"seedance_2p0_fast" => Ok(Self::Seedance2p0Fast),
"seedance_2p0_bp" => Ok(Self::Seedance2p0BytePlus),
"seedance_2p0_bp_fast" => Ok(Self::Seedance2p0BytePlusFast),
"seedance_2p0_u" => Ok(Self::Seedance2p0Ultra),
"seedance_2p0_u_fast" => Ok(Self::Seedance2p0UltraFast),
"seedance_2p0_bpu" => Ok(Self::Seedance2p0BytePlusUltra),
"seedance_2p0_bpu_fast" => Ok(Self::Seedance2p0BytePlusUltraFast),
"sora_2" => Ok(Self::Sora2),
"sora_2_pro" => Ok(Self::Sora2Pro),
"veo_2" => Ok(Self::Veo2),
"veo_3" => Ok(Self::Veo3),
"veo_3_fast" => Ok(Self::Veo3Fast),
"veo_3p1" => Ok(Self::Veo3p1),
"veo_3p1_fast" => Ok(Self::Veo3p1Fast),
// Retired values: collapse onto the Seedance 2.0 equivalents.
"preview_model" => Ok(Self::Seedance2p0),
"preview_model_fast" => Ok(Self::Seedance2p0Fast),
_ => Err(format!("invalid value: {:?}", value)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
BTreeSet::from([
Self::GrokVideo,
Self::GrokImagineVideo,
Self::GrokImagineVideo1p5,
Self::Kling16Pro,
Self::Kling21Pro,
Self::Kling21Master,
Self::Kling2p5TurboPro,
Self::Kling2p6Pro,
Self::Kling3p0Standard,
Self::Kling3p0Pro,
Self::HappyHorse1p0,
Self::Seedance10Lite,
Self::Seedance1p5Pro,
Self::Seedance2p0,
Self::Seedance2p0Fast,
Self::Seedance2p0BytePlus,
Self::Seedance2p0BytePlusFast,
Self::Seedance2p0Ultra,
Self::Seedance2p0UltraFast,
Self::Seedance2p0BytePlusUltra,
Self::Seedance2p0BytePlusUltraFast,
Self::Sora2,
Self::Sora2Pro,
Self::Veo2,
Self::Veo3,
Self::Veo3Fast,
Self::Veo3p1,
Self::Veo3p1Fast,
])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip() {
for variant in UploadedVideoNoteReportedModelType::all_variants() {
assert_eq!(variant, UploadedVideoNoteReportedModelType::from_str(variant.to_str()).unwrap());
assert_eq!(variant, UploadedVideoNoteReportedModelType::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, UploadedVideoNoteReportedModelType::from_str(&format!("{:?}", variant)).unwrap());
}
assert!(UploadedVideoNoteReportedModelType::from_str("foo").is_err());
}
#[test]
fn serde_round_trip() {
for variant in UploadedVideoNoteReportedModelType::all_variants() {
let json = serde_json::to_string(&variant).unwrap();
let deserialized: UploadedVideoNoteReportedModelType = serde_json::from_str(&json).unwrap();
assert_eq!(variant, deserialized);
}
}
/// The MySQL string (to_str) and the JSON string (serde) must stay aligned.
#[test]
fn to_str_matches_serde() {
for variant in UploadedVideoNoteReportedModelType::all_variants() {
let json = serde_json::to_string(&variant).unwrap();
assert_eq!(json, format!("\"{}\"", variant.to_str()));
}
}
#[test]
fn variant_count() {
use strum::IntoEnumIterator;
assert_eq!(UploadedVideoNoteReportedModelType::all_variants().len(), UploadedVideoNoteReportedModelType::iter().len());
assert_eq!(UploadedVideoNoteReportedModelType::COUNT, 28);
}
/// Retired `preview_model*` values must still decode, collapsing onto Seedance 2.0.
#[test]
fn legacy_preview_values_map_to_seedance() {
assert_eq!(
UploadedVideoNoteReportedModelType::from_str("preview_model").unwrap(),
UploadedVideoNoteReportedModelType::Seedance2p0
);
assert_eq!(
UploadedVideoNoteReportedModelType::from_str("preview_model_fast").unwrap(),
UploadedVideoNoteReportedModelType::Seedance2p0Fast
);
let decoded: UploadedVideoNoteReportedModelType =
serde_json::from_str("\"preview_model\"").unwrap();
assert_eq!(decoded, UploadedVideoNoteReportedModelType::Seedance2p0);
}
#[test]
fn serialized_length_ok_for_database() {
const MAX_LENGTH: usize = 32;
for variant in UploadedVideoNoteReportedModelType::all_variants() {
let serialized = variant.to_str();
assert!(!serialized.is_empty(), "variant {:?} is too short", variant);
assert!(serialized.len() <= MAX_LENGTH, "variant {:?} is too long", variant);
}
}
}
@@ -1,122 +0,0 @@
use std::collections::BTreeSet;
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
use utoipa::ToSchema;
/// Used in the `uploaded_video_notes` table in a `VARCHAR(32)` field.
///
/// The website / platform the note's submitter says the video came from.
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum UploadedVideoNoteReportedWebsite {
Runway,
Higgsfield,
Krea,
OpenArt,
Artcraft,
Magnific,
FreePik,
}
impl_enum_display_and_debug_using_to_str!(UploadedVideoNoteReportedWebsite);
impl_mysql_enum_coders!(UploadedVideoNoteReportedWebsite);
impl_mysql_from_row!(UploadedVideoNoteReportedWebsite);
impl UploadedVideoNoteReportedWebsite {
pub fn to_str(&self) -> &'static str {
match self {
Self::Runway => "runway",
Self::Higgsfield => "higgsfield",
Self::Krea => "krea",
Self::OpenArt => "open_art",
Self::Artcraft => "artcraft",
Self::Magnific => "magnific",
Self::FreePik => "free_pik",
}
}
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"runway" => Ok(Self::Runway),
"higgsfield" => Ok(Self::Higgsfield),
"krea" => Ok(Self::Krea),
"open_art" => Ok(Self::OpenArt),
"artcraft" => Ok(Self::Artcraft),
"magnific" => Ok(Self::Magnific),
"free_pik" => Ok(Self::FreePik),
_ => Err(format!("invalid value: {:?}", value)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
BTreeSet::from([
Self::Runway,
Self::Higgsfield,
Self::Krea,
Self::OpenArt,
Self::Artcraft,
Self::Magnific,
Self::FreePik,
])
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_helpers::assert_serialization;
#[test]
fn test_serialization() {
assert_serialization(UploadedVideoNoteReportedWebsite::Runway, "runway");
assert_serialization(UploadedVideoNoteReportedWebsite::Higgsfield, "higgsfield");
assert_serialization(UploadedVideoNoteReportedWebsite::Krea, "krea");
assert_serialization(UploadedVideoNoteReportedWebsite::OpenArt, "open_art");
assert_serialization(UploadedVideoNoteReportedWebsite::Artcraft, "artcraft");
assert_serialization(UploadedVideoNoteReportedWebsite::Magnific, "magnific");
assert_serialization(UploadedVideoNoteReportedWebsite::FreePik, "free_pik");
}
#[test]
fn round_trip() {
for variant in UploadedVideoNoteReportedWebsite::all_variants() {
assert_eq!(variant, UploadedVideoNoteReportedWebsite::from_str(variant.to_str()).unwrap());
assert_eq!(variant, UploadedVideoNoteReportedWebsite::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, UploadedVideoNoteReportedWebsite::from_str(&format!("{:?}", variant)).unwrap());
}
assert!(UploadedVideoNoteReportedWebsite::from_str("foo").is_err());
}
#[test]
fn to_str_matches_serde() {
for variant in UploadedVideoNoteReportedWebsite::all_variants() {
let json = serde_json::to_string(&variant).unwrap();
assert_eq!(json, format!("\"{}\"", variant.to_str()));
}
}
#[test]
fn variant_count() {
use strum::IntoEnumIterator;
assert_eq!(UploadedVideoNoteReportedWebsite::all_variants().len(), UploadedVideoNoteReportedWebsite::iter().len());
assert_eq!(UploadedVideoNoteReportedWebsite::COUNT, 7);
}
#[test]
fn serialized_length_ok_for_database() {
const MAX_LENGTH: usize = 32;
for variant in UploadedVideoNoteReportedWebsite::all_variants() {
let serialized = variant.to_str();
assert!(!serialized.is_empty(), "variant {:?} is too short", variant);
assert!(serialized.len() <= MAX_LENGTH, "variant {:?} is too long", variant);
}
}
}
@@ -1,2 +0,0 @@
pub mod uploaded_video_detected_model_family;
pub mod uploaded_video_detected_model_type;
@@ -1,117 +0,0 @@
use std::collections::BTreeSet;
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
use utoipa::ToSchema;
/// Used in the `uploaded_videos` table in a `VARCHAR(32)` field.
///
/// The detected provenance family of an uploaded video.
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum UploadedVideoDetectedModelFamily {
Seedance,
Veo,
Sora,
Kling,
Grok,
HappyHorse,
}
impl_enum_display_and_debug_using_to_str!(UploadedVideoDetectedModelFamily);
impl_mysql_enum_coders!(UploadedVideoDetectedModelFamily);
impl_mysql_from_row!(UploadedVideoDetectedModelFamily);
impl UploadedVideoDetectedModelFamily {
pub fn to_str(&self) -> &'static str {
match self {
Self::Seedance => "seedance",
Self::Veo => "veo",
Self::Sora => "sora",
Self::Kling => "kling",
Self::Grok => "grok",
Self::HappyHorse => "happy_horse",
}
}
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"seedance" => Ok(Self::Seedance),
"veo" => Ok(Self::Veo),
"sora" => Ok(Self::Sora),
"kling" => Ok(Self::Kling),
"grok" => Ok(Self::Grok),
"happy_horse" => Ok(Self::HappyHorse),
_ => Err(format!("invalid value: {:?}", value)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
BTreeSet::from([
Self::Seedance,
Self::Veo,
Self::Sora,
Self::Kling,
Self::Grok,
Self::HappyHorse,
])
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_helpers::assert_serialization;
#[test]
fn test_serialization() {
assert_serialization(UploadedVideoDetectedModelFamily::Seedance, "seedance");
assert_serialization(UploadedVideoDetectedModelFamily::Veo, "veo");
assert_serialization(UploadedVideoDetectedModelFamily::Sora, "sora");
assert_serialization(UploadedVideoDetectedModelFamily::Kling, "kling");
assert_serialization(UploadedVideoDetectedModelFamily::Grok, "grok");
assert_serialization(UploadedVideoDetectedModelFamily::HappyHorse, "happy_horse");
}
#[test]
fn round_trip() {
for variant in UploadedVideoDetectedModelFamily::all_variants() {
assert_eq!(variant, UploadedVideoDetectedModelFamily::from_str(variant.to_str()).unwrap());
assert_eq!(variant, UploadedVideoDetectedModelFamily::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, UploadedVideoDetectedModelFamily::from_str(&format!("{:?}", variant)).unwrap());
}
assert!(UploadedVideoDetectedModelFamily::from_str("foo").is_err());
}
#[test]
fn to_str_matches_serde() {
for variant in UploadedVideoDetectedModelFamily::all_variants() {
let json = serde_json::to_string(&variant).unwrap();
assert_eq!(json, format!("\"{}\"", variant.to_str()));
}
}
#[test]
fn variant_count() {
use strum::IntoEnumIterator;
assert_eq!(UploadedVideoDetectedModelFamily::all_variants().len(), UploadedVideoDetectedModelFamily::iter().len());
assert_eq!(UploadedVideoDetectedModelFamily::COUNT, 6);
}
#[test]
fn serialized_length_ok_for_database() {
const MAX_LENGTH: usize = 32;
for variant in UploadedVideoDetectedModelFamily::all_variants() {
let serialized = variant.to_str();
assert!(!serialized.is_empty(), "variant {:?} is too short", variant);
assert!(serialized.len() <= MAX_LENGTH, "variant {:?} is too long", variant);
}
}
}
@@ -1,253 +0,0 @@
use std::collections::BTreeSet;
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
use utoipa::ToSchema;
/// Used in the `uploaded_videos` table in a `VARCHAR(32)` field.
///
/// The detected model / variant of an uploaded video. The variant set mirrors
/// [`crate::common::generation::common_video_model::CommonVideoModel`].
///
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
pub enum UploadedVideoDetectedModelType {
#[serde(rename = "grok_video")]
GrokVideo,
#[serde(rename = "grok_imagine_video")]
GrokImagineVideo,
#[serde(rename = "grok_imagine_video_1p5")]
GrokImagineVideo1p5,
#[serde(rename = "kling_1p6_pro")]
Kling16Pro,
#[serde(rename = "kling_2p1_pro")]
Kling21Pro,
#[serde(rename = "kling_2p1_master")]
Kling21Master,
#[serde(rename = "kling_2p5_turbo_pro")]
Kling2p5TurboPro,
#[serde(rename = "kling_2p6_pro")]
Kling2p6Pro,
#[serde(rename = "kling_3p0_standard")]
Kling3p0Standard,
#[serde(rename = "kling_3p0_pro")]
Kling3p0Pro,
#[serde(rename = "happy_horse_1p0")]
HappyHorse1p0,
#[serde(rename = "seedance_1p0_lite")]
Seedance10Lite,
#[serde(rename = "seedance_1p5_pro")]
Seedance1p5Pro,
// `preview_model` is a retired alias that collapses onto Seedance 2.0.
#[serde(rename = "seedance_2p0", alias = "preview_model")]
Seedance2p0,
// `preview_model_fast` is a retired alias that collapses onto Seedance 2.0 Fast.
#[serde(rename = "seedance_2p0_fast", alias = "preview_model_fast")]
Seedance2p0Fast,
#[serde(rename = "seedance_2p0_bp")]
Seedance2p0BytePlus,
#[serde(rename = "seedance_2p0_bp_fast")]
Seedance2p0BytePlusFast,
#[serde(rename = "seedance_2p0_u")]
Seedance2p0Ultra,
#[serde(rename = "seedance_2p0_u_fast")]
Seedance2p0UltraFast,
#[serde(rename = "seedance_2p0_bpu")]
Seedance2p0BytePlusUltra,
#[serde(rename = "seedance_2p0_bpu_fast")]
Seedance2p0BytePlusUltraFast,
#[serde(rename = "sora_2")]
Sora2,
#[serde(rename = "sora_2_pro")]
Sora2Pro,
#[serde(rename = "veo_2")]
Veo2,
#[serde(rename = "veo_3")]
Veo3,
#[serde(rename = "veo_3_fast")]
Veo3Fast,
#[serde(rename = "veo_3p1")]
Veo3p1,
#[serde(rename = "veo_3p1_fast")]
Veo3p1Fast,
}
impl_enum_display_and_debug_using_to_str!(UploadedVideoDetectedModelType);
impl_mysql_enum_coders!(UploadedVideoDetectedModelType);
impl_mysql_from_row!(UploadedVideoDetectedModelType);
impl UploadedVideoDetectedModelType {
pub fn to_str(&self) -> &'static str {
match self {
Self::GrokVideo => "grok_video",
Self::GrokImagineVideo => "grok_imagine_video",
Self::GrokImagineVideo1p5 => "grok_imagine_video_1p5",
Self::Kling16Pro => "kling_1p6_pro",
Self::Kling21Pro => "kling_2p1_pro",
Self::Kling21Master => "kling_2p1_master",
Self::Kling2p5TurboPro => "kling_2p5_turbo_pro",
Self::Kling2p6Pro => "kling_2p6_pro",
Self::Kling3p0Standard => "kling_3p0_standard",
Self::Kling3p0Pro => "kling_3p0_pro",
Self::HappyHorse1p0 => "happy_horse_1p0",
Self::Seedance10Lite => "seedance_1p0_lite",
Self::Seedance1p5Pro => "seedance_1p5_pro",
Self::Seedance2p0 => "seedance_2p0",
Self::Seedance2p0Fast => "seedance_2p0_fast",
Self::Seedance2p0BytePlus => "seedance_2p0_bp",
Self::Seedance2p0BytePlusFast => "seedance_2p0_bp_fast",
Self::Seedance2p0Ultra => "seedance_2p0_u",
Self::Seedance2p0UltraFast => "seedance_2p0_u_fast",
Self::Seedance2p0BytePlusUltra => "seedance_2p0_bpu",
Self::Seedance2p0BytePlusUltraFast => "seedance_2p0_bpu_fast",
Self::Sora2 => "sora_2",
Self::Sora2Pro => "sora_2_pro",
Self::Veo2 => "veo_2",
Self::Veo3 => "veo_3",
Self::Veo3Fast => "veo_3_fast",
Self::Veo3p1 => "veo_3p1",
Self::Veo3p1Fast => "veo_3p1_fast",
}
}
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"grok_video" => Ok(Self::GrokVideo),
"grok_imagine_video" => Ok(Self::GrokImagineVideo),
"grok_imagine_video_1p5" => Ok(Self::GrokImagineVideo1p5),
"kling_1p6_pro" => Ok(Self::Kling16Pro),
"kling_2p1_pro" => Ok(Self::Kling21Pro),
"kling_2p1_master" => Ok(Self::Kling21Master),
"kling_2p5_turbo_pro" => Ok(Self::Kling2p5TurboPro),
"kling_2p6_pro" => Ok(Self::Kling2p6Pro),
"kling_3p0_standard" => Ok(Self::Kling3p0Standard),
"kling_3p0_pro" => Ok(Self::Kling3p0Pro),
"happy_horse_1p0" => Ok(Self::HappyHorse1p0),
"seedance_1p0_lite" => Ok(Self::Seedance10Lite),
"seedance_1p5_pro" => Ok(Self::Seedance1p5Pro),
"seedance_2p0" => Ok(Self::Seedance2p0),
"seedance_2p0_fast" => Ok(Self::Seedance2p0Fast),
"seedance_2p0_bp" => Ok(Self::Seedance2p0BytePlus),
"seedance_2p0_bp_fast" => Ok(Self::Seedance2p0BytePlusFast),
"seedance_2p0_u" => Ok(Self::Seedance2p0Ultra),
"seedance_2p0_u_fast" => Ok(Self::Seedance2p0UltraFast),
"seedance_2p0_bpu" => Ok(Self::Seedance2p0BytePlusUltra),
"seedance_2p0_bpu_fast" => Ok(Self::Seedance2p0BytePlusUltraFast),
"sora_2" => Ok(Self::Sora2),
"sora_2_pro" => Ok(Self::Sora2Pro),
"veo_2" => Ok(Self::Veo2),
"veo_3" => Ok(Self::Veo3),
"veo_3_fast" => Ok(Self::Veo3Fast),
"veo_3p1" => Ok(Self::Veo3p1),
"veo_3p1_fast" => Ok(Self::Veo3p1Fast),
// Retired values: collapse onto the Seedance 2.0 equivalents.
"preview_model" => Ok(Self::Seedance2p0),
"preview_model_fast" => Ok(Self::Seedance2p0Fast),
_ => Err(format!("invalid value: {:?}", value)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
BTreeSet::from([
Self::GrokVideo,
Self::GrokImagineVideo,
Self::GrokImagineVideo1p5,
Self::Kling16Pro,
Self::Kling21Pro,
Self::Kling21Master,
Self::Kling2p5TurboPro,
Self::Kling2p6Pro,
Self::Kling3p0Standard,
Self::Kling3p0Pro,
Self::HappyHorse1p0,
Self::Seedance10Lite,
Self::Seedance1p5Pro,
Self::Seedance2p0,
Self::Seedance2p0Fast,
Self::Seedance2p0BytePlus,
Self::Seedance2p0BytePlusFast,
Self::Seedance2p0Ultra,
Self::Seedance2p0UltraFast,
Self::Seedance2p0BytePlusUltra,
Self::Seedance2p0BytePlusUltraFast,
Self::Sora2,
Self::Sora2Pro,
Self::Veo2,
Self::Veo3,
Self::Veo3Fast,
Self::Veo3p1,
Self::Veo3p1Fast,
])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip() {
for variant in UploadedVideoDetectedModelType::all_variants() {
assert_eq!(variant, UploadedVideoDetectedModelType::from_str(variant.to_str()).unwrap());
assert_eq!(variant, UploadedVideoDetectedModelType::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, UploadedVideoDetectedModelType::from_str(&format!("{:?}", variant)).unwrap());
}
assert!(UploadedVideoDetectedModelType::from_str("foo").is_err());
}
#[test]
fn serde_round_trip() {
for variant in UploadedVideoDetectedModelType::all_variants() {
let json = serde_json::to_string(&variant).unwrap();
let deserialized: UploadedVideoDetectedModelType = serde_json::from_str(&json).unwrap();
assert_eq!(variant, deserialized);
}
}
/// The MySQL string (to_str) and the JSON string (serde) must stay aligned.
#[test]
fn to_str_matches_serde() {
for variant in UploadedVideoDetectedModelType::all_variants() {
let json = serde_json::to_string(&variant).unwrap();
assert_eq!(json, format!("\"{}\"", variant.to_str()));
}
}
#[test]
fn variant_count() {
use strum::IntoEnumIterator;
assert_eq!(UploadedVideoDetectedModelType::all_variants().len(), UploadedVideoDetectedModelType::iter().len());
assert_eq!(UploadedVideoDetectedModelType::COUNT, 28);
}
/// Retired `preview_model*` values must still decode, collapsing onto Seedance 2.0.
#[test]
fn legacy_preview_values_map_to_seedance() {
assert_eq!(
UploadedVideoDetectedModelType::from_str("preview_model").unwrap(),
UploadedVideoDetectedModelType::Seedance2p0
);
assert_eq!(
UploadedVideoDetectedModelType::from_str("preview_model_fast").unwrap(),
UploadedVideoDetectedModelType::Seedance2p0Fast
);
let decoded: UploadedVideoDetectedModelType =
serde_json::from_str("\"preview_model\"").unwrap();
assert_eq!(decoded, UploadedVideoDetectedModelType::Seedance2p0);
}
#[test]
fn serialized_length_ok_for_database() {
const MAX_LENGTH: usize = 32;
for variant in UploadedVideoDetectedModelType::all_variants() {
let serialized = variant.to_str();
assert!(!serialized.is_empty(), "variant {:?} is too short", variant);
assert!(serialized.len() <= MAX_LENGTH, "variant {:?} is too long", variant);
}
}
}
@@ -46,8 +46,6 @@ pub(crate) enum TokenPrefix {
StaffAuditLog,
Tag,
TtsRenderTask, // NB: aichatbot / sqlite
UploadedVideo,
UploadedVideoNote,
User,
UserImpersonationRequest,
UserBookmark,
@@ -138,8 +136,6 @@ impl PrefixGenerator for TokenPrefix {
Self::StaffAuditLog => "stfaud_",
Self::Tag => "tag_",
Self::TtsRenderTask => "tts_task_",
Self::UploadedVideo => "uvt_",
Self::UploadedVideoNote => "uvnote_",
Self::User => "user_", // NB: Previously "U:"
Self::UserImpersonationRequest => "uimpr_",
Self::UserBookmark => "ub_",
@@ -31,8 +31,6 @@ pub mod tts_results;
pub mod twitch_event_rule;
pub mod twitch_oauth_tokens_grouping;
pub mod twitch_oauth_tokens_internal;
pub mod uploaded_video_notes;
pub mod uploaded_videos;
pub mod user_bookmarks;
pub mod user_impersonation_requests;
pub mod user_referral_codes;
@@ -1,17 +0,0 @@
use std::fmt::Debug;
use serde::Deserialize;
use serde::Serialize;
use utoipa::ToSchema;
use crate::prefixes::TokenPrefix;
/// The primary key for uploaded_video_notes.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize, ToSchema)]
#[cfg_attr(feature = "database", derive(sqlx::Type))]
#[cfg_attr(feature = "database", sqlx(transparent))]
pub struct UploadVideoNoteToken(pub String);
impl_string_token!(UploadVideoNoteToken);
impl_mysql_token_from_row!(UploadVideoNoteToken);
impl_crockford_generator!(UploadVideoNoteToken, 32usize, TokenPrefix::UploadedVideoNote, CrockfordLower);
@@ -1,17 +0,0 @@
use std::fmt::Debug;
use serde::Deserialize;
use serde::Serialize;
use utoipa::ToSchema;
use crate::prefixes::TokenPrefix;
/// The primary key for uploaded_videos.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize, ToSchema)]
#[cfg_attr(feature = "database", derive(sqlx::Type))]
#[cfg_attr(feature = "database", sqlx(transparent))]
pub struct UploadedVideoToken(pub String);
impl_string_token!(UploadedVideoToken);
impl_mysql_token_from_row!(UploadedVideoToken);
impl_crockford_generator!(UploadedVideoToken, 32usize, TokenPrefix::UploadedVideo, CrockfordLower);
@@ -5,7 +5,7 @@ use r2d2_redis::RedisConnectionManager;
use sqlx::MySqlPool;
use bootstrap::bootstrap::ContainerEnvironment;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use google_drive_downloader::google_drive_download_command::GoogleDriveDownloadCommand;
use mysql_queries::common_inputs::container_environment_arg::ContainerEnvironmentArg;
@@ -33,8 +33,8 @@ pub struct JobState {
pub redis_pool: r2d2::Pool<RedisConnectionManager>,
pub public_bucket_client: LegacyBucketClient,
pub private_bucket_client: LegacyBucketClient,
pub public_bucket_client: BucketClient,
pub private_bucket_client: BucketClient,
pub firehose_publisher: FirehosePublisher,
pub badge_granter: BadgeGranter,
@@ -4,7 +4,7 @@ use anyhow::anyhow;
use log::info;
use tempdir::TempDir;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use errors::AnyhowResult;
use filesys::create_dir_all_if_missing::create_dir_all_if_missing;
use filesys::file_exists::file_exists;
@@ -38,7 +38,7 @@ impl PretrainedHubertModel {
pub async fn download_if_not_on_filesystem(
&self,
bucket_client: &LegacyBucketClient,
bucket_client: &BucketClient,
temp_dir: &TempDir,
) -> AnyhowResult<()> {
if file_exists(&self.filesystem_path) {
@@ -28,7 +28,7 @@ use sqlx::mysql::MySqlPoolOptions;
use tokio::runtime::Runtime;
use bootstrap::bootstrap::{bootstrap, BootstrapArgs};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use config::common_env::CommonEnv;
use shared_env_var_config::logging::DEFAULT_RUST_LOG;
@@ -96,7 +96,7 @@ async fn main() -> AnyhowResult<()> {
let bucket_timeout = easyenv::get_env_duration_seconds_or_default("BUCKET_TIMEOUT_SECONDS",
Duration::from_secs(60 * 5));
let private_bucket_client = LegacyBucketClient::create(
let private_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -106,7 +106,7 @@ async fn main() -> AnyhowResult<()> {
Some(bucket_timeout),
)?;
let public_bucket_client = LegacyBucketClient::create(
let public_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -5,7 +5,7 @@ use log::{debug, error, info, warn};
use tempdir::TempDir;
use bucket_paths::legacy::typified_paths::public::weight_files::bucket_directory::WeightFileBucketDirectory;
use bucket_paths::legacy::typified_paths::public::weight_files::bucket_file_path::WeightFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use filesys::rename_across_devices::{rename_across_devices, RenameError};
use filesys::file_deletion::safe_delete_directory::safe_delete_directory;
use tokens::tokens::model_weights::ModelWeightToken;
@@ -18,7 +18,7 @@ pub async fn download_package(
model_weight_token: ModelWeightToken,
weights_file_bucket_directory: &WeightFileBucketDirectory,
download_directory: &Path,
bucket_client: &LegacyBucketClient,
bucket_client: &BucketClient,
scoped_tempdir_creator: &ScopedTempDirCreator,
force_download: bool,
) -> Result<(), ProcessSingleJobError> {
@@ -69,7 +69,7 @@ pub async fn do_download_package(
model_weight_token: ModelWeightToken,
weights_file_bucket_directory: &WeightFileBucketDirectory,
download_directory: &Path,
bucket_client: &LegacyBucketClient,
bucket_client: &BucketClient,
temp_dir: &TempDir,
force_download: bool,
entry: GptSovitsPackageFileType,
@@ -5,7 +5,7 @@ use zip::ZipArchive;
use bucket_paths::legacy::typified_paths::public::weight_files::bucket_directory::WeightFileBucketDirectory;
use bucket_paths::legacy::typified_paths::public::weight_files::bucket_file_path::WeightFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use filesys::path_to_string::path_to_string;
use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes;
@@ -14,7 +14,7 @@ use crate::job::job_types::gpt_sovits::upload_model::get_gptsovits_zip_entries::
pub async fn extract_and_upload_gpt_sovits_package_files(
zip_container_file_bytes: &[u8],
bucket_client: &LegacyBucketClient,
bucket_client: &BucketClient,
weights_file_bucket_directory: &WeightFileBucketDirectory,
) -> Result<GptSovitsPackageDetails, GptSovitsPackageError> {
let cursor = Cursor::new(zip_container_file_bytes);
@@ -8,7 +8,7 @@ use tempdir::TempDir;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use bucket_paths::legacy::typified_paths::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath;
use bucket_paths::legacy::typified_paths::public::voice_conversion_results::bucket_file_path::VoiceConversionResultOriginalFilePath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter;
use mysql_queries::payloads::generic_inference_args::inner_payloads::lipsync_payload::LipsyncAnimationAudioSource;
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
@@ -28,7 +28,7 @@ pub struct AudioFile {
pub struct DownloadAudioFileArgs<'a> {
pub audio_source: &'a LipsyncAnimationAudioSource,
pub public_bucket_client: &'a LegacyBucketClient,
pub public_bucket_client: &'a BucketClient,
pub job_progress_reporter: &'a mut Box<dyn JobProgressReporter>,
pub job: &'a AvailableInferenceJob,
pub temp_dir_creator: &'a ScopedTempDirCreator,
@@ -7,7 +7,7 @@ use tempdir::TempDir;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use bucket_paths::legacy::typified_paths::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter;
use mysql_queries::payloads::generic_inference_args::inner_payloads::lipsync_payload::LipsyncAnimationImageSource;
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
@@ -26,7 +26,7 @@ pub struct ImageFile {
pub struct DownloadImageFileArgs<'a> {
pub image_source: &'a LipsyncAnimationImageSource,
pub public_bucket_client: &'a LegacyBucketClient,
pub public_bucket_client: &'a BucketClient,
pub job_progress_reporter: &'a mut Box<dyn JobProgressReporter>,
pub job: &'a AvailableInferenceJob,
pub temp_dir_creator: &'a ScopedTempDirCreator,
@@ -7,7 +7,7 @@ use tempdir::TempDir;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use bucket_paths::legacy::typified_paths::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter;
use mysql_queries::payloads::generic_inference_args::inner_payloads::mocap_payload::MocapVideoSource;
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
@@ -27,7 +27,7 @@ pub struct VideoFile {
// TODO: Replace with remote cloud client
pub async fn download_video_file(
video_source: &MocapVideoSource,
public_bucket_client: &LegacyBucketClient,
public_bucket_client: &BucketClient,
job_progress_reporter: &mut Box<dyn JobProgressReporter>,
job: &AvailableInferenceJob,
temp_dir_creator: &ScopedTempDirCreator,
@@ -8,7 +8,7 @@ use log::{error, info, warn};
use bucket_paths::legacy::typified_paths::private::zs_voices::bucket_directory::{ModelCategory, ModelType};
use bucket_paths::legacy::typified_paths::private::zs_voices::bucket_file_path::ZeroShotVoiceEmbeddingBucketPath;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
use enums::by_table::zs_voices::encoding_type::ZsVoiceEncodingType;
@@ -295,7 +295,7 @@ pub struct AudioFile {
pub async fn download_audio_from_hash(
bucket_hash: &str,
name: &str,
private_bucket_client: &LegacyBucketClient,
private_bucket_client: &BucketClient,
path: &PathBuf
) -> Result<AudioFile, ProcessSingleJobError> {
let unifer = BucketPathUnifier::default_paths();
@@ -8,7 +8,7 @@ use log::{error, info, warn};
use bucket_paths::legacy::typified_paths::private::zs_voices::bucket_directory::{ModelCategory, ModelType};
use bucket_paths::legacy::typified_paths::private::zs_voices::bucket_file_path::ZeroShotVoiceEmbeddingBucketPath;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
@@ -244,7 +244,7 @@ pub struct VoiceFile {
pub async fn download_voice_embedding_from_hash(
bucket_hash: &str,
name: &str,
private_bucket_client: &LegacyBucketClient,
private_bucket_client: &BucketClient,
path: &PathBuf
) -> Result<VoiceFile, ProcessSingleJobError> {
let unifer = BucketPathUnifier::default_paths();
@@ -271,7 +271,7 @@ pub async fn download_voice_embedding_from_hash(
pub async fn download_voice_embedding(
voice: &ZsVoice,
private_bucket_client: &LegacyBucketClient,
private_bucket_client: &BucketClient,
download_path: &PathBuf,
) -> Result<VoiceFile, ProcessSingleJobError> {
@@ -8,7 +8,7 @@ use log::{error, info, warn};
use bucket_paths::legacy::typified_paths::private::zs_voices::bucket_directory::{ModelCategory, ModelType};
use bucket_paths::legacy::typified_paths::private::zs_voices::bucket_file_path::ZeroShotVoiceEmbeddingBucketPath;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
use enums::by_table::zs_voices::encoding_type::ZsVoiceEncodingType;
@@ -316,7 +316,7 @@ pub struct AudioFile {
pub async fn download_audio_from_hash(
bucket_hash: &str,
name: &str,
private_bucket_client: &LegacyBucketClient,
private_bucket_client: &BucketClient,
path: &PathBuf
) -> Result<AudioFile, ProcessSingleJobError> {
let unifer = BucketPathUnifier::default_paths();
@@ -8,7 +8,7 @@ use log::{error, info, warn};
use bucket_paths::legacy::typified_paths::private::zs_voices::bucket_directory::{ModelCategory, ModelType};
use bucket_paths::legacy::typified_paths::private::zs_voices::bucket_file_path::ZeroShotVoiceEmbeddingBucketPath;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
@@ -260,7 +260,7 @@ pub struct VoiceFile {
pub async fn download_voice_embedding_from_hash(
bucket_hash: &str,
name: &str,
private_bucket_client: &LegacyBucketClient,
private_bucket_client: &BucketClient,
path: &PathBuf
) -> Result<VoiceFile, ProcessSingleJobError> {
let unifer = BucketPathUnifier::default_paths();
@@ -287,7 +287,7 @@ pub async fn download_voice_embedding_from_hash(
pub async fn download_voice_embedding(
voice: &ZsVoice,
private_bucket_client: &LegacyBucketClient,
private_bucket_client: &BucketClient,
download_path: &PathBuf,
) -> Result<VoiceFile, ProcessSingleJobError> {
@@ -3,7 +3,7 @@ use std::path::PathBuf;
use anyhow::anyhow;
use log::{error, info};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use filesys::create_dir_all_if_missing::create_dir_all_if_missing;
use filesys::file_exists::file_exists;
use filesys::rename_across_devices::rename_across_devices;
@@ -41,7 +41,7 @@ impl PretrainedHubertModel {
pub async fn download_if_not_on_filesystem(
&self,
bucket_client: &LegacyBucketClient,
bucket_client: &BucketClient,
scoped_tempdir_creator: &ScopedTempDirCreator,
) -> Result<(), ProcessSingleJobError> {
if file_exists(&self.filesystem_path) {
@@ -4,7 +4,7 @@ use anyhow::anyhow;
use tempdir::TempDir;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter;
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
use mysql_queries::queries::model_weights::get::get_weight::RetrievedModelWeight;
@@ -19,7 +19,7 @@ pub struct ModelFile {
// TODO replace this with remote cloud file manager.
pub async fn download_model_file(
model_record: &Option<RetrievedModelWeight>,
public_bucket_client: &LegacyBucketClient,
public_bucket_client: &BucketClient,
job_progress_reporter: &mut Box<dyn JobProgressReporter>,
job: &AvailableInferenceJob,
temp_dir_creator: &ScopedTempDirCreator,
@@ -7,7 +7,7 @@ use tempdir::TempDir;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use bucket_paths::legacy::typified_paths::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter;
use mysql_queries::payloads::generic_inference_args::inner_payloads::videofilter_payload::VideofilterVideoSource;
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
@@ -26,7 +26,7 @@ pub struct VideoFile {
// TODO replace this with remote cloud file manager.
pub async fn download_video_file(
video_source: &VideofilterVideoSource,
public_bucket_client: &LegacyBucketClient,
public_bucket_client: &BucketClient,
job_progress_reporter: &mut Box<dyn JobProgressReporter>,
job: &AvailableInferenceJob,
temp_dir_creator: &ScopedTempDirCreator,
@@ -1,5 +1,5 @@
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use filesys::file_read_bytes::file_read_bytes;
use log::{debug, warn};
use std::path::PathBuf;
@@ -20,12 +20,12 @@ pub enum BucketUploadMessage {
UploadFrame {
disk_path: PathBuf,
bucket_path: MediaFileBucketPath,
bucket_client: LegacyBucketClient,
bucket_client: BucketClient,
result: oneshot::Sender<BucketUploadResult>
},
UploadMultipleFrames {
requests: Vec<BucketUploadRequest>,
bucket_client: LegacyBucketClient,
bucket_client: BucketClient,
result: oneshot::Sender<Vec<(PathBuf, BucketUploadResult)>>,
},
}
@@ -39,7 +39,7 @@ struct BucketUploadActor {
rx: mpsc::Receiver<BucketUploadMessage>,
}
fn handle_single_frame_upload(disk_path: PathBuf, bucket_path: MediaFileBucketPath, bucket_client: LegacyBucketClient) -> (PathBuf,BucketUploadResult) {
fn handle_single_frame_upload(disk_path: PathBuf, bucket_path: MediaFileBucketPath, bucket_client: BucketClient) -> (PathBuf,BucketUploadResult) {
let disk_path2 = disk_path.clone();
let handle = tokio::runtime::Handle::current();
let attempt = handle.block_on(
@@ -139,7 +139,7 @@ impl BucketUploadActorHandle {
}
}
pub async fn upload_frame(&self, disk_path: PathBuf, bucket_path: MediaFileBucketPath, bucket_client: LegacyBucketClient) -> () {
pub async fn upload_frame(&self, disk_path: PathBuf, bucket_path: MediaFileBucketPath, bucket_client: BucketClient) -> () {
let (tx, rx) = oneshot::channel();
let message = BucketUploadMessage::UploadFrame {
disk_path,
@@ -151,7 +151,7 @@ impl BucketUploadActorHandle {
let _ = rx.await;
}
pub async fn upload_multiple_frames(&self, requests: Vec<BucketUploadRequest>, bucket_client: LegacyBucketClient) -> Vec<(PathBuf,BucketUploadResult)> {
pub async fn upload_multiple_frames(&self, requests: Vec<BucketUploadRequest>, bucket_client: BucketClient) -> Vec<(PathBuf,BucketUploadResult)> {
let (tx, rx) = oneshot::channel();
let message = BucketUploadMessage::UploadMultipleFrames {
requests,
@@ -14,7 +14,7 @@ use crate::job::job_types::workflow::video_style_transfer::util::preview_process
use crate::job::job_types::workflow::video_style_transfer::util::preview_processor::dir_walker::{DirWalker, PathBatch};
use bucket_paths::legacy::typified_paths::public::media_files::bucket_directory::MediaFileBucketDirectory;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use crockford::crockford_entropy_lower;
use redis_schema::keys::inference_job::style_transfer_progress_key::StyleTransferProgressKey;
use redis_schema::payloads::inference_job::style_transfer_progress_state::{InferenceProgressDetailsResponse, InferenceStageDetails};
@@ -306,7 +306,7 @@ impl StageDirectoryState {
}
async fn upload_frame_from_disk(&self, bucket_client: &LegacyBucketClient, frame_number: u32, disk_path: PathBuf) -> PreviewFrameUpdate {
async fn upload_frame_from_disk(&self, bucket_client: &BucketClient, frame_number: u32, disk_path: PathBuf) -> PreviewFrameUpdate {
let local_file_extension = match disk_path.extension().and_then(|s| s.to_str()) {
Some(e) => {
if ALLOWED_TYPES_FRAMES.contains(e) {
@@ -355,7 +355,7 @@ impl StageDirectoryState {
}
}
async fn upload_frame_from_disk_with_retry(&self, bucket_client: &LegacyBucketClient, frame_number: u32, disk_path: PathBuf) -> PreviewFrameUpdate {
async fn upload_frame_from_disk_with_retry(&self, bucket_client: &BucketClient, frame_number: u32, disk_path: PathBuf) -> PreviewFrameUpdate {
let mut retries = 0;
loop {
if retries > 3 {
@@ -385,7 +385,7 @@ impl StageDirectoryState {
}
async fn upload_multiple_frames_from_disk(&self, bucket_client: &LegacyBucketClient, frames: Vec<(u32, PathBuf)>) -> Vec<PreviewFrameUpdate> {
async fn upload_multiple_frames_from_disk(&self, bucket_client: &BucketClient, frames: Vec<(u32, PathBuf)>) -> Vec<PreviewFrameUpdate> {
let mut bucket_upload_requests = Vec::with_capacity(frames.len());
let mut updates = Vec::with_capacity(frames.len());
@@ -635,7 +635,7 @@ impl PreviewProcessor {
let _r: String = redis.set_ex(key.to_string(), serde_json::to_string(&status).unwrap(), expire_at).unwrap();
}
pub async fn start_processing(&mut self, bucket_client: &LegacyBucketClient) -> () {
pub async fn start_processing(&mut self, bucket_client: &BucketClient) -> () {
let (frames_tx, mut frames_rx) = mpsc::channel(100);
let walker = DirWalker::new_with_batch_size(self.base_directory.clone(), frames_tx.clone(), 30);
let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(5));
@@ -693,7 +693,7 @@ impl PreviewProcessor {
}
}
pub async fn process_upload(&mut self, bucket_client: &LegacyBucketClient, disk_path: PathBuf) -> () {
pub async fn process_upload(&mut self, bucket_client: &BucketClient, disk_path: PathBuf) -> () {
if !self.is_disk_path_valid(&disk_path) {
log::warn!("Invalid disk path: {:?}", disk_path);
return;
@@ -707,7 +707,7 @@ impl PreviewProcessor {
};
}
async fn process_batch_upload(&mut self, bucket_client: &LegacyBucketClient, disk_paths: PathBatch) -> () {
async fn process_batch_upload(&mut self, bucket_client: &BucketClient, disk_paths: PathBatch) -> () {
let mut paths_by_stage: HashMap<PreviewStage, Vec<(u32, PathBuf)>> = HashMap::new();
for disk_path in disk_paths.get_paths() {
if !self.is_disk_path_valid(&disk_path) {
@@ -749,7 +749,7 @@ impl PreviewProcessor {
}
}
async fn upload_frame_from_disk(&self, stage: PreviewStage, frame_number: u32, bucket_client: &LegacyBucketClient, disk_path: PathBuf) -> PreviewFrameUploadResult {
async fn upload_frame_from_disk(&self, stage: PreviewStage, frame_number: u32, bucket_client: &BucketClient, disk_path: PathBuf) -> PreviewFrameUploadResult {
let stage_state = self.stages.get(&stage).unwrap();
if stage_state.state == PreviewStageState::UploadComplete {
log::debug!("Skipped re-uploading frame: {:?}", disk_path);
@@ -28,7 +28,7 @@ use sqlx::mysql::MySqlPoolOptions;
use bootstrap::bootstrap::{bootstrap, BootstrapArgs};
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use config::common_env::CommonEnv;
use shared_env_var_config::logging::DEFAULT_RUST_LOG;
@@ -117,7 +117,7 @@ async fn main() -> AnyhowResult<()> {
let bucket_timeout = easyenv::get_env_duration_seconds_or_default("BUCKET_TIMEOUT_SECONDS",
Duration::from_secs(60 * 5));
let private_bucket_client = LegacyBucketClient::create(
let private_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -127,7 +127,7 @@ async fn main() -> AnyhowResult<()> {
Some(bucket_timeout),
)?;
let public_bucket_client = LegacyBucketClient::create(
let public_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -137,7 +137,7 @@ async fn main() -> AnyhowResult<()> {
Some(bucket_timeout),
)?;
let auto_gc_bucket_client = LegacyBucketClient::create(
let auto_gc_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -10,7 +10,7 @@ use r2d2_redis::RedisConnectionManager;
use sqlx::MySqlPool;
use bootstrap::bootstrap::ContainerEnvironment;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporterBuilder;
@@ -135,9 +135,9 @@ pub struct DatabaseDependencies {
}
pub struct BucketDependencies {
pub private_bucket_client: LegacyBucketClient,
pub public_bucket_client: LegacyBucketClient,
pub auto_gc_bucket_client: LegacyBucketClient,
pub private_bucket_client: BucketClient,
pub public_bucket_client: BucketClient,
pub auto_gc_bucket_client: BucketClient,
pub bucket_path_unifier: BucketPathUnifier,
}
@@ -2,7 +2,7 @@ use std::path::Path;
use log::{error, info, warn};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use filesys::file_size::file_size;
use filesys::rename_across_devices::{rename_across_devices, RenameError};
use filesys::file_deletion::safe_delete_directory::safe_delete_directory;
@@ -19,7 +19,7 @@ pub struct MaybeDownloadArgs<'a> {
pub name_or_description_of_file: &'a str,
pub final_filesystem_file_path: &'a Path,
pub bucket_object_path: &'a Path,
pub bucket_client: &'a LegacyBucketClient,
pub bucket_client: &'a BucketClient,
pub job_progress_reporter: &'a mut Box<dyn JobProgressReporter>,
pub job_progress_update_description: &'a str,
pub job_id: i64,
@@ -4,7 +4,7 @@ use anyhow::anyhow;
use async_trait::async_trait;
use log::{error, info};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use filesys::create_dir_all_if_missing::create_dir_all_if_missing;
use filesys::file_exists::file_exists;
use filesys::rename_across_devices::{rename_across_devices, RenameError};
@@ -29,7 +29,7 @@ pub trait ModelDownloader {
async fn download_if_not_on_filesystem(
&self,
bucket_client: &LegacyBucketClient,
bucket_client: &BucketClient,
scoped_tempdir_creator: &ScopedTempDirCreator,
) -> Result<(), ProcessSingleJobError> {
let filesystem_path = self.get_filesystem_path();
@@ -4,7 +4,7 @@ use std::sync::Arc;
use log::{error, info, warn};
use bucket_paths::legacy::typified_paths::public::weight_files::bucket_file_path::WeightFileBucketPath;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use errors::AnyhowResult;
use filesys::file_size::file_size;
use filesys::rename_across_devices::{rename_across_devices, RenameError};
@@ -26,7 +26,7 @@ pub struct ModelWeightsCacheDirectory {
pub scoped_tempdir_creator: ScopedTempDirCreator,
/// A client to download from the public bucket.
pub public_bucket_client: LegacyBucketClient,
pub public_bucket_client: BucketClient,
/// NB: Sometimes the downloader incompletely downloads files. Typically, this is a zero file
/// size, but the Rust system may report a non-zero (but small) number of bytes. This should
@@ -49,7 +49,7 @@ impl ModelWeightsCacheDirectory {
/// Configure and try to create the directory if it doesn't exist.
pub fn setup_from_env_and_deps(
scoped_temp_dir_creator: &ScopedTempDirCreator,
public_bucket_client: &LegacyBucketClient,
public_bucket_client: &BucketClient,
) -> AnyhowResult<Self> {
let directory = easyenv::get_env_pathbuf_or_default(
"MODEL_WEIGHTS_CACHE_DIR",
@@ -28,7 +28,7 @@ use sqlx::mysql::MySqlPoolOptions;
use sqlx::MySqlPool;
use tempdir::TempDir;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use config::bad_urls::is_bad_tts_model_download_url;
use config::common_env::CommonEnv;
@@ -74,7 +74,7 @@ struct Downloader {
pub redis_pool: r2d2::Pool<RedisConnectionManager>,
pub bucket_client: LegacyBucketClient,
pub bucket_client: BucketClient,
pub firehose_publisher: FirehosePublisher,
pub badge_granter: BadgeGranter,
pub google_drive_downloader: GoogleDriveDownloadCommand,
@@ -128,7 +128,7 @@ async fn main() -> AnyhowResult<()> {
let bucket_timeout = easyenv::get_env_duration_seconds_or_default("BUCKET_TIMEOUT_SECONDS",
Duration::from_secs(60 * 5));
let bucket_client = LegacyBucketClient::create(
let bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -2,7 +2,7 @@ use std::path::Path;
use log::{info, warn};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter;
use crate::{ProcessSingleJobError, ScopedTempDirCreator};
@@ -13,7 +13,7 @@ pub async fn maybe_download_file_from_bucket(
name_or_description_of_file: &str,
file_path: &Path,
bucket_object_path: &Path,
bucket_client: &LegacyBucketClient,
bucket_client: &BucketClient,
job_progress_reporter: &mut Box<dyn JobProgressReporter>,
job_progress_update_description: &str,
job_id: i64,
@@ -2,7 +2,7 @@ use std::path::PathBuf;
use sqlx::MySqlPool;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporterBuilder;
use jobs_common::job_stats::JobStats;
@@ -25,8 +25,8 @@ pub struct JobArgs {
pub job_progress_reporter: Box<dyn JobProgressReporterBuilder>,
pub private_bucket_client: LegacyBucketClient,
pub public_bucket_client: LegacyBucketClient,
pub private_bucket_client: BucketClient,
pub public_bucket_client: BucketClient,
pub firehose_publisher: FirehosePublisher,
@@ -25,7 +25,7 @@ use r2d2_redis::RedisConnectionManager;
use sqlx::mysql::MySqlPoolOptions;
use sqlx::MySqlPool;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use bucket_paths::legacy::old_bespoke_paths::bucket_path_unifier::BucketPathUnifier;
use collections::multiple_random_from_vec::multiple_random_from_vec;
use config::common_env::CommonEnv;
@@ -126,7 +126,7 @@ async fn main() -> AnyhowResult<()> {
let bucket_timeout = easyenv::get_env_duration_seconds_or_default("BUCKET_TIMEOUT_SECONDS",
Duration::from_secs(60 * 5));
let private_bucket_client = LegacyBucketClient::create(
let private_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -136,7 +136,7 @@ async fn main() -> AnyhowResult<()> {
Some(bucket_timeout),
)?;
let public_bucket_client = LegacyBucketClient::create(
let public_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -1,4 +1,4 @@
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use gmicloud_client::creds::gmicloud_api_key::GmiCloudApiKey;
use jobs_common::job_stats::JobStats;
@@ -10,7 +10,7 @@ pub struct JobDependencies {
pub mysql_pool: MySqlPool,
/// Public GCS/S3 bucket for storing generated videos.
pub public_bucket_client: LegacyBucketClient,
pub public_bucket_client: BucketClient,
/// API key for GmiCloud.
pub gmicloud_api_key: GmiCloudApiKey,
+2 -2
View File
@@ -16,7 +16,7 @@ use log::{info, warn};
use sqlx::mysql::MySqlPoolOptions;
use bootstrap::bootstrap::{bootstrap, BootstrapArgs};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use shared_env_var_config::logging::DEFAULT_RUST_LOG;
use errors::AnyhowResult;
@@ -88,7 +88,7 @@ async fn main() -> AnyhowResult<()> {
Duration::from_secs(60 * 5),
);
let public_bucket_client = LegacyBucketClient::create(
let public_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -1,6 +1,6 @@
use std::sync::Arc;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use grok_api_client::creds::grok_api_key::GrokApiKey;
use jobs_common::job_stats::JobStats;
@@ -14,7 +14,7 @@ pub struct JobDependencies {
pub mysql_pool: MySqlPool,
/// Public GCS/S3 bucket for storing generated videos.
pub public_bucket_client: LegacyBucketClient,
pub public_bucket_client: BucketClient,
/// API key for xAI's Imagine API.
pub grok_api_key: GrokApiKey,
+2 -2
View File
@@ -18,7 +18,7 @@ use sqlx::mysql::MySqlPoolOptions;
use tokio::sync::Notify;
use bootstrap::bootstrap::{bootstrap, BootstrapArgs};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use errors::AnyhowResult;
use grok_api_client::creds::grok_api_key::GrokApiKey;
@@ -89,7 +89,7 @@ async fn main() -> AnyhowResult<()> {
Duration::from_secs(60 * 5),
);
let public_bucket_client = LegacyBucketClient::create(
let public_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -2,7 +2,7 @@ use std::sync::Arc;
use crate::kinovi_version::KinoviVersion;
use chrono::Duration;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use jobs_common::job_stats::JobStats;
use pager::client::pager::Pager;
@@ -16,7 +16,7 @@ pub struct JobDependencies {
pub mysql_pool: MySqlPool,
/// Public GCS/S3 bucket for storing generated videos.
pub public_bucket_client: LegacyBucketClient,
pub public_bucket_client: BucketClient,
/// Session credentials for polling seedance2-pro.com.
pub seedance2pro_session: Seedance2ProSession,
@@ -18,7 +18,7 @@ use sqlx::mysql::MySqlPoolOptions;
use tokio::sync::Notify;
use bootstrap::bootstrap::{bootstrap, BootstrapArgs};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use shared_env_var_config::logging::DEFAULT_RUST_LOG;
use errors::AnyhowResult;
@@ -93,7 +93,7 @@ async fn main() -> AnyhowResult<()> {
Duration::from_secs(60 * 5),
);
let public_bucket_client = LegacyBucketClient::create(
let public_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -1,6 +1,6 @@
use std::path::PathBuf;
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use jobs_common::job_stats::JobStats;
use pager::client::pager::Pager;
@@ -17,7 +17,7 @@ pub struct JobDependencies {
pub mysql_pool: MySqlPool,
/// Public GCS/S3 bucket for downloading source videos and uploading generated thumbnails.
pub public_bucket_client: LegacyBucketClient,
pub public_bucket_client: BucketClient,
pub server_environment: ServerEnvironment,
@@ -17,7 +17,7 @@ use log::{info, warn};
use sqlx::mysql::MySqlPoolOptions;
use bootstrap::bootstrap::{bootstrap, BootstrapArgs};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use shared_env_var_config::logging::DEFAULT_RUST_LOG;
use errors::AnyhowResult;
@@ -85,7 +85,7 @@ async fn main() -> AnyhowResult<()> {
Duration::from_secs(60 * 5),
);
let public_bucket_client = LegacyBucketClient::create(
let public_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -1,4 +1,4 @@
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use jobs_common::job_stats::JobStats;
use server_environment::ServerEnvironment;
@@ -9,7 +9,7 @@ pub struct JobDependencies {
pub mysql_pool: MySqlPool,
/// Public GCS/S3 bucket for storing generated splats.
pub public_bucket_client: LegacyBucketClient,
pub public_bucket_client: BucketClient,
/// API credentials for World Labs.
pub worldlabs_creds: WorldLabsApiCreds,
+2 -2
View File
@@ -16,7 +16,7 @@ use log::{info, warn};
use sqlx::mysql::MySqlPoolOptions;
use bootstrap::bootstrap::{bootstrap, BootstrapArgs};
use cloud_storage::legacy_bucket_client::LegacyBucketClient;
use cloud_storage::bucket_client::BucketClient;
use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
use shared_env_var_config::logging::DEFAULT_RUST_LOG;
use errors::AnyhowResult;
@@ -85,7 +85,7 @@ async fn main() -> AnyhowResult<()> {
Duration::from_secs(60 * 5),
);
let public_bucket_client = LegacyBucketClient::create(
let public_bucket_client = BucketClient::create(
&access_key,
&secret_key,
&region_name,
@@ -38,10 +38,8 @@ actix_helpers.workspace = true
artcraft_api_defs.workspace = true
artcraft_api_keys.workspace = true
artcraft_router.workspace = true
sha1_hash.workspace = true
video_info.workspace = true
bootstrap.workspace = true
bucket_client.workspace = true
bucket_paths.workspace = true
cloud_storage.workspace = true
collections.workspace = true
@@ -365,13 +365,7 @@ use artcraft_api_defs::user_referral_codes::delete_referral_code::*;
use artcraft_api_defs::user_referral_codes::list_referral_codes::*;
use artcraft_api_defs::web_referrals::log_web_referral::*;
use artcraft_api_defs::video_info::read_only::*;
use artcraft_api_defs::video_info::upload::*;
use artcraft_api_defs::video_info::notes::*;
use enums::by_table::uploaded_video_notes::uploaded_video_note_reported_model_type::UploadedVideoNoteReportedModelType;
use enums::by_table::uploaded_video_notes::uploaded_video_note_reported_website::UploadedVideoNoteReportedWebsite;
use crate::http_server::endpoints::video_info::video_info_read_info_handler::*;
use crate::http_server::endpoints::video_info::video_info_upload_handler::*;
use crate::http_server::endpoints::video_info::video_info_notes_handler::*;
use crate::http_server::endpoints::web_referrals::log_web_referral_handler::*;
use crate::http_server::endpoints::image_studio::update_gpt_image_job_status_handler::*;
use crate::http_server::endpoints::voice_conversion::enqueue_seed_vc_inference_handler::*;
@@ -626,8 +620,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
crate::http_server::endpoints::subscriptions::get_session_subscription_handler::get_session_subscription_handler,
// Web Referrals
crate::http_server::endpoints::video_info::video_info_read_info_handler::video_info_read_info_handler,
crate::http_server::endpoints::video_info::video_info_upload_handler::video_info_upload_handler,
crate::http_server::endpoints::video_info::video_info_notes_handler::video_info_notes_handler,
crate::http_server::endpoints::web_referrals::log_web_referral_handler::log_web_referral_handler,
// User Referral Codes
crate::http_server::endpoints::user_referral_codes::create_referral_code_handler::create_referral_code_handler,
@@ -1263,12 +1255,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
// Video info (provenance detection)
VideoInfoReadOnlyForm,
VideoInfoReadOnlyResponse,
VideoInfoUploadForm,
VideoInfoUploadResponse,
VideoInfoNoteRequest,
VideoInfoNoteResponse,
UploadedVideoNoteReportedModelType,
UploadedVideoNoteReportedWebsite,
VideoProvenanceKind,
SeedanceVideoInfo,
VeoVideoInfo,

Some files were not shown because too many files have changed in this diff Show More