Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>JioSaavn Clone</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap'); | |
| body { | |
| font-family: 'Montserrat', sans-serif; | |
| background-color: #121212; | |
| color: white; | |
| } | |
| .sidebar { | |
| scrollbar-width: thin; | |
| scrollbar-color: #535353 transparent; | |
| } | |
| .sidebar::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| .sidebar::-webkit-scrollbar-thumb { | |
| background-color: #535353; | |
| border-radius: 4px; | |
| } | |
| .progress-bar { | |
| -webkit-appearance: none; | |
| height: 4px; | |
| background: #535353; | |
| border-radius: 2px; | |
| } | |
| .progress-bar::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| width: 12px; | |
| height: 12px; | |
| background: white; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| opacity: 0; | |
| transition: opacity 0.2s; | |
| } | |
| .progress-bar:hover::-webkit-slider-thumb { | |
| opacity: 1; | |
| } | |
| .album-art:hover .play-button { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| .play-button { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| transition: all 0.3s ease; | |
| } | |
| .song-row:hover { | |
| background-color: #282828; | |
| } | |
| .search-results { | |
| max-height: 400px; | |
| overflow-y: auto; | |
| scrollbar-width: thin; | |
| scrollbar-color: #535353 transparent; | |
| } | |
| .search-results::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| .search-results::-webkit-scrollbar-thumb { | |
| background-color: #535353; | |
| border-radius: 4px; | |
| } | |
| .blinking { | |
| animation: blink 1.5s infinite; | |
| } | |
| @keyframes blink { | |
| 0% { opacity: 1; } | |
| 50% { opacity: 0.5; } | |
| 100% { opacity: 1; } | |
| } | |
| .wave-animation { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| width: 30px; | |
| height: 20px; | |
| } | |
| .wave-bar { | |
| width: 3px; | |
| background-color: #1db954; | |
| border-radius: 3px; | |
| animation: wave 1.5s ease-in-out infinite; | |
| } | |
| .wave-bar:nth-child(1) { height: 60%; animation-delay: 0.1s; } | |
| .wave-bar:nth-child(2) { height: 30%; animation-delay: 0.3s; } | |
| .wave-bar:nth-child(3) { height: 75%; animation-delay: 0.5s; } | |
| .wave-bar:nth-child(4) { height: 40%; animation-delay: 0.7s; } | |
| .wave-bar:nth-child(5) { height: 60%; animation-delay: 0.9s; } | |
| @keyframes wave { | |
| 0%, 100% { transform: scaleY(1); } | |
| 50% { transform: scaleY(1.5); } | |
| } | |
| </style> | |
| </head> | |
| <body class="h-screen flex overflow-hidden"> | |
| <!-- Sidebar --> | |
| <div class="sidebar w-60 bg-black flex flex-col overflow-y-auto"> | |
| <div class="p-6"> | |
| <div class="flex items-center mb-8"> | |
| <i class="fas fa-music text-3xl text-green-500 mr-2"></i> | |
| <span class="text-xl font-bold">JioSaavn</span> | |
| </div> | |
| <div class="mb-8"> | |
| <div class="mb-4"> | |
| <a href="#" class="flex items-center text-white hover:text-green-500 transition" id="home-link"> | |
| <i class="fas fa-home text-xl mr-4"></i> | |
| <span class="font-medium">Home</span> | |
| </a> | |
| </div> | |
| <div class="mb-4"> | |
| <a href="#" class="flex items-center text-gray-400 hover:text-white transition" id="search-link"> | |
| <i class="fas fa-search text-xl mr-4"></i> | |
| <span class="font-medium">Search</span> | |
| </a> | |
| </div> | |
| <div class="mb-4"> | |
| <a href="#" class="flex items-center text-gray-400 hover:text-white transition" id="library-link"> | |
| <i class="fas fa-book text-xl mr-4"></i> | |
| <span class="font-medium">Your Library</span> | |
| </a> | |
| </div> | |
| </div> | |
| <div class="mb-8"> | |
| <div class="mb-4"> | |
| <a href="#" class="flex items-center text-gray-400 hover:text-white transition" id="create-playlist"> | |
| <i class="fas fa-plus-square text-xl mr-4"></i> | |
| <span class="font-medium">Create Playlist</span> | |
| </a> | |
| </div> | |
| <div class="mb-4"> | |
| <a href="#" class="flex items-center text-gray-400 hover:text-white transition" id="liked-songs"> | |
| <i class="fas fa-heart text-xl mr-4"></i> | |
| <span class="font-medium">Liked Songs</span> | |
| </a> | |
| </div> | |
| </div> | |
| <div class="border-t border-gray-800 pt-4"> | |
| <div class="text-gray-400 text-sm mb-2">PLAYLISTS</div> | |
| <div id="playlists-container"> | |
| <!-- Playlists will be loaded here --> | |
| <div class="mb-2"> | |
| <a href="#" class="text-gray-400 hover:text-white transition block truncate playlist-link" data-id="8291463">Top Hindi Hits</a> | |
| </div> | |
| <div class="mb-2"> | |
| <a href="#" class="text-gray-400 hover:text-white transition block truncate playlist-link" data-id="106114462">Romantic Hits</a> | |
| </div> | |
| <div class="mb-2"> | |
| <a href="#" class="text-gray-400 hover:text-white transition block truncate playlist-link" data-id="103581706">Bollywood Dance</a> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main Content --> | |
| <div class="flex-1 flex flex-col overflow-hidden"> | |
| <!-- Header --> | |
| <div class="bg-gradient-to-r from-purple-900 to-blue-900 p-6" id="main-header"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <div class="flex space-x-4"> | |
| <button class="bg-black bg-opacity-30 rounded-full w-8 h-8 flex items-center justify-center" id="nav-back"> | |
| <i class="fas fa-chevron-left"></i> | |
| </button> | |
| <button class="bg-black bg-opacity-30 rounded-full w-8 h-8 flex items-center justify-center" id="nav-forward"> | |
| <i class="fas fa-chevron-right"></i> | |
| </button> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <button class="bg-white text-black px-4 py-1 rounded-full font-bold text-sm hover:scale-105 transition"> | |
| Upgrade | |
| </button> | |
| <div class="flex items-center bg-black bg-opacity-70 rounded-full px-2 py-1 cursor-pointer hover:bg-opacity-90 transition"> | |
| <div class="w-6 h-6 rounded-full bg-purple-500 mr-2"></div> | |
| <span class="text-sm font-medium">Profile</span> | |
| <i class="fas fa-chevron-down ml-2 text-xs"></i> | |
| </div> | |
| </div> | |
| </div> | |
| <h1 class="text-5xl font-bold mb-6" id="greeting">Good afternoon</h1> | |
| <div class="grid grid-cols-2 md:grid-cols-3 gap-4" id="quick-access"> | |
| <!-- Quick access items will be loaded here --> | |
| <div class="bg-gray-800 bg-opacity-40 rounded flex items-center overflow-hidden hover:bg-gray-700 transition cursor-pointer"> | |
| <img src="https://c.saavncdn.com/editorial/JustHits-hindi_20240208054618.jpg" alt="Album" class="w-16 h-16"> | |
| <span class="ml-4 font-medium">Today's Top Hits</span> | |
| </div> | |
| <div class="bg-gray-800 bg-opacity-40 rounded flex items-center overflow-hidden hover:bg-gray-700 transition cursor-pointer"> | |
| <img src="https://c.saavncdn.com/editorial/BollywoodDanceMusic_20240208054639.jpg" alt="Album" class="w-16 h-16"> | |
| <span class="ml-4 font-medium">Bollywood Dance</span> | |
| </div> | |
| <div class="bg-gray-800 bg-opacity-40 rounded flex items-center overflow-hidden hover:bg-gray-700 transition cursor-pointer"> | |
| <img src="https://c.saavncdn.com/editorial/NewRomanticHindi_20240208054618.jpg" alt="Album" class="w-16 h-16"> | |
| <span class="ml-4 font-medium">Romantic Hits</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Search Section (hidden by default) --> | |
| <div class="hidden p-6 bg-gradient-to-b from-blue-900 to-gray-900" id="search-section"> | |
| <div class="relative mb-6"> | |
| <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i> | |
| <input type="text" id="search-input" class="w-full bg-gray-700 rounded-full py-2 pl-10 pr-4 text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-green-500" placeholder="Search for songs, artists, or albums"> | |
| </div> | |
| <div class="search-results hidden bg-gray-800 bg-opacity-40 rounded-lg p-4 mb-6" id="search-results"> | |
| <!-- Search results will be displayed here --> | |
| </div> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold">Browse all</h2> | |
| </div> | |
| <div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-6" id="browse-categories"> | |
| <!-- Browse categories will be loaded here --> | |
| <div class="bg-gradient-to-br from-purple-600 to-blue-600 rounded-lg p-4 cursor-pointer hover:opacity-90 transition"> | |
| <h3 class="font-bold">Hindi</h3> | |
| </div> | |
| <div class="bg-gradient-to-br from-green-600 to-blue-600 rounded-lg p-4 cursor-pointer hover:opacity-90 transition"> | |
| <h3 class="font-bold">Punjabi</h3> | |
| </div> | |
| <div class="bg-gradient-to-br from-red-600 to-yellow-600 rounded-lg p-4 cursor-pointer hover:opacity-90 transition"> | |
| <h3 class="font-bold">Pop</h3> | |
| </div> | |
| <div class="bg-gradient-to-br from-yellow-600 to-red-600 rounded-lg p-4 cursor-pointer hover:opacity-90 transition"> | |
| <h3 class="font-bold">Romantic</h3> | |
| </div> | |
| <div class="bg-gradient-to-br from-blue-600 to-purple-600 rounded-lg p-4 cursor-pointer hover:opacity-90 transition"> | |
| <h3 class="font-bold">Dance</h3> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Content --> | |
| <div class="flex-1 overflow-y-auto p-6 bg-gradient-to-b from-blue-900 to-gray-900" id="main-content"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold">Made For You</h2> | |
| <a href="#" class="text-sm text-gray-400 hover:underline">Show all</a> | |
| </div> | |
| <div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-6 mb-8" id="featured-playlists"> | |
| <!-- Featured playlists will be loaded here --> | |
| <div class="group"> | |
| <div class="album-art relative mb-3"> | |
| <img src="https://c.saavncdn.com/editorial/JustHits-hindi_20240208054618.jpg" alt="Album" class="w-full rounded shadow-lg"> | |
| <button class="play-button absolute bottom-2 right-2 bg-green-500 rounded-full w-12 h-12 flex items-center justify-center shadow-lg group-hover:opacity-100 group-hover:transform group-hover:translate-y-0"> | |
| <i class="fas fa-play text-xl"></i> | |
| </button> | |
| </div> | |
| <h3 class="font-medium text-white">Today's Top Hits</h3> | |
| <p class="text-sm text-gray-400">The most played tracks right now</p> | |
| </div> | |
| </div> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold">Recently played</h2> | |
| <a href="#" class="text-sm text-gray-400 hover:underline">Show all</a> | |
| </div> | |
| <div class="bg-gray-800 bg-opacity-40 rounded-lg overflow-hidden" id="recently-played"> | |
| <table class="w-full"> | |
| <thead> | |
| <tr class="border-b border-gray-700 text-gray-400 text-left"> | |
| <th class="p-4 w-12">#</th> | |
| <th class="p-4">TITLE</th> | |
| <th class="p-4">ALBUM</th> | |
| <th class="p-4 text-right">DURATION</th> | |
| </tr> | |
| </thead> | |
| <tbody id="songs-table"> | |
| <!-- Songs will be loaded here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <!-- Playlist View (hidden by default) --> | |
| <div class="hidden flex-1 overflow-y-auto p-6 bg-gradient-to-b from-blue-900 to-gray-900" id="playlist-view"> | |
| <div class="flex items-end mb-8"> | |
| <img src="" alt="Playlist" class="w-48 h-48 shadow-2xl mr-6" id="playlist-image"> | |
| <div> | |
| <p class="text-sm font-bold mb-2">PLAYLIST</p> | |
| <h1 class="text-5xl font-bold mb-4" id="playlist-title">Playlist Title</h1> | |
| <p class="text-gray-400 mb-2" id="playlist-description"></p> | |
| <div class="flex items-center text-sm"> | |
| <span class="font-bold" id="playlist-owner">JioSaavn</span> | |
| <span class="mx-1">•</span> | |
| <span id="playlist-song-count">0 songs</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mb-6"> | |
| <button class="bg-green-500 hover:bg-green-600 text-white rounded-full px-6 py-2 font-bold mr-4 transition" id="play-playlist"> | |
| <i class="fas fa-play mr-2"></i> Play | |
| </button> | |
| <button class="text-gray-400 hover:text-white"> | |
| <i class="far fa-heart text-xl"></i> | |
| </button> | |
| </div> | |
| <div class="bg-gray-800 bg-opacity-40 rounded-lg overflow-hidden"> | |
| <table class="w-full"> | |
| <thead> | |
| <tr class="border-b border-gray-700 text-gray-400 text-left"> | |
| <th class="p-4 w-12">#</th> | |
| <th class="p-4">TITLE</th> | |
| <th class="p-4">ALBUM</th> | |
| <th class="p-4 text-right">DURATION</th> | |
| </tr> | |
| </thead> | |
| <tbody id="playlist-songs"> | |
| <!-- Playlist songs will be loaded here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Player --> | |
| <div class="fixed bottom-0 left-0 right-0 bg-gray-900 border-t border-gray-800 h-20 flex items-center px-4"> | |
| <div class="w-1/4 flex items-center"> | |
| <img src="" alt="Album" class="w-14 h-14 mr-3" id="player-album-art"> | |
| <div> | |
| <div class="text-sm font-medium truncate max-w-xs" id="player-song-title">No song selected</div> | |
| <div class="text-xs text-gray-400 truncate max-w-xs" id="player-song-artist">-</div> | |
| </div> | |
| <button class="ml-4 text-gray-400 hover:text-white" id="like-song"> | |
| <i class="far fa-heart"></i> | |
| </button> | |
| </div> | |
| <div class="w-2/4 flex flex-col items-center"> | |
| <div class="flex items-center mb-2"> | |
| <button class="mx-2 text-gray-400 hover:text-white" id="shuffle"> | |
| <i class="fas fa-random"></i> | |
| </button> | |
| <button class="mx-2 text-gray-400 hover:text-white" id="prev-song"> | |
| <i class="fas fa-step-backward"></i> | |
| </button> | |
| <button class="mx-3 bg-white rounded-full w-8 h-8 flex items-center justify-center hover:scale-105 transition" id="play-pause"> | |
| <i class="fas fa-play text-black" id="play-pause-icon"></i> | |
| </button> | |
| <button class="mx-2 text-gray-400 hover:text-white" id="next-song"> | |
| <i class="fas fa-step-forward"></i> | |
| </button> | |
| <button class="mx-2 text-gray-400 hover:text-white" id="repeat"> | |
| <i class="fas fa-redo"></i> | |
| </button> | |
| </div> | |
| <div class="w-full flex items-center"> | |
| <span class="text-xs text-gray-400 mr-2" id="current-time">0:00</span> | |
| <input type="range" class="progress-bar flex-1" min="0" max="100" value="0" id="progress-bar"> | |
| <span class="text-xs text-gray-400 ml-2" id="duration">0:00</span> | |
| </div> | |
| </div> | |
| <div class="w-1/4 flex justify-end items-center"> | |
| <button class="mx-2 text-gray-400 hover:text-white" id="queue"> | |
| <i class="fas fa-list"></i> | |
| </button> | |
| <button class="mx-2 text-gray-400 hover:text-white"> | |
| <i class="fas fa-laptop"></i> | |
| </button> | |
| <button class="mx-2 text-gray-400 hover:text-white"> | |
| <i class="fas fa-volume-up"></i> | |
| </button> | |
| <input type="range" class="w-20 progress-bar" min="0" max="100" value="70" id="volume-control"> | |
| </div> | |
| <!-- Audio element --> | |
| <audio id="audio-player"></audio> | |
| </div> | |
| <script> | |
| // Global variables | |
| let currentAudio = null; | |
| let currentPlaylist = []; | |
| let currentSongIndex = -1; | |
| let isPlaying = false; | |
| let isShuffleOn = false; | |
| let isRepeatOn = false; | |
| let searchTimeout = null; | |
| // DOM elements | |
| const audioPlayer = document.getElementById('audio-player'); | |
| const progressBar = document.getElementById('progress-bar'); | |
| const currentTimeDisplay = document.getElementById('current-time'); | |
| const durationDisplay = document.getElementById('duration'); | |
| const playPauseButton = document.getElementById('play-pause'); | |
| const playPauseIcon = document.getElementById('play-pause-icon'); | |
| const prevSongButton = document.getElementById('prev-song'); | |
| const nextSongButton = document.getElementById('next-song'); | |
| const shuffleButton = document.getElementById('shuffle'); | |
| const repeatButton = document.getElementById('repeat'); | |
| const playerSongTitle = document.getElementById('player-song-title'); | |
| const playerSongArtist = document.getElementById('player-song-artist'); | |
| const playerAlbumArt = document.getElementById('player-album-art'); | |
| // Navigation elements | |
| const homeLink = document.getElementById('home-link'); | |
| const searchLink = document.getElementById('search-link'); | |
| const libraryLink = document.getElementById('library-link'); | |
| const mainHeader = document.getElementById('main-header'); | |
| const searchSection = document.getElementById('search-section'); | |
| const mainContent = document.getElementById('main-content'); | |
| const playlistView = document.getElementById('playlist-view'); | |
| const searchInput = document.getElementById('search-input'); | |
| const searchResults = document.getElementById('search-results'); | |
| const playlistLinks = document.querySelectorAll('.playlist-link'); | |
| // Initialize the app | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Set greeting based on time of day | |
| setGreeting(); | |
| // Load featured content | |
| loadFeaturedContent(); | |
| // Load recently played (mock data) | |
| loadRecentlyPlayed(); | |
| // Event listeners for player controls | |
| playPauseButton.addEventListener('click', togglePlayPause); | |
| prevSongButton.addEventListener('click', playPreviousSong); | |
| nextSongButton.addEventListener('click', playNextSong); | |
| shuffleButton.addEventListener('click', toggleShuffle); | |
| repeatButton.addEventListener('click', toggleRepeat); | |
| progressBar.addEventListener('input', seekAudio); | |
| audioPlayer.addEventListener('timeupdate', updateProgressBar); | |
| audioPlayer.addEventListener('ended', handleSongEnded); | |
| audioPlayer.addEventListener('loadedmetadata', updateDurationDisplay); | |
| // Navigation event listeners | |
| homeLink.addEventListener('click', (e) => { | |
| e.preventDefault(); | |
| showMainContent(); | |
| }); | |
| searchLink.addEventListener('click', (e) => { | |
| e.preventDefault(); | |
| showSearchSection(); | |
| }); | |
| libraryLink.addEventListener('click', (e) => { | |
| e.preventDefault(); | |
| showMainContent(); | |
| }); | |
| // Search functionality | |
| searchInput.addEventListener('input', handleSearchInput); | |
| // Playlist links | |
| playlistLinks.forEach(link => { | |
| link.addEventListener('click', (e) => { | |
| e.preventDefault(); | |
| const playlistId = link.getAttribute('data-id'); | |
| loadPlaylist(playlistId); | |
| }); | |
| }); | |
| // Quick access items | |
| document.querySelectorAll('#quick-access > div').forEach(item => { | |
| item.addEventListener('click', () => { | |
| // For demo purposes, we'll just show a playlist | |
| loadPlaylist('8291463'); // Top Hindi Hits | |
| }); | |
| }); | |
| // Browse categories | |
| document.querySelectorAll('#browse-categories > div').forEach(item => { | |
| item.addEventListener('click', () => { | |
| const category = item.querySelector('h3').textContent; | |
| // For demo purposes, we'll just show a playlist based on category | |
| if (category === 'Hindi') loadPlaylist('8291463'); | |
| else if (category === 'Punjabi') loadPlaylist('1268420'); | |
| else if (category === 'Pop') loadPlaylist('1268420'); | |
| else if (category === 'Romantic') loadPlaylist('106114462'); | |
| else if (category === 'Dance') loadPlaylist('103581706'); | |
| }); | |
| }); | |
| }); | |
| // Functions | |
| function setGreeting() { | |
| const hour = new Date().getHours(); | |
| let greeting = ''; | |
| if (hour < 12) greeting = 'Good morning'; | |
| else if (hour < 18) greeting = 'Good afternoon'; | |
| else greeting = 'Good evening'; | |
| document.getElementById('greeting').textContent = greeting; | |
| } | |
| function showMainContent() { | |
| mainHeader.classList.remove('hidden'); | |
| searchSection.classList.add('hidden'); | |
| mainContent.classList.remove('hidden'); | |
| playlistView.classList.add('hidden'); | |
| } | |
| function showSearchSection() { | |
| mainHeader.classList.add('hidden'); | |
| searchSection.classList.remove('hidden'); | |
| mainContent.classList.add('hidden'); | |
| playlistView.classList.add('hidden'); | |
| searchInput.focus(); | |
| } | |
| function showPlaylistView() { | |
| mainHeader.classList.add('hidden'); | |
| searchSection.classList.add('hidden'); | |
| mainContent.classList.add('hidden'); | |
| playlistView.classList.remove('hidden'); | |
| } | |
| function handleSearchInput() { | |
| clearTimeout(searchTimeout); | |
| const query = searchInput.value.trim(); | |
| if (query.length < 2) { | |
| searchResults.classList.add('hidden'); | |
| return; | |
| } | |
| searchResults.innerHTML = '<div class="text-center py-4"><i class="fas fa-spinner fa-spin mr-2"></i>Searching...</div>'; | |
| searchResults.classList.remove('hidden'); | |
| searchTimeout = setTimeout(() => { | |
| searchJioSaavn(query); | |
| }, 500); | |
| } | |
| function searchJioSaavn(query) { | |
| // Use JioSaavn API for search | |
| fetch(`https://saavn.me/search/songs?query=${encodeURIComponent(query)}&page=1&limit=10`) | |
| .then(response => response.json()) | |
| .then(data => { | |
| displaySearchResults(data.data.results); | |
| }) | |
| .catch(error => { | |
| console.error('Error searching:', error); | |
| searchResults.innerHTML = '<div class="text-center py-4 text-red-500">Error loading search results</div>'; | |
| }); | |
| } | |
| function displaySearchResults(results) { | |
| if (!results || results.length === 0) { | |
| searchResults.innerHTML = '<div class="text-center py-4">No results found</div>'; | |
| return; | |
| } | |
| let html = '<div class="space-y-2">'; | |
| results.forEach((song, index) => { | |
| html += ` | |
| <div class="flex items-center p-2 hover:bg-gray-700 rounded cursor-pointer search-result" data-id="${song.id}"> | |
| <img src="${song.image[1].link}" alt="${song.name}" class="w-10 h-10 mr-3"> | |
| <div class="flex-1"> | |
| <div class="font-medium truncate">${song.name}</div> | |
| <div class="text-sm text-gray-400 truncate">${song.primaryArtists}</div> | |
| </div> | |
| <div class="text-sm text-gray-400">${formatDuration(song.duration)}</div> | |
| </div> | |
| `; | |
| }); | |
| html += '</div>'; | |
| searchResults.innerHTML = html; | |
| // Add click event to search results | |
| document.querySelectorAll('.search-result').forEach(item => { | |
| item.addEventListener('click', () => { | |
| const songId = item.getAttribute('data-id'); | |
| playSongById(songId); | |
| }); | |
| }); | |
| } | |
| function loadFeaturedContent() { | |
| // Use JioSaavn API to get featured playlists | |
| fetch('https://saavn.me/modules?language=hindi,english') | |
| .then(response => response.json()) | |
| .then(data => { | |
| displayFeaturedPlaylists(data.data.trending.playlists); | |
| }) | |
| .catch(error => { | |
| console.error('Error loading featured content:', error); | |
| }); | |
| } | |
| function displayFeaturedPlaylists(playlists) { | |
| const container = document.getElementById('featured-playlists'); | |
| let html = ''; | |
| // Limit to 5 playlists for demo | |
| playlists.slice(0, 5).forEach(playlist => { | |
| html += ` | |
| <div class="group"> | |
| <div class="album-art relative mb-3 cursor-pointer" data-id="${playlist.id}"> | |
| <img src="${playlist.image}" alt="${playlist.title}" class="w-full rounded shadow-lg"> | |
| <button class="play-button absolute bottom-2 right-2 bg-green-500 rounded-full w-12 h-12 flex items-center justify-center shadow-lg group-hover:opacity-100 group-hover:transform group-hover:translate-y-0"> | |
| <i class="fas fa-play text-xl"></i> | |
| </button> | |
| </div> | |
| <h3 class="font-medium text-white">${playlist.title}</h3> | |
| <p class="text-sm text-gray-400">${playlist.subtitle || 'Curated playlist'}</p> | |
| </div> | |
| `; | |
| }); | |
| container.innerHTML = html; | |
| // Add click event to playlist items | |
| document.querySelectorAll('.album-art').forEach(item => { | |
| item.addEventListener('click', () => { | |
| const playlistId = item.getAttribute('data-id'); | |
| loadPlaylist(playlistId); | |
| }); | |
| }); | |
| } | |
| function loadRecentlyPlayed() { | |
| // Mock data for recently played | |
| const songs = [ | |
| { | |
| id: '1', | |
| title: 'Tum Hi Ho', | |
| artist: 'Arijit Singh', | |
| album: 'Aashiqui 2', | |
| duration: '4:22', | |
| image: 'https://c.saavncdn.com/227/Aashiqui-2-Hindi-2013-20230905173600-500x500.jpg' | |
| }, | |
| { | |
| id: '2', | |
| title: 'Kesariya', | |
| artist: 'Arijit Singh', | |
| album: 'Brahmāstra', | |
| duration: '4:28', | |
| image: 'https://c.saavncdn.com/191/Kesariya-From-Brahmastra-Hindi-2022-20220717092820-500x500.jpg' | |
| }, | |
| { | |
| id: '3', | |
| title: 'Apna Bana Le', | |
| artist: 'Arijit Singh', | |
| album: 'Bhediya', | |
| duration: '4:21', | |
| image: 'https://c.saavncdn.com/391/Apna-Bana-Le-From-Bhediya-Hindi-2022-20221018112233-500x500.jpg' | |
| } | |
| ]; | |
| const container = document.getElementById('songs-table'); | |
| let html = ''; | |
| songs.forEach((song, index) => { | |
| html += ` | |
| <tr class="song-row border-b border-gray-700 hover:bg-gray-700 cursor-pointer" data-id="${song.id}"> | |
| <td class="p-4 text-gray-400">${index + 1}</td> | |
| <td class="p-4"> | |
| <div class="flex items-center"> | |
| <img src="${song.image}" alt="Album" class="w-10 h-10 mr-3"> | |
| <div> | |
| <div class="font-medium">${song.title}</div> | |
| <div class="text-sm text-gray-400">${song.artist}</div> | |
| </div> | |
| </div> | |
| </td> | |
| <td class="p-4 text-gray-400">${song.album}</td> | |
| <td class="p-4 text-right text-gray-400">${song.duration}</td> | |
| </tr> | |
| `; | |
| }); | |
| container.innerHTML = html; | |
| // Add click event to song rows | |
| document.querySelectorAll('.song-row').forEach(row => { | |
| row.addEventListener('click', () => { | |
| const songId = row.getAttribute('data-id'); | |
| // For demo, we'll just play the first song | |
| playSong(songs[0]); | |
| }); | |
| }); | |
| } | |
| function loadPlaylist(playlistId) { | |
| showPlaylistView(); | |
| // Show loading state | |
| document.getElementById('playlist-title').textContent = 'Loading...'; | |
| document.getElementById('playlist-image').src = ''; | |
| document.getElementById('playlist-description').textContent = ''; | |
| document.getElementById('playlist-owner').textContent = ''; | |
| document.getElementById('playlist-song-count').textContent = 'Loading songs...'; | |
| document.getElementById('playlist-songs').innerHTML = '<tr><td colspan="4" class="text-center py-4"><i class="fas fa-spinner fa-spin mr-2"></i>Loading playlist...</td></tr>'; | |
| // Fetch playlist details from JioSaavn API | |
| fetch(`https://saavn.me/playlists?id=${playlistId}`) | |
| .then(response => response.json()) | |
| .then(data => { | |
| const playlist = data.data; | |
| displayPlaylist(playlist); | |
| // Store playlist songs for playback | |
| currentPlaylist = playlist.songs; | |
| }) | |
| .catch(error => { | |
| console.error('Error loading playlist:', error); | |
| document.getElementById('playlist-title').textContent = 'Error loading playlist'; | |
| document.getElementById('playlist-songs').innerHTML = '<tr><td colspan="4" class="text-center py-4 text-red-500">Error loading playlist</td></tr>'; | |
| }); | |
| } | |
| function displayPlaylist(playlist) { | |
| document.getElementById('playlist-title').textContent = playlist.name; | |
| document.getElementById('playlist-image').src = playlist.image[1].link; | |
| document.getElementById('playlist-description').textContent = playlist.description || 'Curated playlist'; | |
| document.getElementById('playlist-owner').textContent = playlist.artistName || 'JioSaavn'; | |
| document.getElementById('playlist-song-count').textContent = `${playlist.songCount} songs`; | |
| const container = document.getElementById('playlist-songs'); | |
| let html = ''; | |
| playlist.songs.forEach((song, index) => { | |
| html += ` | |
| <tr class="song-row border-b border-gray-700 hover:bg-gray-700 cursor-pointer" data-id="${song.id}"> | |
| <td class="p-4 text-gray-400">${index + 1}</td> | |
| <td class="p-4"> | |
| <div class="flex items-center"> | |
| <img src="${song.image[1].link}" alt="Album" class="w-10 h-10 mr-3"> | |
| <div> | |
| <div class="font-medium">${song.name}</div> | |
| <div class="text-sm text-gray-400">${song.primaryArtists}</div> | |
| </div> | |
| </div> | |
| </td> | |
| <td class="p-4 text-gray-400">${song.album.name}</td> | |
| <td class="p-4 text-right text-gray-400">${formatDuration(song.duration)}</td> | |
| </tr> | |
| `; | |
| }); | |
| container.innerHTML = html; | |
| // Add click event to playlist song rows | |
| document.querySelectorAll('#playlist-songs .song-row').forEach((row, index) => { | |
| row.addEventListener('click', () => { | |
| playSongFromPlaylist(index); | |
| }); | |
| }); | |
| } | |
| function playSongFromPlaylist(index) { | |
| if (!currentPlaylist || index < 0 || index >= currentPlaylist.length) return; | |
| currentSongIndex = index; | |
| const song = currentPlaylist[index]; | |
| playSong(song); | |
| } | |
| function playSongById(songId) { | |
| // Fetch song details from JioSaavn API | |
| fetch(`https://saavn.me/songs?id=${songId}`) | |
| .then(response => response.json()) | |
| .then(data => { | |
| const song = data.data[0]; | |
| playSong(song); | |
| }) | |
| .catch(error => { | |
| console.error('Error loading song:', error); | |
| }); | |
| } | |
| function playSong(song) { | |
| // Stop current audio if playing | |
| if (currentAudio) { | |
| currentAudio.pause(); | |
| currentAudio = null; | |
| } | |
| // Update player UI | |
| playerSongTitle.textContent = song.name || song.title; | |
| playerSongArtist.textContent = song.primaryArtists || song.artist; | |
| playerAlbumArt.src = song.image[1]?.link || song.image || ''; | |
| // Get download URL for the song | |
| fetch(`https://saavn.me/songs?id=${song.id}`) | |
| .then(response => response.json()) | |
| .then(data => { | |
| const downloadUrl = data.data[0].downloadUrl[4]?.link; | |
| if (downloadUrl) { | |
| audioPlayer.src = downloadUrl; | |
| audioPlayer.play() | |
| .then(() => { | |
| isPlaying = true; | |
| playPauseIcon.classList.remove('fa-play'); | |
| playPauseIcon.classList.add('fa-pause'); | |
| // Update duration display | |
| updateDurationDisplay(); | |
| }) | |
| .catch(error => { | |
| console.error('Error playing song:', error); | |
| }); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error('Error getting song URL:', error); | |
| }); | |
| } | |
| function togglePlayPause() { | |
| if (!audioPlayer.src) { | |
| // If no song is selected, play the first song from current playlist | |
| if (currentPlaylist && currentPlaylist.length > 0) { | |
| playSongFromPlaylist(0); | |
| } | |
| return; | |
| } | |
| if (isPlaying) { | |
| audioPlayer.pause(); | |
| playPauseIcon.classList.remove('fa-pause'); | |
| playPauseIcon.classList.add('fa-play'); | |
| } else { | |
| audioPlayer.play() | |
| .then(() => { | |
| playPauseIcon.classList.remove('fa-play'); | |
| playPauseIcon.classList.add('fa-pause'); | |
| }) | |
| .catch(error => { | |
| console.error('Error playing:', error); | |
| }); | |
| } | |
| isPlaying = !isPlaying; | |
| } | |
| function playPreviousSong() { | |
| if (!currentPlaylist || currentPlaylist.length === 0) return; | |
| if (isShuffleOn) { | |
| currentSongIndex = Math.floor(Math.random() * currentPlaylist.length); | |
| } else { | |
| currentSongIndex = (currentSongIndex - 1 + currentPlaylist.length) % currentPlaylist.length; | |
| } | |
| playSongFromPlaylist(currentSongIndex); | |
| } | |
| function playNextSong() { | |
| if (!currentPlaylist || currentPlaylist.length === 0) return; | |
| if (isShuffleOn) { | |
| currentSongIndex = Math.floor(Math.random() * currentPlaylist.length); | |
| } else { | |
| currentSongIndex = (currentSongIndex + 1) % currentPlaylist.length; | |
| } | |
| playSongFromPlaylist(currentSongIndex); | |
| } | |
| function handleSongEnded() { | |
| if (isRepeatOn) { | |
| audioPlayer.currentTime = 0; | |
| audioPlayer.play(); | |
| } else { | |
| playNextSong(); | |
| } | |
| } | |
| function toggleShuffle() { | |
| isShuffleOn = !isShuffleOn; | |
| shuffleButton.classList.toggle('text-green-500', isShuffleOn); | |
| shuffleButton.classList.toggle('text-gray-400', !isShuffleOn); | |
| } | |
| function toggleRepeat() { | |
| isRepeatOn = !isRepeatOn; | |
| repeatButton.classList.toggle('text-green-500', isRepeatOn); | |
| repeatButton.classList.toggle('text-gray-400', !isRepeatOn); | |
| } | |
| function seekAudio() { | |
| if (audioPlayer.duration) { | |
| const seekTime = (progressBar.value / 100) * audioPlayer.duration; | |
| audioPlayer.currentTime = seekTime; | |
| } | |
| } | |
| function updateProgressBar() { | |
| if (audioPlayer.duration) { | |
| const progress = (audioPlayer.currentTime / audioPlayer.duration) * 100; | |
| progressBar.value = progress; | |
| // Update current time display | |
| currentTimeDisplay.textContent = formatTime(audioPlayer.currentTime); | |
| } | |
| } | |
| function updateDurationDisplay() { | |
| if (audioPlayer.duration) { | |
| durationDisplay.textContent = formatTime(audioPlayer.duration); | |
| } | |
| } | |
| function formatTime(seconds) { | |
| const mins = Math.floor(seconds / 60); | |
| const secs = Math.floor(seconds % 60); | |
| return `${mins}:${secs < 10 ? '0' : ''}${secs}`; | |
| } | |
| function formatDuration(durationInSeconds) { | |
| const mins = Math.floor(durationInSeconds / 60); | |
| const secs = durationInSeconds % 60; | |
| return `${mins}:${secs < 10 ? '0' : ''}${secs}`; | |
| } | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Enoughking/music" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |