diff --git a/make_post_sell/routes.py b/make_post_sell/routes.py index 7d9f88f..e167be8 100644 --- a/make_post_sell/routes.py +++ b/make_post_sell/routes.py @@ -188,6 +188,7 @@ def includeme(config): config.add_route("player", "/player/{product_id}") config.add_route("player_json", "/player/{product_id}/json") config.add_route("watch_json", "/watch/{product_id}/json") + config.add_route("karaoke_process", "/karaoke/{product_id}") config.add_route("random", "/random") config.add_route("tv", "/tv") diff --git a/make_post_sell/static/css/common.css b/make_post_sell/static/css/common.css index 4c126f5..43a1edb 100644 --- a/make_post_sell/static/css/common.css +++ b/make_post_sell/static/css/common.css @@ -3045,6 +3045,10 @@ textarea { color: white; border-color: var(--blue-color, #5871ad); } +.ring-karaoke-btn:disabled { + cursor: wait; + opacity: 0.6; +} .related-content-row-current { background-color: var(--blue-color, #5871ad); color: white; diff --git a/make_post_sell/static/js/watch.js b/make_post_sell/static/js/watch.js index 8fd42e8..0c195a9 100644 --- a/make_post_sell/static/js/watch.js +++ b/make_post_sell/static/js/watch.js @@ -35,6 +35,8 @@ var karaokeMode = 0; // 0=original, 1=instrumentals, 2=vocals var KARAOKE_LABELS = ['Original', 'Instrumentals', 'Vocals']; var karaokeUrls = {original: null, instrumentals: null, vocals: null}; + var karaokeEligible = false; + var karaokeProcessing = false; // --- Ring state (persisted in localStorage) --- var ringProductIds = []; @@ -240,6 +242,8 @@ karaokeUrls.instrumentals = container ? container.getAttribute('data-instrumentals-url') : null; karaokeUrls.vocals = container ? container.getAttribute('data-vocals-url') : null; karaokeUrls.original = activeMedia ? activeMedia.src : null; + karaokeEligible = container ? container.getAttribute('data-karaoke-eligible') === '1' : false; + karaokeProcessing = false; karaokeMode = 0; updateKaraokeButton(); } @@ -248,12 +252,29 @@ var btn = document.getElementById('karaoke-toggle-btn'); if (!btn) return; var hasKaraoke = !!(karaokeUrls.instrumentals || karaokeUrls.vocals); - btn.style.display = hasKaraoke ? '' : 'none'; - btn.textContent = KARAOKE_LABELS[karaokeMode]; - if (karaokeMode === 0) { - btn.classList.remove('active'); - } else { + // Show button when tracks exist OR when eligible for on-demand processing + btn.style.display = (hasKaraoke || karaokeEligible) ? '' : 'none'; + + if (karaokeProcessing) { + btn.textContent = '\u231B'; // hourglass + btn.title = 'Processing karaoke tracks\u2026'; btn.classList.add('active'); + btn.disabled = true; + } else if (hasKaraoke) { + btn.textContent = KARAOKE_LABELS[karaokeMode]; + btn.title = 'Cycle: Original / Instrumentals / Vocals'; + btn.disabled = false; + if (karaokeMode === 0) { + btn.classList.remove('active'); + } else { + btn.classList.add('active'); + } + } else { + // Eligible but no tracks yet — show mic icon + btn.textContent = '\uD83C\uDFA4'; // 🎤 + btn.title = 'Generate karaoke tracks'; + btn.classList.remove('active'); + btn.disabled = false; } } @@ -267,9 +288,45 @@ return modes[(idx + 1) % modes.length]; } + function triggerKaraokeProcessing() { + if (karaokeProcessing || !currentProductId) return; + karaokeProcessing = true; + updateKaraokeButton(); + + fetch('/karaoke/' + currentProductId, {method: 'POST'}) + .then(function(resp) { return resp.json(); }) + .then(function(data) { + if (data.status === 'ready') { + // Tracks already exist — refresh to get URLs + karaokeProcessing = false; + fetchWatchData(currentProductId).then(function(fresh) { + if (fresh && fresh.instrumentals_url) { + karaokeUrls.instrumentals = fresh.instrumentals_url; + karaokeUrls.vocals = fresh.vocals_url; + karaokeUrls.original = fresh.media_url; + updateKaraokeButton(); + // Auto-switch to instrumentals + cycleKaraoke(); + } + }); + } + // status === 'processing' — polling via URL refresh will pick it up + }) + .catch(function() { + karaokeProcessing = false; + updateKaraokeButton(); + }); + } + function cycleKaraoke() { if (!activeMedia) return; var hasKaraoke = !!(karaokeUrls.instrumentals || karaokeUrls.vocals); + + // No tracks yet but eligible — trigger on-demand processing + if (!hasKaraoke && karaokeEligible) { + triggerKaraokeProcessing(); + return; + } if (!hasKaraoke) return; var nextMode = getNextKaraokeMode(); @@ -678,6 +735,8 @@ // Reset karaoke state for the new product karaokeMode = 0; + karaokeProcessing = false; + karaokeEligible = !!data.karaoke_eligible; karaokeUrls.original = data.media_url || null; karaokeUrls.instrumentals = data.instrumentals_url || null; karaokeUrls.vocals = data.vocals_url || null; @@ -903,7 +962,7 @@ + '' + '' + '' - + '' + + '' + '' + '' + '' @@ -1567,9 +1626,19 @@ if (data.product_id !== currentProductId) { scheduleUrlRefresh(); return; } // Refresh karaoke URLs from the fresh response + var hadKaraoke = !!(karaokeUrls.instrumentals || karaokeUrls.vocals); karaokeUrls.original = data.media_url; if (data.instrumentals_url) karaokeUrls.instrumentals = data.instrumentals_url; if (data.vocals_url) karaokeUrls.vocals = data.vocals_url; + if (data.karaoke_eligible !== undefined) karaokeEligible = !!data.karaoke_eligible; + + // Processing just completed — tracks appeared + if (!hadKaraoke && karaokeProcessing && (data.instrumentals_url || data.vocals_url)) { + karaokeProcessing = false; + updateKaraokeButton(); + // Auto-switch to instrumentals + cycleKaraoke(); + } var wasPlaying = !activeMedia.paused; var savedTime = activeMedia.currentTime; diff --git a/make_post_sell/templates/content.j2 b/make_post_sell/templates/content.j2 index bd9b432..9ea4664 100644 --- a/make_post_sell/templates/content.j2 +++ b/make_post_sell/templates/content.j2 @@ -40,7 +40,7 @@ {% if request.shop.watch_mode_enabled and product.extensions.get("product") in video_extensions %} {# Watch mode: direct video render with autoplay #} {% set watch_video_url = request.shop_cdn_endpoint ~ "/" ~ product.s3_path ~ "/product" %} -