Added initial album artwork support.
authorDan
Tue, 05 Aug 2008 13:15:11 -0400
changeset 25 5c377ceb0e4c
parent 24 d275dc8f4203
child 27 20a36fe254c9
Added initial album artwork support.
greyhound.php
imagetools.php
playlist.php
themes/iphone/playlist.tpl
--- a/greyhound.php	Wed Jul 02 11:57:13 2008 -0400
+++ b/greyhound.php	Tue Aug 05 13:15:11 2008 -0400
@@ -40,7 +40,7 @@
 // Allow forking when an HTTP request is received. This has advantages
 // and disadvantages. If this experimental option is enabled, it will
 // result in faster responses and load times but more memory usage.
-$allow_fork = false;
+$allow_fork = true;
 // set to true to enable authentication
 // WARNING: THIS HAS SOME SERIOUS SECURITY PROBLEMS RIGHT NOW. I don't
 // know what's causing it to not prompt for authentication from any
@@ -74,6 +74,7 @@
 require(GREY_ROOT . '/playlist.php');
 require(GREY_ROOT . '/json.php');
 require(GREY_ROOT . '/ajax.php');
+require(GREY_ROOT . '/imagetools.php');
 
 status('doing home directory detection');
 
@@ -118,6 +119,7 @@
   status('initializing handlers');
   $httpd->add_handler('index',                'function', 'amarok_playlist');
   $httpd->add_handler('action.json',          'function', 'ajax_request_handler');
+  $httpd->add_handler('artwork',              'function', 'artwork_request_handler');
   $httpd->add_handler('scripts',              'dir',      GREY_ROOT . '/scripts');
   $httpd->add_handler('favicon.ico',          'file',     GREY_ROOT . '/amarok_icon.ico');
   $httpd->add_handler('apple-touch-icon.png', 'file',     GREY_ROOT . '/apple-touch-icon.png');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagetools.php	Tue Aug 05 13:15:11 2008 -0400
@@ -0,0 +1,205 @@
+<?php
+
+/**
+ * Greyhound - real web management for Amarok
+ * Copyright (C) 2008 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ */
+
+/**
+ * Determines an image's filetype based on its signature.
+ * @param string Path to image file
+ * @return string One of gif, png, or jpg, or false if none of these.
+ */
+
+function get_image_filetype($filename)
+{
+  $filecontents = @file_get_contents($filename);
+  if ( empty($filecontents) )
+    return false;
+  
+  if ( substr($filecontents, 0, 8) == "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" )
+    return 'png';
+  
+  if ( substr($filecontents, 0, 6) == 'GIF87a' || substr($filecontents, 0, 6) == 'GIF89a' )
+    return 'gif';
+  
+  if ( substr($filecontents, 0, 2) == "\xFF\xD8" )
+    return 'jpg';
+  
+  return false;
+}
+
+/**
+ * Scales an image to the specified width and height, and writes the output to the specified
+ * file. Will use ImageMagick if present, but if not will attempt to scale with GD. This will
+ * always scale images proportionally.
+ * 
+ * Ported from Enano CMS (which is also my project)
+ * 
+ * @param string Path to image file
+ * @param string Path to output file
+ * @param int Image width, in pixels
+ * @param int Image height, in pixels
+ * @param bool If true, the output file will be deleted if it exists before it is written
+ * @return bool True on success, false on failure
+ */
+
+function scale_image($in_file, $out_file, $width = 225, $height = 225, $unlink = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  
+  if ( !is_int($width) || !is_int($height) )
+    return false;
+  
+  if ( !file_exists($in_file) )
+    return false;
+  
+  if ( preg_match('/["\'\/\\]/', $in_file) || preg_match('/["\'\/\\]/', $out_file) )
+    return false;
+  
+  if ( file_exists($out_file) && !$unlink )
+    return false;
+  else if ( file_exists($out_file) && $unlink )
+    @unlink($out_file);
+  if ( file_exists($out_file) )
+    // couldn't unlink (delete) the output file
+    return false;
+    
+  $file_ext = substr($in_file, ( strrpos($in_file, '.') + 1));
+  switch($file_ext)
+  {
+    case 'png':
+      $func = 'imagecreatefrompng';
+      break;
+    case 'jpg':
+    case 'jpeg':
+      $func = 'imagecreatefromjpeg';
+      break;
+    case 'gif':
+      $func = 'imagecreatefromgif';
+      break;
+    case 'xpm':
+      $func = 'imagecreatefromxpm';
+      break;
+    default:
+      return false;
+  }
+    
+  // try to find convert in the PATH
+  // FIXME: unix specific (won't work on windows)
+  $path = ( isset($_ENV['PATH']) ) ? $_ENV['PATH'] : ( isset($_SERVER['PATH']) ? $_SERVER['PATH'] : '/usr/local/bin:/usr/bin:/bin' );
+  $path = explode(':', $path);
+  foreach ( $path as $dir )
+  {
+    if ( file_exists("$dir/convert") && is_executable("$dir/convert") )
+    {
+      $magick_path = "$dir/convert";
+    }
+  }
+  
+  $can_use_magick = isset($magick_path);
+  $can_use_gd = (
+      function_exists('getimagesize')         &&
+      function_exists('imagecreatetruecolor') &&
+      function_exists('imagecopyresampled')   &&
+      function_exists($func)
+    );
+  if ( $can_use_magick )
+  {
+    if ( !preg_match('/^([\/A-z0-9_-]+)$/', $magick_path) )
+    {
+      // ImageMagick path seems screwy
+      return false;
+    }
+    $cmdline = "\"$magick_path\" \"$in_file\" -resize \"{$width}x{$height}>\" \"$out_file\"";
+    system($cmdline, $return);
+    if ( !file_exists($out_file) )
+      return false;
+    return true;
+  }
+  else if ( $can_use_gd )
+  {
+    @list($width_orig, $height_orig) = @getimagesize($in_file);
+    if ( !$width_orig || !$height_orig )
+      return false;
+    // calculate new width and height
+    
+    $ratio = $width_orig / $height_orig;
+    if ( $ratio > 1 )
+    {
+      // orig. width is greater that height
+      $new_width = $width;
+      $new_height = round( $width / $ratio );
+    }
+    else if ( $ratio < 1 )
+    {
+      // orig. height is greater than width
+      $new_width = round( $height / $ratio );
+      $new_height = $height;
+    }
+    else if ( $ratio == 1 )
+    {
+      $new_width = $width;
+      $new_height = $width;
+    }
+    if ( $new_width > $width_orig || $new_height > $height_orig )
+    {
+      // Too big for our britches here; set it to only convert the file
+      $new_width = $width_orig;
+      $new_height = $height_orig;
+    }
+    
+    $newimage = @imagecreatetruecolor($new_width, $new_height);
+    if ( !$newimage )
+      return false;
+    $oldimage = @$func($in_file);
+    if ( !$oldimage )
+      return false;
+    
+    // Perform scaling
+    imagecopyresampled($newimage, $oldimage, 0, 0, 0, 0, $new_width, $new_height, $width_orig, $height_orig);
+    
+    // Get output format
+    $out_ext = substr($out_file, ( strrpos($out_file, '.') + 1));
+    switch($out_ext)
+    {
+      case 'png':
+        $outfunc = 'imagepng';
+        break;
+      case 'jpg':
+      case 'jpeg':
+        $outfunc = 'imagejpeg';
+        break;
+      case 'gif':
+        $outfunc = 'imagegif';
+        break;
+      case 'xpm':
+        $outfunc = 'imagexpm';
+        break;
+      default:
+        imagedestroy($newimage);
+        imagedestroy($oldimage);
+        return false;
+    }
+    
+    // Write output
+    $outfunc($newimage, $out_file);
+    
+    // clean up
+    imagedestroy($newimage);
+    imagedestroy($oldimage);
+    
+    // done!
+    return true;
+  }
+  if ( file_exists($out_file) )
+    return true;
+  return false;
+}
+
--- a/playlist.php	Wed Jul 02 11:57:13 2008 -0400
+++ b/playlist.php	Tue Aug 05 13:15:11 2008 -0400
@@ -64,3 +64,75 @@
   $smarty->display('playlist.tpl');
 }
 
