Secure
Audio.php
← Back to Folder Raw Code
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
<?php
class Audio {
    private $webPath;
    private $allowedAudioExtensions = [
        'mp3', 'wav', 'aac', 'flac', 'm4a', 'ogg', 'oga', 'opus'
    ];
    public function __construct($webPath) {
        $this->webPath = $webPath;
    }
    public function isAudioViewable($extension) {
        global $config;
        if (empty($extension) || trim($extension) === '') {
            return false;
        }
        $extension = strtolower($extension);
        if (!in_array($extension, $this->allowedAudioExtensions)) {
            return false;
        }
        $settingKey = getExtensionSetting($extension, 'viewing');
        if ($settingKey !== null) {
            return isset($config['viewable_files'][$settingKey]) ? 
                   $config['viewable_files'][$settingKey] : false;
        }
        return false;
    }
    public function renderAudioPlayer($fullPath, $filename, $extension, $currentPath) {
        global $router, $config;
        $pathParts = explode('/', trim($currentPath, '/'));
        $lastPart = end($pathParts);
        if ($lastPart === $filename) {
            array_pop($pathParts);
            $currentPath = implode('/', $pathParts);
        }
        $this->serveAudioView($fullPath, $filename, $extension, $currentPath);
        exit;
    }
    private function serveAudioView($fullPath, $filename, $extension, $currentPath) {
        global $router, $config, $iconType;
        $fileSize = filesize($fullPath);
        $fileSizeFormatted = $this->formatBytes($fileSize);
        $fileModified = date('Y-m-d H:i:s', filemtime($fullPath));
        $audioInfo = $this->getAudioInfo($fullPath, $extension);
        $downloadUrl = $router->generateFileURL($currentPath, $filename, 'download');
        $viewUrl = $router->generateFileURL($currentPath, $filename, 'view', 'default');
        $originalRawUrl = $router->generateFileURL($currentPath, $filename, 'view', 'raw');
        $audioDisplayUrl = $originalRawUrl;
        $currentFullUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $backUrl = preg_replace('/\/[^\/]+\/\?.*$/', '/', $currentFullUrl);
        if (!preg_match('/\?/', $currentFullUrl)) {
            $backUrl = preg_replace('/\/[^\/]+\/$/', '/', $currentFullUrl);
        }
        $securityStatus = getSecurityStatus();
        $lockIcon = $securityStatus['secure'] 
            ? $this->webPath . '/.indexer_files/icons/app/green.png'
            : $this->webPath . '/.indexer_files/icons/app/red.png';
        $mimeType = $this->getAudioMimeType($extension);
        $canPlayNatively = $this->canPlayInBrowser($extension);
        $displayTitle = $audioInfo['title'] ?: $filename;
        $displayArtist = $audioInfo['artist'];
        $hasCoverArt = !empty($audioInfo['cover_art']);
        $audioIconPath = getIconPath('file', $extension);
        $useIcon = ($iconType !== 'disabled');
        $useEmoji = ($iconType === 'emoji' || $audioIconPath === null);
        $iconSrc = $audioIconPath;
        ?>
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta name="application-name" content="5q12's Indexer">
            <meta name="apple-mobile-web-app-capable" content="yes">
            <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
            <meta name="apple-mobile-web-app-title" content="Indexer">
            <meta name="mobile-web-app-capable" content="yes">
            <meta name="theme-color" content="#2a2a2a">
            <link rel="manifest" href="<?php echo $this->webPath; ?>/.indexer_files/local_api/manifest.json">
            <title><?php echo htmlspecialchars($displayTitle); ?></title>
            <link rel="icon" type="image/x-icon" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/icon.ico">
            <link rel="icon" type="image/png" sizes="16x16" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/16x16.png">
            <link rel="icon" type="image/png" sizes="32x32" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/32x32.png">
            <link rel="icon" type="image/png" sizes="48x48" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/48x48.png">
            <link rel="icon" type="image/png" sizes="96x96" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/96x96.png">
            <link rel="icon" type="image/png" sizes="144x144" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/144x144.png">
            <link rel="icon" type="image/png" sizes="192x192" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/192x192.png">
            <link rel="apple-touch-icon" sizes="180x180" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/180x180.png">
            <link rel="stylesheet" href="<?php echo $this->webPath; ?>/.indexer_files/local_api/style/base-2.0.0-r0.min.css">
            <link rel="stylesheet" href="<?php echo $this->webPath; ?>/.indexer_files/local_api/style/audio-2.0.0-r0.min.css">
        </head>
        <body>
            <div class="security-bar">
                <span class="security-lock" data-tooltip="<?php echo $securityStatus['secure'] ? 'Connection is secure (HTTPS)' : 'Connection is not secure - Consider using HTTPS'; ?>">
                    <img src="<?php echo htmlspecialchars($lockIcon); ?>" alt="<?php echo $securityStatus['secure'] ? 'Secure' : 'Not Secure'; ?>">
                </span>
                <div class="security-bar-filename"><?php echo htmlspecialchars($filename); ?></div>
                <div class="security-bar-buttons">
                    <a href="<?php echo htmlspecialchars($originalRawUrl); ?>" class="security-bar-btn">Raw</a>
                    <a href="#" class="security-bar-btn active">View</a>
                </div>
            </div>
            <div class="audio-container">
                <div class="audio-player-wrapper">
                    <?php if (!$canPlayNatively): ?>
                        <div class="error-message">
                            This audio format (<?php echo strtoupper(htmlspecialchars($extension)); ?>) may not be natively supported by your browser.<br>
                            Please download the file or try opening it in a compatible media player.
                        </div>
                    <?php else: ?>
                        <div class="audio-player">
                            <?php if ($hasCoverArt): ?>
                                <div class="audio-cover-art">
                                    <img src="<?php echo htmlspecialchars($audioInfo['cover_art']); ?>" alt="Cover Art">
                                </div>
                            <?php elseif (!$useIcon): ?>
                            <?php elseif ($useEmoji): ?>
                                <div class="audio-icon-emoji">🎵</div>
                            <?php else: ?>
                                <div class="audio-icon-img">
                                    <img src="<?php echo htmlspecialchars($iconSrc); ?>" alt="<?php echo strtoupper(htmlspecialchars($extension)); ?>">
                                </div>
                            <?php endif; ?>
                            <div class="audio-metadata">
                                <div class="audio-title"><?php echo htmlspecialchars($displayTitle); ?></div>
                                <?php if ($displayArtist): ?>
                                    <div class="audio-artist"><?php echo htmlspecialchars($displayArtist); ?></div>
                                <?php endif; ?>
                                <?php if ($audioInfo['album']): ?>
                                    <div class="audio-album"><?php echo htmlspecialchars($audioInfo['album']); ?></div>
                                <?php endif; ?>
                            </div>
                            <audio controls preload="metadata">
                                <source src="<?php echo htmlspecialchars($audioDisplayUrl); ?>" type="<?php echo htmlspecialchars($mimeType); ?>">
                                Your browser does not support the audio element.
                            </audio>
                        </div>
                    <?php endif; ?>
                </div>
            </div>
            <div class="audio-info">
                <div class="info-grid">
                    <div class="info-label">Filename:</div>
                    <div class="info-value"><?php echo htmlspecialchars($filename); ?></div>
                    <?php if ($audioInfo['title'] && $audioInfo['title'] !== $filename): ?>
                    <div class="info-label">Title:</div>
                    <div class="info-value"><?php echo htmlspecialchars($audioInfo['title']); ?></div>
                    <?php endif; ?>
                    <?php if ($displayArtist): ?>
                    <div class="info-label">Artist:</div>
                    <div class="info-value"><?php echo htmlspecialchars($displayArtist); ?></div>
                    <?php endif; ?>
                    <?php if ($audioInfo['album']): ?>
                    <div class="info-label">Album:</div>
                    <div class="info-value"><?php echo htmlspecialchars($audioInfo['album']); ?></div>
                    <?php endif; ?>
                    <?php if ($audioInfo['year']): ?>
                    <div class="info-label">Year:</div>
                    <div class="info-value"><?php echo htmlspecialchars($audioInfo['year']); ?></div>
                    <?php endif; ?>
                    <?php if ($audioInfo['genre']): ?>
                    <div class="info-label">Genre:</div>
                    <div class="info-value"><?php echo htmlspecialchars($audioInfo['genre']); ?></div>
                    <?php endif; ?>
                    <div class="info-label">Type:</div>
                    <div class="info-value"><?php echo strtoupper(htmlspecialchars($extension)); ?> Audio</div>
                    <?php if ($audioInfo['duration']): ?>
                    <div class="info-label">Duration:</div>
                    <div class="info-value"><?php echo htmlspecialchars($audioInfo['duration']); ?></div>
                    <?php endif; ?>
                    <?php if ($audioInfo['bitrate']): ?>
                    <div class="info-label">Bitrate:</div>
                    <div class="info-value"><?php echo htmlspecialchars($audioInfo['bitrate']); ?></div>
                    <?php endif; ?>
                    <?php if ($audioInfo['sample_rate']): ?>
                    <div class="info-label">Sample Rate:</div>
                    <div class="info-value"><?php echo htmlspecialchars($audioInfo['sample_rate']); ?></div>
                    <?php endif; ?>
                    <?php if ($audioInfo['channels']): ?>
                    <div class="info-label">Channels:</div>
                    <div class="info-value"><?php echo htmlspecialchars($audioInfo['channels']); ?></div>
                    <?php endif; ?>
                    <div class="info-label">File Size:</div>
                    <div class="info-value"><?php echo htmlspecialchars($fileSizeFormatted); ?></div>
                    <div class="info-label">Modified:</div>
                    <div class="info-value"><?php echo htmlspecialchars($fileModified); ?></div>
                </div>
                <div class="action-buttons">
                    <a href="<?php echo htmlspecialchars($backUrl); ?>" class="action-btn primary">← Back to Folder</a>
                    <a href="<?php echo htmlspecialchars($originalRawUrl); ?>" class="action-btn" target="_blank">Open Raw</a>
                    <a href="<?php echo htmlspecialchars($downloadUrl); ?>" class="action-btn">Download</a>
                </div>
            </div>
        </body>
        </html>
        <?php
    }
    private function getAudioMimeType($extension) {
        $mimeTypes = [
            'mp3' => 'audio/mpeg',
            'wav' => 'audio/wav',
            'aac' => 'audio/aac',
            'flac' => 'audio/flac',
            'm4a' => 'audio/mp4',
            'ogg' => 'audio/ogg',
            'oga' => 'audio/ogg',
            'opus' => 'audio/ogg',
        ];
        return $mimeTypes[$extension] ?? 'audio/mpeg';
    }
    private function canPlayInBrowser($extension) {
        $nativelySupported = ['mp3', 'wav', 'ogg', 'oga', 'opus', 'm4a', 'aac', 'flac'];
        if (in_array($extension, $nativelySupported)) {
            return true;
        }
        return false;
    }
    private function getAudioInfo($fullPath, $extension) {
        $info = [
            'title' => null,
            'artist' => null,
            'album' => null,
            'year' => null,
            'genre' => null,
            'duration' => null,
            'bitrate' => null,
            'sample_rate' => null,
            'channels' => null,
            'cover_art' => null
        ];
        $getID3Path = dirname(__FILE__) . '/getid3/getid3.php';
        if (!file_exists($getID3Path)) {
            return $info;
        }
        require_once($getID3Path);
        try {
            $getID3 = new getID3;
            $fileInfo = $getID3->analyze($fullPath);
            if (isset($fileInfo['tags'])) {
                foreach (['id3v2', 'id3v1', 'vorbiscomment', 'quicktime', 'riff', 'asf'] as $tagFormat) {
                    if (isset($fileInfo['tags'][$tagFormat])) {
                        $tags = $fileInfo['tags'][$tagFormat];
                        if (!$info['title'] && isset($tags['title'][0])) {
                            $info['title'] = $tags['title'][0];
                        }
                        if (!$info['artist'] && isset($tags['artist'][0])) {
                            $info['artist'] = $tags['artist'][0];
                        }
                        if (!$info['album'] && isset($tags['album'][0])) {
                            $info['album'] = $tags['album'][0];
                        }
                        if (!$info['year'] && isset($tags['year'][0])) {
                            $info['year'] = $tags['year'][0];
                        }
                        if (!$info['genre'] && isset($tags['genre'][0])) {
                            $info['genre'] = $tags['genre'][0];
                        }
                    }
                }
            }
            if (isset($fileInfo['playtime_seconds'])) {
                $seconds = round($fileInfo['playtime_seconds']);
                $minutes = floor($seconds / 60);
                $seconds = $seconds % 60;
                $info['duration'] = sprintf('%d:%02d', $minutes, $seconds);
            }
            if (isset($fileInfo['audio']['bitrate'])) {
                $bitrate = round($fileInfo['audio']['bitrate'] / 1000);
                $info['bitrate'] = $bitrate . ' kbps';
            }
            if (isset($fileInfo['audio']['sample_rate'])) {
                $sampleRate = round($fileInfo['audio']['sample_rate'] / 1000, 1);
                $info['sample_rate'] = $sampleRate . ' kHz';
            }
            if (isset($fileInfo['audio']['channels'])) {
                $channels = $fileInfo['audio']['channels'];
                if ($channels == 1) {
                    $info['channels'] = 'Mono';
                } elseif ($channels == 2) {
                    $info['channels'] = 'Stereo';
                } else {
                    $info['channels'] = $channels . ' channels';
                }
            }
            if (isset($fileInfo['comments']['picture'][0])) {
                $picture = $fileInfo['comments']['picture'][0];
                if (isset($picture['data'])) {
                    $imageData = $picture['data'];
                    $imageMime = isset($picture['image_mime']) ? $picture['image_mime'] : 'image/jpeg';
                    $info['cover_art'] = 'data:' . $imageMime . ';base64,' . base64_encode($imageData);
                }
            }
        } catch (Exception $e) {
        }
        return $info;
    }
    private function formatBytes($size) {
        if ($size === null) return '-';
        $units = ['B', 'KB', 'MB', 'GB'];
        for ($i = 0; $size > 1024 && $i < count($units) - 1; $i++) {
            $size /= 1024;
        }
        return round($size, 2) . ' ' . $units[$i];
    }
}
?>