Caching Last.fm player with local music player integration
Ruby
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
bin
examples
lib
.gitignore
COPYING
Gemfile
README

README

PURPOSE
-------

When you play Last.fm the "proper" way, you stream content directly
from the Last.fm webservers to your speakers.  The music is never
stored locally.

This has a few advantages, but also several disadvantages.  You're
wasting a lot of bandwidth by downloading the same songs over and
over.  If you have any connectivity issues, your sound will stutter or
stop.  Your connection has to be faster than the bitrate of the song.
And some Last.fm songs actually exceed the maximum bitrate their
servers will stream at, meaning they will stutter even with a perfect
connection.

cache-fm addresses all these concerns by downloading the songs to the
hard drive and ensuring they are fully ready to play before it begins.
It integrates with either MPD or iTunes (Mac only) and uses them to
play the actual songs.

In short, you get the same user interface(s) and benefits you're
already used to, but the music comes from Last.fm, and you never have
to hear network stutters again.


LICENSE
-------

See COPYING for details.


CAVEATS
-------

This program caches all downloaded songs on the local hard drive.
This is not the standard Last.fm approach, and might be a violation of
the terms of use, but I can't seem to find any relevant clauses.

My request to users of this program:

Please don't abuse this client to populate your MP3 library.

  My intent in writing this program is NOT to allow users to get a
  massive free library of music they can listen to at their leisure, but
  rather, to make CORRECT usage of Last.fm painless and fun compared to
  direct streaming.

Please don't abuse this client to play songs on demand.

  Last.fm's radio license (as I understand it) has conditions on how
  frequently an artist can be played.  Please abide by the playlist
  generator's choices as to what it thinks you should listen to next.

Please be discreet if you violate these requests.

  If you're going to violate the ethics (and possibly the terms and
  conditions) of Last.fm, please keep it to yourself.  Advertising
  your abuse will only make said abuse socially acceptable, and thus
  contribute to other people abusing the system as well.

  Last.fm provides a fantastic service, but if that service sees high
  levels of blatant abuse, they could potentially be forced to move
  to a closed-source proprietary protocol, rendering this and all other
  free clients unusable.

  In short, I don't want to be the one to poison the water-hole by
  making a better way to drink from it.

On a technical note, the repository this client creates will get very
large, and there is currently NO code to expunge old files from the
library.  Don't run this without many gigabytes of free disk space.

The iTunes integration will add a lot of songs to your iTunes music
library, and there's currently no easy means to identify and remove
these songs.  If you have a normal music library, you might not
appreciate having hundreds of Last.fm tracks mixed in.  I'm not aware
of a convenient solution at this point.


SETUP (common)
-----

1. Install bundler:

     gem install bundler

2. Create cache directory:

     mkdir -vp ~/.cache-fm/cache

3. Get your login credentials into the bin/play.rb file.

   If you have shell-fm set up, you can (hopefully) skip this step,
   because the script should read your shell-fm.rc file.

   If not, uncomment the line near the top and replace the content of
   the strings.  To get the MD5 of your password, run this:

     echo -n 'your password' | md5sum


SETUP (MPD)
-----

4. Install MPD-based dependencies:

     bundle install --without itunes

5. Set up and start your MPD.

   A sample configuration is provided in the 'examples' directory.
   You can copy that to ~/.mpdconf and change the paths.

   If you use the sample config, you'll have to create an MPD
   playlists directory or else MPD will not start:

     mkdir -vp ~/.cache-fm/mpd/playlists

6. Set up and start mpdscribble. (optional)

   cache-fm is only concerned with delivering the songs to MPD, not
   recording (scrobbling) the songs you choose to play.  In order to
   do the latter, you will need mpdscribble.

   A sample configuration is provided in the 'examples' directory.
   You can copy that to ~/.mpdscribble/mpdscribble.conf and change
   the paths.


SETUP (iTunes for Mac)
-----

4. Install the iTunes-based dependencies:

     bundle install --without mpd

5. Create a playlist named "Last.fm" in iTunes.

   This playlist will serve as your queue.  Feel free to remove tracks
   from this list once they are no longer needed.

6. Disable "Copy files to iTunes Media folder ..."  (optional)

   This option is located on the "Advanced" preferences tab.  There's
   really no need to be making duplicates of every cache-fm file you
   play, and leaving them in the cache-fm directory makes them easier
   to keep track of.

7. Install iScrobbler. (optional)

   iScrobbler lets you scrobble the songs you play so that they appear
   in your Last.fm history.


USAGE
-----

cache-fm is still lacking a UI, but here's a basic guide to usage.

1. Run IRB, the interactive Ruby interpreter:

     irb -rbin/play

2. At the prompt, run

     play "uri"

   Where "uri" is a Last.fm URL, the kind accepted by shell-fm.
   Examples include "artist/future funk squad", "globaltags/ambient",
   "user/xxx/playlist", etc.

Various status messages will come up as the program operates.  Most
should be self-explanatory.

Note that when cache-fm says "download stopped", it means it will no
longer download new playlists.  It will always continue to fetch the
current playlist until done.


COMMANDS
--------

play "uri"

    Tunes to a new station.  Use this to begin playing on startup.

    After startup, this will abort the current fetch and clear the list
    of pending tracks to download, so it should begin fetching the new
    station immediately.  (Untested.)

status
    Gives an overview of the queue status.  '##' indicates the
    currently-fetching track, while '<<' and '>>' indicate prior and
    upcoming tracks, respectively.

    Percentages indicate completion.  These should always be 100% for
    prior tracks, 0% or 100% for upcoming tracks, and anything for
    fetching tracks.

abort

    Aborts fetching the current track.  The track will simply vanish
    from the list, since failed downloads are discarded.


READLINE BUG (Mac only(?))
------------

   If you experience weird problems, such as cache-fm just stalling
   outright and refusing to do anything, you may have a blocking
   Readline (such as Mac's EditLine) that is preventing the worker
   threads from doing their thing.

   A program is provided to test whether you have this problem:

     irb -r examples/readline.rb

   Don't type anything for at least five seconds.  If you see it count
   to five and then exit, then either your Readline is non-blocking,
   or IRB isn't using it at all.

   If it just stalls instead, you will have to disable it.  The usual
   way to do this is to put

     IRB.conf[:USE_READLINE] = false

   at the end of your ~/.irbrc, creating the file if necessary.
   (This may not always work, depending on how your IRB is configured.)


MISC BUGS
---------

Status messages interfere with the IRB prompt.  If this bothers you,
run IRB with --noprompt.

Old tracks are not currently expunged from either the internal
playlist or the MPD/iTunes playlist.  If left running indefinitely, memory
costs could get prohibitive.  I have no idea how long this would take,
but I imagine "rapid-tag" mode (see manager.rb comments) would become
a problem much faster.

If a fetch is aborted, a tempfile (1234.mp3.tmp) is left lying around.
It will simply be overwritten the next time the client tries to
download that track.  Maybe someday the client will support resuming a
partial download, but for now, you may want to occasionally delete
*.tmp when the client is not actively downloading a track.