Index: mythmusic/cdrip.h
===================================================================
--- mythmusic/cdrip.h	(revision 12715)
+++ mythmusic/cdrip.h	(working copy)
@@ -63,7 +63,7 @@
 
     private:
         virtual void run(void);
-        int ripTrack(QString &cddevice, Encoder *encoder, int tracknum);
+        int ripTrack(QString &cddevice, Encoder *encoder, int tracknum, int tracklast);
         void sendEvent(int eventType, const QString &value);
         void sendEvent(int eventType, int value);
 
@@ -111,10 +111,13 @@
     void searchArtist(void);
     void searchAlbum(void);
     void searchGenre(void);
+    void titleChanged(QString newtitle);
+    void searchTitle(void);
 
   private:
     void wireupTheme(void);
     void keyPressEvent(QKeyEvent *e);
+    bool isNewTune(QString &artist, QString &album, QString &title);
     void deleteTrack(QString& artist, QString& album, QString& title);
     void updateTrackList(void);
     void trackListDown(bool page);
@@ -138,12 +141,14 @@
     UIPushButtonType  *m_searchArtistButton;
     UIPushButtonType  *m_searchAlbumButton;
     UIPushButtonType  *m_searchGenreButton;
+    UIRemoteEditType  *m_titleEdit;
+    UIPushButtonType  *m_searchTitleButton;
 
     int                m_currentTrack;
     int                m_totalTracks;
     vector<Metadata*> *m_tracks;
 
-    QString            m_albumName, m_artistName, m_genreName, m_year;
+    QString            m_albumName, m_artistName, m_genreName, m_year, m_titleName;
     QStringList        m_searchList;
     bool               m_somethingwasripped;
     bool               m_mediaMonitorActive;
Index: mythmusic/music-ui.xml
===================================================================
--- mythmusic/music-ui.xml	(revision 12715)
+++ mythmusic/music-ui.xml	(working copy)
@@ -495,6 +495,12 @@
                 <font>labels</font>
                 <value>Track No.:</value>
             </textarea>
+            
+            <textarea name="tracklast_label" draworder="1" align="right">
+                <area>365,350,170,30</area>
+                <font>labels</font>
+                <value>Last Track No.:</value>
+            </textarea>
 
             <textarea name="rating_label" draworder="1" align="right">
                 <area>15,350,170,30</area>
@@ -596,6 +602,11 @@
                 <area>545,310,175,35</area>
                 <font>display</font>
             </remoteedit>
+            
+            <remoteedit name="tracklast_edit" draworder="1" align="left">
+                <area>545,350,175,35</area>
+                <font>display</font>
+            </remoteedit>
 
             <repeatedimage name="rating_image" draworder="1" fleximage="no">
                 <filename>mm_rating.png</filename>
@@ -835,8 +846,14 @@
            </textarea>
 
            <textarea name="title" draworder="4" align="left">
-               <area>100,250,130,30</area>
+               <area>90,250,130,30</area>
                <font>listlabel</font>
+               <value>Last</value>
+           </textarea>
+
+           <textarea name="title" draworder="4" align="left">
+               <area>140,250,130,30</area>
+               <font>listlabel</font>
                <value>Title</value>
            </textarea>
 
@@ -864,9 +881,10 @@
                <fcnfont name="selected" function="selected"></fcnfont>
                <columnpadding>10</columnpadding>
                <column number="1" width="50" context="-1"></column>
-               <column number="2" width="340" context="-1"></column>
-               <column number="3" width="200" context="-1"></column>
-               <column number="4" width="100" context="-1"></column>
+               <column number="2" width="40" context="-1"></column>
+               <column number="3" width="300" context="-1"></column>
+               <column number="4" width="200" context="-1"></column>
+               <column number="5" width="100" context="-1"></column>
                <items>7</items>
                <image function="selectionbar" filename="mm_selectbar.png" location="-2,0"></image>
                <image function="uparrow" filename="uparrow.png" location="735,290"></image>
Index: mythmusic/decoder.h
===================================================================
--- mythmusic/decoder.h	(revision 12715)
+++ mythmusic/decoder.h	(working copy)
@@ -81,6 +81,7 @@
     virtual Metadata *getMetadata(void);
     virtual MetaIO *doCreateTagger (void);
     virtual void commitMetadata(Metadata *mdata);
+    virtual void recalcLength(Metadata *mdata);
 
     // static methods
     static QStringList all();
Index: mythmusic/metadata.cpp
===================================================================
--- mythmusic/metadata.cpp	(revision 12715)
+++ mythmusic/metadata.cpp	(working copy)
@@ -513,6 +513,18 @@
 }
 
 
+QString Metadata::ReorderArtist()
+{ 
+    if (reorderartist.isEmpty()) {
+         QStringList artistreorder = QStringList::split(QRegExp("[>,]"), formattedartist);
+         formattedartist = artistreorder[1].stripWhiteSpace() + " " 
+         + artistreorder[0].stripWhiteSpace();
+         reorderartist = "Y";
+    }
+    return formattedartist;
+}
+
+
 QString Metadata::FormatTitle()
 {
     if (formattedtitle.isEmpty())
@@ -613,6 +625,12 @@
     changed = true;
 }
 
+void Metadata::setTrackLast(int ltracklast)
+{
+	tracklast = ltracklast;
+	changed = true;
+}
+
 QStringList Metadata::fillFieldList(QString field)
 {
     QStringList searchList;
@@ -952,6 +970,8 @@
       
         a_label += music_map[an_id]->FormatArtist();
         a_label += " ~ ";
+        //a_label += music_map[an_id]->Album();
+        //a_label += " ~ ";
         a_label += music_map[an_id]->FormatTitle();
     
 
Index: mythmusic/cddecoder.h
===================================================================
--- mythmusic/cddecoder.h	(revision 12715)
+++ mythmusic/cddecoder.h	(working copy)
@@ -29,6 +29,7 @@
     Metadata *getMetadata(void);
     Metadata *getLastMetadata(void);
     void commitMetadata(Metadata *mdata);
+	void recalcLength(Metadata *mdata);
 
   private:
     void run();
Index: mythmusic/cdrip.cpp
===================================================================
--- mythmusic/cdrip.cpp	(revision 12715)
+++ mythmusic/cdrip.cpp	(working copy)
@@ -81,6 +81,7 @@
     }
 
     // we only care about audio tracks
+	//just counting sectors, don't need tracklast
     if (cdda_track_audiop (device, tracknum))
     {
         cdda_verbose_set(device, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
@@ -240,8 +241,13 @@
                 break;
             }
 
-            ripTrack(cddevice, encoder, trackno + 1);
-
+			//trackno is the counter, 0-start
+			int trackfirst = trackno + 1;
+			int tracklast = track->TrackLast();
+            ripTrack(cddevice, encoder, trackfirst, tracklast);
+			//counter to end of current track selection, inc at the top
+			trackno = tracklast - 1; 
+			
             if (isCancelled())
                 return;
 
@@ -274,7 +280,7 @@
     sendEvent(ST_FINISHED, "");
 }
 
-int CDRipperThread::ripTrack(QString &cddevice, Encoder *encoder, int tracknum)
+int CDRipperThread::ripTrack(QString &cddevice, Encoder *encoder, int tracknum, int tracklast)
 {
     cdrom_drive *device = cdda_identify(cddevice.ascii(), 0, NULL);
 
@@ -289,7 +295,7 @@
 
     cdda_verbose_set(device, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
     long int start = cdda_track_firstsector(device, tracknum);
-    long int end = cdda_track_lastsector(device, tracknum);
+    long int end = cdda_track_lastsector(device, tracklast);
 
     cdrom_paranoia *paranoia = paranoia_init(device);
     if (gContext->GetSetting("ParanoiaLevel") == "full")
@@ -443,6 +449,20 @@
         connect(m_searchAlbumButton, SIGNAL(pushed()), this, SLOT(searchAlbum()));
     }
 
+    m_titleEdit = getUIRemoteEditType("title_edit");
+    if (m_titleEdit)
+    {
+        m_titleEdit->createEdit(this);
+        connect(m_titleEdit, SIGNAL(textChanged(QString)), this, SLOT(titleChanged(QString)));
+    }
+    
+    m_searchTitleButton = getUIPushButtonType("searchtitle_button");
+    if (m_searchTitleButton)
+    {
+        connect(m_searchTitleButton, SIGNAL(pushed()), this, SLOT(searchTitle()));
+    }
+
+
     m_genreEdit = getUIRemoteEditType("genre_edit");
     if (m_genreEdit)
     {
@@ -629,6 +649,8 @@
             track = m_decoder->getMetadata(trackno + 1);
             if (track)
             {
+            //default, tracklast = track, produces same behavior as before
+            track->setTrackLast(trackno + 1); 
                 if (track->Compilation())
                 {
                     isCompilation = true;
@@ -979,6 +1001,21 @@
     m_albumName = newalbum;
 }
 
+void Ripper::titleChanged(QString newtitle)
+{
+    Metadata *data;
+
+    for (int trackno = 0; trackno < m_totalTracks; ++trackno)
+    {
+        data = m_tracks->at(trackno);
+
+        if (data)
+            data->setTitle(newtitle);
+    }
+
+    m_titleName = newtitle;
+}
+
 void Ripper::genreChanged(QString newgenre)
 {
     Metadata *data;
@@ -1164,6 +1201,26 @@
         m_trackList->SetUpArrow(skip > 0);
         m_trackList->SetDownArrow(skip + trackListSize < m_totalTracks);
 
+        //calculate which tracks are active 
+        //and which are skipped by a previous tracklast
+        //skipped show tracklast as 0 and length as -
+        int j;
+        int is_active[m_totalTracks];
+        for (j = 0; j < m_totalTracks; j++)
+        {
+            is_active[j]=1;
+            Metadata *tmptrack = m_tracks->at(j);
+            int next = tmptrack->TrackLast();
+            if (next > m_totalTracks)
+            {
+                next = m_totalTracks;
+            }
+            for (int k=j+1; k < next; k++)
+            {
+                is_active[k]=0;
+            }       
+            j = next - 1;
+        }      
         int i;
         for (i = 0; i < trackListSize; i++)
         {
@@ -1171,17 +1228,24 @@
                 break;
 
             Metadata *track = m_tracks->at(i + skip);
-
-            m_trackList->SetItemText(i, 1, QString::number(track->Track()));
-            m_trackList->SetItemText(i, 2, track->Title());
-            m_trackList->SetItemText(i, 3, track->Artist());
-            int length = track->Length() / 1000;
+            
+            int tracklast = track->TrackLast();
+            int length = track->Length() / 1000; 
             int min, sec;
             min = length / 60;
             sec = length % 60;
             QString s;
-            s.sprintf("%02d:%02d", min, sec);
-            m_trackList->SetItemText(i, 4, s);
+            s.sprintf("%02d:%02d", min, sec); 
+            if (is_active[i + skip] == 0) 
+            { 
+                tracklast = 0;
+                s.sprintf("-");
+            }       
+            m_trackList->SetItemText(i, 1, QString::number(track->Track()));
+            m_trackList->SetItemText(i, 2, QString::number(tracklast));
+            m_trackList->SetItemText(i, 3, track->Title());
+            m_trackList->SetItemText(i, 4, track->Artist());
+            m_trackList->SetItemText(i, 5, s);
 
             if (i + skip == m_currentTrack)
             {
@@ -1250,15 +1314,31 @@
     }
 }
 
+void Ripper::searchTitle()
+{
+    QString s;
+
+    m_searchList = Metadata::fillFieldList("title");
+
+    s = m_titleEdit->getText();
+    if (showList(tr("Select Title"), s))
+    {
+        m_titleEdit->setText(s);
+        titleChanged(s);
+    }
+}
+
+
 void Ripper::searchGenre()
 {
     QString s;
 
     // load genre list
     m_searchList.clear();
-    for (int x = 0; x < genre_table_size; x++)
-        m_searchList.push_back(QString(genre_table[x]));
-    m_searchList.sort();
+    //for (int x = 0; x < genre_table_size; x++)
+    //    m_searchList.push_back(QString(genre_table[x]));
+    //m_searchList.sort();
+    m_searchList = Metadata::fillFieldList("genre");
 
     s = m_genreEdit->getText();
     if (showList(tr("Select a Genre"), s))
Index: mythmusic/playlist.cpp
===================================================================
--- mythmusic/playlist.cpp	(revision 12715)
+++ mythmusic/playlist.cpp	(working copy)
@@ -974,6 +974,7 @@
                 if (tmpdata)
                 {
                     QString a_string = QString("%1 ~ %2").arg(tmpdata->FormatArtist()).arg(tmpdata->FormatTitle());
+                    //QString a_string = QString(QObject::tr("%1 ~ %2 ~ %3")).arg(tmpdata->FormatArtist()).arg(tmpdata->Album()).arg(tmpdata->FormatTitle());
                     GenericTree *added_node = tree_to_write_to->addNode(a_string, it->getValue(), true);
                     ++a_counter;
                     added_node->setAttribute(0, 1);
@@ -1040,7 +1041,8 @@
             {
                 QString a_string = QString("CD: %1 ~ %2 - %3")
                   .arg(tmpdata->Track()).arg(tmpdata->FormatTitle()).arg(tmpdata->FormatArtist());
-
+				//QString a_string = QString(QObject::tr("CD: %1 ~ %2 ~ %3 - %4"))
+                //.arg(tmpdata->FormatArtist()).arg(tmpdata->Album()).arg(tmpdata->Track()).arg(tmpdata->FormatTitle());
                 if(tmpdata->FormatArtist().length() < 1 ||
                    tmpdata->FormatTitle().length() < 1)
                 {
Index: mythmusic/decoder.cpp
===================================================================
--- mythmusic/decoder.cpp	(revision 12715)
+++ mythmusic/decoder.cpp	(working copy)
@@ -161,6 +161,11 @@
     }
 }
 
+//only cddecoder knows
+void Decoder::recalcLength(Metadata *mdata)
+{
+}
+
 // static methods
 
 int Decoder::ignore_id3 = 0;
Index: mythmusic/metadata.h
===================================================================
--- mythmusic/metadata.h	(revision 12715)
+++ mythmusic/metadata.h	(working copy)
@@ -28,7 +28,7 @@
                 title = ltitle;
                 formattedartist = "";
                 formattedtitle = "";
-                 genre = lgenre;
+                genre = lgenre;
                 year = lyear;
                 tracknum = ltracknum;
                 length = llength;
@@ -40,6 +40,7 @@
                 changed = false;
                 show = true;
                 format = lformat;
+                reorderartist = "";
             }
 
     Metadata(const Metadata &other)
@@ -85,6 +86,7 @@
 
     QString FormatArtist();
     QString FormatTitle();
+    QString ReorderArtist();
 
     QString Genre() { return genre; }
     void setGenre(const QString &lgenre) { genre = lgenre; }
@@ -125,6 +127,9 @@
     bool isVisible() { return show; }
     void setVisible(bool visible) { show = visible; }
 
+    int TrackLast() { return tracklast; }
+    void setTrackLast(int tracklast);
+
     // track is part of a compilation album
     bool Compilation() { return compilation; }
     void setCompilation(bool state) { compilation = state; formattedartist = formattedtitle = ""; }
@@ -162,6 +167,8 @@
     QString lastplay;
     int playcount;
     bool compilation;
+    QString reorderartist;
+    int tracklast;
      
     unsigned int id;
     QString filename;
Index: mythmusic/editmetadata.cpp
===================================================================
--- mythmusic/editmetadata.cpp	(revision 12715)
+++ mythmusic/editmetadata.cpp	(working copy)
@@ -102,6 +102,14 @@
     {
         compilation_check->setState(m_metadata->Compilation());
     }
+
+	if (tracklast_edit)
+    {
+        QString s;
+        s = s.setNum(m_metadata->TrackLast());
+        tracklast_edit->setText(s);
+    }
+
 }
 
 void EditMetadataDialog::incRating(bool up_or_down)
@@ -227,6 +235,13 @@
         track_edit->createEdit(this);
         connect(track_edit, SIGNAL(loosingFocus()), this, SLOT(editLostFocus()));
     }
+    
+    tracklast_edit = getUIRemoteEditType("tracklast_edit");
+    if (tracklast_edit)
+    {
+        tracklast_edit->createEdit(this);
+        connect(tracklast_edit, SIGNAL(loosingFocus()), this, SLOT(editLostFocus()));
+    }
             
     lastplay_text = getUITextType("lastplay_text");
     playcount_text = getUITextType("playcount_text");
@@ -256,6 +271,12 @@
     {
         connect(searchalbum_button, SIGNAL(pushed()), this, SLOT(searchAlbum()));
     }
+	
+	searchtitle_button = getUIPushButtonType("searchtitle_button");
+    if (searchtitle_button)
+    {
+        connect(searchtitle_button, SIGNAL(pushed()), this, SLOT(searchAlbum()));
+    }
 
     searchgenre_button = getUIPushButtonType("searchgenre_button");
     if (searchgenre_button)
@@ -316,6 +337,10 @@
     else if (whichEditor == track_edit)
     {
         m_metadata->setTrack(track_edit->getText().toInt());
+    }   
+    else if (whichEditor == tracklast_edit)
+    {
+        m_metadata->setTrackLast(tracklast_edit->getText().toInt());
     }
 
 }
@@ -489,6 +514,20 @@
     cancelPopup();
 
     *m_sourceMetadata = m_metadata;
+     //update length in case a tracklast has been added
+    Decoder *decoder = Decoder::create(m_metadata->Filename(), NULL, NULL, true);
+    if (decoder)
+    {
+        decoder->recalcLength(m_metadata);
+        delete decoder;
+    }
+    *m_sourceMetadata = m_metadata;
+    if (m_metadata->TrackLast() < m_metadata->Track()) 
+    {
+        m_metadata->setTrackLast(m_metadata->Track());
+    } 
+    //set tracklast in the new metadata copy
+    m_sourceMetadata->setTrackLast(m_metadata->TrackLast());
     done(1);
 }
 
Index: mythmusic/editmetadata.h
===================================================================
--- mythmusic/editmetadata.h	(revision 12715)
+++ mythmusic/editmetadata.h	(working copy)
@@ -64,7 +64,8 @@
     UIRemoteEditType    *genre_edit;
     UIRemoteEditType    *year_edit;
     UIRemoteEditType    *track_edit;
-    
+    UIRemoteEditType	*tracklast_edit;
+        
     UITextType          *lastplay_text;
     UITextType          *playcount_text;
     UITextType          *filename_text;
@@ -74,8 +75,9 @@
     UIPushButtonType    *searchartist_button;
     UIPushButtonType    *searchcompilation_artist_button;
     UIPushButtonType    *searchalbum_button;
-    UIPushButtonType    *searchgenre_button;
+    UIPushButtonType    *searchgenre_button;  
     UIPushButtonType    *rating_button;
+    UIPushButtonType    *searchtitle_button;
     
     UICheckBoxType      *compilation_check;
     
Index: mythmusic/playbackbox.h
===================================================================
--- mythmusic/playbackbox.h	(revision 12715)
+++ mythmusic/playbackbox.h	(working copy)
@@ -87,6 +87,7 @@
     void byAlbum();
     void byGenre();
     void byYear();    
+    void byTitle();
     void fromCD();
     void showSmartPlaylistDialog();
     void showSearchDialog();
Index: mythmusic/cddecoder.cpp
===================================================================
--- mythmusic/cddecoder.cpp	(revision 12715)
+++ mythmusic/cddecoder.cpp	(working copy)
@@ -437,6 +437,62 @@
     return retdata;
 }    
 
+void CdDecoder::recalcLength(Metadata *mdata)
+{
+    int cd = cd_init_device((char *)devicename.ascii());
+
+    struct disc_info discinfo;
+    if (cd_stat(cd, &discinfo) != 0)
+    {
+        error("Couldn't stat CD, Error.");
+        cd_finish(cd);
+    }
+
+    if (!discinfo.disc_present)
+    {
+        error("No disc present");
+        cd_finish(cd);
+    }
+
+    int tracknum = mdata->Track();
+    int tracklast = mdata->TrackLast();
+
+    if (tracknum > discinfo.disc_total_tracks)
+    {
+        error("No such track on CD");
+        cd_finish(cd);
+        return;
+    }
+
+    if (tracklast > discinfo.disc_total_tracks)
+    {
+        error("No such track on CD");
+        cd_finish(cd);
+        return;
+    }
+    
+    if (tracklast < tracknum)
+    {
+    	error("Negative-length track");
+    	cd_finish(cd);
+    	return;
+    }
+    
+    int length = 0;
+    for (int i = tracknum - 1; i < tracklast; i++)
+    { 
+        int ltemp = discinfo.disc_track[i].track_length.minutes * 60 +
+            discinfo.disc_track[i].track_length.seconds;
+        ltemp = ltemp < 0 ? 0 : ltemp;
+        length += ltemp;
+    }
+    length *= 1000;
+    VERBOSE(VB_IMPORTANT, QString("Recalculating length to %1").arg(length));
+    mdata->setLength(length);
+    cd_finish(cd);
+    return;
+}    
+
 void CdDecoder::commitMetadata(Metadata *mdata)
 {
     int cd = cd_init_device((char *)devicename.ascii());
