Go to the documentation of this file.
21 query.
prepare(
"SELECT directory_id, path FROM music_directories");
31 query.
prepare(
"SELECT genre_id, LOWER(genre) FROM music_genres");
41 query.
prepare(
"SELECT artist_id, LOWER(artist_name) FROM music_artists");
51 query.
prepare(
"SELECT album_id, artist_id, LOWER(album_name) FROM music_albums");
80 d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
82 QFileInfoList list =
d.entryInfoList();
88 for (
const auto& fi : qAsConst(list))
90 QString
filename = fi.absoluteFilePath();
110 LOG(VB_GENERAL, LOG_ERR,
111 QString(
"Failed to get directory id for path %1")
136 LOG(VB_GENERAL, LOG_INFO,
137 QString(
"Found file with unsupported extension %1")
147 QString extension = fi.suffix().toLower();
151 return !extension.isEmpty() && nameFilter.indexOf(extension.toLower()) > -1;
157 QString extension = fi.suffix().toLower();
160 return !extension.isEmpty() && nameFilter.indexOf(extension.toLower()) > -1;
175 if (directory.isEmpty())
181 query.
prepare(
"SELECT directory_id FROM music_directories "
182 "WHERE path = BINARY :DIRECTORY ;");
198 query.
prepare(
"INSERT INTO music_directories (path, parent_id) "
199 "VALUES (:DIRECTORY, :PARENTID);");
221 const QString &
filename,
const QString &date_modified)
224 QDateTime dt = fi.lastModified();
228 return !old_dt.isValid() || (dt > old_dt);
230 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to stat file: %1")
252 QString extension =
filename.section(
'.', -1 ) ;
254 directory.remove(0, startDir.length());
255 directory = directory.section(
'/', 0, -2);
260 if (nameFilter.indexOf(extension.toLower()) > -1)
262 QString name =
filename.section(
'/', -1);
266 "SET filename = :FILE, directory_id = :DIRID, "
267 "imagetype = :TYPE, hostname = :HOSTNAME;");
286 LOG(VB_GENERAL, LOG_WARNING, QString(
"Ignoring filename with unsupported filename: '%1'").
arg(
filename));
290 LOG(VB_FILE, LOG_INFO, QString(
"Reading metadata from %1").
arg(
filename));
297 QString album_cache_string;
310 album_cache_string = QString::number(data->
getArtistId()) +
"#"
311 + data->
Album().toLower();
338 album_cache_string = QString::number(data->
getArtistId()) +
"#"
339 + data->
Album().toLower();
370 LOG(VB_GENERAL, LOG_INFO,
"Cleaning old entries from music database");
376 if (!
query.
exec(
"SELECT g.genre_id FROM music_genres g "
377 "LEFT JOIN music_songs s ON g.genre_id=s.genre_id "
378 "WHERE s.genre_id IS NULL;"))
381 deletequery.
prepare(
"DELETE FROM music_genres WHERE genre_id=:GENREID");
385 deletequery.
bindValue(
":GENREID", genreid);
386 if (!deletequery.
exec())
392 if (!
query.
exec(
"SELECT a.album_id FROM music_albums a "
393 "LEFT JOIN music_songs s ON a.album_id=s.album_id "
394 "WHERE s.album_id IS NULL;"))
397 deletequery.
prepare(
"DELETE FROM music_albums WHERE album_id=:ALBUMID");
401 deletequery.
bindValue(
":ALBUMID", albumid);
402 if (!deletequery.
exec())
408 if (!
query.
exec(
"SELECT a.artist_id FROM music_artists a "
409 "LEFT JOIN music_songs s ON a.artist_id=s.artist_id "
410 "LEFT JOIN music_albums l ON a.artist_id=l.artist_id "
411 "WHERE s.artist_id IS NULL AND l.artist_id IS NULL"))
415 deletequery.
prepare(
"DELETE FROM music_artists WHERE artist_id=:ARTISTID");
419 deletequery.
bindValue(
":ARTISTID", artistid);
420 if (!deletequery.
exec())
427 if (!
query.
exec(
"SELECT d.directory_id, d.parent_id FROM music_directories d "
428 "LEFT JOIN music_songs s ON d.directory_id=s.directory_id "
429 "WHERE s.directory_id IS NULL ORDER BY directory_id DESC;"))
432 deletequery.
prepare(
"DELETE FROM music_directories WHERE directory_id=:DIRECTORYID");
435 parentquery.
prepare(
"SELECT COUNT(*) FROM music_directories "
436 "WHERE parent_id=:DIRECTORYID ");
438 int deletedCount = 0;
454 parentquery.
bindValue(
":DIRECTORYID", directoryid);
455 if (!parentquery.
exec())
456 MythDB::DBError(
"MusicFileScanner::cleanDB - get parent directory count",
459 if (parentquery.
next())
461 int parentCount = parentquery.
value(0).toInt();
463 if (parentCount == 0)
465 deletequery.
bindValue(
":DIRECTORYID", directoryid);
466 if (!deletequery.
exec())
467 MythDB::DBError(
"MusicFileScanner::cleanDB - delete music_directories",
476 }
while (deletedCount > 0);
479 if (!
query.
exec(
"SELECT a.albumart_id FROM music_albumart a LEFT JOIN "
480 "music_songs s ON a.song_id=s.song_id WHERE "
481 "embedded='1' AND s.song_id IS NULL;"))
484 deletequery.
prepare(
"DELETE FROM music_albumart WHERE albumart_id=:ALBUMARTID");
488 deletequery.
bindValue(
":ALBUMARTID", albumartid);
489 if (!deletequery.
exec())
508 sqlfilename.remove(0, startDir.length());
510 QString directory = sqlfilename.section(
'/', 0, -2 ) ;
511 sqlfilename = sqlfilename.section(
'/', -1 ) ;
513 QString extension = sqlfilename.section(
'.', -1 ) ;
516 "*.png;*.jpg;*.jpeg;*.gif;*.bmp");
518 if (nameFilter.indexOf(extension.toLower()) > -1)
521 query.
prepare(
"DELETE FROM music_albumart WHERE filename= :FILE AND "
522 "directory_id= :DIRID;");
537 query.
prepare(
"DELETE FROM music_songs WHERE filename = :NAME ;");
540 MythDB::DBError(
"MusicFileScanner::RemoveFileFromDB - deleting music_songs",
559 dbFilename.remove(0, startDir.length());
562 directory.remove(0, startDir.length());
563 directory = directory.section(
'/', 0, -2);
568 if (db_meta && disk_meta)
570 if (db_meta->
ID() <= 0)
572 LOG(VB_GENERAL, LOG_ERR, QString(
"Asked to update track with "
574 .
arg(db_meta->
ID()));
580 disk_meta->
setID(db_meta->
ID());
585 QString album_cache_string;
598 album_cache_string = QString::number(disk_meta->
getArtistId()) +
"#" +
599 disk_meta->
Album().toLower();
627 album_cache_string = QString::number(disk_meta->
getArtistId()) +
"#" +
628 disk_meta->
Album().toLower();
654 if (!lastRun.isEmpty())
657 if (dtLastRun.isValid())
661 LOG(VB_GENERAL, LOG_INFO,
"Music file scanner has been running for more than 60 minutes. Lets reset and try again");
669 LOG(VB_GENERAL, LOG_INFO,
"Music file scanner is already running");
679 LOG(VB_GENERAL, LOG_INFO,
"Music file scanner started");
683 QString status = QString(
"running");
691 MusicLoadedMap::Iterator iter;
693 for (
int x = 0; x <
dirList.count(); x++)
697 LOG(VB_GENERAL, LOG_INFO, QString(
"Searching '%1' for music files").
arg(startDir));
708 LOG(VB_GENERAL, LOG_INFO,
"Updating database");
723 for (iter = music_files.begin(); iter != music_files.end(); iter++)
736 for (iter = art_files.begin(); iter != art_files.end(); iter++)
752 QString trackStatus = QString(
"total tracks found: %1 (unchanged: %2, added: %3, removed: %4, updated %5)")
755 QString coverartStatus = QString(
"total coverart found: %1 (unchanged: %2, added: %3, removed: %4, updated %5)")
760 LOG(VB_GENERAL, LOG_INFO,
"Music file scanner finished ");
761 LOG(VB_GENERAL, LOG_INFO, trackStatus);
762 LOG(VB_GENERAL, LOG_INFO, coverartStatus);
769 status = QString(
"success - %1 - %2").arg(trackStatus).arg(coverartStatus);
782 MusicLoadedMap::Iterator iter;
785 query.
prepare(
"SELECT CONCAT_WS('/', path, filename), date_modified "
786 "FROM music_songs LEFT JOIN music_directories ON "
787 "music_songs.directory_id=music_directories.directory_id "
788 "WHERE filename NOT LIKE BINARY ('%://%') "
789 "AND hostname = :HOSTNAME");
796 LOG(VB_GENERAL, LOG_INFO,
"Checking tracks");
807 if ((iter = music_files.find(name)) != music_files.end())
811 if (iter != music_files.end())
820 music_files.erase(iter);
838 MusicLoadedMap::Iterator iter;
842 "FROM music_albumart "
843 "LEFT JOIN music_directories ON music_albumart.directory_id=music_directories.directory_id "
844 "WHERE music_albumart.embedded = 0 "
845 "AND music_albumart.hostname = :HOSTNAME");
852 LOG(VB_GENERAL, LOG_INFO,
"Checking artwork");
863 if ((iter = music_files.find(name)) != music_files.end())
867 if (iter != music_files.end())
872 music_files.erase(iter);
QMap< QString, MusicFileData > MusicLoadedMap
bool isActive(void) const
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
void ScanArtwork(MusicLoadedMap &music_files)
Check a list of files against images already in the database.
void SendMessage(const QString &message)
static void updateLastRunEnd(void)
QVariant lastInsertId()
Return the id of the last inserted row.
QVariant value(int i) const
arg(title).arg(filename).arg(doDelete))
void AddFileToDB(const QString &filename, const QString &startDir)
Insert file details into database. If it is an audio file, read the metadata and insert that informat...
void BuildFileList(QString &directory, MusicLoadedMap &music_files, MusicLoadedMap &art_files, int parentid)
Builds a list of all the files found descending recursively into the given directory.
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
MusicFileLocation location
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
static ImageType guessImageType(const QString &filename)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
unsigned sleep(unsigned int x)
static bool IsRunning(void)
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
MusicFileScanner(bool force=false)
static void DBError(const QString &where, const MSqlQuery &query)
static bool IsArtFile(const QString &filename)
void RemoveFileFromDB(const QString &filename, const QString &startDir)
Removes a file from the database.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void ScanMusic(MusicLoadedMap &music_files)
Check a list of files against musics files already in the database.
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
static void updateLastRunStatus(QString &status)
static int GetDirectoryId(const QString &directory, int parentid)
Get an ID for the given directory from the database. If it doesn't already exist in the database,...
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
void SearchDirs(const QStringList &dirList)
Scan a list of directories recursively for music and albumart. Inserts, updates and removes any files...
static void cleanDB()
Clear orphaned entries from the genre, artist, album and albumart tables.
int numRowsAffected() const
QString GetHostName(void)
static void updateLastRunStart(void)
void UpdateFileInDB(const QString &filename, const QString &startDir)
Updates a file in the database.
static const iso6937table * d
void SaveSetting(const QString &key, int newValue)
static bool HasFileChanged(const QString &filename, const QString &date_modified)
Check if file has been modified since given date/time.
void dumpToDatabase(void)
saves or updates the image details in the DB
MSqlQuery query(MSqlQuery::InitCon())
QString GetSetting(const QString &key, const QString &defaultval="")
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
static bool IsMusicFile(const QString &filename)