onurerg07's picture
Update static/app.js
e78c2ad verified
/* static/app.js - HİBRİT + DUPLICATE KILLER + AUTO-NEXT FIX */
const playerUI = document.getElementById("player-ui");
const titleEl = playerUI.querySelector(".title");
const subEl = playerUI.querySelector(".subtitle");
const nextBtn = playerUI.querySelector(".next-btn");
const iframe = document.getElementById("soundcloud-player");
const debug = document.getElementById("debug-info");
const vinylEl = playerUI.querySelector(".vinyl");
const bgLayer = document.getElementById("bg-layer");
/* USER CONTEXT */
const urlParams = new URLSearchParams(window.location.search);
const currentUser = urlParams.get('user') || 'guest';
let currentLang = urlParams.get('lang') || 'en';
console.log("🚀 App Başladı (Robust Mode) | User:", currentUser);
if (debug) debug.textContent = "Sistem Hazırlanıyor...";
/* ======================================================
STATE VARIABLES
====================================================== */
let currentMood = null;
let globalDeck = [];
let poolIndex = 0;
const TRACKS_PER_CHUNK = 5;
// Aynı Şarkı Dedektörü İçin
let lastTrackID = null;
let skipCount = 0;
// Widget Yönetimi
let scWidget = null; // Widget instance'ını burada tutacağız
// Arka Plan Değişkenleri
let bgPlaylist = [];
let bgIndex = 0;
let bgTimer = null;
/* THEME & UTIL */
function applyTheme(color) {
if (!playerUI) return;
playerUI.style.borderColor = color;
playerUI.style.boxShadow = `0 0 20px ${color}40`;
if (titleEl) {
titleEl.style.color = color;
titleEl.style.textShadow = `0 0 15px ${color}`;
}
if (subEl) subEl.style.color = color;
if (nextBtn) nextBtn.style.backgroundColor = color;
if (vinylEl) vinylEl.style.borderColor = color;
}
function shuffleArray(arr){
for (let i = arr.length - 1; i > 0; i--){
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
/* ======================================================
🔥 SOUNDCLOUD WIDGET EVENTS (YENİLENEN YAPI)
====================================================== */
function setupWidgetEvents() {
if (typeof SC === 'undefined' || !iframe) return;
// Widget'ı her seferinde iframe elementi üzerinden yeniden tanımla
scWidget = SC.Widget(iframe);
// 1. READY: Widget hazır olduğunda (Oynatmayı zorla)
scWidget.bind(SC.Widget.Events.READY, function() {
console.log("✅ Widget Hazır (READY Event)");
// Tarayıcı otomatik oynatmayı engelliyorsa buradaki play komutu
// bazen konsola hata düşürür ama denemekten zarar gelmez.
scWidget.play();
// Ses seviyesini kontrol et (Opsiyonel: Ses kapalıysa açar)
scWidget.setVolume(100);
});
// 2. FINISH: Şarkı bittiğinde (Otomatik sıradaki)
scWidget.bind(SC.Widget.Events.FINISH, function() {
console.log("🏁 Şarkı bitti, sıradakine geçiliyor...");
skipCount = 0;
playNext();
});
// 3. PLAY & DUPLICATE CHECK: Çalmaya başladığında
scWidget.bind(SC.Widget.Events.PLAY, function() {
if(vinylEl) vinylEl.style.animationPlayState = "running";
scWidget.getCurrentSound(function(sound) {
if (sound) {
console.log(`🔊 Çalan ID: ${sound.id} | Önceki ID: ${lastTrackID}`);
// AYNI ŞARKI KONTROLÜ
if (lastTrackID !== null && sound.id === lastTrackID) {
if (skipCount < 5) {
console.warn("⚠️ AYNI ŞARKI ALGILANDI! Otomatik atlanıyor...");
skipCount++;
setTimeout(playNext, 300); // Biraz bekle ve geç
} else {
console.error("❌ Çok fazla deneme yapıldı (Loop). Çalmaya devam ediliyor.");
skipCount = 0;
}
} else {
lastTrackID = sound.id;
skipCount = 0;
}
}
});
});
// 4. PAUSE
scWidget.bind(SC.Widget.Events.PAUSE, function() {
if(vinylEl) vinylEl.style.animationPlayState = "paused";
});
// 5. ERROR: Herhangi bir yükleme hatası olursa
scWidget.bind(SC.Widget.Events.ERROR, function() {
console.error("⚠️ Widget Hatası. Bir sonrakine geçiliyor.");
setTimeout(playNext, 1000);
});
}
/* ======================================================
🎶 MÜZİK MANTIĞI
====================================================== */
async function loadPlaylist(){
try {
const r = await fetch(`/api/music?user=${currentUser}&lang=${currentLang}&t=` + Date.now());
const d = await r.json();
applyTheme(d.color || "#ffffff");
if (titleEl) titleEl.textContent = `${d.icon || "🎵"} ${d.mood_header || d.mood}`;
if (subEl) subEl.textContent = d.title || "SoundCloud";
let moodChunks = d.chunks || [];
if (moodChunks.length === 0 && d.embed_src) moodChunks = [d.embed_src];
if (moodChunks.length === 0) {
console.warn("Müzik listesi boş!");
return;
}
globalDeck = [];
moodChunks.forEach((chunkUrl, cIndex) => {
let cleanBase = chunkUrl.split("&")[0];
for (let i = 0; i < TRACKS_PER_CHUNK; i++) {
globalDeck.push({
url: cleanBase,
trackIndex: i,
chunkId: cIndex
});
}
});
shuffleArray(globalDeck);
poolIndex = 0;
console.log(`🎵 Playlist Hazır. ${globalDeck.length} Şarkı.`);
playNext();
} catch (err) {
console.error("Playlist Load Error:", err);
}
}
function playNext(){
if (!globalDeck || globalDeck.length === 0) return;
if (!iframe) return;
if (poolIndex >= globalDeck.length) {
shuffleArray(globalDeck);
poolIndex = 0;
}
let card = globalDeck[poolIndex];
poolIndex++;
// Yeni SRC oluştur
// ÖNEMLİ: visual=true görsel moddur, bazen API'da daha stabil çalışır.
let newSrc = `${card.url}&auto_play=true&visual=true&start_track=${card.trackIndex}&cb=${Date.now()}`;
// SRC'yi değiştirmeden önce event listener'ları temizlemeye gerek yok,
// çünkü iframe yenilenince widget instance'ı boşa düşer.
iframe.src = newSrc;
// Debug güncelle
if (debug && currentMood) {
debug.textContent = `[${currentMood.toUpperCase()}] Parça: ${card.trackIndex + 1} (Deste: ${card.chunkId + 1})`;
}
// Iframe yüklendiğinde Widget Eventlerini TEKRAR bağla
// Iframe'in "onload" eventi, yeni src tamamen yüklendiğinde tetiklenir.
iframe.onload = function() {
console.log("📥 Iframe Yüklendi -> Eventler Bağlanıyor...");
setupWidgetEvents();
};
}
/* 🔥 FETCH & WATCH LOGIC */
async function watchMood(){
try{
const r = await fetch(`/api/get_current_mood?user=${currentUser}`);
const d = await r.json();
if (d.mood && (d.mood !== currentMood || currentMood === null)){
console.log("Mood Algılandı:", d.mood);
currentMood = d.mood;
if (debug) debug.textContent = "Mood → " + currentMood.toUpperCase();
lastTrackID = null;
loadPlaylist();
loadBackgroundPlaylist();
}
}catch(e){
console.error("Mood watch error", e);
}
}
/* ======================================================
🖼️ ARKA PLAN MANTIĞI
====================================================== */
async function loadBackgroundPlaylist(){
try{
const r = await fetch(`/api/playlist?user=${currentUser}&t=` + Date.now());
const d = await r.json();
if (!Array.isArray(d) || d.length === 0) return;
bgPlaylist = d;
bgIndex = 0;
showNextBackground();
}catch(e){
console.error("BG Load Error:", e);
}
}
function showNextBackground(){
if (!bgPlaylist.length || !bgLayer) return;
const item = bgPlaylist[bgIndex];
bgIndex = (bgIndex + 1) % bgPlaylist.length;
bgLayer.src = item.url;
if (bgTimer) clearTimeout(bgTimer);
bgTimer = setTimeout(showNextBackground, item.duration);
}
/* ======================================================
LISTENERS
====================================================== */
if (nextBtn) nextBtn.addEventListener("click", () => {
skipCount = 0;
playNext();
});
window.addEventListener("message", (event) => {
if (event.data.type === "LANGUAGE_UPDATE") {
if (event.data.lang && event.data.lang !== currentLang) {
currentLang = event.data.lang;
loadPlaylist();
}
}
});
// Başlat
(async () => {
if(debug) debug.textContent = "Veriler Alınıyor...";
await loadBackgroundPlaylist();
await watchMood();
setInterval(watchMood, 3000);
})();