#!/bin/bash # Generate a collage with the covers of your favorite albums according to your last.fm profile. # Inspired by Gijsco's Last.fm Desktop Generator (http://build.last.fm/item/37) and Jamie Zawinski's webcollage (http://www.jwz.org/webcollage/) # Requires imagemagick and xsltproc (fairly standard) # Also requires parse_pictures.xsl which you should find wherever you found this script. # # Usage: # Copy the script and parse_pictures.xsl in a directory of your choice. # Running the script from the command line will use the default values. # Use ./lastCollage -u yourlastfmusername to make the collage with your profile and default values. See output for a description of the parameters. # You can delete the sub-directory lccache if you want to start afresh. It'll be re-created. # # More explanations at http://ledazibao.free.fr/lastCollage # # Koant (http://www.last.fm/user/Koant/) # Thu 15 May 2008 # # Possible improvements, if you feel like it: # . better random; RANDOM produces extremely correlated numbers. Had to re-seed after each use. # . use other feeds than top albums # . speed things up # Default Settings username='Koant' # last.fm username type='overall' # 3month, 6month, 12month or overall AlbumSize=300 # size of each album cover, in pixel Final=1280x1024 # dimension of the final image, in pixel AlbumOpacity=80 # from 0 to 100 (100 is completely opaque, the cover won't blend into the background) GradientSize=20 # in pixel. Transparency gradient size for an album. The bigger the larger the area of the cover is transparent. ImageOpacity=70 # darken the final image, from 0 to 100 (0 is completely black) iteration=1 # Number of times the algorithm is run. 2 is usually enough cache='lccache' # name of cache directory # Checking out dependencies (bc, ImageMagick and xsltproc) if which bc > /dev/null; then echo "bc is installed." else echo echo " bc is not installed! I can't proceed." exit fi if which convert > /dev/null; then echo "ImageMagick is installed." else echo echo " ImageMagick is not installed! I can't proceed." exit fi if which xsltproc > /dev/null; then echo "xsltproc is installed." else echo echo " xsltproc is not installed! I can't proceed." exit fi # Reading out parameters # from http://www.ibm.com/developerworks/library/l-bash-parameters.html by Ian Shields while getopts ":u:O:o:n:f:c:a:t:g:i:" optval "$@" do case "$optval" in "u") username=$OPTARG ;; "O") ImageOpacity=$OPTARG ;; "o") AlbumOpacity=$OPTARG ;; "n") imagename=$OPTARG ;; "f") Final=$OPTARG ;; "c") Canvas=$OPTARG ;; "a") AlbumSize=$OPTARG ;; "t") type=$OPTARG ;; "g") GradientSize=$OPTARG ;; "i") iteration=$OPTARG ;; "?") echo "Unknown option $OPTARG, ignored." ;; ":") echo "No argument value for option $OPTARG" ;; *) # Should not occur echo "Unknown error while processing options" ;; esac done # processing and reverting to default if needs be imagename=${imagename:-"$username"} # Default imagename is username Canvas=${Canvas:-"$Final"} # Default Canvas size is Final's FinalWidth=$(echo $Final | cut -d'x' -f1) FinalHeight=$(echo $Final | cut -d'x' -f2) CanvasWidth=$(echo $Canvas | cut -d'x' -f1) CanvasHeight=$(echo $Canvas | cut -d'x' -f2) echo "I'll be using the following parameters:-" echo " (u) Username: $username " echo " (t) How far back: $type (should be one of '3month', '6month' or '12month')" echo " (n) Name of the picture: $imagename.jpg" echo " (c) Size of the canvas: "$CanvasWidth"x"$CanvasHeight echo " (f) Size of the final image: "$FinalWidth"x"$FinalHeight echo " (a) Album size: $AlbumSize pixels" echo " (o) Album opacity: $AlbumOpacity (in [0 100]. 100 means no transparency)" echo " (g) Gradient size: $GradientSize pixels (should be between 1 and half the album size)" echo " (O) Darkness of final image: $ImageOpacity (in [0 100]. 0 makes the image completely black)" echo " (i) Number of iterations: $iteration" echo "(use the letter in parentheses to change the value, as argument to the script)" # URL URL="http://ws.audioscrobbler.com/1.0/user/$username/topalbums.xml?type=$type" # Make script crontab friendly: cd $(dirname $0) # Create cache if doesn't exist already if test ! -d $cache then mkdir $cache fi # returns a random integer between $1 and $2 function get_rand { RANDOM=$(dd if=/dev/urandom count=2 2> /dev/null | cksum | cut -f1 -d" ") # re-seed l=`expr $2 - $1` r=`echo "r=($l+1)* ($RANDOM/32767); if (r<1) print 0 else print r" |bc -l |cut -d'.' -f1` echo `expr $r + $1` } #add + sign if needs be function add_sign { if ! echo $1 | grep -e "-" >/dev/null then echo +$1 else echo $1 fi } # Create picture log if doesn't exist already # (list of all URL of pics that have been downloaded) if test ! -f $cache/pixlog then touch $cache/pixlog chmod a+w $cache/pixlog echo "http://cdn.last.fm/depth/catalogue/noimage/cover_med.gif" >> $cache/pixlog # empty album cover, won't be dl. fi # fetching the list echo "Fetching the list of albums..." rm -f albumlist.xml wget -q -O albumlist.xml "$URL" # Download new pictures only echo "Downloading new pictures..." urllist=$(xsltproc parse_pictures.xsl albumlist.xml 2> /dev/null) touch filelist for url in $urllist do if ! grep "$url" $cache/pixlog > /dev/null # check whether it's already in the cache then # download and add to the list if need be echo $url wget -q -P $cache "$url" && echo $url >> $cache/temp.log cat $cache/temp.log >> $cache/pixlog rm -f $cache/temp.log fi done # list of pictures to actually use, in random order echo "Preparing the list of pictures..." rm -f tempfilelist touch tempfilelist for url in $urllist # shuflles the list of pictures do x=$(get_rand 1000 9999) echo $x ${url##*/} >> tempfilelist done sort tempfilelist | cut -d' ' -f2 > filelist rm -f tempfilelist # Useful quantities Dx=`echo "r=($CanvasWidth - $FinalWidth)/2; if (r*r<1) print 0 else print r" |bc -l |cut -d'.' -f1` Dy=`echo "r=($CanvasHeight - $FinalHeight)/2; if (r*r<1) print 0 else print r" |bc -l |cut -d'.' -f1` startx=`expr 0 - $Dx` starty=`expr 0 - $Dy` rangex=`expr $FinalWidth + $Dx - $AlbumSize` rangey=`expr $FinalHeight + $Dy - $AlbumSize` # prepare the mask echo "Preparing the mask..." intensity=`echo "254*($AlbumOpacity/100)+1" | bc -l | cut -d'.' -f1` ln=`expr $AlbumSize - $GradientSize` convert -size "$AlbumSize"x"$AlbumSize" xc:black -stroke rgb\($intensity,$intensity,$intensity\) -fill rgb\($intensity,$intensity,$intensity\) -draw "roundRectangle $GradientSize,$GradientSize $ln,$ln $GradientSize,$GradientSize" -gaussian "$GradientSize"x"$GradientSize" mask.png # make the background echo "Preparing the background..." if test -f $imagename.jpg # use former image as background if exists. Resize if necessary then echo "$imagename.jpg exists, I'll paste the new collage on it." convert $imagename.jpg -resize "$FinalWidth"x"$FinalHeight"! background.png else convert -size "$FinalWidth"x"$FinalHeight" xc:black background.png fi # add images from list echo "Add images (might take a while)..." for ((i=1;i<=$iteration;i+=1)); do echo " iteration $i of $iteration" while read fn do if test -f $cache/$fn then # echo $cache/$fn convert -resize "$AlbumSize"x"$AlbumSize"! $cache/$fn mask.png +matte -compose CopyOpacity -composite temp.png x=$(add_sign $(get_rand $startx $rangex)) y=$(add_sign $(get_rand $starty $rangey)) convert background.png \( temp.png -repage "$x""$y" \) -flatten background.png fi done < filelist done # darken and jpg echo "Darken the final image..." intensity=`echo "254*($ImageOpacity/100)+1" |bc -l | cut -d'.' -f1` convert background.png \( -size "$FinalWidth"x"$FinalHeight" xc:rgb\($intensity,$intensity,$intensity\) \) +matte -compose Multiply -composite $imagename.jpg # cleaning up rm -f background.png mask.png temp.png filelist albumlist.xml echo "Finished! Image saved in $imagename.jpg"