| | |
| | foreach ($entries as $e) { |
| | - /** |
| | - * View Orchestration: |
| | - * Ask Git (the data authority) for the size, then pass it to File (the display object). |
| | - */ |
| | $size = $e['isDir'] ? 0 : $this->git->getObjectSize($e['sha']); |
| | |
 |
| | |
| | private function renderBlob($targetHash) { |
| | - $content = ''; |
| | - $this->git->stream($targetHash, function($d) use (&$content) { $content = $d; }); |
| | + $repoParam = '&repo=' . urlencode($this->currentRepo['safe_name']); |
| | + $size = $this->git->getObjectSize($targetHash); |
| | + |
| | + // 1. Check for size limit (512KB = 524288 bytes) |
| | + if ($size > 524288) { |
| | + $this->renderDownloadState($targetHash, "File is too large to display (" . $this->formatSize($size) . ")."); |
| | + return; |
| | + } |
| | + |
| | + // 2. Sniff content type (read first 12 bytes) |
| | + $buffer = ''; |
| | + $this->git->stream($targetHash, function($d) use (&$buffer) { |
| | + if (strlen($buffer) < 12) $buffer .= $d; |
| | + }); |
| | + |
| | + // We pass an empty filename '' because the blob view URL doesn't always contain the filename |
| | + $category = MediaTypeSniffer::isCategory($buffer, ''); |
| | + $mimeType = MediaTypeSniffer::isMediaType($buffer, ''); |
| | + |
| | $this->renderBreadcrumbs($targetHash, 'File'); |
| | echo '<h2>' . substr($targetHash, 0, 7) . '</h2>'; |
| | - echo '<div class="blob-content"><div class="blob-code">' . htmlspecialchars($content) . '</div></div>'; |
| | + |
| | + $rawUrl = '?action=raw&hash=' . $targetHash . $repoParam; |
| | + |
| | + // 3. Render View based on Category |
| | + if ($category === MediaTypeSniffer::CAT_IMAGE) { |
| | + echo '<div class="blob-content" style="text-align:center; padding: 20px; background: #f6f8fa;">'; |
| | + echo '<img src="' . $rawUrl . '" style="max-width: 100%; border: 1px solid #dfe2e5;">'; |
| | + echo '</div>'; |
| | + } elseif ($category === MediaTypeSniffer::CAT_VIDEO) { |
| | + echo '<div class="blob-content" style="text-align:center; padding: 20px;">'; |
| | + echo '<video controls style="max-width: 100%;"><source src="' . $rawUrl . '" type="' . $mimeType . '"></video>'; |
| | + echo '</div>'; |
| | + } elseif ($category === MediaTypeSniffer::CAT_TEXT) { |
| | + $content = ''; |
| | + $this->git->stream($targetHash, function($d) use (&$content) { $content .= $d; }); |
| | + echo '<div class="blob-content"><div class="blob-code">' . htmlspecialchars($content) . '</div></div>'; |
| | + } else { |
| | + $this->renderDownloadState($targetHash, "This is a binary file."); |
| | + } |
| | + } |
| | + |
| | + private function renderDownloadState($hash, $reason) { |
| | + $url = '?action=raw&hash=' . $hash . '&repo=' . urlencode($this->currentRepo['safe_name']); |
| | + echo '<div class="empty-state" style="text-align: center; padding: 40px; border: 1px solid #e1e4e8; border-radius: 6px; margin-top: 10px;">'; |
| | + echo '<p style="margin-bottom: 20px; color: #586069;">' . htmlspecialchars($reason) . '</p>'; |
| | + echo '<a href="' . $url . '" style="display: inline-block; padding: 6px 16px; background: #0366d6; color: white; text-decoration: none; border-radius: 6px; font-weight: 600;">Download Raw File</a>'; |
| | + echo '</div>'; |
| | + } |
| | + |
| | + private function formatSize($size) { |
| | + if ($size <= 0) return '0 B'; |
| | + $units = ['B', 'KB', 'MB', 'GB']; |
| | + $i = (int)floor(log($size, 1024)); |
| | + return round($size / pow(1024, $i), 1) . ' ' . $units[$i]; |
| | } |
| | |
 |
| | } |
| | } |
| | - |
| | |