Kendi radyo projem için yapay zekâ araçlarını kullanarak hazırladığım sistemin kodlarını paylaşıyorum. Sistemin üzerinde çalışıp daha da geliştirmek fikrim var (arayüzü geliştirme, dağıtık sunucu desteği, vs.) ama mevcut hâlini kendiniz değiştirebilir veya kodlarını yapay zekâ araçlarına promptla birlikte vererek görünümünü ve işlevlerini kendinize göre özelleştirebilirsiniz. Hatta Wordpress eklentisi, vs. hâline de getirebilirsiniz. Şimdiki hâlinde şarkıları tek tek tanımlamak biraz meşakkatli gelebilir ama yapay zekâya bu iş için yönetim paneli yazdırabilirsiniz. Test amaçlı hazırladığım prototipten gelişmiş bir yazılım elde edebilirsiniz.

Kodun özelliği sunucu saatine göre gece 0:00'dan itibaren belirlenen oynatma listesini döngüye sokup çalması ve yayını farklı saatlerde dinlemeye başlayan kişilerin sırası gelen şarkıyı aşağı yukarı aynı saniyelerde dinleyebilmesidir. Bu da gerçek bir radyo yayını hissini verebilir. Oynatma listesindeki şarkılar kendi hostinginizde veya hotlinkinge izin veren bir başka hosting (dosya depolama veya paylaşma alanı, vs.) olabilir.

Kullanıcı arayüzü: radyo.html
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>Radyo Simülasyonu</title>
    <style>
              :root {
            --player-bg: #282c34;
            --control-bg: #3c4049;
            --primary-color: #61afef;
            --text-color: #ffffff;
            --progress-fill: #98c379;
            --progress-handle: #e06c75;
        }
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            text-align: center;
            padding: 20px;
            background-color: #1e2127;
            color: var(--text-color);
            display: flex;
            flex-direction: column;
            align-items: center;
            min-height: 100vh;
        }
        h1 {
            color: var(--primary-color);
            margin-bottom: 5px;
        }
        p {
            color: #abb2bf;
            margin-bottom: 30px;
            font-size: 0.9em;
        }
        #playerContainer {
            background-color: var(--player-bg);
            border-radius: 15px;
            padding: 30px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
            width: 100%;
            max-width: 500px;
        }
        #trackInfo {
            background-color: var(--control-bg);
            padding: 15px;
            border-radius: 10px;
            margin-bottom: 20px;
            text-align: left;
            border-left: 5px solid var(--primary-color);
        }
        #trackInfo h2 {
            margin: 0 0 5px 0;
            color: var(--progress-fill);
            font-size: 1.4em;
        }
        #trackInfo p {
            margin: 3px 0;
            color: #abb2bf;
            font-size: 0.9em;
            line-height: 1.4;
        }
        #playButton {
            padding: 12px 25px;
            background: var(--primary-color);
            color: var(--text-color);
            border: none;
            border-radius: 50px;
            cursor: pointer;
            font-size: 18px;
            font-weight: bold;
            transition: background 0.2s, transform 0.1s;
            margin-top: 20px;
            margin-bottom: 20px;
            box-shadow: 0 4px 15px rgba(97, 175, 239, 0.4);
        }
        #playButton:hover {
            background: #4a90e2;
        }
        #playButton:active {
            transform: scale(0.98);
        }
        #progressCanvas {
            margin-top: 10px;
            border: none;
            background-color: var(--control-bg);
            border-radius: 5px;
            cursor: pointer;
            width: 100%;
            height: 10px !important;
        }
        #volumeControl {
            margin-top: 25px;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0 10px;
        }
        #volumeLabel {
            font-size: 14px;
            color: #abb2bf;
            white-space: nowrap;
            margin-right: 15px;
            min-width: 80px;
        }
        #timeDisplay {
            display: flex;
            justify-content: space-between;
            margin-top: 5px;
            font-size: 14px;
            color: #abb2bf;
        }
    </style>
</head>
<body>
    <div id="playerContainer">
        <h1>Radyo Simülasyonu</h1>
        <p>Şarkı listesi döngüye alınır ve sunucu saatine göre yayını farklı saatlerde açan kişilerin yayın saati gelen şarkıların aynı saniyelerini dinlemeleri amaçlanır.</p>
        <div id="trackInfo">
            <h2 id="songTitle">Yüklenmeye Hazır</h2>
            <p>Sanatçı: <span id="artistName">---</span></p>
            <p>Besteci: <span id="composerName">---</span></p>
            <p>Lisans: <span id="licenseInfo">---</span></p>
        </div>
        <audio id="audio" preload="metadata"></audio>
        <canvas id="progressCanvas" width="500" height="10"></canvas>
        <div id="timeDisplay">
            <span id="currentTimeDisplay">00:00</span>
            <span id="durationDisplay">00:00</span>
        </div>
        <button id="playButton">Oynat</button>
        <div id="volumeControl">
            <label id="volumeLabel" for="volumeSlider">Ses Düzeyi: 100%</label>
            <input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="1">
        </div>
    </div>
    <script>
        // DOM elementleri ve değişkenler (Değişmedi)
    const audio = document.getElementById('audio');
    const playButton = document.getElementById('playButton');
    const progressCanvas = document.getElementById('progressCanvas');
    const ctx = progressCanvas.getContext('2d');
    const volumeSlider = document.getElementById('volumeSlider');
    const volumeLabel = document.getElementById('volumeLabel');
    const currentTimeDisplay = document.getElementById('currentTimeDisplay');
    const durationDisplay = document.getElementById('durationDisplay');
    const songTitle = document.getElementById('songTitle');
    const artistName = document.getElementById('artistName');
    const composerName = document.getElementById('composerName');
    const licenseInfo = document.getElementById('licenseInfo');
    
    const RANDOM_ENDPOINT = 'mp3_sunucusu.php';
    let isPlaying = false;
    let firstTrack = true;
    let currentUrl = null;
    let currentTrackInfo = null;
    let pauseStartTime = null;
    function formatTime(seconds) {
        if (isNaN(seconds) || seconds < 0) return "00:00";
        const minutes = Math.floor(seconds / 60);
        const remainingSeconds = Math.floor(seconds % 60);
        return `${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`;
    }
    
    function updateTrackInfo(info) {
        songTitle.textContent = info.sarki_adi || 'Bilinmeyen Şarkı';
        artistName.textContent = info.sanatci_adi || 'Bilinmiyor';
        composerName.textContent = info.besteci_adi || 'Bilinmiyor';
        licenseInfo.textContent = info.lisans || 'Bilinmiyor';
        currentTrackInfo = info;
    }
    volumeSlider.addEventListener('input', (event) => {
        const volume = event.target.value;
        audio.volume = volume;
        volumeLabel.textContent = `Ses Düzeyi: ${Math.round(volume * 100)}%`;
    });
    
    audio.addEventListener('pause', () => {
        if (isPlaying) {
            pauseStartTime = new Date().getTime();
            isPlaying = false;
            playButton.textContent = 'Oynat';
            console.log("Müzik duraklatıldı. Naklen yayın sayacı başlatıldı.");
        }
    });
    
    audio.addEventListener('play', async () => {
        if (audio.paused) return;
        
        isPlaying = true;
        playButton.textContent = 'Duraklat';
        if (pauseStartTime) {
            const pausedDurationMs = new Date().getTime() - pauseStartTime;
            const skipSeconds = Math.floor(pausedDurationMs / 1000);
            
            console.log(`Müzik devam ediyor. Duraklatılan süre: ${skipSeconds} saniye.`);
            
            pauseStartTime = null;
            
            const newTime = audio.currentTime + skipSeconds;
            const duration = audio.duration || 0;
            if (!isFinite(duration) || newTime >= duration) {
                console.log(`Atlama süresi (${formatTime(newTime)}) şarkı süresini (${formatTime(duration)}) geçti. Yeni şarkı yükleniyor...`);
                
                try {
                     const info = await fetchRandomUrl();
                     if (!info || !info.url) throw new Error('Yeni URL veya bilgi alınamadı');
                    
                     currentUrl = info.url;
                     updateTrackInfo(info);
                    
                    
                     const offsetSec = info.ek_saniye_ofseti || 0;
                     const startSec = offsetSec;
                    
                     console.log(`Yeni şarkı yükleniyor. Başlangıç saniyesi: ${offsetSec} = ${startSec}.`);
                    
                     firstTrack = false;
                     await loadAndPlay(currentUrl, startSec);
                    
                } catch(err) {
                     alert('Naklen yayın geçişinde hata oluştu: ' + err.message);
                     console.error('Naklen geçiş hatası:', err);
                     isPlaying = false;
                     playButton.textContent = 'Oynat';
                }
            } else {
                console.log(`Şarkı ${skipSeconds} saniye ileri sarılıyor. Yeni zaman: ${formatTime(newTime)}`);
                try {
                    audio.currentTime = newTime;
                } catch (e) {
                    console.warn("currentTime ayarlanamadı:", e);
                }
            }
        }
    });
    playButton.addEventListener('click', async () => {
        if (isPlaying) {
            audio.pause();
            return;
        }
        if (!currentUrl) {
            try {
                const info = await fetchRandomUrl();
                if (!info || !info.url) throw new Error('URL alınamadı');
                
                currentUrl = info.url;
                updateTrackInfo(info);
                let startTime = 0;
                if(firstTrack) {
                    
                    const offsetSec = info.ek_saniye_ofseti || 0;
                    startTime = offsetSec;
                    console.log(`İlk oynatma. Başlangıç saniyesi: ${offsetSec} = ${startTime}.`);
                } else {
                    console.log(`Oynatılıyor. Başlangıç saniyesi: 0.`);
                }
                
                await loadAndPlay(currentUrl, startTime);
                firstTrack = false;
            } catch (err) {
                alert('Şarkı yüklenemedi: ' + err.message);
                return;
            }
        } else {
            try {
                await audio.play();
            } catch (err) {
                console.error('Play hatası:', err);
            }
        }
    });
    audio.addEventListener('ended', async () => {
        console.log("Şarkı sona erdi. Sıradaki şarkı yükleniyor (Baştan başlama kuralı).");
        try {
            const info = await fetchRandomUrl();
            if (!info || !info.url) {
                console.warn('Yeni URL alınamadı.');
                playButton.textContent = 'Oynat';
                isPlaying = false;
                updateTrackInfo({ sarki_adi: "Bitti", sanatci_adi: "---", besteci_adi: "---", lisans: "---" });
                return;
            }
            
            currentUrl = info.url;
            updateTrackInfo(info);
            const startTime = 0;
            firstTrack = false;
            await loadAndPlay(currentUrl, startTime);
            
        } catch (err) {
            console.error('Ended hata:', err);
            playButton.textContent = 'Oynat';
            isPlaying = false;
            updateTrackInfo({ sarki_adi: "Hata", sanatci_adi: "---", besteci_adi: "---", lisans: "---" });
        }
    });
    
    progressCanvas.addEventListener('click', (e) => {
        const rect = progressCanvas.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const clickRatio = x / progressCanvas.width;
        
        if (isFinite(audio.duration) && audio.duration > 0) {
            pauseStartTime = null;
            audio.currentTime = audio.duration * clickRatio;
        }
    });
    audio.addEventListener('timeupdate', () => {
        const currentTime = audio.currentTime || 0;
        const duration = audio.duration || 0;
        
        ctx.clearRect(0, 0, progressCanvas.width, progressCanvas.height);
        ctx.fillStyle = '#3c4049';
        ctx.fillRect(0, 0, progressCanvas.width, progressCanvas.height);
        const progressWidth = (duration > 0) ? (currentTime / duration) * progressCanvas.width : 0;
        ctx.fillStyle = 'var(--progress-fill)';
        ctx.fillRect(0, 0, progressWidth, progressCanvas.height);
        
        ctx.beginPath();
        ctx.arc(progressWidth, progressCanvas.height / 2, 7, 0, 2 * Math.PI);
        ctx.fillStyle = 'var(--progress-handle)';
        ctx.fill();
        
        currentTimeDisplay.textContent = formatTime(currentTime);
        durationDisplay.textContent = formatTime(duration);
    });
    
    audio.addEventListener('loadedmetadata', () => {
        durationDisplay.textContent = formatTime(audio.duration);
        console.log(`Metadata yüklendi. Şarkı süresi: ${formatTime(audio.duration)}`);
    });
    audio.addEventListener('error', (e) => {
        console.error('Audio hata:', e);
        alert('Ses oynatılamıyor veya URL hatalı.');
        playButton.textContent = 'Oynat';
        isPlaying = false;
    });
    // Rastgele URL ve Meta Veri almak için PHP endpoint'e istek (GELİŞTİRİLDİ)
    async function fetchRandomUrl() {
        try {
            const resp = await fetch(RANDOM_ENDPOINT, { cache: 'no-store' });
            
            // HTTP durum kodu kontrolü
            if (!resp.ok) {
                 const statusText = resp.statusText || 'Bilinmeyen Hata';
                 throw new Error(`Sunucudan hatalı cevap alındı: ${resp.status} - ${statusText}`);
            }
            
            const text = (await resp.text()).trim();
            console.log(`mp3_sunucusu.php'den dönen ham veri: "${text.substring(0, 100)}..."`); // İlk 100 karakteri konsola yazdır
            if (!text) throw new Error('Sunucu boş veri döndü.');
            
            // JSON desteği (opsiyonel) - Mantık aynı
            if (text.startsWith('{') && text.endsWith('}')) {
                try {
                    const json = JSON.parse(text);
                    json.ek_saniye_ofseti = parseInt(json.ek_saniye_ofseti) || 0;
                    return json;
                } catch(e) {
                    console.warn("JSON ayrıştırma hatası. PSV formatı deneniyor.");
                }
            }
            
            // PSV Formatı: url|şarkı adı|sanatçı adı|besteci adı|lisans|ek_saniye
            const parts = text.split('|');
            
            // 5 yerine 6 parça bekleniyor (sonuncusu ek saniye)
            if (parts.length < 5) {
                throw new Error(`Dönen veri ayrıştırılamadı. Beklenen minimum 5 parça, ${parts.length} parça geldi. Ham veri: ${text}`);
            }
            // Ek saniyeyi kontrol et (6. parça, index 5) ve tam sayıya çevir, yoksa 0 kullan.
            const ekSaniyeStr = parts.length > 5 ? parts[5].trim() : "0";
            const ekSaniye = parseInt(ekSaniyeStr) || 0;
            
            // URL kontrolü yap (ilk parça)
            if (!parts[0].trim()) {
                throw new Error(`Ayrıştırılan URL boş çıktı. Ham veri: ${text}`);
            }
            return {
                url: parts[0].trim(),
                sarki_adi: parts[1].trim(),
                sanatci_adi: parts[2].trim(),
                besteci_adi: parts[3].trim(),
                lisans: parts[4].trim(),
                ek_saniye_ofseti: ekSaniye
            };
        } catch (err) {
            // Hata yakalandıktan sonra daha açıklayıcı bir mesaj döndür
            console.error('FETCH HATA:', err);
            return null; // Null döndürerek üst katmanın hatayı işlemesini sağla
        }
    }
    // audio.src = url yap, gerekirse başlangıç zamanını ayarla ve çal (Mantık aynı)
    async function loadAndPlay(url, startSeconds = 0) {
        return new Promise((resolve, reject) => {
            audio.pause();
            audio.removeAttribute('src');
            audio.src = url;
            audio.load();
            const onLoaded = () => {
                try {
                    audio.removeEventListener('loadedmetadata', onLoaded);
                    
                    let finalStartSeconds = startSeconds;
                    const duration = audio.duration || 0;
                    if (isFinite(duration) && duration > 0) {
                        // Modülo işlemi ile başlangıç süresini şarkı süresi içinde tut.
                        if (finalStartSeconds > 0) {
                            finalStartSeconds = finalStartSeconds % duration;
                        }
                    }
                    
                    if (finalStartSeconds > 0) {
                        try {
                            audio.currentTime = finalStartSeconds;
                            console.log(`currentTime ${formatTime(finalStartSeconds)} olarak ayarlandı.`);
                        } catch(e) {
                            console.warn('currentTime ayarlanamadı (Tarayıcı kısıtlaması olabilir):', e);
                        }
                    } else {
                        audio.currentTime = 0;
                        console.log(`currentTime 00:00 olarak ayarlandı.`);
                    }
                } catch(e) {
                    console.error('loadedmetadata handling error:', e);
                }

                audio.play().then(() => {
                    resolve();
                }).catch(err => {
                    isPlaying = false;
                    playButton.textContent = 'Oynat';
                    reject(err);
                });
            };
            audio.addEventListener('loadedmetadata', onLoaded);
            const timeout = setTimeout(() => {
                audio.removeEventListener('loadedmetadata', onLoaded);
                reject(new Error('Media metadata yüklenmesi zaman aşımına uğradı.'));
            }, 15000);
            const origResolve = resolve;
            resolve = (...args) => { clearTimeout(timeout); origResolve(...args); };
            const origReject = reject;
            reject = (...args) => { clearTimeout(timeout); origReject(...args); };
        });
    }
    
    // Başlangıç ayarları (Aynı)
    updateTrackInfo({
        sarki_adi: "Yüklenmeye Hazır",
        sanatci_adi: "---",
        besteci_adi: "---",
        lisans: "---"
    });
    currentTimeDisplay.textContent = formatTime(0);
    durationDisplay.textContent = formatTime(0);
    volumeLabel.textContent = `Ses Düzeyi: ${Math.round(audio.volume * 100)}%`;
    </script>
