Index: mythtv/libs/libmyth/lcddevice.cpp
===================================================================
--- mythtv/libs/libmyth/lcddevice.cpp	(revision 7537)
+++ mythtv/libs/libmyth/lcddevice.cpp	(working copy)
@@ -192,7 +192,7 @@
 #endif
         // Just stream the text out the socket
 
-        os << someText << "\n";
+        os << someText << "\n" << flush;
     }
     else
     {
@@ -387,9 +387,18 @@
     else if (value > 1.0)
         value = 1.0;
         
-    sendToServer("SET_GENERIC_PROGRESS " + QString().setNum(value));    
+    sendToServer("SET_GENERIC_PROGRESS " + QString().setNum (false) + 
+                 " " + QString().setNum(value));    
 }
 
+void LCD::setGenericBusy ()
+{
+    if (!lcd_ready || !lcd_showgeneric)
+        return;
+
+    sendToServer("SET_GENERIC_PROGRESS 1 0.0");
+}
+
 void LCD::setMusicProgress(QString time, float value)
 {
     if (!lcd_ready || !lcd_showmusic)
Index: mythtv/libs/libmyth/mythdialogs.cpp
===================================================================
--- mythtv/libs/libmyth/mythdialogs.cpp	(revision 7537)
+++ mythtv/libs/libmyth/mythdialogs.cpp	(working copy)
@@ -1520,10 +1520,7 @@
     progress->setBackgroundOrigin(ParentOrigin);
     progress->setProgress(0);
 
-    m_totalSteps = totalSteps;
-    steps = totalSteps / 1000;
-    if (steps == 0)
-        steps = 1;
+    setTotalSteps (totalSteps);
 
     if (class LCD * lcddev = LCD::Get())
     {
@@ -1588,6 +1585,57 @@
         MythDialog::keyPressEvent(e);
 }
 
+void MythProgressDialog::setTotalSteps (int totalSteps) {
+    m_totalSteps = totalSteps;
+    steps = totalSteps / 1000;
+    if (steps == 0)
+        steps = 1;
+}
+
+MythBusyDialog::MythBusyDialog (const QString &title) : 
+    MythProgressDialog (title, 0),
+    timer (NULL)
+{
+}
+
+MythBusyDialog::~MythBusyDialog () {
+    if (timer) 
+        delete timer;
+}
+
+void 
+MythBusyDialog::start (int interval) {
+    if (timer == NULL) {
+        timer = new QTimer (this);
+    }
+    connect (timer, SIGNAL (timeout ()), SLOT (timeout ()));
+    timer->start (interval);
+}
+
+void 
+MythBusyDialog::Close () {
+    if (timer) {
+        disconnect (timer, SIGNAL (timeout ()), this, SLOT (timeout ()));
+        delete timer;
+        timer = 0;
+    }
+
+    MythProgressDialog::Close ();
+}
+
+void
+MythBusyDialog::setProgress ()  {
+    progress->setProgress (progress->progress () + 10);
+    qApp->processEvents ();
+    if (LCD *lcddev = LCD::Get())
+        lcddev->setGenericBusy ();
+}
+
+void
+MythBusyDialog::timeout ()  {
+    setProgress ();
+}
+
 MythThemedDialog::MythThemedDialog(MythMainWindow *parent, QString window_name,
                                    QString theme_filename, const char* name,
                                    bool setsize)
Index: mythtv/libs/libmyth/lcddevice.h
===================================================================
--- mythtv/libs/libmyth/lcddevice.h	(revision 7537)
+++ mythtv/libs/libmyth/lcddevice.h	(working copy)
@@ -147,9 +147,18 @@
     // define the screen, row, and alignment of the text
     void switchToGeneric(QPtrList<LCDTextItem> *textItems);
 
-    // Do a progress bar with the generic level between 0 and 1.0
+    /** Update the generic progress bar.
+        \param generic_progress a value between 0 and 1.0
+    */
     void setGenericProgress(float generic_progress);
 
+    /** Update the generic screen to display a busy spinner.
+
+		\note The LCD busy spinner only 'moves' when this is called
+		instead of the lcdserver just handling it itself. 
+    */
+    void setGenericBusy();
+
     // Do a music progress bar with the generic level between 0 and 1.0
     void setMusicProgress(QString time, float generic_progress);
 
Index: mythtv/libs/libmyth/mythdialogs.h
===================================================================
--- mythtv/libs/libmyth/mythdialogs.h	(revision 7537)
+++ mythtv/libs/libmyth/mythdialogs.h	(working copy)
@@ -11,6 +11,7 @@
 #include <qevent.h>
 #include <qvaluevector.h>
 #include <qscrollview.h>
+#include <qthread.h>
 
 #include <vector>
 using namespace std;
@@ -229,28 +230,101 @@
     bool arrowAccel;
 };
 
+/** The MythTV progress bar dialog.
+
+    This dialog is responsible for displaying a progress bar box on
+    the screen. This is used when you have a known set of steps to
+    perform and the possibility of calling the \p setProgress call at
+    the end of each step.
+
+	If you do not know the number of steps, use \p MythBusyDialog
+	instead.
+
+    The dialog widget also updates the LCD display if present.
+
+*/
 class MythProgressDialog: public MythDialog
 {
   public:
+    /** Create a progress bar dialog.
+        
+        \param message the title string to appear in the progress dialog.
+        \param totalSteps the total number of steps
+     */
     MythProgressDialog(const QString& message, int totalSteps);
 
+	/* \brief Close the dialog.
+	   This will close the dialog and return the LCD to the Time screen 
+	*/
     void Close(void);
+	/* \brief Update thr progress bar.  
+
+	    This will move the progress bar the percentage-completed as
+	    determined by \p curprogress and the totalsteps as set by the
+	    call to the constructor.
+
+		The LCD is updated as well.
+	 */
     void setProgress(int curprogress);
+
     void keyPressEvent(QKeyEvent *);
 
+  protected:
+    QProgressBar *progress;
+
   private:
-    QProgressBar *progress;
+	void setTotalSteps (int totalSteps);	
     int steps;
-
+    int m_totalSteps;
     QPtrList<class LCDTextItem> * textItems;
+};
 
-    int m_totalSteps;
+/** MythDialog box that displays a busy spinner-style dialog box to
+    indicate the program is busy, but that the number of steps needed
+    is unknown. 
+
+	Ie. used by MythMusic when scanning the filesystem for musicfiles.
+ */
+class MythBusyDialog : public MythProgressDialog {
+    Q_OBJECT
+  public:
+    /** \brief Create the busy indicator.  
+
+	    Creates the dialog widget and sets up the timer that causes
+	    the widget to indicate progress every 100msec;
+
+        \param title the title to appear in the progress bar dialog
+    */
+    MythBusyDialog (const QString &title);
+
+    ~MythBusyDialog ();
+
+	/** \brief Setup a timer to 'move' the spinner
+
+		This will create a \p QTimer object that will update the
+		spinner ever \p interval msecs.
+
+		\param interval msecs between movement, default is 100
+	*/
+	void start (int interval = 100);
+
+    /** \brief Close the dialog.
+        This will close the dialog and stop the timer.		
+     */
+    void Close ();
+
+  protected slots:
+	void setProgress();
+	void timeout ();
+
+  private:
+	QTimer *timer;
 };
 
 class MythThemedDialog : public MythDialog
 {
-    Q_OBJECT
-  public:
+    Q_OBJECT 
+ public:
     MythThemedDialog(MythMainWindow *parent, QString window_name,
                      QString theme_filename = "", const char *name = 0,
                      bool setsize = true);
Index: mythtv/programs/mythlcdserver/lcdprocclient.cpp
===================================================================
--- mythtv/programs/mythlcdserver/lcdprocclient.cpp	(revision 7537)
+++ mythtv/programs/mythlcdserver/lcdprocclient.cpp	(working copy)
@@ -959,6 +959,7 @@
 void LCDProcClient::startMusic(QString artist, QString album, QString track)
 {
     QString aString;
+    music_progress = 0.0;
     if (lcd_showmusic)
       setPriority("Music", HIGH);
     aString = artist;
@@ -1016,7 +1017,7 @@
     QString aString;
 
     if (lcd_showgeneric)
-      setPriority("Generic", HIGH);
+      setPriority("Generic", TOP);
 
     // Clear out the LCD.  Do this before checking if its empty incase the user
     //  wants to just clear the lcd
@@ -1029,6 +1030,11 @@
         return;
 
     activeScreen = "Generic";
+
+    busy_progress = false;
+    busy_pos = 1;
+    busy_direction = 1;
+    busy_indicator_size = 2.0;
     generic_progress = 0.0;
 
     // Return if there are no more items
@@ -1505,7 +1511,7 @@
     outputChannel();    
 }
 
-void LCDProcClient::setGenericProgress(float value)
+void LCDProcClient::setGenericProgress(bool b, float value)
 {
     if (!lcd_ready)
         return;
@@ -1517,6 +1523,21 @@
     else if (generic_progress > 1.0)
         generic_progress = 1.0;
 
+    // Note, this will let us switch to/from busy indicator by alternating between
+    // being passed true or false for b.
+    busy_progress = b;
+    if (busy_progress) {
+        // If we're at either end of the line, switch direction
+        if (busy_pos + busy_direction > (signed int)lcdWidth - busy_indicator_size || 
+            busy_pos + busy_direction < 1) {
+            busy_direction = -busy_direction;
+        }
+        busy_pos += busy_direction;
+        generic_progress = busy_indicator_size / (float)lcdWidth;
+    } else {
+        busy_pos = 1;
+    }
+
     outputGeneric();
 }
 
@@ -1794,7 +1815,9 @@
 void LCDProcClient::outputGeneric()
 {
     QString aString;
-    aString = "widget_set Generic progressBar 1 ";
+    aString = "widget_set Generic progressBar ";
+    aString += QString::number (busy_pos);
+    aString += " ";
     aString += QString::number(lcdHeight);
     aString += " ";
     aString += QString::number((int)rint(generic_progress * lcdWidth * 
@@ -2003,7 +2026,12 @@
                                   "- is the master server running?\n\t\t\t"
                                   "Will retry in 30 seconds");
             QTimer::singleShot(30 * 1000, this, SLOT(updateRecordingList()));
-            switchToTime();
+
+            // If we can't get the recording status and we're showing
+            // it, switch back to time. Maybe it would be even better
+            // to show that the backend is unreachable ?
+            if  (activeScreen == "RecStatus")
+                switchToTime();
             return;
         }    
     }
Index: mythtv/programs/mythlcdserver/lcdserver.cpp
===================================================================
--- mythtv/programs/mythlcdserver/lcdserver.cpp	(revision 7537)
+++ mythtv/programs/mythlcdserver/lcdserver.cpp	(working copy)
@@ -39,7 +39,8 @@
         time is a string
         progress is a float between 0.0 and 1.0
 
-    SET_GENERIC_PROGRESS <progress>
+    SET_GENERIC_PROGRESS <busy> <progress>
+        busy is 0 for busy spinner, 0 for normal progess bar
         progress is a float between 0.0 and 1.0
     
     UPDATE_LEDS
@@ -577,7 +578,7 @@
 
     QString flat = tokens.join(" ");
    
-    if (tokens.count() != 2)
+    if (tokens.count() != 3)
     {
         VERBOSE(VB_IMPORTANT, "LCDServer: bad SET_GENERIC_PROGRESS command: "
                 << flat);
@@ -586,9 +587,17 @@
     }
      
     bool bOK;
-    float progress = tokens[1].toFloat(&bOK);
+    bool busy = tokens[1].toInt (&bOK);
     if (!bOK)
     {
+        VERBOSE(VB_IMPORTANT, "LCDServer: bad bool value in "
+                "SET_GENERIC_PROGRESS command: %1 %2" << tokens[1] << tokens[2]);
+        sendMessage(socket, "HUH?");
+        return;
+    }
+    float progress = tokens[2].toFloat(&bOK);
+    if (!bOK)
+    {
         VERBOSE(VB_IMPORTANT, "LCDServer: bad float value in "
                 "SET_GENERIC_PROGRESS command: %1" << tokens[1]);
         sendMessage(socket, "HUH?");
@@ -596,7 +605,7 @@
     }
     
     if (m_lcd)
-        m_lcd->setGenericProgress(progress);
+        m_lcd->setGenericProgress(busy, progress);
         
     sendMessage(socket, "OK");
 }
Index: mythtv/programs/mythlcdserver/lcdprocclient.h
===================================================================
--- mythtv/programs/mythlcdserver/lcdprocclient.h	(revision 7537)
+++ mythtv/programs/mythlcdserver/lcdprocclient.h	(working copy)
@@ -49,7 +49,7 @@
                       bool popMenu = true);
     
     void switchToGeneric(QPtrList<LCDTextItem> *textItems);
-    void setGenericProgress(float generic_progress);
+    void setGenericProgress(bool busy, float generic_progress);
 
     void switchToVolume(QString app_name);
     void setVolumeLevel(float volume_level);
@@ -162,6 +162,14 @@
         
     float EQlevels[10];
     float progress;
+    /** TRUE if the generic progress indicator is a busy (ie. doesn't have a known total steps */
+    bool busy_progress;
+    /** Current position of the busy indicator, used if @p busy_progress is true. */
+    int busy_pos;
+    /** How many "blocks" the busy indicator must be, used if @p busy_progress is true. */
+    float busy_indicator_size;
+    /** Dicrection of the busy indicator on the, -1 or 1, used if @p busy_progress is true. */
+    int busy_direction;
     float generic_progress;
     float volume_level;
 
Index: mythplugins/mythmusic/mythmusic/decoder.h
===================================================================
--- mythplugins/mythmusic/mythmusic/decoder.h	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/decoder.h	(working copy)
@@ -8,6 +8,7 @@
 #include <qptrlist.h>
 
 class Metadata;
+class MetaIO;
 class Decoder;
 class DecoderFactory;
 
@@ -79,9 +80,54 @@
     static Decoder *create(const QString &, QIODevice *, AudioOutput *, 
                            bool = FALSE);
 
-    virtual Metadata *getMetadata() = 0;
-    virtual void commitMetadata(Metadata *mdata) = 0;
+    /** \brief Read the metadata from \p filename directly.
+	
+        Creates a \p MetaIO object using \p Decoder::doCreateTagger and uses
+        the MetaIO object to read the metadata.
+        
+        \returns an instance of \p Metadata owned by the caller
+     */
+    virtual Metadata *readMetadata();
 
+    /** \brief Get the metadata  for \p filename 
+	
+        Tries first to read the metadata from the database. If there
+        is no database entry, it'll call \p Decoder::readMetadata
+
+		@returns an instance of \p Metadata owned by the caller
+    */
+    virtual Metadata *getMetadata();
+
+    /** \brife Create a \p MetaIO object for the format.
+
+        This method should be overwritten by subclasses to return an
+        instance of the appropriate MetaIO subtype. It is used by \p
+        Decoder::getMetadata, \p Decoder::readMetadata and \p
+        Decoder::commitMetadata.
+        
+        The default implementation returns a NULL pointer, which
+        essentially means, that if the decoder does not overrider this
+        method or all of the users (see previous paragraph), files
+        that the decoder supports cannot be indexed using metadata in
+        the file.
+
+		Eg. the mp3 decoder (\p MadDecoder) implements this, whereas
+		the audio CD decoder (\p CdDecoder) does not.
+
+		\returns an instance of \p MetaIO owned by the caller
+     */
+    virtual MetaIO *doCreateTagger ();
+
+    /** \brief Write the given metadata to the \p filename.
+	
+        Creates a \p MetaIO object using \p Decoder::createTagger and
+        asks the MetaIO object to write the contents of mdata to \p
+        filename.
+
+        @\arams mdata the metadata to write to the disk
+     */
+    virtual void commitMetadata(Metadata *mdata);
+
     static void SetLocationFormatUseTags(void);
 
     QString getFilename(void) { return filename; }
Index: mythplugins/mythmusic/mythmusic/aacdecoder.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/aacdecoder.cpp	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/aacdecoder.cpp	(working copy)
@@ -614,39 +614,9 @@
     deinit();
 }
 
-Metadata* aacDecoder::getMetadata()
+MetaIO* aacDecoder::doCreateTagger()
 {
-
-    Metadata *mdata = new Metadata(filename);
-    if (mdata->isInDatabase(musiclocation))
-    {
-      return mdata;
-    }
-    
-    delete mdata;
-
-    MetaIOMP4* p_tagger = new MetaIOMP4;
-    if (ignore_id3) {
-        mdata = p_tagger->readFromFilename(filename);
-    } else {
-        mdata = p_tagger->read(filename);
-    }
-    
-    delete p_tagger;
-
-    if (mdata)
-        mdata->dumpToDatabase(musiclocation);
-    else
-      error(QString("aacdecoder.o: Could not read metadata from \"%1\"").arg(filename.local8Bit()));
-
-    return mdata;
-}    
-
-void aacDecoder::commitMetadata(Metadata *mdata)
-{
-    MetaIOMP4* p_tagger = new MetaIOMP4;
-    p_tagger->write(mdata);
-    delete p_tagger;
+    return new MetaIOMP4;
 }
 
 uint32_t aacDecoder::aacRead(char *buffer, uint32_t length)
Index: mythplugins/mythmusic/mythmusic/metadata.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/metadata.cpp	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/metadata.cpp	(working copy)
@@ -1,4 +1,5 @@
 #include <iostream> 
+#include <qapplication.h>
 #include <qregexp.h> 
 #include <qdatetime.h>
 #include <qdir.h>
@@ -148,7 +149,7 @@
         playcount = query.value(10).toInt();
         lastplay = query.value(11).toString();
         compilation = (query.value(12).toInt() > 0);
-        
+
         retval = true;
     }
 
@@ -194,9 +195,10 @@
         return;
 
     query.prepare("INSERT INTO musicmetadata (artist,compilation_artist,album,title,"
-                  "genre,year,tracknum,length,filename,compilation,date_added) VALUES "
+                  "genre,year,tracknum,length,filename,compilation,date_added,"
+                  "date_modified) VALUES "
                   "(:ARTIST, :COMPILATION_ARTIST, :ALBUM, :TITLE, :GENRE, :YEAR, :TRACKNUM, "
-                  ":LENGTH, :FILENAME, :COMPILATION, :DATE_ADDED );");
+                  ":LENGTH, :FILENAME, :COMPILATION, :DATE_ADDED, :DATE_MODIFIED );");
     query.bindValue(":ARTIST", artist.utf8());
     query.bindValue(":COMPILATION_ARTIST", compilation_artist.utf8());
     query.bindValue(":ALBUM", album.utf8());
@@ -207,7 +209,8 @@
     query.bindValue(":LENGTH", length);
     query.bindValue(":FILENAME", sqlfilename.utf8());
     query.bindValue(":COMPILATION", compilation);
-    query.bindValue(":DATE_ADDED", QDate::currentDate());
+    query.bindValue(":DATE_ADDED", QDateTime::currentDateTime());
+    query.bindValue(":DATE_MODIFIED", QDateTime::currentDateTime());
     
     query.exec();
 
@@ -364,7 +367,8 @@
                   "compilation_artist = :COMPILATION_ARTIST, "
                   "title = :TITLE, genre = :GENRE, year = :YEAR, "
                   "tracknum = :TRACKNUM, rating = :RATING, " 
-                  "compilation = :COMPILATION "
+                  "compilation = :COMPILATION, "
+                  "date_modified= :DATE_MODIFIED "
                   "WHERE intid = :ID;");
     query.bindValue(":ARTIST", artist.utf8());
     query.bindValue(":COMPILATION_ARTIST", compilation_artist.utf8());
@@ -375,6 +379,7 @@
     query.bindValue(":TRACKNUM", tracknum);
     query.bindValue(":RATING", rating);
     query.bindValue(":COMPILATION", compilation);
+    query.bindValue(":DATE_MODIFIED", QDateTime::currentDateTime());
     query.bindValue(":ID", id);
 
     if (!query.exec())
@@ -660,7 +665,7 @@
 void MetadataLoadingThread::run()
 {
     //if you want to simulate a big music collection load
-    //sleep(3); 
+    //sleep (10);
     parent->resync();
 }
 
@@ -683,8 +688,8 @@
     //  loading and sorting
     //
     
-    metadata_loader = new MetadataLoadingThread(this);
-    metadata_loader->start();
+    metadata_loader = NULL;
+    startLoading ();
 
     all_music.setAutoDelete(true);
     top_nodes.setAutoDelete(true);
@@ -718,6 +723,22 @@
     return false;
 }
 
+bool AllMusic::startLoading () {
+    // Set this to false early rather than letting it be delayed till
+    // the thread calls resync.
+    done_loading = false;
+
+    if (metadata_loader) {
+        cleanOutThreads ();
+        delete metadata_loader;
+    }
+
+    metadata_loader = new MetadataLoadingThread(this);
+    metadata_loader->start ();    
+    
+    return true;
+}
+
 void AllMusic::resync()
 {
     done_loading = false;
@@ -736,7 +757,8 @@
     query.exec(aquery);
 
     all_music.clear();
-    
+
+    /* Create the medata objects */ 
     if (query.isActive() && query.size() > 0)
     {
         while (query.next())
@@ -1193,6 +1215,7 @@
         if( *it != "genre"  &&
             *it != "artist" &&
             *it != "splitartist" && 
+            *it != "splitartist1" && 
             *it != "album"  &&
             *it != "title")
         {
@@ -1502,4 +1525,3 @@
         ++iter;
     }
 }
-
Index: mythplugins/mythmusic/mythmusic/decoder.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/decoder.cpp	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/decoder.cpp	(working copy)
@@ -6,6 +6,8 @@
 
 #include "decoder.h"
 #include "constants.h"
+#include "metadata.h"
+#include "metaio.h"
 #include <mythtv/output.h>
 #include <mythtv/visual.h>
 
@@ -87,7 +89,52 @@
     listeners.remove(object);
 }
 
+Metadata *Decoder::readMetadata () {
+    Metadata *mdata = NULL;
+    MetaIO* p_tagger = doCreateTagger ();
 
+    if (p_tagger) {
+        if (ignore_id3)
+            mdata = p_tagger->readFromFilename(filename);
+        else
+            mdata = p_tagger->read(filename);
+        
+        delete p_tagger;
+    } else {
+        if (!mdata)
+            cerr << "maddecoder.o: Could not read metadata from " << filename.local8Bit() << endl;
+    }
+
+    return mdata;    
+}
+
+Metadata* Decoder::getMetadata()
+{
+
+    Metadata *mdata = new Metadata(filename);
+    if (mdata->isInDatabase(musiclocation))
+    {
+      return mdata;
+    }
+    
+    delete mdata;
+
+    return readMetadata ();
+}    
+
+void Decoder::commitMetadata(Metadata *mdata)
+{
+    MetaIO* p_tagger = doCreateTagger ();
+    if (p_tagger) {
+        p_tagger->write(mdata);
+        delete p_tagger;
+    }
+}
+
+MetaIO *Decoder::doCreateTagger () {
+    return NULL;
+}
+
 // static methods
 
 int Decoder::ignore_id3 = 0;
Index: mythplugins/mythmusic/mythmusic/aacdecoder.h
===================================================================
--- mythplugins/mythmusic/mythmusic/aacdecoder.h	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/aacdecoder.h	(working copy)
@@ -29,8 +29,7 @@
     void seek(double);
     void stop();
 
-    Metadata *getMetadata();
-    void commitMetadata(Metadata *mdata);
+    MetaIO *doCreateTagger();
 
     bool     initializeMP4();
     int      getAACTrack(mp4ff_t *infile);
Index: mythplugins/mythmusic/mythmusic/metadata.h
===================================================================
--- mythplugins/mythmusic/mythmusic/metadata.h	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/metadata.h	(working copy)
@@ -244,6 +244,16 @@
     Metadata*   getMetadata(int an_id);
     bool        updateMetadata(int an_id, Metadata *the_track);
     void        save();
+	/** \brief Start loading metadata.
+		Makes the AllMusic object run it's resync in a thread. Once done, it's
+		doneLoading method will return true.
+
+		@note Alternatively, it could be made to emit a signal so the
+		caller won't have to poll for completion.
+
+		\returns true if the loader thread was started
+	*/
+	bool        startLoading ();
     void        resync();   //  After a CD rip, for example
     void        clearCDData();
     void        addCDTrack(Metadata *the_track);
@@ -264,7 +274,6 @@
     bool        cleanOutThreads();
     int         getCDTrackCount(){return cd_data.count();}
     void        resetListings(){last_listed = -1;}
-    
   private:
   
     QPtrList<Metadata>  all_music;
Index: mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp	(working copy)
@@ -293,38 +293,9 @@
     deinit();
 }
 
-Metadata *VorbisDecoder::getMetadata()
+MetaIO *VorbisDecoder::doCreateTagger()
 {
-    Metadata *mdata = new Metadata(filename);
-    if (mdata->isInDatabase(musiclocation))
-    {
-        return mdata;
-    }
-
-    delete mdata;
-
-
-    MetaIOOggVorbisComment* p_tagger = new MetaIOOggVorbisComment;
-    if (ignore_id3)
-        mdata = p_tagger->readFromFilename(filename);
-    else
-        mdata = p_tagger->read(filename);
-
-    delete p_tagger;
-
-    if (mdata)
-        mdata->dumpToDatabase(musiclocation);
-    else
-        cerr << "vorbisdecoder.o: Could not read metadata from " << filename.local8Bit() << endl;    
-
-    return mdata;
-}    
-
-void VorbisDecoder::commitMetadata(Metadata *mdata)
-{
-    MetaIOOggVorbisComment* p_tagger = new MetaIOOggVorbisComment;
-    p_tagger->write(mdata);
-    delete p_tagger;
+    return new MetaIOOggVorbisComment;
 }
 
 
Index: mythplugins/mythmusic/mythmusic/flacdecoder.h
===================================================================
--- mythplugins/mythmusic/mythmusic/flacdecoder.h	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/flacdecoder.h	(working copy)
@@ -22,8 +22,7 @@
     void doWrite(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
     void setFlacMetadata(const FLAC__StreamMetadata *metadata);
 
-    Metadata *getMetadata();
-    void commitMetadata(Metadata *mdata);
+    MetaIO *doCreateTagger();
 
   private:
     void run();
Index: mythplugins/mythmusic/mythmusic/avfdecoder.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/avfdecoder.cpp	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/avfdecoder.cpp	(working copy)
@@ -357,40 +357,11 @@
     deinit();
 }
 
-Metadata* avfDecoder::getMetadata()
+MetaIO* avfDecoder::doCreateTagger()
 {
-    Metadata *mdata = new Metadata(filename);
-    if (mdata->isInDatabase(musiclocation))
-    {
-        return mdata;
-    }
-
-    delete mdata;
-
-
-    MetaIOAVFComment* p_tagger = new MetaIOAVFComment;
-    if (ignore_id3)
-        mdata = p_tagger->readFromFilename(filename);
-    else
-        mdata = p_tagger->read(filename);
-    
-    delete p_tagger;
-
-    if (mdata)
-        mdata->dumpToDatabase(musiclocation);
-    else
-        cerr << "avfdecoder.o: Could not read metadata from " << filename << endl;
-
-    return mdata;
+    return new MetaIOAVFComment;
 }    
 
-void avfDecoder::commitMetadata(Metadata *mdata)
-{
-    MetaIOAVFComment* p_tagger = new MetaIOAVFComment;
-    p_tagger->write(mdata);
-    delete p_tagger;
-}
-
 bool avfDecoderFactory::supports(const QString &source) const
 {
     return (source.right(extension().length()).lower() == extension());
Index: mythplugins/mythmusic/mythmusic/main.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/main.cpp	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/main.cpp	(working copy)
@@ -6,6 +6,8 @@
 #include <qapplication.h>
 #include <qsqldatabase.h>
 #include <qregexp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include <cdaudio.h>
@@ -65,16 +67,57 @@
     return decoder;
 }
 
-void CheckFile(const QString &filename)
+// Add a file to the database
+void AddFileToDB(const QString &directory, const QString &filename)
 {
     Decoder *decoder = getDecoder(filename);
 
     if (decoder)
     {
         Metadata *data = decoder->getMetadata();
-        if (data)
+        if (data) 
+        {
+            data->dumpToDatabase(directory);
             delete data;
+        }
+        delete decoder;
+    }
+}
 
+// Remove a file from the database
+void RemoveFileFromDB (const QString &directory, const QString &filename)
+{
+    QString name(filename);
+    name.remove(0, directory.length());
+    MSqlQuery query(MSqlQuery::InitCon());
+    query.prepare("DELETE FROM musicmetadata WHERE "
+                  "filename = :NAME ;");
+    query.bindValue(":NAME", name.utf8());
+    query.exec();
+}
+
+// Update a file's metadata in the database, preserving it's id
+void UpdateFileInDB (const QString &directory, const QString &filename)
+{
+    Decoder *decoder = getDecoder (filename);
+
+    if (decoder)
+    {
+        Metadata *db_meta = decoder->getMetadata ();
+        Metadata *disk_meta = decoder->readMetadata ();
+
+        if (db_meta && disk_meta)
+        {
+            disk_meta->setID (db_meta->ID ());
+            disk_meta->updateDatabase (directory);
+        }
+
+        if (disk_meta)
+            delete disk_meta;
+
+        if (db_meta)
+            delete db_meta;
+
         delete decoder;
     }
 }
@@ -83,7 +126,7 @@
 {
     kFileSystem,
     kDatabase,
-    kBoth
+    kNeedUpdate,
 };
 
 typedef QMap <QString, MusicFileLocation> MusicLoadedMap;
@@ -102,19 +145,42 @@
     QFileInfoListIterator it(*list);
     QFileInfo *fi;
 
+    /* Recursively traverse directory, calling
+       QApplication::processEvents every now and then to ensure the UI
+       updates */ 
+    int update_int = 0;
     while ((fi = it.current()) != 0)
     {
         ++it;
         if (fi->fileName() == "." || fi->fileName() == "..")
             continue;
         QString filename = fi->absFilePath();
-        if (fi->isDir())
+        if (fi->isDir()) {
+            qApp->processEvents ();
             BuildFileList(filename, music_files);
-        else
-            music_files[filename] = kFileSystem;
+        } else {
+            // ensure UI updates for dirs with many many files
+            if (++update_int > 100) {
+                qApp->processEvents ();
+                update_int = 0;
+            }
+            music_files[filename] = kFileSystem;            
+        }
     }
 }
 
+/* Check if the file's mdate is after the date_modified */
+bool HasFileChanged (const QString &filename, const QString &date_modified) 
+{
+    struct stat sbuf;
+    if (stat (filename.ascii (), &sbuf) == 0) {
+        if (sbuf.st_mtime > (time_t)QDateTime::fromString (date_modified, Qt::ISODate).toTime_t ()) {
+            return true;
+        }
+    }
+    return false;
+}
+
 void SavePending(int pending)
 {
     //  Temporary Hack until mythmusic
@@ -176,19 +242,28 @@
 {
     MusicLoadedMap music_files;
     MusicLoadedMap::Iterator iter;
+    
+    {
+        /* Let the user know we're doing something, since ie. building
+           the filelist over NFS can take quite a while, so progress
+           bar now...
+        */
+        MythBusyDialog busy (QObject::tr("Searching for music files"));
+        busy.start ();
+        BuildFileList(directory, music_files);
+        busy.Close ();
+    }
 
-    BuildFileList(directory, music_files);
-
     MSqlQuery query(MSqlQuery::InitCon());
-    query.exec("SELECT filename FROM musicmetadata "
+    query.exec("SELECT filename, date_modified FROM musicmetadata "
                     "WHERE filename NOT LIKE ('%://%');");
 
+    MythProgressDialog *progress;
+    progress = new MythProgressDialog(QObject::tr("Scanning music files"),
+                                      query.numRowsAffected());
+
     int counter = 0;
 
-    MythProgressDialog *file_checking;
-    file_checking = new MythProgressDialog(QObject::tr("Searching for music files"),
-                                           query.numRowsAffected());
-
     if (query.isActive() && query.size() > 0)
     {
         while (query.next())
@@ -196,43 +271,56 @@
             QString name = directory + QString::fromUtf8(query.value(0).toString());
             if (name != QString::null)
             {
-                if ((iter = music_files.find(name)) != music_files.end())
-                    music_files.remove(iter);
-                else
+                if ((iter = music_files.find(name)) != music_files.end()) {
+                    if (HasFileChanged (name, query.value (1).toString ())) {
+                        music_files[name] = kNeedUpdate;
+                    } else {
+                        music_files.remove(iter);
+                    }
+                } else {
                     music_files[name] = kDatabase;
+                }
             }
-            file_checking->setProgress(++counter);
+            progress->setProgress(++counter);
         }
     }
 
-    file_checking->Close();
-    delete file_checking;
+    progress->Close();
+    delete progress;
 
-    file_checking = new MythProgressDialog(QObject::tr("Updating music database"), 
+    counter = 0;
+    progress = new MythProgressDialog(QObject::tr("Updating music database"), 
                                            music_files.size());
 
+    // This can be optimised quite a bit by consolidating all commands
+    // via a lot of refactoring. 
+
+    // 1) group all files of the same decoder type, and don't
+    // create/delete a Decoder pr. AddFileToDB. Maybe make Decoders be
+    // singletons ?
+
+    // 2) RemoveFileFromDB should group the remove into one big SQL.
+
+    // 3) UpdateFileInDB, see 1).
+
     QRegExp quote_regex("\"");
     for (iter = music_files.begin(); iter != music_files.end(); iter++)
     {
-        if (*iter == kFileSystem)
-        {
-            CheckFile(iter.key());
+        switch (*iter) {
+        case kFileSystem:
+            AddFileToDB(directory, iter.key());
+            break;
+        case kDatabase:
+            RemoveFileFromDB (directory, iter.key());
+            break;
+        case kNeedUpdate:
+            UpdateFileInDB (directory, iter.key ());
+            break;
         }
-        else if (*iter == kDatabase)
-        {
-            QString name(iter.key());
-            name.remove(0, directory.length());
-
-            query.prepare("DELETE FROM musicmetadata WHERE "
-                          "filename = :NAME ;");
-            query.bindValue(":NAME", name.utf8());
-            query.exec();
-        }
-
-        file_checking->setProgress(++counter);
+        progress->setProgress(++counter);
     }
-    file_checking->Close();
-    delete file_checking;
+    progress->Close();
+    delete progress;
 }
 
 void startPlayback(PlaylistsContainer *all_playlists, AllMusic *all_music)
@@ -283,6 +371,18 @@
     AllMusic *all_music;
 };
 
+void RebuildMusicTree (MusicData *mdata) {
+    MythBusyDialog busy (QObject::tr("Rebuilding music tree"));            
+    busy.start ();
+    mdata->all_music->startLoading ();
+    while (!mdata->all_music->doneLoading ()) {                
+        qApp->processEvents ();
+        usleep (50000);
+    }
+    mdata->all_playlists->postLoad();
+    busy.Close ();
+}
+
 void MusicCallback(void *data, QString &selection)
 {
     MusicData *mdata = (MusicData *)data;
@@ -302,8 +402,7 @@
             //  Reconcile with the database
             SearchDir(mdata->startdir);
             //  Tell the metadata to reset itself
-            mdata->all_music->resync();
-            mdata->all_playlists->postLoad();
+            RebuildMusicTree (mdata);
         }
     }
     else if (sel == "settings_scan")
@@ -311,8 +410,7 @@
         if ("" != mdata->startdir)
         {
             SearchDir(mdata->startdir);
-            mdata->all_music->resync();
-            mdata->all_playlists->postLoad();
+            RebuildMusicTree (mdata);
         }
     }
     else if (sel == "music_set_general")
@@ -554,8 +652,7 @@
         // if startRipper returns true, then new files should be present
         // so we should look for them.
         SearchDir(mdata.startdir);
-        mdata.all_music->resync();
-        mdata.all_playlists->postLoad();
+        RebuildMusicTree (&mdata);
     }
     postMusic(&mdata);
 }
Index: mythplugins/mythmusic/mythmusic/flacdecoder.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/flacdecoder.cpp	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/flacdecoder.cpp	(working copy)
@@ -385,40 +385,12 @@
         char *field_value;
 } Argument_VcField;
 
-Metadata *FlacDecoder::getMetadata()
+MetaIO *FlacDecoder::doCreateTagger()
 {
-    Metadata *mdata = new Metadata(filename);
-    if (mdata->isInDatabase(musiclocation))
-    {
-        return mdata;
-    }
+    return new MetaIOFLACVorbisComment;
+}
 
-    delete mdata;
 
-    MetaIOFLACVorbisComment* p_tagger = new MetaIOFLACVorbisComment;
-    if (ignore_id3)
-        mdata = p_tagger->readFromFilename(filename);
-    else
-        mdata = p_tagger->read(filename);
-
-    delete p_tagger;
-
-    if (mdata)
-        mdata->dumpToDatabase(musiclocation);
-    else
-        cerr << "flacdecoder.o: Could not read metadata from " << filename.local8Bit() << endl;
-
-    return mdata;
-}    
-
-void FlacDecoder::commitMetadata(Metadata *mdata)
-{
-    MetaIOFLACVorbisComment* p_tagger = new MetaIOFLACVorbisComment;
-    p_tagger->write(mdata);
-    delete p_tagger;
-    }
-
-
 bool FlacDecoderFactory::supports(const QString &source) const
 {
     return (source.right(extension().length()).lower() == extension());
Index: mythplugins/mythmusic/mythmusic/maddecoder.h
===================================================================
--- mythplugins/mythmusic/mythmusic/maddecoder.h	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/maddecoder.h	(working copy)
@@ -24,8 +24,7 @@
     static const int maxFrameCheck;
     static const int initialFrameSize;
 
-    Metadata *getMetadata();
-    void commitMetadata(Metadata *mdata);
+    MetaIO *doCreateTagger();
 
 private:
     void run();
Index: mythplugins/mythmusic/mythmusic/vorbisdecoder.h
===================================================================
--- mythplugins/mythmusic/mythmusic/vorbisdecoder.h	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/vorbisdecoder.h	(working copy)
@@ -18,8 +18,7 @@
     void seek(double);
     void stop();
 
-    Metadata *getMetadata();
-    void commitMetadata(Metadata *mdata);
+    MetaIO *doCreateTagger();
 
   private:
     void run();
Index: mythplugins/mythmusic/mythmusic/avfdecoder.h
===================================================================
--- mythplugins/mythmusic/mythmusic/avfdecoder.h	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/avfdecoder.h	(working copy)
@@ -18,8 +18,7 @@
     void seek(double);
     void stop();
 
-    Metadata *getMetadata();
-    void commitMetadata(Metadata *mdata);
+    MetaIO *doCreateTagger();
 
   private:
     void run();
Index: mythplugins/mythmusic/mythmusic/maddecoder.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/maddecoder.cpp	(revision 7537)
+++ mythplugins/mythmusic/mythmusic/maddecoder.cpp	(working copy)
@@ -512,40 +512,11 @@
     return MAD_FLOW_STOP;
 }
 
-Metadata *MadDecoder::getMetadata()
+MetaIO *MadDecoder::doCreateTagger()
 {
-    Metadata *mdata = new Metadata(filename);
-    if (mdata->isInDatabase(musiclocation))
-    {
-        return mdata;
-    }
-
-    delete mdata;
-
-
-    MetaIOID3v2* p_tagger = new MetaIOID3v2;
-    if (ignore_id3)
-        mdata = p_tagger->readFromFilename(filename);
-    else
-        mdata = p_tagger->read(filename);
-
-    delete p_tagger;
-
-    if (mdata)
-        mdata->dumpToDatabase(musiclocation);
-    else
-        cerr << "maddecoder.o: Could not read metadata from " << filename.local8Bit() << endl;
-
-    return mdata;
+    return new MetaIOID3v2;
 }
 
-void MadDecoder::commitMetadata(Metadata *mdata)
-{
-    MetaIOID3v2* p_tagger = new MetaIOID3v2;
-    p_tagger->write(mdata);
-    delete p_tagger;
-}
-
 bool MadDecoderFactory::supports(const QString &source) const
 {
     bool res = false;
