File: //tmp/cs-sound-ready-bootstrap.patch
*** Begin Patch
*** Update File: /home/kiwerkzeuge.de/public_html/creator-studio/_lib/bootstrap.php
@@
'creator_studio.photo_carousel_brief.created' => [
'lane' => 'Freigabe',
'agent' => 'Content Agent',
'priority' => 'normal',
- 'objective' => 'Review the photo carousel template, cover image, slide order, CTA, and compliance before TikTok upload or direct photo post.',
- 'labels' => ['creator-studio', 'photo-carousel', 'content-agent'],
+ 'objective' => 'Review the photo carousel or sound-ready MP4 brief, confirm cover, slide order, visible URL/QR, AI disclosure, and compliance before TikTok inbox handoff.',
+ 'labels' => ['creator-studio', 'photo-carousel', 'sound-ready-mp4', 'content-agent'],
],
@@
function cs_photo_carousel_templates(): array
{
@@
];
}
+
+function cs_photo_carousel_delivery_modes(): array
+{
+ return [
+ 'photo_media_upload' => [
+ 'mode' => 'photo_media_upload',
+ 'label' => 'Photo/Carousel inbox upload',
+ 'objective' => 'Prepare the image set for TikTok MEDIA_UPLOAD and final editing in the TikTok app.',
+ ],
+ 'sound_ready_mp4' => [
+ 'mode' => 'sound_ready_mp4',
+ 'label' => 'Sound-ready vertical MP4',
+ 'objective' => 'Render the carousel as a 1080×1920 MP4 with embedded audio, visible URL/QR, and burned-in AI disclosure before TikTok inbox handoff.',
+ ],
+ ];
+}
+
+function cs_photo_carousel_delivery_mode(string $mode): array
+{
+ $mode = preg_replace('/[^a-z0-9_-]/i', '', $mode) ?: 'photo_media_upload';
+ $modes = cs_photo_carousel_delivery_modes();
+ return $modes[$mode] ?? $modes['photo_media_upload'];
+}
@@
function cs_photo_carousel_brief_agent_payload(array $brief): array
{
return [
'brief_id' => (string) ($brief['brief_id'] ?? ''),
'template_id' => (string) ($brief['template_id'] ?? ''),
'template_label' => (string) ($brief['template_label'] ?? ''),
+ 'delivery_mode' => (string) ($brief['delivery_mode'] ?? 'photo_media_upload'),
+ 'delivery_label' => (string) ($brief['delivery_label'] ?? ''),
'status' => (string) ($brief['status'] ?? ''),
'image_count' => (int) ($brief['image_count'] ?? 0),
'image_hosts' => array_values(array_filter($brief['image_hosts'] ?? [], 'is_string')),
'image_batch_hash' => (string) ($brief['image_batch_hash'] ?? ''),
'cover_index' => (int) ($brief['cover_index'] ?? 0),
'title_hash' => (string) ($brief['title_hash'] ?? ''),
'description_hash' => (string) ($brief['description_hash'] ?? ''),
+ 'cta_host' => (string) ($brief['cta_host'] ?? ''),
+ 'cta_url_hash' => (string) ($brief['cta_url_hash'] ?? ''),
+ 'sound_direction_hash' => (string) ($brief['sound_direction_hash'] ?? ''),
+ 'visible_url_required' => !empty($brief['visible_url_required']),
+ 'qr_required' => !empty($brief['qr_required']),
+ 'ai_disclosure_required' => !empty($brief['ai_disclosure_required']),
+ 'editor_aigc_switch_required' => !empty($brief['editor_aigc_switch_required']),
+ 'mp4_workaround_required' => !empty($brief['mp4_workaround_required']),
'agency_review' => is_array($brief['agency_review'] ?? null) ? $brief['agency_review'] : [],
'source' => (string) ($brief['source'] ?? ''),
'is_test' => !empty($brief['is_test']),
'created_at' => (string) ($brief['created_at'] ?? ''),
@@
$template = cs_photo_carousel_template($templateId);
$templateId = (string) $template['template_id'];
+ $delivery = cs_photo_carousel_delivery_mode((string) ($input['delivery_mode'] ?? 'photo_media_upload'));
+ $deliveryMode = (string) $delivery['mode'];
+ $ctaUrl = trim((string) ($input['cta_url'] ?? ''));
+ if ($ctaUrl !== '') {
+ $ctaUrl = cs_validate_https_url($ctaUrl, 'CTA URL');
+ }
+ $ctaHost = '';
+ if ($ctaUrl !== '') {
+ $host = parse_url($ctaUrl, PHP_URL_HOST);
+ $ctaHost = is_string($host) ? strtolower($host) : '';
+ }
+ $soundDirection = cs_clean_lead_text($input['sound_direction'] ?? '', 240);
+ if ($soundDirection === '' && $deliveryMode === 'sound_ready_mp4') {
+ $soundDirection = 'Brand-safe upbeat bed embedded into the vertical MP4 before TikTok handoff.';
+ }
+ $visibleUrlRequired = cs_notification_bool_value($input['visible_url_required'] ?? ($deliveryMode === 'sound_ready_mp4'), $deliveryMode === 'sound_ready_mp4');
+ $qrRequired = cs_notification_bool_value($input['qr_required'] ?? ($deliveryMode === 'sound_ready_mp4'), $deliveryMode === 'sound_ready_mp4');
+ $aiDisclosureRequired = cs_notification_bool_value($input['ai_disclosure_required'] ?? true, true);
+ if ($deliveryMode === 'sound_ready_mp4' && ($visibleUrlRequired || $qrRequired) && $ctaUrl === '') {
+ throw new RuntimeException('Sound-ready MP4 briefs need a CTA URL when visible URL or QR is required.');
+ }
$coverIndex = max(0, min((int) ($input['cover_index'] ?? 0), count($imageUrls) - 1));
@@
'next_action' => count($imageUrls) >= $recommendedMin
- ? 'Review cover promise, slide order, CTA, and compliance before TikTok upload.'
+ ? ($deliveryMode === 'sound_ready_mp4'
+ ? 'Review cover promise, slide order, sound direction, visible URL/QR, AI disclosure, and MP4 render requirements before TikTok inbox handoff.'
+ : 'Review cover promise, slide order, CTA, and compliance before TikTok upload.')
: 'Add more images before using this as the selected carousel template.',
- 'checks' => array_values(array_filter($template['checks'] ?? [], 'is_string')),
+ 'checks' => array_values(array_filter(array_merge($template['checks'] ?? [], $deliveryMode === 'sound_ready_mp4' ? [
+ 'render as 1080×1920 MP4',
+ 'embed sound in the MP4',
+ 'burn in visible URL or QR',
+ 'burn in AI disclosure and set TikTok editor AIGC switch',
+ ] : []), 'is_string')),
];
@@
'template_id' => $templateId,
'template_label' => (string) ($template['label'] ?? $templateId),
'template_objective' => (string) ($template['objective'] ?? ''),
+ 'delivery_mode' => $deliveryMode,
+ 'delivery_label' => (string) ($delivery['label'] ?? $deliveryMode),
+ 'delivery_objective' => (string) ($delivery['objective'] ?? ''),
'image_urls' => $imageUrls,
@@
'title_hash' => substr(hash('sha256', strtolower($title)), 0, 16),
'description' => $description,
'description_hash' => $description !== '' ? substr(hash('sha256', strtolower($description)), 0, 16) : '',
+ 'cta_url' => $ctaUrl,
+ 'cta_host' => $ctaHost,
+ 'cta_url_hash' => $ctaUrl !== '' ? substr(hash('sha256', strtolower($ctaUrl)), 0, 16) : '',
+ 'sound_direction' => $soundDirection,
+ 'sound_direction_hash' => $soundDirection !== '' ? substr(hash('sha256', strtolower($soundDirection)), 0, 16) : '',
+ 'visible_url_required' => $visibleUrlRequired,
+ 'qr_required' => $qrRequired,
+ 'ai_disclosure_required' => $aiDisclosureRequired,
+ 'editor_aigc_switch_required' => $aiDisclosureRequired,
+ 'mp4_workaround_required' => $deliveryMode === 'sound_ready_mp4',
+ 'normalization_requirements' => $deliveryMode === 'sound_ready_mp4'
+ ? ['image_format' => 'JPEG/sRGB', 'video_format' => '1080×1920 MP4', 'audio' => 'embedded', 'url' => 'visible URL/QR inside the video']
+ : ['image_format' => 'JPEG/sRGB recommended for TikTok Photo MEDIA_UPLOAD'],
'agency_notes' => cs_clean_lead_text($input['agency_notes'] ?? '', 1200, true),
@@
$real = 0;
$test = 0;
$readyForReview = 0;
+ $soundReadyMp4 = 0;
+ $soundReadyMp4Tests = 0;
$latest = '';
@@
- if (cs_photo_carousel_brief_is_test($brief)) {
+ $isTest = cs_photo_carousel_brief_is_test($brief);
+ if ($isTest) {
$test += 1;
} else {
$real += 1;
}
+ if (($brief['delivery_mode'] ?? '') === 'sound_ready_mp4') {
+ if ($isTest) {
+ $soundReadyMp4Tests += 1;
+ } else {
+ $soundReadyMp4 += 1;
+ }
+ }
@@
- return ['total' => count($briefs), 'real_total' => $real, 'test_total' => $test, 'ready_for_review' => $readyForReview, 'latest_created_at' => $latest];
+ return ['total' => count($briefs), 'real_total' => $real, 'test_total' => $test, 'ready_for_review' => $readyForReview, 'sound_ready_mp4' => $soundReadyMp4, 'sound_ready_mp4_tests' => $soundReadyMp4Tests, 'latest_created_at' => $latest];
}
*** End Patch