+function artwork_request_handler($httpd, $socket)
+{
+  global $homedir;
+  
+  if ( !isset($_GET['artist']) || !isset($_GET['album']) )
+  {
+    echo 'Please specify artist and album.';
+    return;
+  }
+  // get hash
+  $artwork_hash = md5( strtolower(trim($_GET['artist'])) . strtolower(trim($_GET['album'])) );
+  $artwork_dir = "$homedir/.kde/share/apps/amarok/albumcovers";
+  if ( file_exists("$artwork_dir/large/$artwork_hash") )
+  {
+    // artwork file found - scale and convert to PNG
+    if ( !is_dir("$artwork_dir/greyhoundthumbnails") )
+    {
+      if ( !@mkdir("$artwork_dir/greyhoundthumbnails") )
+      {
+        return false;
+      }
+    }
+    // check for the scaled cover image
+    $target_file = "$artwork_dir/greyhoundthumbnails/$artwork_hash.png";
+    if ( !file_exists($target_file) )
+    {
+      // not scaled yet, scale to uniform 50x50 image
+      $artwork_filetype = get_image_filetype("$artwork_dir/large/$artwork_hash");
+      if ( !$artwork_filetype )
+      {
+        return false;
+      }
+      // we'll need to copy the existing artwork file to our thumbnail dir to let scale_image() detect the type properly (it doesn't use magic bytes)
+      if ( !copy("$artwork_dir/large/$artwork_hash", "$artwork_dir/greyhoundthumbnails/tmp{$artwork_hash}.$artwork_filetype") )
+      {
+        return false;
+      }
+      // finally, scale the image
+      if ( !scale_image("$artwork_dir/greyhoundthumbnails/tmp{$artwork_hash}.$artwork_filetype", $target_file, 50, 50) )
+      {
+        return false;
+      }
+      // delete our temp file
+      if ( !unlink("$artwork_dir/greyhoundthumbnails/tmp{$artwork_hash}.$artwork_filetype") )
+      {
+        echo 'Couldn\'t delete the temp file';
+        return false;
+      }
+    }
+    // we have it now, send the image through
+    $fh = @fopen($target_file, 'r');
+    if ( !$fh )
+      return false;
+    $httpd->header('Content-type: image/png');
+    $httpd->header('Content-length: ' . filesize($target_file));
+    $httpd->header('Expires: Wed, 1 Jan 2020 01:00:00 GMT');
+    while ( !feof($fh) )
+    {
+      socket_write($socket, fread($fh, 51200));
+    }
+    fclose($fh);
+  }
+  else
+  {
+    // artwork file doesn't exist
+    $ar = htmlspecialchars($_GET['artist']);
+    $al = htmlspecialchars($_GET['album']);
+    $httpd->send_http_error($socket, 404, "The requested artwork file for $ar:$al could not be found on this server.");
+  }
+}
+
+
--- a/themes/iphone/playlist.tpl	Wed Jul 02 11:57:13 2008 -0400
+++ b/themes/iphone/playlist.tpl	Tue Aug 05 13:15:11 2008 -0400
@@ -74,6 +74,9 @@
               {$track.title|escape}
             </a>
             <div id="track_inner_{$tid}" class="track_inner">
+              <div style="float: left; margin-right: 5px;">
+                <img alt=" " src="/artwork?artist={$track.artist|urlencode}&album={$track.album|urlencode}" />
+              </div>
               <small>
               <b>Artist:</b> {$track.artist|escape}<br />
               <b>Album:</b> {$track.album|escape}<br />