Created
March 19, 2011 06:43
-
-
Save jonhoo/877286 to your computer and use it in GitHub Desktop.
A standalone, drop-in gallery for collections of videos and images
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
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Graphical directory listing of <?php echo basename ( realpath ( '.' ) ); ?></title> | |
| <meta charset="utf-8" /> | |
| <style type="text/css"> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| border: none; | |
| } | |
| html, body { | |
| background-color: #333; | |
| } | |
| h1 { | |
| text-align: center; | |
| margin-top: 80px; | |
| color: #EEEEEE; | |
| } | |
| ul { | |
| margin: 10px 100px; | |
| list-style-type: none; | |
| border: 1px solid #888; | |
| background-color: #666; | |
| overflow: hidden; | |
| } | |
| ul li { | |
| float: left; | |
| } | |
| ul li a { | |
| display: block; | |
| width: 200px; | |
| margin: 20px; | |
| height: 162px; | |
| background-color: #FFFFFF; | |
| text-align: center; | |
| padding: 20px; | |
| border: 1px solid #111; | |
| text-decoration: none; | |
| color: #224; | |
| line-height: 17px; | |
| font-size: 14px; | |
| position: relative; | |
| } | |
| ul li a:hover { | |
| background-color: #DDDDDD; | |
| border: 1px solid #444444; | |
| } | |
| ul li a.video.nopreview .content { | |
| margin-top: 60px; | |
| margin-bottom: 60px; | |
| color: #666; | |
| } | |
| ul li a .timecode { | |
| position: absolute; | |
| top: 27px; | |
| right: 27px; | |
| background-color: #000000; | |
| color: #FFFFFF; | |
| font-weight: bold; | |
| display: block; | |
| width: 50px; | |
| font-size: 12px; | |
| text-align: center; | |
| opacity: 0.85; | |
| } | |
| ul li a.audio .timecode { | |
| margin: 40px auto; | |
| padding: 5px; | |
| font-size: 14px; | |
| position: static; | |
| line-height: 1; | |
| } | |
| ul li a img { | |
| border: 1px solid #555; | |
| } | |
| ul li a p { | |
| display: none; | |
| } | |
| ul li a .title { | |
| display: block; | |
| margin-top: 10px; | |
| } | |
| ul li a .title .extension { | |
| color: #777; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <?php | |
| /** | |
| * File format definitions | |
| */ | |
| $formats = array( | |
| // Images | |
| 'image' => array( | |
| 'jpeg', | |
| 'jpg', | |
| 'bmp', | |
| 'gif', | |
| 'png', | |
| 'tiff', | |
| ), | |
| // Videos | |
| 'video' => array( | |
| 'mov', | |
| 'mp4', | |
| 'mpeg', | |
| 'mpg', | |
| 'avi', | |
| 'mkv', | |
| 'wmv', | |
| 'vob', | |
| ), | |
| // Audio | |
| 'audio' => array( | |
| 'ogg', | |
| 'mp3', | |
| 'wav', | |
| 'wma', | |
| 'aac', | |
| ), | |
| // Plain text | |
| 'text' => array( | |
| 'txt', | |
| 'log', | |
| 'rtf', | |
| 'phps', | |
| 'js', | |
| 'html', | |
| 'xml', | |
| 'css', | |
| ), | |
| // Hidden | |
| 'hidden' => array( | |
| 'php', | |
| 'asp', | |
| 'java', | |
| 'pl', | |
| ), | |
| ); | |
| /** | |
| * Make format table more easily searchable by switching the indexes to an associative array | |
| */ | |
| $resolveType = array(); | |
| foreach ( $formats as $type => $extensions ) { | |
| foreach ( $extensions as $extension ) { | |
| $resolveType[$extension] = $type; | |
| } | |
| } | |
| unset($formats); // Save memory | |
| echo '<h1>Directory listing for ' . htmlentities ( dirname ( $_SERVER['SCRIPT_NAME'] ), ENT_COMPAT, 'UTF-8' ) . '</h1>'; | |
| /** | |
| * Print the files with an optional preview | |
| */ | |
| echo '<ul>'; | |
| foreach (glob("*") as $file) { | |
| // Hide "secret" files | |
| if ( $file == 'index.php' ) continue; | |
| if ( $file[0] == '.' ) continue; | |
| // Get some file info | |
| $extension = strtolower ( pathinfo ( $file, PATHINFO_EXTENSION ) ); | |
| $type = array_key_exists ( $extension, $resolveType ) ? $resolveType[$extension] : 'unknown'; | |
| // Hide hidden files | |
| if ( $type == 'hidden' ) continue; | |
| // Get presentational information | |
| $niceName = ucwords ( preg_replace ( '/[_\-\.]/', ' ', pathinfo ( $file, PATHINFO_FILENAME ) ) ); | |
| $preview = makePreview ( $file, $type, 200, 133 ); | |
| // Show element | |
| echo '<li>'; | |
| echo '<a href="' . urlencode ( $file ) . '" class="preview' . ( empty ( $preview ) ? ' nopreview' : '' ) . ' ' . $type . '">'; | |
| echo ( !empty ( $preview ) ? $preview : '<p class="content">No preview</p>' ); | |
| echo '<span class="title">' . htmlentities ( $niceName, ENT_COMPAT, 'UTF-8' ) . ' <span class="extension">(' . $extension . ')</span></span>'; | |
| echo '</a>'; | |
| echo '</li>'; | |
| } | |
| echo '</ul>'; | |
| /** | |
| * Makes a preview for the given file type | |
| * This wrapper function calls the function by the name of makePreview<type> if it exists | |
| * @param String file The file to generate a preview for | |
| * @param String type The file type | |
| * @param int width The preview width | |
| * @param int height The preview height | |
| * @return mixed Returns boolean false if it cannot generate a preview, otherwise a HTML string rendering the preview | |
| */ | |
| function makePreview ( $file, $type, $width, $height ) { | |
| $function = "makePreview" . ucfirst ( strtolower ( $type ) ); | |
| if ( !function_exists ( $function ) ) return false; | |
| return $function( $file, $width, $height ); | |
| } | |
| /** | |
| * Preview generators | |
| * Follows the same syntax as makePreview(), except without the type argument | |
| */ | |
| function makePreviewImage ( $file, $width, $height ) { | |
| $extension = strtolower ( pathinfo ( $file, PATHINFO_EXTENSION ) ); | |
| if ( !function_exists ( 'imagecreatefrompng' ) ) return false; | |
| if ( !is_writable ( '.' ) ) return false; | |
| if ( file_exists ( '.dropingallery.' . $file . '.png' ) ) return renderPreviewImage ( $file, $width, $height ); | |
| $resized = smart_resize_image ( $file, $width, $height, true, '.dropingallery.' . $file . '.png' ); | |
| if ( !$resized ) return false; | |
| return renderPreviewImage ( $file, $width, $height ); | |
| } | |
| function renderPreviewImage ( $file, $width, $height ) { | |
| if ( !file_exists ( '.dropingallery.' . $file . '.png' ) ) return false; | |
| $outstring = '<img src=".dropingallery.' . $file . '.png" alt="Preview for ' . $file . '" />'; | |
| return $outstring; | |
| } | |
| // Credit to http://github.com/maxim/smart_resize_image | |
| function smart_resize_image($file, | |
| $width = 0, | |
| $height = 0, | |
| $proportional = false, | |
| $output = 'thumb.png', | |
| $delete_original = true, | |
| $use_linux_commands = false ) { | |
| if ( $height <= 0 && $width <= 0 ) return false; | |
| # Setting defaults and meta | |
| $info = getimagesize($file); | |
| $image = ''; | |
| $final_width = 0; | |
| $final_height = 0; | |
| list($width_old, $height_old) = $info; | |
| # Calculating proportionality | |
| if ($proportional) { | |
| if ($width == 0) $factor = $height/$height_old; | |
| elseif ($height == 0) $factor = $width/$width_old; | |
| else $factor = min( $width / $width_old, $height / $height_old ); | |
| $final_width = round( $width_old * $factor ); | |
| $final_height = round( $height_old * $factor ); | |
| } | |
| else { | |
| $final_width = ( $width <= 0 ) ? $width_old : $width; | |
| $final_height = ( $height <= 0 ) ? $height_old : $height; | |
| } | |
| # Loading image to memory according to type | |
| switch ( $info[2] ) { | |
| case IMAGETYPE_GIF: $image = imagecreatefromgif($file); break; | |
| case IMAGETYPE_JPEG: $image = imagecreatefromjpeg($file); break; | |
| case IMAGETYPE_PNG: $image = imagecreatefrompng($file); break; | |
| default: return false; | |
| } | |
| # This is the resizing/resampling/transparency-preserving magic | |
| $image_resized = imagecreatetruecolor( $final_width, $final_height ); | |
| if ( ($info[2] == IMAGETYPE_GIF) || ($info[2] == IMAGETYPE_PNG) ) { | |
| $transparency = imagecolortransparent($image); | |
| if ($transparency >= 0) { | |
| $transparent_color = imagecolorsforindex($image, $trnprt_indx); | |
| $transparency = imagecolorallocate($image_resized, $trnprt_color['red'], $trnprt_color['green'], $trnprt_color['blue']); | |
| imagefill($image_resized, 0, 0, $transparency); | |
| imagecolortransparent($image_resized, $transparency); | |
| } | |
| elseif ($info[2] == IMAGETYPE_PNG) { | |
| imagealphablending($image_resized, false); | |
| $color = imagecolorallocatealpha($image_resized, 0, 0, 0, 127); | |
| imagefill($image_resized, 0, 0, $color); | |
| imagesavealpha($image_resized, true); | |
| } | |
| } | |
| imagecopyresampled($image_resized, $image, 0, 0, 0, 0, $final_width, $final_height, $width_old, $height_old); | |
| imagepng($image_resized, $output); | |
| return true; | |
| } | |
| function makePreviewVideo ( $file, $width, $height ) { | |
| if ( !is_executable ( '/usr/bin/ffmpeg' ) ) return false; | |
| if ( !is_writable ( '.' ) ) return false; | |
| if ( file_exists ( '.dropingallery.' . $file . '.prev' ) ) return renderPreviewVideo ( $file, $width, $height ); | |
| $totalLength = 0; | |
| // get the duration and a random place within that | |
| $escapedFile = str_replace ( "'", "\'", $file ); | |
| $cmd = "/usr/bin/ffmpeg -i '$escapedFile' 2>&1"; | |
| if (preg_match('/Duration: ((\d+):(\d+):(\d+))/s', `$cmd`, $time)) { | |
| $totalLength = ($time[2] * 3600) + ($time[3] * 60) + $time[4]; | |
| } | |
| // $sizeLimit = min($width, $height); | |
| $ratio = $height / $width; | |
| while ( $height % 1 === 0 && ( $width % 2 || $height % 2 ) ) { | |
| $width--; | |
| $height = $ratio * $width; | |
| } | |
| $previewAt = 15; | |
| if ( $totalLength < 5 ) { | |
| $previewAt = $totalLength - 1; | |
| } else if ( $totalLength < 15 ) { | |
| $previewAt = $totalLength - 6; | |
| } | |
| // get a screenshot | |
| $cmd = "/usr/bin/ffmpeg -i '$escapedFile' -deinterlace -an -ss " . $previewAt . " -s $width" . 'x' . "$height -r 1 -y -vcodec mjpeg -f mjpeg '.dropingallery.$file.jpg'"; | |
| $return = false; | |
| system($cmd, $return); | |
| // If it fails, no preview | |
| if ( $return !== 0 || !file_exists ( '.dropingallery.' . $file . '.jpg' ) ) return false; | |
| $metadata = array( | |
| 'length' => $totalLength, | |
| 'thumb' => '.dropingallery.' . $file . '.jpg', | |
| ); | |
| $datastring = ''; | |
| foreach ( $metadata as $label => $data ) { | |
| $datastring .= "$label = $data\n"; | |
| } | |
| file_put_contents ( '.dropingallery.' . $file . '.prev', $datastring ); | |
| return renderPreviewVideo ( $file, $width, $height ); | |
| } | |
| function renderPreviewVideo ( $file, $width, $height ) { | |
| if ( !file_exists ( '.dropingallery.' . $file . '.prev' ) ) return false; | |
| $settings = parse_ini_file ( '.dropingallery.' . $file . '.prev' ); | |
| $hours = intval($settings['length'] / (60*60)); | |
| $minutes = intval( ( $settings['length'] - $hours * 60 * 60 ) / 60); | |
| $seconds = intval($settings['length'] - $hours * 60 * 60 - $minutes * 60 ); | |
| $outstring .= '<span class="timecode">' . sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds) . '</span>'; | |
| $outstring .= '<img src="' . $settings['thumb'] . '" alt="Preview for ' . $file . '" />'; | |
| return $outstring; | |
| } | |
| function makePreviewText ( $file, $width, $height ) { | |
| if ( file_exists ( '.dropingallery.' . $file . '.png' ) ) return renderPreviewText ( $file, $width, $height ); | |
| if ( !function_exists ( 'imagecreatetruecolor' ) ) return false; | |
| if ( !is_writable ( '.' ) ) return false; | |
| $image = imagecreatetruecolor ( $width, $height ); | |
| $fitHorizontally = intval ( ( $width - 6 ) / imagefontwidth ( 2 ) ); | |
| $fitVertically = intval ( ( $height - 6 ) / imagefontheight ( 2 ) ); | |
| if ( $fitHorizontally == 0 || $fitVertically == 0 ) return false; | |
| $data = file_get_contents ( $file, 0, NULL, 0, $fitHorizontally * $fitVertically ); | |
| if ( strlen ( $data ) == 0 ) return false; | |
| $black = imagecolorallocate ( $image, 0, 0, 0 ); | |
| $white = imagecolorallocate ( $image, 255, 255, 255 ); | |
| imagefill ( $image, 0, 0, $white ); | |
| for ( $char = 0; $char < strlen ( $data ); $char += $fitHorizontally ) { | |
| $line = intval ( $char / $fitHorizontally ); | |
| imagestring ( $image, 1, 3, 3 + $line * imagefontheight ( 2 ), substr ( $data, $char, $fitHorizontally ), $black ); | |
| } | |
| imagepng ( $image, '.dropingallery.' . $file . '.png' ); | |
| return renderPreviewText ( $file, $width, $height ); | |
| } | |
| function renderPreviewText ( $file, $width, $height ) { | |
| if ( !file_exists ( '.dropingallery.' . $file . '.png' ) ) return false; | |
| $outstring .= '<img src=".dropingallery.' . $file . '.png" alt="Preview for ' . $file . '" />'; | |
| $outstring .= '<p>' . htmlentities ( file_get_contents ( $file, 0, NULL, 0, 50 ), ENT_COMPAT, 'UTF-8' ) . '</p>'; | |
| return $outstring; | |
| } | |
| function makePreviewAudio ( $file, $width, $height ) { | |
| if ( !is_executable ( '/usr/bin/ffmpeg' ) ) return false; | |
| if ( !is_writable ( '.' ) ) return false; | |
| $totalLength = 0; | |
| // get the duration and a random place within that | |
| $escapedFile = str_replace ( "'", "\'", $file ); | |
| $cmd = "/usr/bin/ffmpeg -i '$escapedFile' 2>&1"; | |
| if (preg_match('/Duration: ((\d+):(\d+):(\d+))/s', `$cmd`, $time)) { | |
| $totalLength = ($time[2] * 3600) + ($time[3] * 60) + $time[4]; | |
| } | |
| return renderPreviewAudio ( $file, $totalLength ); | |
| } | |
| function renderPreviewAudio ( $file, $totalLength ) { | |
| $hours = intval( $totalLength / ( 60 * 60 ) ); | |
| $minutes = intval( ( $totalLength - $hours * 60 * 60 ) / 60); | |
| $seconds = intval( $totalLength - $hours * 60 * 60 - $minutes * 60 ); | |
| $outstring .= '<span class="timecode">' . sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds) . '</span>'; | |
| return $outstring; | |
| } | |
| ?> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment