Last active
October 11, 2025 01:21
-
-
Save s3va/32e0d4d07dc88ce5d6f831f6945e8fbd to your computer and use it in GitHub Desktop.
audio player of oga files in html page my javascript in php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // $files = glob("*.oga"); | |
| $files = glob('*.{oga,mp3}', GLOB_BRACE); | |
| sort($files); | |
| function formatSize($bytes) { | |
| if ($bytes >= 1048576) return number_format($bytes / 1048576, 2) . ' MB'; | |
| if ($bytes >= 1024) return number_format($bytes / 1024, 2) . ' KB'; | |
| return $bytes . ' bytes'; | |
| } | |
| ?> | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <title>OGA Audio Player with Sizes and Label</title> | |
| <style> | |
| html { color-scheme: dark; } | |
| body { font-family: Arial, sans-serif; margin: 20px; } | |
| ul.playlist { list-style: none; padding: 0; max-width: 500px; } | |
| ul.playlist li { cursor: pointer; padding: 5px 10px; border-bottom: 1px solid #ccc; display: flex; justify-content: space-between; } | |
| ul.playlist li:hover { background: #404040; } | |
| ul.playlist li.active { background: #007BFF; color: white; } | |
| .filename { flex-grow: 1; } | |
| .filesize { margin-left: 10px; font-size: 0.9em; white-space: nowrap; } | |
| /*.filesize { margin-left: 10px; color: #666; font-size: 0.9em; white-space: nowrap; }*/ | |
| #currentPlaying { margin-bottom: 10px; font-weight: bold; } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- .filesize { margin-left: 10px; color: #666; font-size: 0.9em; white-space: nowrap; } --> | |
| <h2>OGA Files Playlist with Sizes</h2> | |
| <ul class="playlist" id="playlist"> | |
| <?php foreach ($files as $index => $file): ?> | |
| <li data-index="<?= $index ?>"> | |
| <span class="filename"><?= htmlspecialchars($file) ?></span> | |
| <span class="filesize">(<?= formatSize(filesize($file)) ?>)</span> | |
| </li> | |
| <?php endforeach; ?> | |
| </ul> | |
| <div id="currentPlaying">No file playing</div> | |
| <audio id="audioPlayer" controls preload="auto" style="width: 500px;"> | |
| Your browser does not support the audio element. | |
| </audio> | |
| <script> | |
| const files = <?= json_encode($files) ?>; | |
| const playlist = document.getElementById('playlist'); | |
| const audioPlayer = document.getElementById('audioPlayer'); | |
| const currentPlayingLabel = document.getElementById('currentPlaying'); | |
| let currentIndex = -1; | |
| function formatSize(bytes) { | |
| if (bytes >= 1048576) return (bytes / 1048576).toFixed(2) + ' MB'; | |
| if (bytes >= 1024) return (bytes / 1024).toFixed(2) + ' KB'; | |
| return bytes + ' bytes'; | |
| } | |
| function updateCurrentPlaying(index) { | |
| if (index < 0 || index >= files.length) { | |
| currentPlayingLabel.textContent = 'No file playing'; | |
| return; | |
| } | |
| const file = files[index]; | |
| fetch(file, { method: 'HEAD' }).then(response => { | |
| const size = response.headers.get('content-length'); | |
| currentPlayingLabel.textContent = `${file} (${formatSize(parseInt(size))})`; | |
| }).catch(() => { | |
| currentPlayingLabel.textContent = `${file} (size unknown)`; | |
| }); | |
| } | |
| function setActiveItem(index) { | |
| Array.from(playlist.children).forEach((li, i) => { | |
| li.classList.toggle('active', i === index); | |
| }); | |
| } | |
| function playFile(index) { | |
| if (index < 0 || index >= files.length) return; | |
| currentIndex = index; | |
| audioPlayer.src = files[currentIndex]; | |
| audioPlayer.play(); | |
| setActiveItem(currentIndex); | |
| updateCurrentPlaying(currentIndex); | |
| } | |
| playlist.addEventListener('click', e => { | |
| const li = e.target.tagName === 'LI' ? e.target : e.target.closest('li'); | |
| if (!li) return; | |
| const index = parseInt(li.getAttribute('data-index'), 10); | |
| playFile(index); | |
| }); | |
| audioPlayer.addEventListener('ended', () => { | |
| if (currentIndex + 1 < files.length) { | |
| playFile(currentIndex + 1); | |
| } else { | |
| currentPlayingLabel.textContent = 'No file playing'; | |
| setActiveItem(-1); | |
| currentIndex = -1; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Dark-themed Directory Index | |
| * Matches YYYYMMDD pattern and sorts by date | |
| */ | |
| // Dark theme CSS | |
| $darkTheme = " | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| background: linear-gradient(135deg, #0c0c0c 0%, #1a1a1a 100%); | |
| color: #e0e0e0; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| min-height: 100vh; | |
| padding: 20px; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| background: rgba(30, 30, 30, 0.95); | |
| border-radius: 15px; | |
| border: 1px solid #333; | |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); | |
| /* overflow: hidden; */ | |
| } | |
| .header { | |
| background: linear-gradient(135deg, #2d2d2d 0%, #1a1a1a 100%); | |
| padding: 30px; | |
| text-align: center; | |
| border-bottom: 2px solid #444; | |
| } | |
| .header h1 { | |
| color: #ffffff; | |
| font-size: 2.5em; | |
| margin-bottom: 10px; | |
| text-shadow: 0 2px 4px rgba(0,0,0,0.5); | |
| } | |
| .header p { | |
| color: #b0b0b0; | |
| font-size: 1.1em; | |
| } | |
| .stats { | |
| display: flex; | |
| justify-content: center; | |
| gap: 30px; | |
| margin-top: 20px; | |
| flex-wrap: wrap; | |
| } | |
| .stat-box { | |
| background: rgba(40, 40, 40, 0.8); | |
| padding: 15px 25px; | |
| border-radius: 10px; | |
| border: 1px solid #444; | |
| text-align: center; | |
| } | |
| .stat-number { | |
| font-size: 2em; | |
| font-weight: bold; | |
| color: #4fc3f7; | |
| display: block; | |
| } | |
| .stat-label { | |
| color: #888; | |
| font-size: 0.9em; | |
| } | |
| .content { | |
| padding: 30px; | |
| } | |
| .controls { | |
| background: rgba(40, 40, 40, 0.6); | |
| padding: 20px; | |
| border-radius: 10px; | |
| margin-bottom: 25px; | |
| border: 1px solid #333; | |
| } | |
| .control-group { | |
| display: flex; | |
| gap: 15px; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| } | |
| .btn { | |
| background: linear-gradient(135deg, #4fc3f7 0%, #29b6f6 100%); | |
| color: #000; | |
| border: none; | |
| padding: 10px 20px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: bold; | |
| transition: all 0.3s ease; | |
| text-decoration: none; | |
| display: inline-block; | |
| } | |
| .btn:hover { | |
| background: linear-gradient(135deg, #29b6f6 0%, #0288d1 100%); | |
| transform: translateY(-2px); | |
| box-shadow: 0 5px 15px rgba(41, 182, 246, 0.3); | |
| } | |
| .btn-secondary { | |
| background: linear-gradient(135deg, #666 0%, #444 100%); | |
| color: #fff; | |
| } | |
| .btn-secondary:hover { | |
| background: linear-gradient(135deg, #777 0%, #555 100%); | |
| } | |
| .directory-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| background: rgba(25, 25, 25, 0.8); | |
| border-radius: 10px; | |
| overflow: hidden; | |
| border: 1px solid #333; | |
| } | |
| .directory-table th { | |
| background: linear-gradient(135deg, #333 0%, #222 100%); | |
| padding: 15px; | |
| text-align: left; | |
| color: #4fc3f7; | |
| font-weight: 600; | |
| border-bottom: 2px solid #444; | |
| } | |
| .directory-table td { | |
| padding: 15px; | |
| border-bottom: 1px solid #333; | |
| transition: background 0.3s ease; | |
| } | |
| .directory-table td { | |
| padding: 15px; | |
| border-bottom: 1px solid #333; | |
| transition: background 0.3s ease; | |
| } | |
| .directory-table tr:hover td { | |
| background: rgba(60, 60, 60, 0.5); | |
| } | |
| .directory-table tr:last-child td { | |
| border-bottom: none; | |
| } | |
| .directory-name { | |
| color: #ffffff; | |
| font-weight: bold; | |
| font-family: 'Courier New', monospace; | |
| font-size: 1.1em; | |
| } | |
| .date-info { | |
| color: #b0b0b0; | |
| } | |
| .day-highlight { | |
| color: #4fc3f7; | |
| font-weight: bold; | |
| } | |
| .age-indicator { | |
| display: inline-block; | |
| width: 10px; | |
| height: 10px; | |
| border-radius: 50%; | |
| margin-right: 8px; | |
| } | |
| .age-recent { background: #4caf50; } | |
| .age-medium { background: #ff9800; } | |
| .age-old { background: #f44336; } | |
| .empty-state { | |
| text-align: center; | |
| padding: 50px; | |
| color: #888; | |
| } | |
| .empty-state i { | |
| font-size: 3em; | |
| margin-bottom: 20px; | |
| display: block; | |
| color: #444; | |
| } | |
| .footer { | |
| text-align: center; | |
| padding: 20px; | |
| color: #666; | |
| border-top: 1px solid #333; | |
| background: rgba(20, 20, 20, 0.8); | |
| } | |
| .badge { | |
| background: #4fc3f7; | |
| color: #000; | |
| padding: 3px 8px; | |
| border-radius: 12px; | |
| font-size: 0.8em; | |
| font-weight: bold; | |
| margin-left: 8px; | |
| } | |
| @media (max-width: 768px) { | |
| .container { | |
| margin: 10px; | |
| border-radius: 10px; | |
| } | |
| .header h1 { | |
| font-size: 2em; | |
| } | |
| .diectory-table { | |
| font-size: 0.9em; | |
| } | |
| .control-group { | |
| justify-content: center; | |
| } | |
| } | |
| @media (max-width: 640px) { | |
| body { | |
| padding: 0px; | |
| } | |
| .directory-table hd { | |
| padding-left: 0px; | |
| padding-right: 0px; | |
| } | |
| .directory-table td { | |
| padding-left: 0px; | |
| padding-right: 0px; | |
| } | |
| .content { | |
| padding: 0px; | |
| } | |
| } | |
| </style> | |
| "; | |
| // Function to get age indicator | |
| function getAgeIndicator($date) { | |
| $now = new DateTime(); | |
| $diff = $now->diff($date); | |
| $days = $diff->days; | |
| if ($days <= 7) return '<span class="age-indicator age-recent" title="Recent (β€ 7 days)"></span>'; | |
| if ($days <= 30) return '<span class="age-indicator age-medium" title="Medium (β€ 30 days)"></span>'; | |
| return '<span class="age-indicator age-old" title="Old (> 30 days)"></span>'; | |
| } | |
| // Scan directories | |
| $currentDir = '.'; | |
| $pattern = '/^\d{8}$/'; | |
| $matchedDirs = []; | |
| $totalDirs = 0; | |
| $validDirs = 0; | |
| if ($handle = opendir($currentDir)) { | |
| while (false !== ($entry = readdir($handle))) { | |
| if( $entry !== '.' && $entry !== '..' && is_dir($entry) ){ | |
| $totalDirs++; | |
| if ($entry !== '.' && $entry !== '..' && is_dir($entry) && preg_match($pattern, $entry)) { | |
| $date = DateTime::createFromFormat('Ymd', $entry); | |
| if ($date) { | |
| $matchedDirs[] = [ | |
| 'name' => $entry, | |
| 'date' => $date, | |
| 'formatted' => $date->format('Y-m-d'), | |
| 'day' => $date->format('l'), | |
| 'timestamp' => $date->getTimestamp() | |
| ]; | |
| $validDirs++; | |
| } | |
| } | |
| } | |
| } | |
| closedir($handle); | |
| } | |
| // Sort by date (newest first) | |
| usort($matchedDirs, function($a, $b) { | |
| return $b['timestamp'] - $a['timestamp']; | |
| }); | |
| // Get date range | |
| $dateRange = 'N/A'; | |
| if (!empty($matchedDirs)) { | |
| $oldest = end($matchedDirs); | |
| $newest = reset($matchedDirs); | |
| $dateRange = $oldest['formatted'] . ' to ' . $newest['formatted']; | |
| } | |
| // Output HTML | |
| echo "<!DOCTYPE html> | |
| <html lang='en'> | |
| <head> | |
| <meta charset='UTF-8'> | |
| <meta name='viewport' content='width=device-width, initial-scale=1.0'> | |
| <title>Directory Index - YYYYMMDD</title> | |
| $darkTheme | |
| </head> | |
| <body> | |
| <div class='container'> | |
| <div class='header'> | |
| <h1>π Directory Index</h1> | |
| <p>Directories matching YYYYMMDD date pattern</p> | |
| <div class='stats'> | |
| <div class='stat-box'> | |
| <span class='stat-number'>$totalDirs</span> | |
| <span class='stat-label'>Total Directories</span> | |
| </div> | |
| <div class='stat-box'> | |
| <span class='stat-number'>$validDirs</span> | |
| <span class='stat-label'>Date Pattern Matches</span> | |
| </div> | |
| <div class='stat-box'> | |
| <span class='stat-number'>" . count($matchedDirs) . "</span> | |
| <span class='stat-label'>Valid Dates</span> | |
| </div> | |
| <div class='stat-box'> | |
| <span class='stat-number'>$dateRange</span> | |
| <span class='stat-label'>Date Range</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class='content'> | |
| <div class='controls'> | |
| <div class='control-group'> | |
| <button class='btn' onclick='location.reload()'>π Refresh</button> | |
| <button class='btn btn-secondary' onclick='exportToFile()'>π₯ Export List</button> | |
| <span style='color: #888; margin-left: auto;'> | |
| " . date('Y-m-d H:i:s') . " | |
| </span> | |
| </div> | |
| </div>"; | |
| if (empty($matchedDirs)) { | |
| echo "<div class='empty-state'> | |
| <i>π</i> | |
| <h3>No directories found</h3> | |
| <p>No directories matching the YYYYMMDD pattern were found in the current directory.</p> | |
| </div>"; | |
| } else { | |
| echo "<table class='directory-table'> | |
| <thead> | |
| <tr> | |
| <th>Directory Name</th> | |
| <th>Date</th> | |
| <th>Day</th> | |
| <th>Age</th> | |
| <th>Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody>"; | |
| foreach ($matchedDirs as $dir) { | |
| $ageIndicator = getAgeIndicator($dir['date']); | |
| $daysAgo = $dir['date']->diff(new DateTime())->days; | |
| $ageText = $daysAgo == 0 ? 'Today' : ($daysAgo == 1 ? '1 day ago' : "$daysAgo days ago"); | |
| echo "<tr> | |
| <td> | |
| <span class='directory-name'>π {$dir['name']}</span> | |
| </td> | |
| <td class='date-info'>{$dir['formatted']}</td> | |
| <td><span class='day-highlight'>{$dir['day']}</span></td> | |
| <td class='date-info'> | |
| $ageIndicator $ageText | |
| </td> | |
| <td> | |
| <button class='btn btn-secondary' onclick=\"openDirectory('{$dir['name']}')\"> | |
| Open | |
| </button> | |
| </td> | |
| </tr>"; | |
| } | |
| echo "</tbody></table>"; | |
| } | |
| echo " </div> | |
| <div class='footer'> | |
| <p>Generated by Directory Index β’ " . count($matchedDirs) . " directories found β’ Pattern: YYYYMMDD</p> | |
| </div> | |
| </div> | |
| <script> | |
| function openDirectory(dirName) { | |
| if (confirm('Open directory: ' + dirName + '?')) { | |
| window.open('./' + dirName, '_blank'); | |
| } | |
| } | |
| function exportToFile() { | |
| const content = " . json_encode(array_map(function($dir) { | |
| return [ | |
| 'directory' => $dir['name'], | |
| 'date' => $dir['formatted'], | |
| 'day' => $dir['day'] | |
| ]; | |
| }, $matchedDirs)) . "; | |
| const blob = new Blob([JSON.stringify(content, null, 2)], { type: 'application/json' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'directory-index-' + new Date().toISOString().split('T')[0] + '.json'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| } | |
| // Add some interactive effects | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const rows = document.querySelectorAll('.directory-table tr'); | |
| rows.forEach((row, index) => { | |
| row.style.animationDelay = (index * 0.1) + 's'; | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html>"; | |
| ?> | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Dark-themed Directory Index | |
| * Matches YYYYMMDD pattern and sorts by date | |
| */ | |
| // Dark theme CSS | |
| $darkTheme = " | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| background: linear-gradient(135deg, #0c0c0c 0%, #1a1a1a 100%); | |
| color: #e0e0e0; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| min-height: 100vh; | |
| padding: 20px; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| background: rgba(30, 30, 30, 0.95); | |
| border-radius: 15px; | |
| border: 1px solid #333; | |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); | |
| /* overflow: hidden; */ | |
| } | |
| .header { | |
| background: linear-gradient(135deg, #2d2d2d 0%, #1a1a1a 100%); | |
| padding: 30px; | |
| text-align: center; | |
| border-bottom: 2px solid #444; | |
| } | |
| .header h1 { | |
| color: #ffffff; | |
| font-size: 2.5em; | |
| margin-bottom: 10px; | |
| text-shadow: 0 2px 4px rgba(0,0,0,0.5); | |
| } | |
| .header p { | |
| color: #b0b0b0; | |
| font-size: 1.1em; | |
| } | |
| .stats { | |
| display: flex; | |
| justify-content: center; | |
| gap: 30px; | |
| margin-top: 20px; | |
| flex-wrap: wrap; | |
| } | |
| .stat-box { | |
| background: rgba(40, 40, 40, 0.8); | |
| padding: 15px 25px; | |
| border-radius: 10px; | |
| border: 1px solid #444; | |
| text-align: center; | |
| } | |
| .stat-number { | |
| font-size: 2em; | |
| font-weight: bold; | |
| color: #4fc3f7; | |
| display: block; | |
| } | |
| .stat-label { | |
| color: #888; | |
| font-size: 0.9em; | |
| } | |
| .content { | |
| padding: 30px; | |
| } | |
| .controls { | |
| background: rgba(40, 40, 40, 0.6); | |
| padding: 20px; | |
| border-radius: 10px; | |
| margin-bottom: 25px; | |
| border: 1px solid #333; | |
| } | |
| .control-group { | |
| display: flex; | |
| gap: 15px; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| } | |
| .btn { | |
| background: linear-gradient(135deg, #4fc3f7 0%, #29b6f6 100%); | |
| color: #000; | |
| border: none; | |
| padding: 10px 20px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: bold; | |
| transition: all 0.3s ease; | |
| text-decoration: none; | |
| display: inline-block; | |
| } | |
| .btn:hover { | |
| background: linear-gradient(135deg, #29b6f6 0%, #0288d1 100%); | |
| transform: translateY(-2px); | |
| box-shadow: 0 5px 15px rgba(41, 182, 246, 0.3); | |
| } | |
| .btn-secondary { | |
| background: linear-gradient(135deg, #666 0%, #444 100%); | |
| color: #fff; | |
| } | |
| .btn-secondary:hover { | |
| background: linear-gradient(135deg, #777 0%, #555 100%); | |
| } | |
| .directory-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| background: rgba(25, 25, 25, 0.8); | |
| border-radius: 10px; | |
| overflow: hidden; | |
| border: 1px solid #333; | |
| } | |
| .directory-table th { | |
| background: linear-gradient(135deg, #333 0%, #222 100%); | |
| padding: 15px; | |
| text-align: left; | |
| color: #4fc3f7; | |
| font-weight: 600; | |
| border-bottom: 2px solid #444; | |
| } | |
| .directory-table td { | |
| padding: 15px; | |
| border-bottom: 1px solid #333; | |
| transition: background 0.3s ease; | |
| } | |
| .directory-table td { | |
| padding: 15px; | |
| border-bottom: 1px solid #333; | |
| transition: background 0.3s ease; | |
| } | |
| .directory-table tr:hover td { | |
| background: rgba(60, 60, 60, 0.5); | |
| } | |
| .directory-table tr:last-child td { | |
| border-bottom: none; | |
| } | |
| .directory-name { | |
| color: #ffffff; | |
| font-weight: bold; | |
| font-family: 'Courier New', monospace; | |
| font-size: 1.1em; | |
| } | |
| .date-info { | |
| color: #b0b0b0; | |
| } | |
| .day-highlight { | |
| color: #4fc3f7; | |
| font-weight: bold; | |
| } | |
| .age-indicator { | |
| display: inline-block; | |
| width: 10px; | |
| height: 10px; | |
| border-radius: 50%; | |
| margin-right: 8px; | |
| } | |
| .age-recent { background: #4caf50; } | |
| .age-medium { background: #ff9800; } | |
| .age-old { background: #f44336; } | |
| .empty-state { | |
| text-align: center; | |
| padding: 50px; | |
| color: #888; | |
| } | |
| .empty-state i { | |
| font-size: 3em; | |
| margin-bottom: 20px; | |
| display: block; | |
| color: #444; | |
| } | |
| .footer { | |
| text-align: center; | |
| padding: 20px; | |
| color: #666; | |
| border-top: 1px solid #333; | |
| background: rgba(20, 20, 20, 0.8); | |
| } | |
| .badge { | |
| background: #4fc3f7; | |
| color: #000; | |
| padding: 3px 8px; | |
| border-radius: 12px; | |
| font-size: 0.8em; | |
| font-weight: bold; | |
| margin-left: 8px; | |
| } | |
| @media (max-width: 768px) { | |
| .container { | |
| margin: 10px; | |
| border-radius: 10px; | |
| } | |
| .header h1 { | |
| font-size: 2em; | |
| } | |
| .diectory-table { | |
| font-size: 0.9em; | |
| } | |
| .control-group { | |
| justify-content: center; | |
| } | |
| } | |
| @media (max-width: 640px) { | |
| body { | |
| padding: 0px; | |
| } | |
| .directory-table hd { | |
| padding-left: 0px; | |
| padding-right: 0px; | |
| } | |
| .directory-table td { | |
| padding-left: 0px; | |
| padding-right: 0px; | |
| } | |
| .content { | |
| padding: 0px; | |
| } | |
| } | |
| </style> | |
| "; | |
| // Function to get age indicator | |
| function getAgeIndicator($date) { | |
| $now = new DateTime(); | |
| $diff = $now->diff($date); | |
| $days = $diff->days; | |
| if ($days <= 7) return '<span class="age-indicator age-recent" title="Recent (β€ 7 days)"></span>'; | |
| if ($days <= 30) return '<span class="age-indicator age-medium" title="Medium (β€ 30 days)"></span>'; | |
| return '<span class="age-indicator age-old" title="Old (> 30 days)"></span>'; | |
| } | |
| // Scan directories | |
| $currentDir = '.'; | |
| $pattern = '/^\d{8}$/'; | |
| $matchedDirs = []; | |
| $totalDirs = 0; | |
| $validDirs = 0; | |
| if ($handle = opendir($currentDir)) { | |
| while (false !== ($entry = readdir($handle))) { | |
| if( $entry !== '.' && $entry !== '..' && is_dir($entry) ){ | |
| $totalDirs++; | |
| if ($entry !== '.' && $entry !== '..' && is_dir($entry) && preg_match($pattern, $entry)) { | |
| $date = DateTime::createFromFormat('Ymd', $entry); | |
| if ($date) { | |
| $matchedDirs[] = [ | |
| 'name' => $entry, | |
| 'date' => $date, | |
| 'formatted' => $date->format('Y-m-d'), | |
| 'day' => $date->format('l'), | |
| 'timestamp' => $date->getTimestamp() | |
| ]; | |
| $validDirs++; | |
| } | |
| } | |
| } | |
| } | |
| closedir($handle); | |
| } | |
| // Sort by date (newest first) | |
| usort($matchedDirs, function($a, $b) { | |
| return $b['timestamp'] - $a['timestamp']; | |
| }); | |
| // Get date range | |
| $dateRange = 'N/A'; | |
| if (!empty($matchedDirs)) { | |
| $oldest = end($matchedDirs); | |
| $newest = reset($matchedDirs); | |
| $dateRange = $oldest['formatted'] . ' to ' . $newest['formatted']; | |
| } | |
| // Output HTML | |
| echo "<!DOCTYPE html> | |
| <html lang='en'> | |
| <head> | |
| <meta charset='UTF-8'> | |
| <meta name='viewport' content='width=device-width, initial-scale=1.0'> | |
| <title>Directory Index - YYYYMMDD</title> | |
| $darkTheme | |
| </head> | |
| <body> | |
| <div class='container'> | |
| <div class='header'> | |
| <h1>π Directory Index</h1> | |
| <p>Directories matching YYYYMMDD date pattern</p> | |
| <div class='stats'> | |
| <div class='stat-box'> | |
| <span class='stat-number'>$totalDirs</span> | |
| <span class='stat-label'>Total Directories</span> | |
| </div> | |
| <div class='stat-box'> | |
| <span class='stat-number'>$validDirs</span> | |
| <span class='stat-label'>Date Pattern Matches</span> | |
| </div> | |
| <div class='stat-box'> | |
| <span class='stat-number'>" . count($matchedDirs) . "</span> | |
| <span class='stat-label'>Valid Dates</span> | |
| </div> | |
| <div class='stat-box'> | |
| <span class='stat-number'>$dateRange</span> | |
| <span class='stat-label'>Date Range</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class='content'> | |
| <div class='controls'> | |
| <div class='control-group'> | |
| <button class='btn' onclick='location.reload()'>π Refresh</button> | |
| <button class='btn btn-secondary' onclick='exportToFile()'>π₯ Export List</button> | |
| <span style='color: #888; margin-left: auto;'> | |
| " . date('Y-m-d H:i:s') . " | |
| </span> | |
| </div> | |
| </div>"; | |
| if (empty($matchedDirs)) { | |
| echo "<div class='empty-state'> | |
| <i>π</i> | |
| <h3>No directories found</h3> | |
| <p>No directories matching the YYYYMMDD pattern were found in the current directory.</p> | |
| </div>"; | |
| } else { | |
| echo "<table class='directory-table'> | |
| <thead> | |
| <tr> | |
| <th>Directory Name</th> | |
| <th>Date</th> | |
| <th>Day</th> | |
| <th>Age</th> | |
| <th>Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody>"; | |
| foreach ($matchedDirs as $dir) { | |
| $ageIndicator = getAgeIndicator($dir['date']); | |
| $daysAgo = $dir['date']->diff(new DateTime())->days; | |
| $ageText = $daysAgo == 0 ? 'Today' : ($daysAgo == 1 ? '1 day ago' : "$daysAgo days ago"); | |
| echo "<tr> | |
| <td> | |
| <span class='directory-name'>π {$dir['name']}</span> | |
| </td> | |
| <td class='date-info'>{$dir['formatted']}</td> | |
| <td><span class='day-highlight'>{$dir['day']}</span></td> | |
| <td class='date-info'> | |
| $ageIndicator $ageText | |
| </td> | |
| <td> | |
| <button class='btn btn-secondary' onclick=\"openDirectory('{$dir['name']}')\"> | |
| Open | |
| </button> | |
| </td> | |
| </tr>"; | |
| } | |
| echo "</tbody></table>"; | |
| } | |
| echo " </div> | |
| <div class='footer'> | |
| <p>Generated by Directory Index β’ " . count($matchedDirs) . " directories found β’ Pattern: YYYYMMDD</p> | |
| </div> | |
| </div> | |
| <script> | |
| function openDirectory(dirName) { | |
| if (confirm('Open directory: ' + dirName + '?')) { | |
| window.open('./' + dirName, '_blank'); | |
| } | |
| } | |
| function exportToFile() { | |
| const content = " . json_encode(array_map(function($dir) { | |
| return [ | |
| 'directory' => $dir['name'], | |
| 'date' => $dir['formatted'], | |
| 'day' => $dir['day'] | |
| ]; | |
| }, $matchedDirs)) . "; | |
| const blob = new Blob([JSON.stringify(content, null, 2)], { type: 'application/json' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'directory-index-' + new Date().toISOString().split('T')[0] + '.json'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| } | |
| // Add some interactive effects | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const rows = document.querySelectorAll('.directory-table tr'); | |
| rows.forEach((row, index) => { | |
| row.style.animationDelay = (index * 0.1) + 's'; | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html>"; | |
| ?> | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // Get all mp4 files in current directory | |
| $mp4files = array_filter(scandir('.'), function($file) { | |
| return is_file($file) && strtolower(pathinfo($file, PATHINFO_EXTENSION)) === 'mp4'; | |
| }); | |
| ?> | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>MP4 Video Player</title> | |
| <style> | |
| html { color-scheme: dark; } | |
| body { | |
| font-family: Arial, sans-serif; | |
| margin: 20px; | |
| } | |
| #videoPlayer { | |
| width: 100%; | |
| max-width: 800px; | |
| height: auto; | |
| background: black; | |
| } | |
| #fileList { | |
| margin-top: 20px; | |
| max-width: 800px; | |
| } | |
| #fileList button { | |
| display: block; | |
| width: 100%; | |
| padding: 10px; | |
| margin: 5px 0; | |
| font-size: 1rem; | |
| text-align: left; | |
| cursor: pointer; | |
| border: 1px solid #ccc; | |
| /* background: #f7f7f7;*/ | |
| } | |
| #fileList button:hover { | |
| /* background: #e2e2e2;*/ | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>MP4 Video Player</h1> | |
| <video id="videoPlayer" controls> | |
| <source src="" type="video/mp4" /> | |
| Your browser does not support the video tag. | |
| </video> | |
| <div id="fileList"> | |
| <h2>Available Videos</h2> | |
| <?php if (empty($mp4files)): ?> | |
| <p>No MP4 files found in this directory.</p> | |
| <?php else: ?> | |
| <?php foreach ($mp4files as $file): ?> | |
| <button type="button" onclick="loadVideo('<?= htmlspecialchars($file, ENT_QUOTES) ?>')"> | |
| <?= htmlspecialchars($file) ?> | |
| </button> | |
| <?php endforeach; ?> | |
| <?php endif; ?> | |
| </div> | |
| <script> | |
| function loadVideo(filename) { | |
| const video = document.getElementById('videoPlayer'); | |
| // Change video source | |
| video.src = filename; | |
| video.load(); | |
| video.play(); | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment