00001 #include <unistd.h>
00002 #include <inttypes.h>
00003 #include <cstdlib>
00004 #include <iostream>
00005 #include <map>
00006 using namespace std;
00007 #include "playlist.h"
00008 #include "qdatetime.h"
00009 #include <mythtv/mythcontext.h>
00010 #include "smartplaylist.h"
00011 #include <mythtv/mythdbcon.h>
00012 #include <mythtv/compat.h>
00013 #include <mythtv/mythmediamonitor.h>
00014
00015 #include <qfileinfo.h>
00016 #include <qprocess.h>
00017 #include <qapplication.h>
00018
00019 Track::Track(int x, AllMusic *all_music_ptr)
00020 {
00021 index_value = x;
00022 all_available_music = all_music_ptr;
00023 my_widget = NULL;
00024 parent = NULL;
00025 bad_reference = false;
00026 label = QObject::tr("Not Initialized");
00027 cd_flag = false;
00028 }
00029
00030 void Track::postLoad(PlaylistsContainer *grandparent)
00031 {
00032 if (cd_flag)
00033 {
00034 label = all_available_music->getLabel(index_value, &bad_reference);
00035 return;
00036 }
00037
00038 if (index_value > 0)
00039 label = all_available_music->getLabel(index_value, &bad_reference);
00040 else if (index_value < 0)
00041 label = grandparent->getPlaylistName( (-1 * index_value), bad_reference);
00042 else
00043 {
00044 VERBOSE(VB_IMPORTANT, "playlist.o: Not sure how I got 0 as a track "
00045 "number, but it ain't good");
00046 }
00047 }
00048
00049 void Track::setParent(Playlist *parent_ptr)
00050 {
00051
00052 parent = parent_ptr;
00053 }
00054
00055 void Playlist::postLoad()
00056 {
00057 Track *it;
00058 for (it = songs.first(); it; it = songs.current())
00059 {
00060 it->postLoad(parent);
00061 if (it->badReference())
00062 {
00063 songs.remove(it);
00064 Changed();
00065 }
00066 else
00067 it = songs.next();
00068 }
00069 }
00070
00071 bool Playlist::checkTrack(int a_track_id, bool cd_flag)
00072 {
00073
00074
00075 Track *it;
00076
00077 for (it = songs.first(); it; it = songs.next())
00078 {
00079 if (it->getValue() == a_track_id && it->getCDFlag() == cd_flag)
00080 {
00081 return true;
00082 }
00083 }
00084
00085 return false;
00086 }
00087
00088 void Playlist::copyTracks(Playlist *to_ptr, bool update_display)
00089 {
00090 Track *it;
00091 for (it = songs.first(); it; it = songs.next())
00092 {
00093 if (!it->getCDFlag())
00094 to_ptr->addTrack((*it).getValue(), update_display, false);
00095 }
00096
00097 to_ptr->fillSonglistFromSongs();
00098 }
00099
00100
00101
00102 void Playlist::addTrack(int the_track, bool update_display, bool cd)
00103 {
00104
00105
00106 Track *a_track = new Track(the_track, all_available_music);
00107 a_track->setCDFlag(cd);
00108 a_track->postLoad(parent);
00109 a_track->setParent(this);
00110 songs.append(a_track);
00111 changed = true;
00112
00113
00114
00115 if (!update_display)
00116 return;
00117
00118 PlaylistTitle *which_widget = parent->getActiveWidget();
00119
00120 if (which_widget)
00121 a_track->putYourselfOnTheListView(which_widget);
00122 }
00123
00124 void Track::deleteYourself()
00125 {
00126 parent->removeTrack(index_value, cd_flag);
00127 }
00128
00129 void Track::deleteYourWidget()
00130 {
00131 if (my_widget)
00132 {
00133 my_widget->RemoveFromParent();
00134
00135 my_widget = NULL;
00136 }
00137 }
00138
00139 void Playlist::removeAllTracks()
00140 {
00141 Track *it;
00142 for (it = songs.first(); it; it = songs.current())
00143 {
00144 it->deleteYourWidget();
00145 songs.remove(it);
00146 }
00147
00148 changed = true;
00149 }
00150
00151 void Playlist::removeAllWidgets()
00152 {
00153 Track *it;
00154 for (it = songs.first(); it; it = songs.next())
00155 {
00156 it->deleteYourWidget();
00157 }
00158 }
00159
00160 void Playlist::ripOutAllCDTracksNow()
00161 {
00162 Track *it;
00163 for (it = songs.first(); it; it = songs.current())
00164 {
00165 if (it->getCDFlag())
00166 {
00167 it->deleteYourWidget();
00168 songs.remove(it);
00169 }
00170 else
00171 it = songs.next();
00172 }
00173 changed = true;
00174 }
00175
00176 void Playlist::removeTrack(int the_track, bool cd_flag)
00177 {
00178
00179 Track *it;
00180 for (it = songs.first(); it; it = songs.current())
00181 {
00182 if (it->getValue() == the_track && cd_flag == it->getCDFlag())
00183 {
00184 it->deleteYourWidget();
00185 songs.remove(it);
00186
00187 }
00188 else
00189 it = songs.next();
00190 }
00191 changed = true;
00192 }
00193
00194 void Playlist::moveTrackUpDown(bool flag, Track *the_track)
00195 {
00196
00197
00198
00199 songs.setAutoDelete(false);
00200
00201 uint insertion_point = 0;
00202 int where_its_at = songs.findRef(the_track);
00203 if (where_its_at < 0)
00204 VERBOSE(VB_IMPORTANT, "playlist.o: A playlist was asked to move a "
00205 "track, but can'd find it");
00206 else
00207 {
00208 if (flag)
00209 insertion_point = ((uint)where_its_at) - 1;
00210 else
00211 insertion_point = ((uint)where_its_at) + 1;
00212
00213 songs.remove(the_track);
00214 songs.insert(insertion_point, the_track);
00215 }
00216
00217 songs.setAutoDelete(true);
00218 changed = true;
00219 }
00220
00221 void Track::moveUpDown(bool flag)
00222 {
00223 parent->moveTrackUpDown(flag, this);
00224 }
00225
00226 PlaylistLoadingThread::PlaylistLoadingThread(PlaylistsContainer *parent_ptr,
00227 AllMusic *all_music_ptr)
00228 {
00229 parent = parent_ptr;
00230 all_music = all_music_ptr;
00231 }
00232
00233 void PlaylistLoadingThread::run()
00234 {
00235 while(!all_music->doneLoading())
00236 {
00237 sleep(1);
00238 }
00239 parent->load();
00240 }
00241
00242 void PlaylistsContainer::clearCDList()
00243 {
00244 cd_playlist.clear();
00245 }
00246
00247 void PlaylistsContainer::addCDTrack(int track)
00248 {
00249 cd_playlist.append(track);
00250 }
00251
00252 void PlaylistsContainer::removeCDTrack(int track)
00253 {
00254 cd_playlist.remove(track);
00255 }
00256
00257 bool PlaylistsContainer::checkCDTrack(int track)
00258 {
00259 for (int i = 0; i < (int)cd_playlist.count(); i++)
00260 {
00261 if (cd_playlist[i] == track)
00262 return true;
00263 }
00264 return false;
00265 }
00266
00267 PlaylistsContainer::PlaylistsContainer(AllMusic *all_music, QString host_name)
00268 {
00269 active_widget = NULL;
00270 my_host = host_name;
00271
00272 active_playlist = NULL;
00273 backup_playlist = NULL;
00274 all_other_playlists = NULL;
00275
00276 all_available_music = all_music;
00277
00278 done_loading = false;
00279
00280 RatingWeight = gContext->GetNumSetting("IntelliRatingWeight", 2);
00281 PlayCountWeight = gContext->GetNumSetting("IntelliPlayCountWeight", 2);
00282 LastPlayWeight = gContext->GetNumSetting("IntelliLastPlayWeight", 2);
00283 RandomWeight = gContext->GetNumSetting("IntelliRandomWeight", 2);
00284
00285 playlists_loader = new PlaylistLoadingThread(this, all_music);
00286 playlists_loader->start();
00287 }
00288
00289 PlaylistsContainer::~PlaylistsContainer()
00290 {
00291 if (active_playlist)
00292 delete active_playlist;
00293 if (backup_playlist)
00294 delete backup_playlist;
00295 if (all_other_playlists)
00296 delete all_other_playlists;
00297
00298 playlists_loader->wait();
00299 delete playlists_loader;
00300 }
00301
00302 void PlaylistsContainer::FillIntelliWeights(int &rating, int &playcount,
00303 int &lastplay, int &random)
00304 {
00305 rating = RatingWeight;
00306 playcount = PlayCountWeight;
00307 lastplay = LastPlayWeight;
00308 random = RandomWeight;
00309 }
00310
00311 void PlaylistsContainer::load()
00312 {
00313 done_loading = false;
00314 active_playlist = new Playlist(all_available_music);
00315 active_playlist->setParent(this);
00316
00317 backup_playlist = new Playlist(all_available_music);
00318 backup_playlist->setParent(this);
00319
00320 all_other_playlists = new QPtrList<Playlist>;
00321 all_other_playlists->setAutoDelete(true);
00322
00323 cd_playlist.clear();
00324
00325 active_playlist->loadPlaylist("default_playlist_storage", my_host);
00326 active_playlist->fillSongsFromSonglist(false);
00327
00328 backup_playlist->loadPlaylist("backup_playlist_storage", my_host);
00329 backup_playlist->fillSongsFromSonglist(false);
00330
00331 all_other_playlists->clear();
00332
00333 MSqlQuery query(MSqlQuery::InitCon());
00334 query.prepare("SELECT playlist_id FROM music_playlists "
00335 "WHERE playlist_name != :DEFAULT"
00336 " AND playlist_name != :BACKUP "
00337 " AND (hostname = '' OR hostname = :HOST) "
00338 "ORDER BY playlist_id;");
00339 query.bindValue(":DEFAULT", "default_playlist_storage");
00340 query.bindValue(":BACKUP", "backup_playlist_storage");
00341 query.bindValue(":HOST", my_host);
00342
00343 if (query.exec() && query.isActive() && query.size() > 0)
00344 {
00345 while (query.next())
00346 {
00347 Playlist *temp_playlist = new Playlist(all_available_music);
00348 temp_playlist->setParent(this);
00349 temp_playlist->loadPlaylistByID(query.value(0).toInt(), my_host);
00350 temp_playlist->fillSongsFromSonglist(false);
00351 all_other_playlists->append(temp_playlist);
00352 }
00353 }
00354 postLoad();
00355
00356 pending_writeback_index = 0;
00357
00358 int x = gContext->GetNumSetting("LastMusicPlaylistPush");
00359 setPending(x);
00360 done_loading = true;
00361 }
00362
00363 void PlaylistsContainer::describeYourself()
00364 {
00365
00366
00367 active_playlist->describeYourself();
00368 Playlist *a_list;
00369 for (a_list = all_other_playlists->first(); a_list;
00370 a_list = all_other_playlists->next())
00371 {
00372 a_list->describeYourself();
00373 }
00374 }
00375
00376 Playlist::Playlist(AllMusic *all_music_ptr)
00377 {
00378
00379 playlistid = 0;
00380 name = QObject::tr("oops");
00381 raw_songlist = "";
00382 songs.setAutoDelete(true);
00383 all_available_music = all_music_ptr;
00384 changed = false;
00385 }
00386
00387 void Track::putYourselfOnTheListView(UIListGenericTree *a_listviewitem)
00388 {
00389 if (cd_flag)
00390 {
00391 my_widget = new PlaylistCD(a_listviewitem, label);
00392 my_widget->setOwner(this);
00393 }
00394 else
00395 {
00396 if (index_value > 0)
00397 {
00398 my_widget = new PlaylistTrack(a_listviewitem, label);
00399 my_widget->setOwner(this);
00400 }
00401 else if (index_value < 0)
00402 {
00403 my_widget = new PlaylistPlaylist(a_listviewitem, label);
00404 my_widget->setOwner(this);
00405 }
00406 }
00407 }
00408
00409 void Playlist::putYourselfOnTheListView(UIListGenericTree *a_listviewitem)
00410 {
00411 Track *it;
00412 for (it = songs.first(); it; it = songs.next())
00413 it->putYourselfOnTheListView(a_listviewitem);
00414 }
00415
00416 int Playlist::getFirstTrackID()
00417 {
00418 Track *it = songs.first();
00419 if (it)
00420 {
00421 return it->getValue();
00422 }
00423 return 0;
00424 }
00425
00426 Playlist::~Playlist()
00427 {
00428 songs.setAutoDelete(true);
00429 songs.clear();
00430 }
00431
00432 Playlist& Playlist::operator=(const Playlist& rhs)
00433 {
00434 if (this == &rhs)
00435 {
00436 return *this;
00437 }
00438
00439 playlistid = rhs.playlistid;
00440 name = rhs.name;
00441 raw_songlist = rhs.raw_songlist;
00442 songs = rhs.songs;
00443 return *this;
00444 }
00445
00446 void Playlist::describeYourself()
00447 {
00448
00449
00450
00451
00452
00453
00454
00455
00456 Track *it;
00457 for(it = songs.first(); it; it = songs.next())
00458 {
00459 cout << it->getValue() << "," ;
00460 }
00461
00462 cout << endl;
00463 }
00464
00465
00466 void Playlist::loadPlaylist(QString a_name, QString a_host)
00467 {
00468 QString thequery;
00469 if (a_host.length() < 1)
00470 {
00471 VERBOSE(VB_IMPORTANT, "loadPlaylist() - We need a valid hostname");
00472 return;
00473 }
00474
00475 MSqlQuery query(MSqlQuery::InitCon());
00476
00477 if (name == "default_playlist_storage" || name == "backup_playlist_storage")
00478 {
00479 query.prepare("SELECT playlist_id, playlist_name, playlist_songs "
00480 "FROM music_playlists "
00481 "WHERE playlist_name = :NAME"
00482 " AND hostname = :HOST;");
00483 }
00484 else
00485 {
00486
00487
00488 query.prepare("SELECT playlist_id, playlist_name, playlist_songs "
00489 "FROM music_playlists "
00490 "WHERE playlist_name = :NAME"
00491 " AND (hostname = '' OR hostname = :HOST);");
00492 }
00493 query.bindValue(":NAME", a_name.utf8());
00494 query.bindValue(":HOST", a_host);
00495
00496 if (query.exec() && query.size() > 0)
00497 {
00498 while (query.next())
00499 {
00500 playlistid = query.value(0).toInt();
00501 name = QString::fromUtf8(query.value(1).toString());
00502 raw_songlist = query.value(2).toString();
00503 }
00504 if (name == "default_playlist_storage")
00505 name = "the user should never see this";
00506 if (name == "backup_playlist_storage")
00507 name = "and they should **REALLY** never see this";
00508 }
00509 else
00510 {
00511
00512 playlistid = 0;
00513
00514 raw_songlist = "";
00515 savePlaylist(a_name, a_host);
00516 changed = true;
00517 }
00518 }
00519
00520 void Playlist::loadPlaylistByID(int id, QString a_host)
00521 {
00522 MSqlQuery query(MSqlQuery::InitCon());
00523 query.prepare("SELECT playlist_id, playlist_name, playlist_songs "
00524 "FROM music_playlists "
00525 "WHERE playlist_id = :ID"
00526 " AND (hostname = '' OR hostname = :HOST);");
00527 query.bindValue(":ID", id);
00528 query.bindValue(":HOST", a_host);
00529
00530 query.exec();
00531
00532 while (query.next())
00533 {
00534 playlistid = query.value(0).toInt();
00535 name = QString::fromUtf8(query.value(1).toString());
00536 raw_songlist = query.value(2).toString();
00537 }
00538
00539 if (name == "default_playlist_storage")
00540 name = "the user should never see this";
00541 if (name == "backup_playlist_storage")
00542 name = "and they should **REALLY** never see this";
00543 }
00544
00545 void Playlist::fillSongsFromSonglist(QString songList, bool filter)
00546 {
00547 raw_songlist = songList;
00548 fillSongsFromSonglist(filter);
00549 }
00550
00551 void Playlist::fillSongsFromSonglist(bool filter)
00552 {
00553 int an_int;
00554
00555 if (filter)
00556 all_available_music->setAllVisible(false);
00557
00558 QStringList list = QStringList::split(",", raw_songlist);
00559 QStringList::iterator it = list.begin();
00560 for (; it != list.end(); it++)
00561 {
00562 an_int = QString(*it).toInt();
00563 if (an_int != 0)
00564 {
00565 if (filter)
00566 {
00567 Metadata *md = all_available_music->getMetadata(an_int);
00568 if(md)
00569 md->setVisible(true);
00570 }
00571 else
00572 {
00573 Track *a_track = new Track(an_int, all_available_music);
00574 a_track->setParent(this);
00575 songs.append(a_track);
00576 }
00577 }
00578 else
00579 {
00580 changed = true;
00581 VERBOSE(VB_IMPORTANT, "Taking a 0 (zero) off a "
00582 "playlist. If this happens on repeated invocations of "
00583 "mythmusic, then something is really wrong");
00584 }
00585 }
00586
00587 if (filter)
00588 {
00589 all_available_music->clearTree();
00590 all_available_music->buildTree();
00591 all_available_music->sortTree();
00592 }
00593 }
00594
00595 void Playlist::fillSonglistFromSongs()
00596 {
00597 QString a_list = "";
00598 Track *it;
00599 for (it = songs.first(); it; it = songs.next())
00600 {
00601 if (!it->getCDFlag())
00602 {
00603 a_list += QString(",%1").arg(it->getValue());
00604 }
00605 }
00606
00607 raw_songlist = "";
00608 if (a_list.length() > 1)
00609 raw_songlist = a_list.remove(0, 1);
00610 }
00611
00612 void Playlist::fillSonglistFromQuery(QString whereClause,
00613 bool removeDuplicates,
00614 InsertPLOption insertOption,
00615 int currentTrackID)
00616 {
00617 QString orig_songlist;
00618
00619 if (insertOption != PL_FILTERONLY)
00620 removeAllTracks();
00621
00622 MSqlQuery query(MSqlQuery::InitCon());
00623
00624 QString theQuery;
00625
00626 theQuery = "SELECT song_id FROM music_songs "
00627 "LEFT JOIN music_directories ON music_songs.directory_id=music_directories.directory_id "
00628 "LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id "
00629 "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
00630 "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id "
00631 "LEFT JOIN music_artists AS music_comp_artists ON "
00632 "music_albums.artist_id=music_comp_artists.artist_id ";
00633 if (whereClause.length() > 0)
00634 theQuery += whereClause;
00635
00636 if (!query.exec(theQuery))
00637 {
00638 MythContext::DBError("Load songlist from query", query);
00639 raw_songlist = "";
00640 return;
00641 }
00642
00643 QString new_songlist = "";
00644 while (query.next())
00645 {
00646 new_songlist += "," + query.value(0).toString();
00647 }
00648 new_songlist.remove(0, 1);
00649
00650 if (insertOption != PL_FILTERONLY && removeDuplicates)
00651 {
00652 new_songlist = removeDuplicateTracks(new_songlist);
00653 }
00654
00655 switch (insertOption)
00656 {
00657 case PL_REPLACE:
00658 raw_songlist = new_songlist;
00659 break;
00660
00661 case PL_INSERTATBEGINNING:
00662 raw_songlist = new_songlist + "," + raw_songlist;
00663 break;
00664
00665 case PL_INSERTATEND:
00666 raw_songlist = raw_songlist + "," + new_songlist;
00667 break;
00668
00669 case PL_INSERTAFTERCURRENT:
00670 {
00671 QStringList list = QStringList::split(",", raw_songlist);
00672 QStringList::iterator it = list.begin();
00673 raw_songlist = "";
00674 bool bFound = false;
00675
00676 for (; it != list.end(); it++)
00677 {
00678 int an_int = QString(*it).toInt();
00679 raw_songlist += "," + QString(*it);
00680 if (!bFound && an_int == currentTrackID)
00681 {
00682 bFound = true;
00683 raw_songlist += "," + new_songlist;
00684 }
00685 }
00686
00687 if (!bFound)
00688 {
00689 raw_songlist += "," + new_songlist;
00690 }
00691
00692 raw_songlist.remove(0, 1);
00693
00694 break;
00695 }
00696
00697 case PL_FILTERONLY:
00698 orig_songlist = raw_songlist;
00699 raw_songlist = new_songlist;
00700 break;
00701
00702 default:
00703 raw_songlist = new_songlist;
00704 }
00705
00706 if (insertOption != PL_FILTERONLY)
00707 {
00708 fillSongsFromSonglist(false);
00709 postLoad();
00710 }
00711 else
00712 {
00713 fillSongsFromSonglist(true);
00714 raw_songlist = orig_songlist;
00715 }
00716 }
00717
00718 void Playlist::fillSongsFromCD()
00719 {
00720 for (int i = 1; i <= all_available_music->getCDTrackCount(); i++)
00721 addTrack(-1 * i, false, true);
00722 }
00723
00724 void Playlist::fillSonglistFromSmartPlaylist(QString category, QString name,
00725 bool removeDuplicates,
00726 InsertPLOption insertOption,
00727 int currentTrackID)
00728 {
00729 MSqlQuery query(MSqlQuery::InitCon());
00730
00731
00732 int categoryID = SmartPlaylistEditor::lookupCategoryID(category);
00733 if (categoryID == -1)
00734 {
00735 cout << "Cannot find Smartplaylist Category: " << category << endl;
00736 return;
00737 }
00738
00739
00740 int ID;
00741 QString matchType;
00742 QString orderBy;
00743 int limitTo;
00744
00745 query.prepare("SELECT smartplaylistid, matchtype, orderby, limitto "
00746 "FROM music_smartplaylists WHERE categoryid = :CATEGORYID AND name = :NAME;");
00747 query.bindValue(":NAME", name.utf8());
00748 query.bindValue(":CATEGORYID", categoryID);
00749
00750 if (query.exec())
00751 {
00752 if (query.isActive() && query.size() > 0)
00753 {
00754 query.first();
00755 ID = query.value(0).toInt();
00756 matchType = (query.value(1).toString() == "All") ? " AND " : " OR ";
00757 orderBy = QString::fromUtf8(query.value(2).toString());
00758 limitTo = query.value(3).toInt();
00759 }
00760 else
00761 {
00762 cout << "Cannot find smartplaylist: " << name << endl;
00763 return;
00764 }
00765 }
00766 else
00767 {
00768 MythContext::DBError("Find SmartPlaylist", query);
00769 return;
00770 }
00771
00772
00773 QString whereClause = "WHERE ";
00774
00775 query.prepare("SELECT field, operator, value1, value2 "
00776 "FROM music_smartplaylist_items WHERE smartplaylistid = :ID;");
00777 query.bindValue(":ID", ID);
00778 query.exec();
00779 if (query.isActive() && query.size() > 0)
00780 {
00781 bool bFirst = true;
00782 while (query.next())
00783 {
00784 QString fieldName = QString::fromUtf8(query.value(0).toString());
00785 QString operatorName = QString::fromUtf8(query.value(1).toString());
00786 QString value1 = QString::fromUtf8(query.value(2).toString());
00787 QString value2 = QString::fromUtf8(query.value(3).toString());
00788 if (!bFirst)
00789 whereClause += matchType + getCriteriaSQL(fieldName, operatorName, value1, value2);
00790 else
00791 {
00792 bFirst = false;
00793 whereClause += " " + getCriteriaSQL(fieldName, operatorName, value1, value2);
00794 }
00795 }
00796 }
00797
00798
00799 whereClause += getOrderBySQL(orderBy);
00800
00801
00802 if (limitTo > 0)
00803 whereClause += " LIMIT " + QString::number(limitTo);
00804
00805 fillSonglistFromQuery(whereClause, removeDuplicates, insertOption, currentTrackID);
00806 }
00807
00808 void Playlist::savePlaylist(QString a_name, QString a_host)
00809 {
00810 name = a_name.simplifyWhiteSpace();
00811 if (name.length() < 1)
00812 {
00813 VERBOSE(VB_GENERAL, "Not going to save a playlist with no name");
00814 return;
00815 }
00816
00817 if (a_host.length() < 1)
00818 {
00819 VERBOSE(VB_GENERAL, "Not going to save a playlist with no hostname");
00820 return;
00821 }
00822 if (name.length() < 1)
00823 return;
00824
00825 fillSonglistFromSongs();
00826 MSqlQuery query(MSqlQuery::InitCon());
00827
00828 int length = 0, songcount = 0, playtime = 0, an_int;
00829 QStringList list = QStringList::split(",", raw_songlist);
00830 QStringList::iterator it = list.begin();
00831 for (; it != list.end(); it++)
00832 {
00833 an_int = QString(*it).toInt();
00834 if (an_int != 0)
00835 {
00836 songcount++;
00837 if (an_int > 0)
00838 {
00839 Metadata *md = all_available_music->getMetadata(an_int);
00840 if(md)
00841 length = md->Length();
00842 }
00843 else
00844 {
00845 query.prepare("SELECT length FROM music_playlists "
00846 "WHERE playlist_id = :ID ;");
00847 an_int *= -1;
00848 query.bindValue(":ID", an_int);
00849 query.exec();
00850
00851 if (query.size() > 0)
00852 {
00853 query.next();
00854 length = query.value(0).toInt();
00855 }
00856 }
00857
00858 playtime += length;
00859 }
00860 }
00861
00862 bool save_host = ("default_playlist_storage" == a_name
00863 || "backup_playlist_storage" == a_name);
00864 if (playlistid > 0)
00865 {
00866 QString str_query = "UPDATE music_playlists SET "
00867 "playlist_songs = :LIST, "
00868 "playlist_name = :NAME, "
00869 "songcount = :SONGCOUNT, "
00870 "length = :PLAYTIME";
00871 if (save_host)
00872 str_query += ", hostname = :HOSTNAME";
00873 str_query += " WHERE playlist_id = :ID ;";
00874
00875 query.prepare(str_query);
00876 query.bindValue(":ID", playlistid);
00877 }
00878 else
00879 {
00880 QString str_query = "INSERT INTO music_playlists"
00881 " (playlist_name, playlist_songs, songcount, length";
00882 if (save_host)
00883 str_query += ", hostname";
00884 str_query += ") VALUES(:NAME, :LIST, :SONGCOUNT, :PLAYTIME";
00885 if (save_host)
00886 str_query += ", :HOSTNAME";
00887 str_query += ");";
00888
00889 query.prepare(str_query);
00890 }
00891 query.bindValue(":LIST", raw_songlist);
00892 query.bindValue(":NAME", a_name.utf8());
00893 query.bindValue(":SONGCOUNT", songcount);
00894 query.bindValue(":PLAYTIME", playtime);
00895 if (save_host)
00896 query.bindValue(":HOSTNAME", a_host);
00897
00898 if (!query.exec() || (playlistid < 1 && query.numRowsAffected() < 1))
00899 {
00900 MythContext::DBError("Problem saving playlist", query);
00901 }
00902
00903 if (playlistid < 1)
00904 playlistid = query.lastInsertId().toInt();
00905 }
00906
00907 QString Playlist::removeDuplicateTracks(const QString &new_songlist)
00908 {
00909 raw_songlist.remove(' ');
00910
00911 QStringList curList = QStringList::split(",", raw_songlist);
00912 QStringList newList = QStringList::split(",", new_songlist);
00913 QStringList::iterator it = newList.begin();
00914 QString songlist = "";
00915
00916 for (; it != newList.end(); it++)
00917 {
00918 if (curList.find(QString(*it)) == curList.end())
00919 songlist += "," + QString(*it);
00920 }
00921 songlist.remove(0, 1);
00922 return songlist;
00923 }
00924
00925 int Playlist::writeTree(GenericTree *tree_to_write_to, int a_counter)
00926 {
00927 Track *it;
00928
00929
00930 int playcountMin = 0;
00931 int playcountMax = 0;
00932 double lastplayMin = 0.0;
00933 double lastplayMax = 0.0;
00934
00935 typedef map<QString, uint32_t> AlbumMap;
00936 AlbumMap album_map;
00937 AlbumMap::iterator Ialbum;
00938 QString album;
00939
00940 typedef map<QString, uint32_t> ArtistMap;
00941 ArtistMap artist_map;
00942 ArtistMap::iterator Iartist;
00943 QString artist;
00944
00945 for (it = songs.first(); it; it = songs.next())
00946 {
00947 if (!it->getCDFlag())
00948 {
00949 if (it->getValue() == 0)
00950 {
00951 VERBOSE(VB_IMPORTANT, "Song with ID of 0 in playlist, this "
00952 "shouldn't happen.");
00953 }
00954 if (it->getValue() > 0)
00955 {
00956
00957 Metadata *tmpdata = all_available_music->getMetadata(it->getValue());
00958 if (tmpdata && tmpdata->isVisible())
00959 {
00960 if (songs.at() == 0)
00961 {
00962 playcountMin = playcountMax = tmpdata->PlayCount();
00963 lastplayMin = lastplayMax = tmpdata->LastPlay();
00964 }
00965 else
00966 {
00967 if (tmpdata->PlayCount() < playcountMin)
00968 playcountMin = tmpdata->PlayCount();
00969 else if (tmpdata->PlayCount() > playcountMax)
00970 playcountMax = tmpdata->PlayCount();
00971
00972 if (tmpdata->LastPlay() < lastplayMin)
00973 lastplayMin = tmpdata->LastPlay();
00974 else if (tmpdata->LastPlay() > lastplayMax)
00975 lastplayMax = tmpdata->LastPlay();
00976 }
00977 }
00978
00979 album = tmpdata->Album();
00980 if ((Ialbum = album_map.find(album)) == album_map.end())
00981 {
00982 album_map.insert(AlbumMap::value_type(album,0));
00983 }
00984
00985
00986 artist = tmpdata->Artist() + "~" + tmpdata->Title();
00987 if ((Iartist = artist_map.find(artist)) == artist_map.end())
00988 {
00989 artist_map.insert(ArtistMap::value_type(artist,0));
00990 }
00991 }
00992 }
00993 }
00994
00995 uint32_t album_count = 1;
00996 for (Ialbum = album_map.begin(); Ialbum != album_map.end(); Ialbum++)
00997 {
00998 Ialbum->second = album_count;
00999 album_count++;
01000 }
01001
01002
01003 uint32_t count = 1;
01004 for (Iartist = artist_map.begin(); Iartist != artist_map.end(); Iartist++)
01005 {
01006 Iartist->second = count;
01007 count++;
01008 }
01009
01010 int RatingWeight = 2;
01011 int PlayCountWeight = 2;
01012 int LastPlayWeight = 2;
01013 int RandomWeight = 2;
01014
01015 parent->FillIntelliWeights(RatingWeight, PlayCountWeight, LastPlayWeight,
01016 RandomWeight);
01017
01018 for (it = songs.first(); it; it = songs.next())
01019 {
01020 if (!it->getCDFlag())
01021 {
01022 if (it->getValue() == 0)
01023 {
01024 VERBOSE(VB_IMPORTANT, "Song with ID of 0 in playlist, this "
01025 "shouldn't happen.");
01026 }
01027 if (it->getValue() > 0)
01028 {
01029
01030 Metadata *tmpdata = all_available_music->getMetadata(it->getValue());
01031 if (tmpdata && tmpdata->isVisible())
01032 {
01033 QString a_string = QString("%1 ~ %2").arg(tmpdata->FormatArtist()).arg(tmpdata->FormatTitle());
01034 GenericTree *added_node = tree_to_write_to->addNode(a_string, it->getValue(), true);
01035 ++a_counter;
01036 added_node->setAttribute(0, 1);
01037 added_node->setAttribute(1, a_counter);
01038 added_node->setAttribute(2, rand());
01039
01040
01041
01042
01043
01044 int rating = tmpdata->Rating();
01045 int playcount = tmpdata->PlayCount();
01046 double lastplaydbl = tmpdata->LastPlay();
01047 double ratingValue = (double)(rating) / 10;
01048 double playcountValue, lastplayValue;
01049
01050 if (playcountMax == playcountMin)
01051 playcountValue = 0;
01052 else
01053 playcountValue = ((playcountMin - (double)playcount) / (playcountMax - playcountMin) + 1);
01054
01055 if (lastplayMax == lastplayMin)
01056 lastplayValue = 0;
01057 else
01058 lastplayValue = ((lastplayMin - lastplaydbl) / (lastplayMax - lastplayMin) + 1);
01059
01060 double rating_value = (RatingWeight * ratingValue + PlayCountWeight * playcountValue +
01061 LastPlayWeight * lastplayValue + RandomWeight * (double)rand() /
01062 (RAND_MAX + 1.0));
01063 uint32_t integer_rating = (int) (4000001 - rating_value * 10000);
01064 added_node->setAttribute(3, integer_rating);
01065
01066
01067 uint32_t album_order;
01068 album = tmpdata->Album();
01069 if ((Ialbum = album_map.find(album)) == album_map.end())
01070 {
01071
01072
01073
01074 album_order = 1;
01075 }
01076 else
01077 {
01078 album_order = Ialbum->second * 100;
01079 }
01080 album_order += tmpdata->Track();
01081 added_node->setAttribute(4, album_order);
01082
01083
01084
01085 uint32_t integer_order;
01086 artist = tmpdata->Artist() + "~" + tmpdata->Title();
01087 if ((Iartist = artist_map.find(artist)) == artist_map.end())
01088 {
01089
01090
01091
01092 integer_order = 1;
01093 }
01094 else
01095 {
01096 integer_order = Iartist->second;
01097 }
01098 added_node->setAttribute(5, integer_order);
01099 }
01100 }
01101 if (it->getValue() < 0)
01102 {
01103
01104 Playlist *level_down = parent->getPlaylist((it->getValue()) * -1);
01105 if (level_down)
01106 {
01107 a_counter = level_down->writeTree(tree_to_write_to, a_counter);
01108 }
01109 }
01110 }
01111 else
01112 {
01113 Metadata *tmpdata = all_available_music->getMetadata(it->getValue());
01114 if (tmpdata)
01115 {
01116 QString a_string = QString("(CD) %1 ~ %2")
01117 .arg(tmpdata->FormatArtist()).arg(tmpdata->FormatTitle());
01118
01119 if (tmpdata->FormatArtist().length() < 1 ||
01120 tmpdata->FormatTitle().length() < 1)
01121 {
01122 a_string = QString("(CD) Track %1").arg(tmpdata->Track());
01123 }
01124 GenericTree *added_node = tree_to_write_to->addNode(a_string, it->getValue(), true);
01125 ++a_counter;
01126 added_node->setAttribute(0, 1);
01127 added_node->setAttribute(1, a_counter);
01128 added_node->setAttribute(2, rand());
01129 added_node->setAttribute(3, rand());
01130 }
01131 }
01132 }
01133 return a_counter;
01134 }
01135
01136 GenericTree* PlaylistsContainer::writeTree(GenericTree *tree_to_write_to)
01137 {
01138 all_available_music->writeTree(tree_to_write_to);
01139
01140 GenericTree *sub_node = tree_to_write_to->addNode(QObject::tr("All My Playlists"), 1);
01141 sub_node->setAttribute(0, 1);
01142 sub_node->setAttribute(1, 1);
01143 sub_node->setAttribute(2, 1);
01144 sub_node->setAttribute(3, 1);
01145
01146 GenericTree *subsub_node = sub_node->addNode(QObject::tr("Active Play Queue"), 0);
01147 subsub_node->setAttribute(0, 0);
01148 subsub_node->setAttribute(1, 0);
01149 subsub_node->setAttribute(2, rand());
01150 subsub_node->setAttribute(3, rand());
01151
01152 active_playlist->writeTree(subsub_node, 0);
01153
01154 int a_counter = 0;
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179 QPtrListIterator<Playlist> iterator( *all_other_playlists );
01180 Playlist *a_list;
01181 while( ( a_list = iterator.current() ) != 0)
01182 {
01183 ++a_counter;
01184 GenericTree *new_node = sub_node->addNode(a_list->getName(), a_list->getID());
01185 new_node->setAttribute(0, 0);
01186 new_node->setAttribute(1, a_counter);
01187 new_node->setAttribute(2, rand());
01188 new_node->setAttribute(3, rand());
01189 a_list->writeTree(new_node, 0);
01190 ++iterator;
01191 }
01192
01193 GenericTree* active_playlist_node = subsub_node->findLeaf();
01194 if(!active_playlist_node) active_playlist_node = subsub_node;
01195 return active_playlist_node;
01196 }
01197
01198 void PlaylistsContainer::save()
01199 {
01200 Playlist *a_list;
01201
01202 for(a_list = all_other_playlists->first(); a_list; a_list = all_other_playlists->next())
01203 {
01204 if(a_list->hasChanged())
01205 {
01206 a_list->fillSonglistFromSongs();
01207 a_list->savePlaylist(a_list->getName(), my_host);
01208 }
01209 }
01210
01211 active_playlist->savePlaylist("default_playlist_storage", my_host);
01212 backup_playlist->savePlaylist("backup_playlist_storage", my_host);
01213 }
01214
01215 void PlaylistsContainer::createNewPlaylist(QString name)
01216 {
01217 Playlist *new_list = new Playlist(all_available_music);
01218 new_list->setParent(this);
01219
01220
01221 new_list->savePlaylist(name, my_host);
01222 new_list->Changed();
01223 all_other_playlists->append(new_list);
01224
01225
01226
01227
01228 }
01229
01230 void PlaylistsContainer::copyNewPlaylist(QString name)
01231 {
01232 Playlist *new_list = new Playlist(all_available_music);
01233 new_list->setParent(this);
01234
01235
01236 new_list->savePlaylist(name, my_host);
01237 new_list->Changed();
01238 all_other_playlists->append(new_list);
01239 active_playlist->copyTracks(new_list, false);
01240 pending_writeback_index = 0;
01241 active_widget->setText(QObject::tr("Active Play Queue"));
01242 active_playlist->removeAllTracks();
01243 active_playlist->addTrack(new_list->getID() * -1, true, false);
01244 }
01245
01246 void PlaylistsContainer::setActiveWidget(PlaylistTitle *widget)
01247 {
01248 active_widget = widget;
01249 if (active_widget && pending_writeback_index > 0)
01250 {
01251 bool bad = false;
01252 QString newlabel = QString(QObject::tr("Active Play Queue (%1)")).arg(getPlaylistName(pending_writeback_index, bad));
01253 active_widget->setText(newlabel);
01254 }
01255 }
01256
01257 void PlaylistsContainer::popBackPlaylist()
01258 {
01259 Playlist *destination = getPlaylist(pending_writeback_index);
01260 if (!destination)
01261 {
01262 VERBOSE(VB_IMPORTANT, QString("Unknown playlist: %1")
01263 .arg(pending_writeback_index));
01264 return;
01265 }
01266 destination->removeAllTracks();
01267 destination->Changed();
01268 active_playlist->copyTracks(destination, false);
01269 active_playlist->removeAllTracks();
01270 backup_playlist->copyTracks(active_playlist, true);
01271 pending_writeback_index = 0;
01272 active_widget->setText(QObject::tr("Active Play Queue"));
01273
01274 active_playlist->Changed();
01275 backup_playlist->Changed();
01276 }
01277
01278 void PlaylistsContainer::copyToActive(int index)
01279 {
01280 backup_playlist->removeAllTracks();
01281 active_playlist->copyTracks(backup_playlist, false);
01282
01283 pending_writeback_index = index;
01284 if(active_widget)
01285 {
01286 bool bad = false;
01287 QString newlabel = QString(QObject::tr("Active Play Queue (%1)"))
01288 .arg(getPlaylistName(index, bad));
01289 active_widget->setText(newlabel);
01290 }
01291 active_playlist->removeAllTracks();
01292 Playlist *copy_from = getPlaylist(index);
01293 if (!copy_from)
01294 {
01295 VERBOSE(VB_IMPORTANT, QString("Unknown playlist: %1").arg(index));
01296 return;
01297 }
01298 copy_from->copyTracks(active_playlist, true);
01299
01300 active_playlist->Changed();
01301 backup_playlist->Changed();
01302 }
01303
01304
01305 void PlaylistsContainer::renamePlaylist(int index, QString new_name)
01306 {
01307 Playlist *list_to_rename = getPlaylist(index);
01308 if (list_to_rename)
01309 {
01310 list_to_rename->setName(new_name);
01311 list_to_rename->Changed();
01312 if(list_to_rename->getID() == pending_writeback_index)
01313 {
01314 QString newlabel = QString(QObject::tr("Active Play Queue (%1)"))
01315 .arg(new_name);
01316 active_widget->setText(newlabel);
01317 }
01318 }
01319 }
01320
01321 void PlaylistsContainer::deletePlaylist(int kill_me)
01322 {
01323 Playlist *list_to_kill = getPlaylist(kill_me);
01324 if (!list_to_kill)
01325 {
01326 VERBOSE(VB_IMPORTANT, QString("Unknown playlist: %1").arg(kill_me));
01327 return;
01328 }
01329
01330
01331
01332
01333 if (kill_me == pending_writeback_index)
01334 popBackPlaylist();
01335
01336 active_playlist->removeTrack(kill_me * -1, false);
01337
01338 QPtrListIterator<Playlist> iterator( *all_other_playlists );
01339 Playlist *a_list;
01340 while( ( a_list = iterator.current() ) != 0)
01341 {
01342 ++iterator;
01343 if(a_list != list_to_kill)
01344 {
01345 a_list->removeTrack(kill_me * -1, false);
01346 }
01347 }
01348
01349 MSqlQuery query(MSqlQuery::InitCon());
01350 query.prepare("DELETE FROM music_playlists WHERE playlist_id = :ID ;");
01351 query.bindValue(":ID", kill_me);
01352
01353 if (!query.exec() || query.numRowsAffected() < 1)
01354 {
01355 MythContext::DBError("playlist delete", query);
01356 }
01357 list_to_kill->removeAllTracks();
01358 all_other_playlists->remove(list_to_kill);
01359 }
01360
01361
01362 QString PlaylistsContainer::getPlaylistName(int index, bool &reference)
01363 {
01364 if(active_playlist)
01365 {
01366 if(active_playlist->getID() == index)
01367 {
01368 return active_playlist->getName();
01369 }
01370
01371 Playlist *a_list;
01372 for(a_list = all_other_playlists->last(); a_list; a_list = all_other_playlists->prev())
01373 {
01374 if (a_list->getID() == index)
01375 {
01376 return a_list->getName();
01377 }
01378 }
01379 }
01380 VERBOSE(VB_IMPORTANT, "getPlaylistName() called with unknown index number");
01381 reference = true;
01382 return QObject::tr("Something is Wrong");
01383 }
01384
01385 bool Playlist::containsReference(int to_check, int depth)
01386 {
01387 if(depth > 10)
01388 {
01389 VERBOSE(VB_IMPORTANT, "Recursively checking playlists, and have "
01390 "reached a search depth over 10 ");
01391 }
01392 bool ref_exists = false;
01393
01394 int check;
01395
01396
01397
01398 Track *it;
01399 for(it = songs.first(); it; it = songs.next())
01400 {
01401 check = it->getValue();
01402 if (check < 0 && !it->getCDFlag())
01403 {
01404 if(check * -1 == to_check)
01405 {
01406 ref_exists = true;
01407 return ref_exists;
01408 }
01409 else
01410 {
01411
01412 int new_depth = depth + 1;
01413 Playlist *new_check = parent->getPlaylist(check * -1);
01414 if (new_check)
01415 ref_exists = new_check->containsReference(to_check,
01416 new_depth);
01417 }
01418 }
01419 }
01420 return ref_exists;
01421 }
01422
01423 Playlist *PlaylistsContainer::getPlaylist(int id)
01424 {
01425
01426
01427
01428 if(active_playlist->getID() == id)
01429 {
01430 return active_playlist;
01431 }
01432
01433
01434
01435
01436
01437
01438 QPtrListIterator<Playlist> iterator( *all_other_playlists );
01439 Playlist *a_list;
01440 while( ( a_list = iterator.current() ) != 0)
01441 {
01442 ++iterator;
01443 if(a_list->getID() == id)
01444 {
01445 return a_list;
01446 }
01447 }
01448 VERBOSE(VB_IMPORTANT, "getPlaylistName() called with unknown index number");
01449 return NULL;
01450 }
01451
01452 void PlaylistsContainer::showRelevantPlaylists(TreeCheckItem *alllists)
01453 {
01454 QString templevel, temptitle;
01455 int id;
01456
01457 while (alllists->childCount() > 0)
01458 {
01459 UIListGenericTree *first_child;
01460 first_child = (UIListGenericTree *)(alllists->getChildAt(0));
01461 {
01462 first_child->RemoveFromParent();
01463
01464 }
01465 }
01466
01467
01468 Playlist *some_list;
01469 for (some_list = all_other_playlists->first(); some_list;
01470 some_list = all_other_playlists->next())
01471 {
01472 id = some_list->getID() * -1 ;
01473 temptitle = some_list->getName();
01474 templevel = "playlist";
01475
01476 TreeCheckItem *some_item = new TreeCheckItem(alllists, temptitle,
01477 templevel, id);
01478
01479 some_item->setCheckable(true);
01480 some_item->setActive(true);
01481
01482 if (some_list->containsReference(pending_writeback_index, 0) ||
01483 (id * -1) == pending_writeback_index)
01484 {
01485 some_item->setCheckable(false);
01486 some_item->setActive(false);
01487 }
01488
01489 some_list->putYourselfOnTheListView(some_item);
01490 }
01491
01492 if (alllists->childCount() == 0)
01493 alllists->setCheckable(false);
01494 else
01495 alllists->setCheckable(true);
01496 }
01497
01498 void PlaylistsContainer::refreshRelevantPlaylists(TreeCheckItem *alllists)
01499 {
01500 if (alllists->childCount() == 0)
01501 {
01502 alllists->setCheckable(false);
01503 return;
01504 }
01505
01506 UIListGenericTree *walker = (UIListGenericTree *)(alllists->getChildAt(0));
01507 while (walker)
01508 {
01509 if(TreeCheckItem *check_item = dynamic_cast<TreeCheckItem*>(walker))
01510 {
01511 int id = check_item->getID() * -1;
01512 Playlist *check_playlist = getPlaylist(id);
01513 if((check_playlist &&
01514 check_playlist->containsReference(pending_writeback_index, 0)) ||
01515 id == pending_writeback_index)
01516 {
01517 check_item->setCheckable(false);
01518 check_item->setActive(false);
01519 }
01520 else
01521 {
01522 check_item->setCheckable(true);
01523 check_item->setActive(true);
01524 }
01525 }
01526 walker = (UIListGenericTree *)(walker->nextSibling(1));
01527 }
01528
01529 alllists->setCheckable(true);
01530 }
01531
01532 void PlaylistsContainer::postLoad()
01533 {
01534
01535
01536
01537 active_playlist->postLoad();
01538 backup_playlist->postLoad();
01539 QPtrListIterator<Playlist> iterator( *all_other_playlists );
01540 Playlist *a_list;
01541 while( ( a_list = iterator.current() ) != 0)
01542 {
01543 ++iterator;
01544 a_list->postLoad();
01545 }
01546 }
01547
01548 bool PlaylistsContainer::pendingWriteback()
01549 {
01550 if(pending_writeback_index > 0)
01551 {
01552 return true;
01553 }
01554 return false;
01555 }
01556
01557 bool PlaylistsContainer::nameIsUnique(QString a_name, int which_id)
01558 {
01559 if(a_name == "default_playlist_storage")
01560 {
01561 return false;
01562 }
01563
01564 if(a_name == "backup_playlist_storage")
01565 {
01566 return false;
01567 }
01568
01569 QPtrListIterator<Playlist> iterator( *all_other_playlists );
01570 Playlist *a_list;
01571 while( ( a_list = iterator.current() ) != 0)
01572 {
01573 ++iterator;
01574 if(a_list->getName() == a_name &&
01575 a_list->getID() != which_id)
01576 {
01577 return false;
01578 }
01579 }
01580 return true ;
01581 }
01582
01583 bool PlaylistsContainer::cleanOutThreads()
01584 {
01585 if(playlists_loader->finished())
01586 {
01587 return true;
01588 }
01589 playlists_loader->wait();
01590 return false;
01591 }
01592
01593 void PlaylistsContainer::clearActive()
01594 {
01595 backup_playlist->removeAllTracks();
01596 active_playlist->removeAllTracks();
01597 backup_playlist->Changed();
01598 active_playlist->Changed();
01599 pending_writeback_index = 0;
01600 active_widget->setText(QObject::tr("Active Play Queue"));
01601 }
01602
01603
01604
01605 void Playlist::computeSize(double &size_in_MB, double &size_in_sec)
01606 {
01607 Track *it;
01608 double child_MB;
01609 double child_sec;
01610
01611
01612 size_in_MB = 0.0;
01613 size_in_sec = 0.0;
01614
01615 for (it = songs.first(); it; it = songs.next())
01616 {
01617 if (it->getCDFlag())
01618 continue;
01619
01620 if (it->getValue() == 0)
01621 {
01622 VERBOSE(VB_IMPORTANT, "Song with ID of 0 in playlist, this "
01623 "shouldn't happen.");
01624 }
01625 else if (it->getValue() > 0)
01626 {
01627
01628 Metadata *tmpdata = all_available_music->getMetadata(it->getValue());
01629 if (tmpdata)
01630 {
01631 if (tmpdata->Length() > 0)
01632 size_in_sec += tmpdata->Length();
01633 else
01634 VERBOSE(VB_GENERAL, "Computing track lengths. "
01635 "One track <=0");
01636
01637
01638 QFileInfo finfo(tmpdata->Filename());
01639
01640 size_in_MB += finfo.size() / 1000000;
01641 }
01642 }
01643 if (it->getValue() < 0)
01644 {
01645
01646
01647
01648 Playlist *level_down = parent->getPlaylist((it->getValue()) * -1);
01649 if (level_down)
01650 {
01651 level_down->computeSize(child_MB, child_sec);
01652 size_in_MB += child_MB;
01653 size_in_sec += child_sec;
01654 }
01655 }
01656 }
01657 }
01658
01659 int Playlist::CreateCDMP3(void)
01660 {
01661
01662 if (!gContext->GetNumSetting("CDWriterEnabled"))
01663 {
01664 VERBOSE(VB_GENERAL, "CD Writer is not enabled.");
01665 return 1;
01666 }
01667
01668 QString scsidev = MediaMonitor::defaultCDWriter();
01669 if (scsidev.isEmpty() || scsidev.isNull())
01670 {
01671 VERBOSE(VB_GENERAL, "No CD Writer device defined.");
01672 return 1;
01673 }
01674
01675 int disksize = gContext->GetNumSetting("CDDiskSize", 2);
01676 QString writespeed = gContext->GetSetting("CDWriteSpeed", "2");
01677 bool MP3_dir_flag = gContext->GetNumSetting("CDCreateDir", 1);
01678
01679 double size_in_MB = 0.0;
01680
01681 QStringList reclist;
01682
01683 Track *it;
01684 for (it = songs.first(); it; it = songs.next())
01685 {
01686 if (it->getCDFlag())
01687 continue;
01688
01689 if (it->getValue() == 0)
01690 {
01691 VERBOSE(VB_IMPORTANT, "Song with ID of 0 in playlist, this "
01692 "shouldn't happen.");
01693 }
01694 else if (it->getValue() > 0)
01695 {
01696
01697 Metadata *tmpdata = all_available_music->getMetadata(it->getValue());
01698 if (tmpdata)
01699 {
01700
01701 QFileInfo testit(tmpdata->Filename());
01702 if (!testit.exists())
01703 continue;
01704 size_in_MB += testit.size() / 1000000.0;
01705 QString outline;
01706 if (MP3_dir_flag)
01707 {
01708 if (tmpdata->Artist().length() > 0)
01709 outline += tmpdata->Artist() + "/";
01710 if (tmpdata->Album().length() > 0)
01711 outline += tmpdata->Album() + "/";
01712 }
01713
01714 outline += "=";
01715 outline += tmpdata->Filename();
01716
01717 reclist += outline;
01718 }
01719 }
01720 else if (it->getValue() < 0)
01721 {
01722
01723 }
01724 }
01725
01726 int max_size;
01727 if (disksize == 0)
01728 max_size = 650;
01729 else
01730 max_size = 700;
01731
01732 if (size_in_MB >= max_size)
01733 {
01734 VERBOSE(VB_GENERAL, "MP3 CD creation aborted -- cd size too big.");
01735 return 1;
01736 }
01737
01738
01739 char tmprecordlist[L_tmpnam];
01740 char tmprecordisofs[L_tmpnam];
01741
01742 tmpnam(tmprecordlist);
01743 tmpnam(tmprecordisofs);
01744
01745 QFile reclistfile(tmprecordlist);
01746
01747 if (!reclistfile.open(IO_WriteOnly))
01748 {
01749 VERBOSE(VB_IMPORTANT, "Unable to open temporary file");
01750 return 1;
01751 }
01752
01753 QTextStream recstream(&reclistfile);
01754
01755 QStringList::Iterator iter;
01756
01757 for (iter = reclist.begin(); iter != reclist.end(); ++iter)
01758 {
01759 recstream << *iter << "\n";
01760 }
01761
01762 reclistfile.close();
01763
01764 MythProgressDialog *progress;
01765 progress = new MythProgressDialog(QObject::tr("Creating CD File System"),
01766 100);
01767 progress->setProgress(1);
01768
01769 QStringList args;
01770 args = "mkisofs";
01771 args += "-graft-points";
01772 args += "-path-list";
01773 args += tmprecordlist;
01774 args += "-o";
01775 args += tmprecordisofs;
01776 args += "-J";
01777 args += "-R";
01778
01779 cout << "Running: " << args.join(" ") << endl;
01780
01781 bool retval = 0;
01782
01783 QProcess isofs(args);
01784
01785 if (isofs.start())
01786 {
01787 while (1)
01788 {
01789 while (isofs.canReadLineStderr())
01790 {
01791 QString buf = isofs.readLineStderr();
01792 if (buf[6] == '%')
01793 {
01794 buf = buf.mid(0, 3);
01795 progress->setProgress(buf.stripWhiteSpace().toInt());
01796 }
01797 }
01798 if (isofs.isRunning())
01799 {
01800 qApp->processEvents();
01801 usleep(100000);
01802 }
01803 else
01804 {
01805 if (!isofs.normalExit())
01806 {
01807 VERBOSE(VB_IMPORTANT, "Unable to run 'mkisofs'");
01808 retval = 1;
01809 }
01810 break;
01811 }
01812 }
01813 }
01814 else
01815 {
01816 VERBOSE(VB_IMPORTANT, "Unable to run 'mkisofs'");
01817 retval = 1;
01818 }
01819
01820 progress->Close();
01821 progress->deleteLater();
01822
01823 progress = new MythProgressDialog(QObject::tr("Burning CD"), 100);
01824 progress->setProgress(2);
01825
01826 args = "cdrecord";
01827 args += "-v";
01828
01829 args += "dev=";
01830 args += scsidev;
01831
01832 if (writespeed.toInt() > 0)
01833 {
01834 args += "-speed=";
01835 args += writespeed;
01836 }
01837
01838 args += "-data";
01839 args += tmprecordisofs;
01840
01841 cout << "Running: " << args.join(" ") << endl;
01842
01843 QProcess burn(args);
01844
01845 if (burn.start())
01846 {
01847 while (1)
01848 {
01849 while (burn.canReadLineStderr())
01850 {
01851 QString err = burn.readLineStderr();
01852 if (err == "cdrecord: Drive needs to reload the media" ||
01853 err == "cdrecord: Input/output error." ||
01854 err == "cdrecord: No disk / Wrong disk!")
01855 {
01856 VERBOSE(VB_IMPORTANT, err);
01857 burn.kill();
01858 retval = 1;
01859 }
01860 }
01861 while (burn.canReadLineStdout())
01862 {
01863 QString line = burn.readLineStdout();
01864 if (line.mid(15, 2) == "of")
01865 {
01866 int mbdone = line.mid(10, 5).stripWhiteSpace().toInt();
01867 int mbtotal = line.mid(17, 5).stripWhiteSpace().toInt();
01868
01869 if (mbtotal > 0)
01870 {
01871 progress->setProgress((mbdone * 100) / mbtotal);
01872 }
01873 }
01874 }
01875
01876 if (burn.isRunning())
01877 {
01878 qApp->processEvents();
01879 usleep(10000);
01880 }
01881 else
01882 {
01883 if (!burn.normalExit())
01884 {
01885 VERBOSE(VB_IMPORTANT, "Unable to run 'cdrecord'");
01886 retval = 1;
01887 }
01888 break;
01889 }
01890 }
01891 }
01892 else
01893 {
01894 VERBOSE(VB_IMPORTANT, "Unable to run 'cdrecord'");
01895 retval = 1;
01896 }
01897
01898 progress->Close();
01899 progress->deleteLater();
01900
01901 QFile::remove(tmprecordlist);
01902 QFile::remove(tmprecordisofs);
01903
01904 return retval;
01905 }
01906
01907 int Playlist::CreateCDAudio(void)
01908 {
01909 return -1;
01910 }
01911