Beispiel #1
0
/** Do a non-recursive import of all the songs in a directory. Does NOT decend into subdirectories.
    @param trackDao The track data access object which provides a connection to the database. We use this parameter in order to make this function callable from separate threads. You need to use a different DB connection for each thread.
    @return true if the scan completed without being cancelled. False if the scan was cancelled part-way through.
*/
bool TrackCollection::importDirectory(const QString& directory, TrackDAO& trackDao,
                                      const QStringList& nameFilters,
                                      volatile bool* cancel) {
    //qDebug() << "TrackCollection::importDirectory(" << directory<< ")";

    emit(startedLoading());
    // QFileInfoList files;

    //get a list of the contents of the directory and go through it.
    QDirIterator it(directory, nameFilters, QDir::Files | QDir::NoDotAndDotDot);
    while (it.hasNext()) {

        //If a flag was raised telling us to cancel the library scan then stop.
        if (*cancel) {
            return false;
        }

        QString absoluteFilePath = it.next();

        // If the track is in the database, mark it as existing. This code gets exectuted
        // when other files in the same directory have changed (the directory hash has changed).
        trackDao.markTrackLocationAsVerified(absoluteFilePath);

        // If the file already exists in the database, continue and go on to
        // the next file.

        // If the file doesn't already exist in the database, then add
        // it. If it does exist in the database, then it is either in the
        // user's library OR the user has "removed" the track via
        // "Right-Click -> Remove". These tracks stay in the library, but
        // their mixxx_deleted column is 1.
        if (!trackDao.trackExistsInDatabase(absoluteFilePath)) {
            //qDebug() << "Loading" << it.fileName();
            emit(progressLoading(it.fileName()));

            TrackPointer pTrack = TrackPointer(new TrackInfoObject(
                                                   absoluteFilePath), &QObject::deleteLater);

            if (trackDao.addTracksAdd(pTrack.data(), false)) {
                // Successful added
                // signal the main instance of TrackDao, that there is a
                // new Track in the database
                m_trackDao->databaseTrackAdded(pTrack);
            } else {
                qDebug() << "Track ("+absoluteFilePath+") could not be added";
            }
        }
    }
    emit(finishedLoading());
    return true;
}
Beispiel #2
0
LibraryScanner::LibraryScanner(QWidget* pParentWidget, TrackCollection* collection)
              : m_pCollection(collection),
                m_libraryHashDao(m_database),
                m_cueDao(m_database),
                m_playlistDao(m_database),
                m_crateDao(m_database),
                m_directoryDao(m_database),
                m_analysisDao(m_database, collection->getConfig()),
                m_trackDao(m_database, m_cueDao, m_playlistDao,
                           m_crateDao, m_analysisDao, m_libraryHashDao,
                           collection->getConfig()) {
    // Don't initialize m_database here, we need to do it in run() so the DB
    // conn is in the right thread.
    qDebug() << "Starting LibraryScanner thread.";

    // Move LibraryScanner to its own thread so that our signals/slots will
    // queue to our event loop.
    moveToThread(this);
    m_pool.moveToThread(this);

    unsigned static id = 0; // the id of this LibraryScanner, for debugging purposes
    setObjectName(QString("LibraryScanner %1").arg(++id));

    m_pool.setMaxThreadCount(kScannerThreadPoolSize);

    // Listen to signals from our public methods (invoked by other threads) and
    // connect them to our slots to run the command on the scanner thread.
    connect(this, SIGNAL(startScan()),
            this, SLOT(slotStartScan()));

    // Force the GUI thread's TrackInfoObject cache to be cleared when a library
    // scan is finished, because we might have modified the database directly
    // when we detected moved files, and the TIOs corresponding to the moved
    // files would then have the wrong track location.
    connect(this, SIGNAL(scanFinished()),
            &(collection->getTrackDAO()), SLOT(clearCache()));
    connect(this, SIGNAL(trackAdded(TrackPointer)),
            &(collection->getTrackDAO()), SLOT(databaseTrackAdded(TrackPointer)));
    connect(this, SIGNAL(tracksMoved(QSet<int>, QSet<int>)),
            &(collection->getTrackDAO()), SLOT(databaseTracksMoved(QSet<int>, QSet<int>)));
    connect(this, SIGNAL(tracksChanged(QSet<int>)),
            &(collection->getTrackDAO()), SLOT(databaseTracksChanged(QSet<int>)));

    // Parented to pParentWidget so we don't need to delete it.
    LibraryScannerDlg* pProgress = new LibraryScannerDlg(pParentWidget);
    connect(this, SIGNAL(progressLoading(QString)),
            pProgress, SLOT(slotUpdate(QString)));
    connect(this, SIGNAL(progressHashing(QString)),
            pProgress, SLOT(slotUpdate(QString)));
    connect(this, SIGNAL(scanStarted()),
            pProgress, SLOT(slotScanStarted()));
    connect(this, SIGNAL(scanFinished()),
            pProgress, SLOT(slotScanFinished()));
    connect(pProgress, SIGNAL(scanCancelled()),
            this, SLOT(cancel()));
    connect(&m_trackDao, SIGNAL(progressVerifyTracksOutside(QString)),
            pProgress, SLOT(slotUpdate(QString)));
    connect(&m_trackDao, SIGNAL(progressCoverArt(QString)),
            pProgress, SLOT(slotUpdateCover(QString)));

    start();
}
Beispiel #3
0
void LibraryScanner::slotStartScan() {
    qDebug() << "LibraryScanner::slotStartScan";
    QSet<QString> trackLocations = m_trackDao.getTrackLocations();
    QHash<QString, int> directoryHashes = m_libraryHashDao.getDirectoryHashes();
    QRegExp extensionFilter =
            QRegExp(SoundSourceProxy::supportedFileExtensionsRegex(),
                    Qt::CaseInsensitive);
    QRegExp coverExtensionFilter =
            QRegExp(CoverArtUtils::supportedCoverArtExtensionsRegex(),
                    Qt::CaseInsensitive);
    QStringList directoryBlacklist = ScannerUtil::getDirectoryBlacklist();

    m_scannerGlobal = ScannerGlobalPointer(
        new ScannerGlobal(trackLocations, directoryHashes, extensionFilter,
                          coverExtensionFilter, directoryBlacklist));
    m_scannerGlobal->startTimer();

    emit(scanStarted());

    // Try to upgrade the library from 1.7 (XML) to 1.8+ (DB) if needed. If the
    // upgrade_filename already exists, then do not try to upgrade since we have
    // already done it.
    // TODO(XXX) SETTINGS_PATH may change in new Mixxx Versions. Here we need
    // the SETTINGS_PATH from Mixxx V <= 1.7
    QString upgrade_filename = QDir::homePath().append("/").append(SETTINGS_PATH).append("DBUPGRADED");
    qDebug() << "upgrade filename is " << upgrade_filename;
    QFile upgradefile(upgrade_filename);
    if (!upgradefile.exists()) {
        QTime t2;
        t2.start();
        LegacyLibraryImporter libImport(m_trackDao, m_playlistDao);
        connect(&libImport, SIGNAL(progress(QString)),
                this, SIGNAL(progressLoading(QString)));
        ScopedTransaction transaction(m_database);
        libImport.import();
        transaction.commit();
        qDebug("Legacy importer took %d ms", t2.elapsed());
    }

    // First, we're going to mark all the directories that we've previously
    // hashed as needing verification. As we search through the directory tree
    // when we rescan, we'll mark any directory that does still exist as
    // verified.
    m_libraryHashDao.invalidateAllDirectories();

    // Mark all the tracks in the library as needing verification of their
    // existence. (ie. we want to check they're still on your hard drive where
    // we think they are)
    m_trackDao.invalidateTrackLocationsInLibrary();

    qDebug() << "Recursively scanning library.";

    // Start scanning the library. This prepares insertion queries in TrackDAO
    // (must be called before calling addTracksAdd) and begins a transaction.
    m_trackDao.addTracksPrepare();

    // Recursivly scan each directory in the directories table.
    QStringList dirs = m_directoryDao.getDirs();

    // If there are no directories then we have nothing to do. Cleanup and
    // finish the scan immediately.
    if (dirs.isEmpty()) {
        slotFinishScan();
        return;
    }

    // Queue up recursive scan tasks for every directory. When all tasks are
    // done, TaskWatcher will signal slotFinishScan.
    TaskWatcher* pWatcher = &m_scannerGlobal->getTaskWatcher();
    connect(pWatcher, SIGNAL(allTasksDone()),
            this, SLOT(slotFinishScan()));

    foreach (const QString& dirPath, dirs) {
        // Acquire a security bookmark for this directory if we are in a
        // sandbox. For speed we avoid opening security bookmarks when recursive
        // scanning so that relies on having an open bookmark for the containing
        // directory.
        MDir dir(dirPath);

        queueTask(new RecursiveScanDirectoryTask(this, m_scannerGlobal, dir.dir(),
                                                 dir.token()));
    }