</body>
</html>
MP3 sunucusu: mp3_sunucusu.php
<?php
// Şarkı listesi
$songs = [
    "sarki1.mp3|Şarkı 1|Şarkıcı adı|Besteci adı|Lisans|saniye",
    "sarki2.mp3|Şarkı 2|Şarkıcı adı|Besteci adı|Lisans|saniye"
        
];
// Playlist oluştur: Sadece süreleri çıkar
$durations = [];
foreach ($songs as $song) {
    if (preg_match('/\|(\d+)$/', $song, $matches)) {
        $durations[] = (int)$matches[1];
    } else {
        $durations[] = 0; // Hatalı format durumunda
    }
}
// Toplam playlist süresi
$totalDuration = array_sum($durations);
// Radyo yayınının başlangıç zamanı (gece 00:00)
$startTimestamp = strtotime('today midnight'); // Bugünün gece yarısı
$currentTimestamp = time();
$elapsedSeconds = $currentTimestamp - $startTimestamp;
// Döngüsel oynatma için geçen süreyi mod al
$currentPosition = $elapsedSeconds % $totalDuration;
// Hangi şarkının oynatılacağını bul
$currentTime = 0;
$currentSongIndex = 0;
$startTime = 0;
foreach ($durations as $index => $duration) {
    if ($currentPosition >= $currentTime && $currentPosition < $currentTime + $duration) {
        $currentSongIndex = $index;
        $startTime = $currentPosition - $currentTime; // Şarkının içindeki saniye
        break;
    }
    $currentTime += $duration;
}
// Seçilen şarkıyı al
$currentSong = $songs[$currentSongIndex];
// Son kısmı (süre) başlangıç saniyesiyle değiştir
$output = preg_replace('/\|\d+$/', '|' . $startTime, $currentSong);
// Yanıt
header('Content-Type: text/plain');
echo $output;
?>
Not:
    "sarki1.mp3|Şarkı 1|Şarkıcı adı|Besteci adı|Lisans|saniye",
    "sarki2.mp3|Şarkı 2|Şarkıcı adı|Besteci adı|Lisans|saniye"
Bu kısmı değiştirirken en son satırda virgül bulunmadığına dikkat edin. sarki1.mp3 yerine şarkının bulunduğu url de yazılabilir (örneğin: https://uzaktaki sunucu.com/sarki1.mp3). Şarkıların uzunluğu en sonda saniye cinsinden yazılıyor (örneğin şarkı 2:11 ise 131). Besteci adı yerine albüm adı, lisans yerine yayın yılı, vb. değişiklikleri kendinize göre yapabilirsiniz.