TreeItem* ITunesFeature::parsePlaylists(QXmlStreamReader &xml) { qDebug() << "Parse iTunes playlists"; TreeItem* rootItem = new TreeItem(); QSqlQuery query_insert_to_playlists(m_database); query_insert_to_playlists.prepare("INSERT INTO itunes_playlists (id, name) " "VALUES (:id, :name)"); QSqlQuery query_insert_to_playlist_tracks(m_database); query_insert_to_playlist_tracks.prepare( "INSERT INTO itunes_playlist_tracks (playlist_id, track_id, position) " "VALUES (:playlist_id, :track_id, :position)"); while (!xml.atEnd() && !m_cancelImport) { xml.readNext(); //We process and iterate the <dict> tags holding playlist summary information here if (xml.isStartElement() && xml.name() == "dict") { parsePlaylist(xml, query_insert_to_playlists, query_insert_to_playlist_tracks, rootItem); continue; } if (xml.isEndElement()) { if (xml.name() == "array") break; } } return rootItem; }
// Purpose: Parsing all the folder and playlists of Traktor // This is a complex operation since Traktor uses the concept of folders and playlist. // A folder can contain folders and playlists. A playlist contains entries but no folders. // In other words, Traktor uses a tree structure to organize music. // Inner nodes represent folders while leaves are playlists. TreeItem* TraktorFeature::parsePlaylists(QXmlStreamReader &xml) { qDebug() << "Process RootFolder"; //Each playlist is unique and can be identified by a path in the tree structure. QString current_path = ""; QMap<QString,QString> map; QString delimiter = "-->"; TreeItem *rootItem = new TreeItem(); TreeItem * parent = rootItem; bool inPlaylistTag = false; QSqlQuery query_insert_to_playlists(m_database); query_insert_to_playlists.prepare("INSERT INTO traktor_playlists (name) " "VALUES (:name)"); QSqlQuery query_insert_to_playlist_tracks(m_database); query_insert_to_playlist_tracks.prepare( "INSERT INTO traktor_playlist_tracks (playlist_id, track_id, position) " "VALUES (:playlist_id, :track_id, :position)"); while (!xml.atEnd() && !m_cancelImport) { //read next XML element xml.readNext(); if (xml.isStartElement()) { if (xml.name() == "NODE") { QXmlStreamAttributes attr = xml.attributes(); QString name = attr.value("NAME").toString(); QString type = attr.value("TYPE").toString(); //TODO: What happens if the folder node is a leaf (empty folder) // Idea: Hide empty folders :-) if (type == "FOLDER") { current_path += delimiter; current_path += name; //qDebug() << "Folder: " +current_path << " has parent " << parent->data().toString(); map.insert(current_path, "FOLDER"); TreeItem * item = new TreeItem(name,current_path, this, parent); parent->appendChild(item); parent = item; } if (type == "PLAYLIST") { current_path += delimiter; current_path += name; //qDebug() << "Playlist: " +current_path << " has parent " << parent->data().toString(); map.insert(current_path, "PLAYLIST"); TreeItem * item = new TreeItem(name,current_path, this, parent); parent->appendChild(item); // process all the entries within the playlist 'name' having path 'current_path' parsePlaylistEntries(xml, current_path, query_insert_to_playlists, query_insert_to_playlist_tracks); } } if (xml.name() == "ENTRY" && inPlaylistTag) { } } if (xml.isEndElement()) { if (xml.name() == "NODE") { if (map.value(current_path) == "FOLDER") { parent = parent->parent(); } //Whenever we find a closing NODE, remove the last component of the path int lastSlash = current_path.lastIndexOf (delimiter); int path_length = current_path.size(); current_path.remove(lastSlash, path_length - lastSlash); } if (xml.name() == "PLAYLIST") { inPlaylistTag = false; } //We leave the infinte loop, if twe have the closing "PLAYLIST" tag if (xml.name() == "PLAYLISTS") { break; } } } return rootItem; }
TreeItem* RhythmboxFeature::importPlaylists() { QFile db(QDir::homePath() + "/.gnome2/rhythmbox/playlists.xml"); if ( ! db.exists()) { db.setFileName(QDir::homePath() + "/.local/share/rhythmbox/playlists.xml"); if (!db.exists()) return NULL; } //Open file if (!db.open(QIODevice::ReadOnly | QIODevice::Text)) return NULL; QSqlQuery query_insert_to_playlists(m_database); query_insert_to_playlists.prepare("INSERT INTO rhythmbox_playlists (id, name) " "VALUES (:id, :name)"); QSqlQuery query_insert_to_playlist_tracks(m_database); query_insert_to_playlist_tracks.prepare( "INSERT INTO rhythmbox_playlist_tracks (playlist_id, track_id, position) " "VALUES (:playlist_id, :track_id, :position)"); //The tree structure holding the playlists TreeItem* rootItem = new TreeItem(); QXmlStreamReader xml(&db); while (!xml.atEnd() && !m_cancelImport) { xml.readNext(); if (xml.isStartElement() && xml.name() == "playlist") { QXmlStreamAttributes attr = xml.attributes(); //Only parse non build-in playlists if (attr.value("type").toString() == "static") { QString playlist_name = attr.value("name").toString(); //Construct the childmodel TreeItem * item = new TreeItem(playlist_name, playlist_name, this, rootItem); rootItem->appendChild(item); //Execute SQL statement query_insert_to_playlists.bindValue(":name", playlist_name); if (!query_insert_to_playlists.exec()) { LOG_FAILED_QUERY(query_insert_to_playlists) << "Couldn't insert playlist:" << playlist_name; continue; } // get playlist_id int playlist_id = query_insert_to_playlists.lastInsertId().toInt(); //Process playlist entries importPlaylist(xml, query_insert_to_playlist_tracks, playlist_id); } } } if (xml.hasError()) { // do error handling qDebug() << "Cannot process Rhythmbox music collection"; qDebug() << "XML ERROR: " << xml.errorString(); return NULL; } db.close(); return rootItem; }