void ImportMusicDialog::setTitleWordCaps(void) { Metadata *data = m_tracks->at(m_currentTrack)->metadata; QString title = data->Title(); bool bInWord = false; for (int x = 0; x < title.length(); x++) { if (title[x].isSpace()) bInWord = false; else { if (title[x].isLetter()) { if (!bInWord) { title[x] = title[x].toUpper(); bInWord = true; } else title[x] = title[x].toLower(); } } } data->setTitle(title); fillWidgets(); }
void Ripper::switchTitlesAndArtists() { if (!m_compilationCheck->GetBooleanCheckState()) return; Metadata *data; // Switch title and artist for each track QString tmp; if (m_tracks->size() > 0) { for (int track = 0; track < m_tracks->size(); ++track) { data = m_tracks->at(track)->metadata; if (data) { tmp = data->Artist(); data->setArtist(data->Title()); data->setTitle(tmp); } } updateTrackList(); } }
void ImportMusicDialog::metadataChanged(void) { Metadata *editMeta = m_tracks->at(m_currentTrack)->metadata; m_tracks->at(m_currentTrack)->metadataHasChanged = true; m_tracks->at(m_currentTrack)->isNewTune = Ripper::isNewTune(editMeta->Artist(), editMeta->Album(), editMeta->Title()); fillWidgets(); }
void Ripper::updateTrackList(void) { if (m_tracks->isEmpty()) return; QString tmptitle; if (m_trackList) { m_trackList->Reset(); int i; for (i = 0; i < (int)m_tracks->size(); i++) { if (i >= m_tracks->size()) break; RipTrack *track = m_tracks->at(i); Metadata *metadata = track->metadata; MythUIButtonListItem *item = new MythUIButtonListItem(m_trackList,""); item->setCheckable(true); item->SetData(qVariantFromValue(track)); if (track->isNew) item->DisplayState("new", "yes"); else item->DisplayState("new", "no"); if (track->active) item->setChecked(MythUIButtonListItem::FullChecked); else item->setChecked(MythUIButtonListItem::NotChecked); item->SetText(QString::number(metadata->Track()), "track"); item->SetText(metadata->Title(), "title"); item->SetText(metadata->Artist(), "artist"); int length = track->length / 1000; if (length > 0) { int min, sec; min = length / 60; sec = length % 60; QString s; s.sprintf("%02d:%02d", min, sec); item->SetText(s, "length"); } else item->SetText("", "length"); // if (i == m_currentTrack) // m_trackList->SetItemCurrent(i); } } }
void ImportMusicDialog::setAlbum(void) { if (!m_haveDefaults) return; Metadata *data = m_tracks->at(m_currentTrack)->metadata; data->setAlbum(m_defaultAlbum); m_tracks->at(m_currentTrack)->isNewTune = Ripper::isNewTune( data->Artist(), data->Album(), data->Title()); fillWidgets(); }
void ImportMusicDialog::fillWidgets() { if (m_tracks->size() > 0) { // update current m_currentText->SetText(QString("%1 of %2") .arg(m_currentTrack + 1).arg(m_tracks->size())); Metadata *meta = m_tracks->at(m_currentTrack)->metadata; m_filenameText->SetText(meta->Filename()); m_compilationCheck->SetCheckState(meta->Compilation()); m_compartistText->SetText(meta->CompilationArtist()); m_artistText->SetText(meta->Artist()); m_albumText->SetText(meta->Album()); m_titleText->SetText(meta->Title()); m_genreText->SetText(meta->Genre()); m_yearText->SetText(QString::number(meta->Year())); m_trackText->SetText(QString::number(meta->Track())); if (m_tracks->at(m_currentTrack)->isNewTune) { m_coverartButton->SetVisible(false); m_statusText->SetText(tr("New File")); } else { m_coverartButton->SetVisible(true); m_statusText->SetText(tr("Already in Database")); } } else { // update current m_currentText->SetText(tr("Not found")); m_filenameText->Reset(); m_compilationCheck->SetCheckState(false); m_compartistText->Reset(); m_artistText->Reset(); m_albumText->Reset(); m_titleText->Reset(); m_genreText->Reset(); m_yearText->Reset(); m_trackText->Reset(); m_statusText->Reset(); m_coverartButton->SetVisible(false); } }
void ImportMusicDialog::scanDirectory(QString &directory, vector<TrackInfo*> *tracks) { QDir d(directory); if (!d.exists()) return; const QFileInfoList list = d.entryInfoList(); if (list.isEmpty()) return; QFileInfoList::const_iterator it = list.begin(); const QFileInfo *fi; while (it != list.end()) { fi = &(*it); ++it; if (fi->fileName() == "." || fi->fileName() == "..") continue; QString filename = fi->absoluteFilePath(); if (fi->isDir()) scanDirectory(filename, tracks); else { Decoder *decoder = Decoder::create(filename, NULL, NULL, true); if (decoder) { Metadata *metadata = decoder->getMetadata(); if (metadata) { TrackInfo * track = new TrackInfo; track->metadata = metadata; track->isNewTune = Ripper::isNewTune(metadata->Artist(), metadata->Album(), metadata->Title()); track->metadataHasChanged = false; tracks->push_back(track); m_sourceFiles.append(filename); } delete decoder; } } } }
void ImportMusicDialog::setTitleInitialCap(void) { Metadata *data = m_tracks->at(m_currentTrack)->metadata; QString title = data->Title(); bool bFoundCap = false; for (int x = 0; x < title.length(); x++) { if (title[x].isLetter()) { if (bFoundCap == false) { title[x] = title[x].toUpper(); bFoundCap = true; } else title[x] = title[x].toLower(); } } data->setTitle(title); fillWidgets(); }
void DatabaseBox::entered(UIListTreeType *treetype, UIListGenericTree *item) { if (!item || !treetype) return; // Determin if this is a CD entry bool cd = false; if (dynamic_cast<CDCheckItem*>(item)) cd = true; TreeCheckItem *item_ptr = dynamic_cast<TreeCheckItem*>(item); if (item_ptr && item->childCount() == 0 && item_ptr->getLevel() == "title") { int id = item_ptr->getID(); Metadata *mdata; if (!cd) { mdata = gMusicData->all_music->getMetadata(id); if (!mdata) return; } else { // Need to allocate storage for CD Metadata mdata = new Metadata; if (!gMusicData->all_music->getCDMetadata(id, mdata)) { delete mdata; return; } } unsigned int line = 0; QString tmpstr; if (mdata->Compilation()) { tmpstr = tr("Compilation Artist:\t") + mdata->CompilationArtist(); if (m_lines.at(line)) m_lines.at(line++)->SetText(tmpstr); } tmpstr = tr("Artist:\t") + mdata->Artist(); if (m_lines.at(line)) m_lines.at(line++)->SetText(tmpstr); tmpstr = tr("Album:\t") + mdata->Album(); if (m_lines.at(line)) m_lines.at(line++)->SetText(tmpstr); tmpstr = tr("Title:\t") + mdata->Title(); if (m_lines.at(line)) m_lines.at(line++)->SetText(tmpstr); if (m_lines.at(line)) { int maxTime = mdata->Length() / 1000; int maxh = maxTime / 3600; int maxm = (maxTime / 60) % 60; int maxs = maxTime % 60; QString timeStr; if (maxh > 0) timeStr.sprintf("%02d:%02d:%02d", maxh, maxm, maxs); else timeStr.sprintf("%02d:%02d", maxm, maxs); tmpstr = tr("Length:\t") + timeStr; m_lines.at(line++)->SetText(tmpstr); } tmpstr = tr("Genre: ") + mdata->Genre(); if (m_lines.at(line)) { m_lines.at(line)->SetText(tmpstr); } else { QString prevvalue = m_lines.at(line-1)->GetText(); tmpstr = prevvalue + " " + tmpstr; m_lines.at(line-1)->SetText(tmpstr); } // Pre increment as not incremented from previous use. while (++line < (unsigned) m_lines.size()) m_lines.at(line)->SetText(""); // Don't forget to delete the mdata storage if we allocated it. if (cd) delete mdata; return; } QStringList pathto = treetype->getRouteToCurrent(); int linelen = 0; int dispat = 0; QString data; for (QStringList::Iterator it = pathto.begin(); it != pathto.end(); ++it) { if (it == pathto.begin()) continue; if (!data.isEmpty()) data += " / "; data += *it; linelen++; if (linelen == 2) { if (m_lines.at(dispat)) { m_lines.at(dispat)->SetText(data); } data.clear(); linelen = 0; dispat++; } } if (linelen != 0) { if (m_lines.at(dispat)) { m_lines.at(dispat)->SetText(data); } dispat++; } for (unsigned int i = dispat; i < (unsigned) m_lines.size(); i++) m_lines.at(i)->SetText(""); }
void Ripper::ScanFinished() { delete m_scanThread; m_scanThread = NULL; m_tracks->clear(); bool isCompilation = false; bool newTune = true; if (m_decoder) { QString label; Metadata *metadata; m_artistName.clear(); m_albumName.clear(); m_genreName.clear(); m_year.clear(); bool yesToAll = false; bool noToAll = false; for (int trackno = 0; trackno < m_decoder->getNumTracks(); trackno++) { RipTrack *ripTrack = new RipTrack; metadata = m_decoder->getMetadata(trackno + 1); if (metadata) { ripTrack->metadata = metadata; ripTrack->length = metadata->Length(); ripTrack->active = true; if (metadata->Compilation()) { isCompilation = true; m_artistName = metadata->CompilationArtist(); } else if (m_artistName.isEmpty()) { m_artistName = metadata->Artist(); } if (m_albumName.isEmpty()) m_albumName = metadata->Album(); if (m_genreName.isEmpty() && !metadata->Genre().isEmpty()) m_genreName = metadata->Genre(); if (m_year.isEmpty() && metadata->Year() > 0) m_year = QString::number(metadata->Year()); QString title = metadata->Title(); newTune = Ripper::isNewTune(m_artistName, m_albumName, title); if (newTune) { m_tracks->push_back(ripTrack); } else { if (yesToAll) { deleteTrack(m_artistName, m_albumName, title); m_tracks->push_back(ripTrack); } else if (noToAll) { delete ripTrack; delete metadata; continue; } else { DialogBox *dlg = new DialogBox( GetMythMainWindow(), tr("Artist: %1\n" "Album: %2\n" "Track: %3\n\n" "This track is already in the database. \n" "Do you want to remove the existing track?") .arg(m_artistName).arg(m_albumName).arg(title)); dlg->AddButton("No"); dlg->AddButton("No To All"); dlg->AddButton("Yes"); dlg->AddButton("Yes To All"); DialogCode res = dlg->exec(); dlg->deleteLater(); dlg = NULL; if (kDialogCodeButton0 == res) { delete ripTrack; delete metadata; } else if (kDialogCodeButton1 == res) { noToAll = true; delete ripTrack; delete metadata; } else if (kDialogCodeButton2 == res) { deleteTrack(m_artistName, m_albumName, title); m_tracks->push_back(ripTrack); } else if (kDialogCodeButton3 == res) { yesToAll = true; deleteTrack(m_artistName, m_albumName, title); m_tracks->push_back(ripTrack); } else // treat cancel as no { delete ripTrack; delete metadata; } } } } else delete ripTrack; } m_artistEdit->SetText(m_artistName); m_albumEdit->SetText(m_albumName); m_genreEdit->SetText(m_genreName); m_yearEdit->SetText(m_year); m_compilationCheck->SetCheckState(isCompilation); if (!isCompilation) m_switchTitleArtist->SetVisible(false); else m_switchTitleArtist->SetVisible(true); } BuildFocusList(); updateTrackList(); CloseBusyPopup(); }
void CDRipperThread::run(void) { if (!m_tracks->size() > 0) return; Metadata *track = m_tracks->at(0)->metadata; QString tots; if (track->Compilation()) { tots = track->CompilationArtist() + " ~ " + track->Album(); } else { tots = track->Artist() + " ~ " + track->Album(); } QApplication::postEvent( m_parent, new RipStatusEvent(RipStatusEvent::kOverallTextEvent, tots)); QApplication::postEvent( m_parent, new RipStatusEvent(RipStatusEvent::kOverallProgressEvent, 0)); QApplication::postEvent( m_parent, new RipStatusEvent(RipStatusEvent::kTrackProgressEvent, 0)); QString textstatus; QString encodertype = gCoreContext->GetSetting("EncoderType"); bool mp3usevbr = gCoreContext->GetNumSetting("Mp3UseVBR", 0); m_totalSectors = 0; m_totalSectorsDone = 0; for (int trackno = 0; trackno < m_tracks->size(); trackno++) { m_totalSectors += getSectorCount(m_CDdevice, trackno + 1); } QApplication::postEvent(m_parent, new RipStatusEvent(RipStatusEvent::kOverallStartEvent, m_totalSectors)); if (LCD *lcd = LCD::Get()) { QString lcd_tots = QObject::tr("Importing ") + tots; QList<LCDTextItem> textItems; textItems.append(LCDTextItem(1, ALIGN_CENTERED, lcd_tots, "Generic", false)); lcd->switchToGeneric(textItems); } Metadata *titleTrack = NULL; QString outfile; std::auto_ptr<Encoder> encoder; for (int trackno = 0; trackno < m_tracks->size(); trackno++) { if (isCancelled()) break; QApplication::postEvent( m_parent, new RipStatusEvent(RipStatusEvent::kStatusTextEvent, QString("Track %1 of %2") .arg(trackno + 1).arg(m_tracks->size()))); QApplication::postEvent( m_parent, new RipStatusEvent(RipStatusEvent::kTrackProgressEvent, 0)); track = m_tracks->at(trackno)->metadata; if (track) { textstatus = track->Title(); QApplication::postEvent( m_parent, new RipStatusEvent( RipStatusEvent::kTrackTextEvent, textstatus)); QApplication::postEvent( m_parent, new RipStatusEvent(RipStatusEvent::kTrackProgressEvent, 0)); QApplication::postEvent( m_parent, new RipStatusEvent(RipStatusEvent::kTrackPercentEvent, 0)); // do we need to start a new file? if (m_tracks->at(trackno)->active) { titleTrack = track; titleTrack->setLength(m_tracks->at(trackno)->length); outfile = Ripper::filenameFromMetadata(track); if (m_quality < 3) { if (encodertype == "mp3") { outfile += ".mp3"; encoder.reset(new LameEncoder(outfile, m_quality, titleTrack, mp3usevbr)); } else // ogg { outfile += ".ogg"; encoder.reset(new VorbisEncoder(outfile, m_quality, titleTrack)); } } else { outfile += ".flac"; encoder.reset(new FlacEncoder(outfile, m_quality, titleTrack)); } if (!encoder->isValid()) { QApplication::postEvent( m_parent, new RipStatusEvent( RipStatusEvent::kEncoderErrorEvent, "Encoder failed to open file for writing")); VERBOSE(VB_IMPORTANT, "MythMusic: Encoder failed" " to open file for writing"); return; } } if (!encoder.get()) { // This should never happen. QApplication::postEvent( m_parent, new RipStatusEvent(RipStatusEvent::kEncoderErrorEvent, "Failed to create encoder")); VERBOSE(VB_IMPORTANT, QString("MythMusic: Error: No encoder, failing")); return; } ripTrack(m_CDdevice, encoder.get(), trackno + 1); if (isCancelled()) return; // save the metadata to the DB if (m_tracks->at(trackno)->active) { titleTrack->setFilename(outfile); titleTrack->dumpToDatabase(); } } } QString PostRipCDScript = gCoreContext->GetSetting("PostCDRipScript"); if (!PostRipCDScript.isEmpty()) myth_system(PostRipCDScript); QApplication::postEvent( m_parent, new RipStatusEvent(RipStatusEvent::kFinishedEvent, "")); }
bool Ripper::deleteExistingTrack(RipTrack *track) { if (!track) return false; Metadata *metadata = track->metadata; if (!metadata) return false; QString artist = metadata->Artist(); QString album = metadata->Album(); QString title = metadata->Title(); MSqlQuery query(MSqlQuery::InitCon()); QString queryString("SELECT song_id, " "CONCAT_WS('/', music_directories.path, music_songs.filename) AS filename " "FROM music_songs " "LEFT JOIN music_artists" " ON music_songs.artist_id=music_artists.artist_id " "LEFT JOIN music_albums" " ON music_songs.album_id=music_albums.album_id " "LEFT JOIN music_directories " " ON music_songs.directory_id=music_directories.directory_id " "WHERE artist_name REGEXP \'"); QString token = artist; token.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"), QString(".")); queryString += token + "\' AND " + "album_name REGEXP \'"; token = album; token.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"), QString(".")); queryString += token + "\' AND " + "name REGEXP \'"; token = title; token.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"), QString(".")); queryString += token + "\' ORDER BY artist_name, album_name," " name, song_id, filename LIMIT 1"; query.prepare(queryString); if (!query.exec() || !query.isActive()) { MythDB::DBError("Search music database", query); return false; } if (query.next()) { int trackID = query.value(0).toInt(); QString filename = gMusicData->musicDir + query.value(1).toString(); // delete file if (!QFile::remove(filename)) { LOG(VB_GENERAL, LOG_NOTICE, QString("Ripper::deleteExistingTrack() " "Could not delete %1") .arg(filename)); return false; } // remove database entry MSqlQuery deleteQuery(MSqlQuery::InitCon()); deleteQuery.prepare("DELETE FROM music_songs" " WHERE song_id = :SONG_ID"); deleteQuery.bindValue(":SONG_ID", trackID); if (!deleteQuery.exec()) { MythDB::DBError("Delete Track", deleteQuery); return false; } return true; } return false; }
void Ripper::ScanFinished() { delete m_scanThread; m_scanThread = NULL; m_tracks->clear(); bool isCompilation = false; if (m_decoder) { QString label; Metadata *metadata; m_artistName.clear(); m_albumName.clear(); m_genreName.clear(); m_year.clear(); for (int trackno = 0; trackno < m_decoder->getNumTracks(); trackno++) { RipTrack *ripTrack = new RipTrack; metadata = m_decoder->getMetadata(trackno + 1); if (metadata) { ripTrack->metadata = metadata; ripTrack->length = metadata->Length(); if (metadata->Compilation()) { isCompilation = true; m_artistName = metadata->CompilationArtist(); } else if (m_artistName.isEmpty()) { m_artistName = metadata->Artist(); } if (m_albumName.isEmpty()) m_albumName = metadata->Album(); if (m_genreName.isEmpty() && !metadata->Genre().isEmpty()) m_genreName = metadata->Genre(); if (m_year.isEmpty() && metadata->Year() > 0) m_year = QString::number(metadata->Year()); QString title = metadata->Title(); ripTrack->isNew = isNewTune(m_artistName, m_albumName, title); ripTrack->active = ripTrack->isNew; m_tracks->push_back(ripTrack); } else delete ripTrack; } m_artistEdit->SetText(m_artistName); m_albumEdit->SetText(m_albumName); m_genreEdit->SetText(m_genreName); m_yearEdit->SetText(m_year); m_compilationCheck->SetCheckState(isCompilation); if (!isCompilation) m_switchTitleArtist->SetVisible(false); else m_switchTitleArtist->SetVisible(true); } BuildFocusList(); updateTrackList(); CloseBusyPopup(); }
void ImportMusicDialog::addPressed() { if (m_tracks->size() == 0) return; Metadata *meta = m_tracks->at(m_currentTrack)->metadata; // is the current track a new file? if (m_tracks->at(m_currentTrack)->isNewTune) { // get the save filename - this also creates the correct directory stucture QString saveFilename = Ripper::filenameFromMetadata(meta); // we need to manually copy the file extension QFileInfo fi(meta->Filename()); saveFilename += "." + fi.suffix(); // copy the file to the new location if (!copyFile(meta->Filename(), saveFilename)) { ShowOkPopup(tr("Copy Failed\nCould not copy file to: %1") .arg(saveFilename)); return; } meta->setFilename(saveFilename); // do we need to update the tags? if (m_tracks->at(m_currentTrack)->metadataHasChanged) { Decoder *decoder = Decoder::create(saveFilename, NULL, NULL, true); if (decoder) { decoder->commitMetadata(meta); delete decoder; } } // update the database meta->dumpToDatabase(); // read any embedded images from the tag MetaIO *tagger = meta->getTagger(); if (tagger && tagger->supportsEmbeddedImages()) { AlbumArtList artList = tagger->getAlbumArtList(meta->Filename()); meta->setEmbeddedAlbumArt(artList); meta->getAlbumArtImages()->dumpToDatabase(); } m_somethingWasImported = true; m_tracks->at(m_currentTrack)->isNewTune = Ripper::isNewTune( meta->Artist(), meta->Album(), meta->Title()); // update the UI fillWidgets(); } else ShowOkPopup(tr("This track is already in the database")); }
int Playlist::writeTree(GenericTree *tree_to_write_to, int a_counter) { // compute max/min playcount,lastplay for this playlist int playcountMin = 0; int playcountMax = 0; double lastplayMin = 0.0; double lastplayMax = 0.0; typedef map<QString, uint32_t> AlbumMap; AlbumMap album_map; AlbumMap::iterator Ialbum; QString album; typedef map<QString, uint32_t> ArtistMap; ArtistMap artist_map; ArtistMap::iterator Iartist; QString artist; uint idx = 0; SongList::const_iterator it = songs.begin(); for (; it != songs.end(); ++it, ++idx) { if (!(*it)->getCDFlag()) { if ((*it)->getValue() == 0) { VERBOSE(VB_IMPORTANT, LOC_ERR + kID0err); } if ((*it)->getValue() > 0) { // Normal track Metadata *tmpdata = all_available_music->getMetadata((*it)->getValue()); if (tmpdata) { if (tmpdata->isVisible()) { if (0 == idx) { // first song playcountMin = playcountMax = tmpdata->PlayCount(); lastplayMin = lastplayMax = tmpdata->LastPlay().toTime_t(); } else { if (tmpdata->PlayCount() < playcountMin) playcountMin = tmpdata->PlayCount(); else if (tmpdata->PlayCount() > playcountMax) playcountMax = tmpdata->PlayCount(); if (tmpdata->LastPlay().toTime_t() < lastplayMin) lastplayMin = tmpdata->LastPlay().toTime_t(); else if (tmpdata->LastPlay().toTime_t() > lastplayMax) lastplayMax = tmpdata->LastPlay().toTime_t(); } } // pre-fill the album-map with the album name. // This allows us to do album mode in album order album = tmpdata->Album(); // pre-fill the artist map with the artist name and song title artist = tmpdata->Artist() + "~" + tmpdata->Title(); } if ((Ialbum = album_map.find(album)) == album_map.end()) album_map.insert(AlbumMap::value_type(album,0)); if ((Iartist = artist_map.find(artist)) == artist_map.end()) artist_map.insert(ArtistMap::value_type(artist,0)); } } } // populate the sort id into the album map uint32_t album_count = 1; for (Ialbum = album_map.begin(); Ialbum != album_map.end(); Ialbum++) { Ialbum->second = album_count; album_count++; } // populate the sort id into the artist map uint32_t count = 1; for (Iartist = artist_map.begin(); Iartist != artist_map.end(); Iartist++) { Iartist->second = count; count++; } int RatingWeight = 2; int PlayCountWeight = 2; int LastPlayWeight = 2; int RandomWeight = 2; parent->FillIntelliWeights(RatingWeight, PlayCountWeight, LastPlayWeight, RandomWeight); for (it = songs.begin(); it != songs.end(); ++it) { if (!(*it)->getCDFlag()) { if ((*it)->getValue() == 0) { VERBOSE(VB_IMPORTANT, LOC_ERR + kID0err); } if ((*it)->getValue() > 0) { // Normal track Metadata *tmpdata = all_available_music->getMetadata((*it)->getValue()); if (tmpdata && tmpdata->isVisible()) { QString a_string = QString("%1 ~ %2") .arg(tmpdata->FormatArtist()) .arg(tmpdata->FormatTitle()); GenericTree *added_node = tree_to_write_to->addNode( a_string, (*it)->getValue(), true); ++a_counter; added_node->setAttribute(0, 1); added_node->setAttribute(1, a_counter); // regular order added_node->setAttribute(2, rand()); // random order // // Compute "intelligent" weighting // int rating = tmpdata->Rating(); int playcount = tmpdata->PlayCount(); double lastplaydbl = tmpdata->LastPlay().toTime_t(); double ratingValue = (double)(rating) / 10; double playcountValue, lastplayValue; if (playcountMax == playcountMin) playcountValue = 0; else playcountValue = ((playcountMin - (double)playcount) / (playcountMax - playcountMin) + 1); if (lastplayMax == lastplayMin) lastplayValue = 0; else lastplayValue = ((lastplayMin - lastplaydbl) / (lastplayMax - lastplayMin) + 1); double rating_value = (RatingWeight * ratingValue + PlayCountWeight * playcountValue + LastPlayWeight * lastplayValue + RandomWeight * (double)rand() / (RAND_MAX + 1.0)); uint32_t integer_rating = (int) (4000001 - rating_value * 10000); // "intelligent" order added_node->setAttribute(3, integer_rating); // "intellegent/album" order uint32_t album_order; album = tmpdata->Album(); if ((Ialbum = album_map.find(album)) == album_map.end()) { // we didn't find this album in the map, // yet we pre-loaded them all. we are broken, // but we just set the track order to 1, since there // is no real point in reporting an error album_order = 1; } else { album_order = Ialbum->second * 100; } album_order += tmpdata->Track(); added_node->setAttribute(4, album_order); // "artist" order, sorts by artist name then track title // uses the pre-prepared artist map to do this uint32_t integer_order; artist = tmpdata->Artist() + "~" + tmpdata->Title(); if ((Iartist = artist_map.find(artist)) == artist_map.end()) { // we didn't find this track in the map, // yet we pre-loaded them all. we are broken, // but we just set the track order to 1, since there // is no real point in reporting an error integer_order = 1; } else { integer_order = Iartist->second; } added_node->setAttribute(5, integer_order); } } if ((*it)->getValue() < 0) { // it's a playlist, recurse (mildly) Playlist *level_down = parent->getPlaylist(((*it)->getValue()) * -1); if (level_down) { a_counter = level_down->writeTree(tree_to_write_to, a_counter); } } } else { Metadata *tmpdata = all_available_music->getMetadata((*it)->getValue()); if (tmpdata) { QString a_string = QString("(CD) %1 ~ %2") .arg(tmpdata->FormatArtist()).arg(tmpdata->FormatTitle()); if (tmpdata->FormatArtist().length() < 1 || tmpdata->FormatTitle().length() < 1) { a_string = QString("(CD) Track %1").arg(tmpdata->Track()); } GenericTree *added_node = tree_to_write_to->addNode(a_string, (*it)->getValue(), true); ++a_counter; added_node->setAttribute(0, 1); added_node->setAttribute(1, a_counter); // regular order added_node->setAttribute(2, rand()); // random order added_node->setAttribute(3, rand()); // "intelligent" order } } } return a_counter; }
/** * Lookup FreeDB/CDDB, populate m_mData with results */ void CdDecoder::lookupCDDB(const QString &hexID, uint totalTracks) { QString helloID = getenv("USER"); QString queryID = "cddb+query+"; uint trk; if (helloID.isEmpty()) helloID = "anon"; helloID += QString("+%1+MythTV+%2+") .arg(gCoreContext->GetHostName()).arg(MYTH_BINARY_VERSION); queryID += QString("%1+%2+").arg(hexID).arg(totalTracks); for (trk = 0; trk < totalTracks; ++trk) queryID += QString::number(m_tracks[trk]) + '+'; queryID += QString::number(m_lengthInSecs); // First, try HTTP: QString URL = "http://freedb.freedb.org/~cddb/cddb.cgi?cmd="; QString URL2 = URL + queryID + "&hello=" + helloID + "&proto=5"; QString cddb = HttpComms::getHttp(URL2); #if 0 LOG(VB_MEDIA, LOG_INFO, "CDDB lookup: " + URL2); LOG(VB_MEDIA, LOG_INFO, "...returned: " + cddb); #endif // // e.g. "200 rock 960b5e0c Nichole Nordeman / Woven & Spun" // Extract/remove 3 digit status: uint stat = cddb.left(3).toUInt(); cddb = cddb.mid(4); // We should check for errors here, and possibly do a CDDB lookup // (telnet 8880) if it failed, but Nigel is feeling lazy. if (stat == 210 || stat == 211) // Multiple matches { // e.g. 210 Found exact matches, list follows (until terminating `.') // folk 9c09590b Michael W Smith / Stand // misc 9c09590b Michael W. Smith / Stand // rock 9c09590b Michael W. Smith / Stand // classical 9c09590b Michael W. Smith / Stand // . // TODO // Parse disks, put up dialog box, select disk, prune cddb to selected LOG(VB_MEDIA, LOG_INFO, "Multiple CDDB matches. Please implement this code"); // For now, we just choose the first match. //int EOL = cddb.indexOf('\n'); cddb.remove(0, cddb.indexOf('\n')); LOG(VB_MEDIA, LOG_INFO, "String now: " + cddb); stat = 200; } if (stat == 200) // One unique match { QString album; QString artist; bool compn = false; QString genre = cddb.section(' ', 0, 0); int year = 0; // Now we can lookup all its details: URL2 = URL + "cddb+read+" + genre + "+" + hexID + "&hello=" + helloID + "&proto=5"; cddb = HttpComms::getHttp(URL2); #if 0 LOG(VB_MEDIA, LOG_INFO, "CDDB detail: " + URL2); LOG(VB_MEDIA, LOG_INFO, "...returned: " + cddb); #endif // Successful lookup. // Clear current titles (filenames), because we append to them for (trk = 0; trk < totalTracks; ++trk) m_mData[trk]->setTitle(""); // Parse returned data: cddb.replace(QRegExp(".*#"), ""); // Remove comment block while (cddb.length()) { // Lines should be of the form "FIELD=value\r\n" QString art; QString line = cddb.section(QRegExp("(\r|\n)+"), 0, 0); QString value = line.section('=', 1, 1); if (value.contains(" / ")) { art = value.section(" / ", 0, 0); // Artist in *TITLE value = value.section(" / ", 1, 1); } if (line.startsWith("DGENRE=")) genre = value; else if (line.startsWith("DYEAR=")) year = value.toInt(); else if (line.startsWith("DTITLE=")) { // Albums (and maybe artists?) can wrap over multiple lines: artist += art; album += value; } else if (line.startsWith("TTITLE")) { trk = line.remove("TTITLE").remove(QRegExp("=.*")).toUInt(); if (trk < totalTracks) { Metadata *m = m_mData[trk]; // Titles can wrap over multiple lines, so we load+store: m->setTitle(m->Title() + value); if (art.length()) { compn = true; // Probably a compilation m->setArtist(M_QSTRING_UNICODE(art)); } } else LOG(VB_GENERAL, LOG_INFO, QString("CDDB returned %1 on a %2 track disk!") .arg(trk+1).arg(totalTracks)); } // Get next THINGY=value line: cddb = cddb.section('\n', 1, 0xffffffff); } for (trk = 0; trk < totalTracks; ++trk) { Metadata *m = m_mData[trk]; if (compn) m->setCompilation(true); m->setGenre(M_QSTRING_UNICODE(genre)); if (year) m->setYear(year); if (album.length()) m->setAlbum(M_QSTRING_UNICODE(album)); if (artist.length()) if (compn) m->setCompilationArtist(M_QSTRING_UNICODE(artist)); else m->setArtist(M_QSTRING_UNICODE(artist)); } } }