~ubuntu-branches/ubuntu/saucy/clementine/saucy

« back to all changes in this revision

Viewing changes to src/library/librarywatcher.cpp

  • Committer: Package Import Robot
  • Author(s): Thomas PIERSON
  • Date: 2012-01-01 20:43:39 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120101204339-lsb6nndwhfy05sde
Tags: 1.0.1+dfsg-1
New upstream release. (Closes: #653926, #651611, #657391)

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
*/
17
17
 
18
18
#include "librarywatcher.h"
 
19
 
19
20
#include "librarybackend.h"
 
21
#include "core/filesystemwatcherinterface.h"
 
22
#include "core/logging.h"
20
23
#include "core/taskmanager.h"
21
24
#include "playlistparsers/cueparser.h"
22
25
 
23
 
#include <QFileSystemWatcher>
24
26
#include <QDateTime>
25
27
#include <QDirIterator>
26
28
#include <QtDebug>
34
36
#include <fileref.h>
35
37
#include <tag.h>
36
38
 
 
39
// This is defined by one of the windows headers that is included by taglib.
 
40
#ifdef RemoveDirectory
 
41
#undef RemoveDirectory
 
42
#endif
 
43
 
37
44
QStringList LibraryWatcher::sValidImages;
38
45
 
39
46
const char* LibraryWatcher::kSettingsGroup = "LibraryWatcher";
42
49
  : QObject(parent),
43
50
    backend_(NULL),
44
51
    task_manager_(NULL),
 
52
    fs_watcher_(FileSystemWatcherInterface::Create(this)),
45
53
    stop_requested_(false),
46
54
    scan_on_startup_(true),
47
55
    monitor_(true),
107
115
  if (watcher_->monitor_) {
108
116
    // Watch the new subdirectories
109
117
    foreach (const Subdirectory& subdir, new_subdirs) {
110
 
      watcher_->AddWatch(watcher_->watched_dirs_[dir_].watcher, subdir.path);
 
118
      watcher_->AddWatch(watcher_->watched_dirs_[dir_], subdir.path);
111
119
    }
112
120
  }
113
121
}
131
139
  // TODO: Make this faster
132
140
  SongList ret;
133
141
  foreach (const Song& song, cached_songs_) {
134
 
    if (song.filename().section('/', 0, -2) == path)
 
142
    if (song.url().toLocalFile().section('/', 0, -2) == path)
135
143
      ret << song;
136
144
  }
137
145
  return ret;
177
185
void LibraryWatcher::AddDirectory(const Directory& dir, const SubdirectoryList& subdirs) {
178
186
  DirData data;
179
187
  data.dir = dir;
180
 
  data.watcher = new QFileSystemWatcher(this);
181
 
  connect(data.watcher, SIGNAL(directoryChanged(QString)), SLOT(DirectoryChanged(QString)));
182
188
  watched_dirs_[dir.id] = data;
183
189
 
184
190
  if (subdirs.isEmpty()) {
201
207
        ScanSubdirectory(subdir.path, subdir, &transaction);
202
208
 
203
209
      if (monitor_)
204
 
        AddWatch(data.watcher, subdir.path);
 
210
        AddWatch(data, subdir.path);
205
211
    }
206
212
  }
207
213
 
315
321
 
316
322
      // watch out for cue songs which have their mtime equal to qMax(media_file_mtime, cue_sheet_mtime)
317
323
      bool changed = (matching_song.mtime() != qMax(file_info.lastModified().toTime_t(), song_cue_mtime))
318
 
                     || cue_deleted || cue_added;
 
324
                     || cue_deleted || cue_added
 
325
                     || matching_song.is_unavailable();
319
326
 
320
327
      // Also want to look to see whether the album art has changed
321
328
      QString image = ImageForSong(file, album_art);
328
335
 
329
336
      // the song's changed - reread the metadata from file
330
337
      if (t->ignores_mtime() || changed) {
331
 
        qDebug() << file << "changed";
 
338
        qLog(Debug) << file << "changed";
332
339
 
333
340
        // if cue associated...
334
341
        if(!cue_deleted && (matching_song.has_cue() || cue_added)) {
346
353
        continue;
347
354
      }
348
355
 
349
 
      qDebug() << file << "created";
 
356
      qLog(Debug) << file << "created";
350
357
      // choose an image for the song(s)
351
358
      QString image = ImageForSong(file, album_art);
352
359
 
362
369
 
363
370
  // Look for deleted songs
364
371
  foreach (const Song& song, songs_in_db) {
365
 
    if (!files_on_disk.contains(song.filename())) {
366
 
      qDebug() << "Song deleted from disk:" << song.filename();
 
372
    if (!song.is_unavailable() && !files_on_disk.contains(song.url().toLocalFile())) {
 
373
      qLog(Debug) << "Song deleted from disk:" << song.url().toLocalFile();
367
374
      t->deleted_songs << song;
368
375
    }
369
376
  }
396
403
  QFile cue(matching_cue);
397
404
  cue.open(QIODevice::ReadOnly);
398
405
 
399
 
  SongList old_sections = backend_->GetSongsByFilename(file);
 
406
  SongList old_sections = backend_->GetSongsByUrl(QUrl::fromLocalFile(file));
400
407
 
401
408
  QHash<quint64, Song> sections_map;
402
409
  foreach(const Song& song, old_sections) {
436
443
  // 'raw' (cueless) song and we just remove the rest of the sections
437
444
  // from the library
438
445
  if(cue_deleted) {
439
 
    foreach(const Song& song, backend_->GetSongsByFilename(file)) {
 
446
    foreach(const Song& song, backend_->GetSongsByUrl(QUrl::fromLocalFile(file))) {
440
447
      if(!song.IsMetadataEqual(matching_song)) {
441
448
        t->deleted_songs << song;
442
449
      }
469
476
    // media files. Playlist parser for CUEs considers every entry in sheet
470
477
    // valid and we don't want invalid media getting into library!
471
478
    foreach(const Song& cue_song, cue_parser_->Load(&cue, matching_cue, path)) {
472
 
      if(cue_song.filename() == file && cue_song.HasProperMediaFile()) {
 
479
      if(cue_song.url().toLocalFile() == file && cue_song.HasProperMediaFile()) {
473
480
        song_list << cue_song;
474
481
      }
475
482
    }
509
516
  out->set_score(matching_song.score());
510
517
  out->set_art_manual(matching_song.art_manual());
511
518
 
512
 
  if (!matching_song.IsMetadataEqual(*out)) {
513
 
    qDebug() << file << "metadata changed";
 
519
  // The song was deleted from the database (e.g. due to an unmounted 
 
520
  // filesystem), but has been restored.
 
521
  if (matching_song.is_unavailable()) {
 
522
    qLog(Debug) << file << " unavailable song restored";
 
523
    
 
524
    t->new_songs << *out;
 
525
  } else if (!matching_song.IsMetadataEqual(*out)) {
 
526
    qLog(Debug) << file << "metadata changed";
514
527
 
515
528
    // Update the song in the DB
516
529
    t->new_songs << *out;
533
546
             : 0;
534
547
}
535
548
 
536
 
void LibraryWatcher::AddWatch(QFileSystemWatcher* w, const QString& path) {
 
549
void LibraryWatcher::AddWatch(const DirData& dir, const QString& path) {
537
550
  if (!QFile::exists(path))
538
551
    return;
539
552
 
540
 
  w->addPath(path);
 
553
  connect(fs_watcher_, SIGNAL(PathChanged(const QString&)), this,
 
554
      SLOT(DirectoryChanged(const QString&)), Qt::UniqueConnection);
 
555
  fs_watcher_->AddPath(path);
 
556
  subdir_mapping_[path] = dir;
541
557
}
542
558
 
543
559
void LibraryWatcher::RemoveDirectory(const Directory& dir) {
544
 
  if (watched_dirs_.contains(dir.id)) {
545
 
    delete watched_dirs_[dir.id].watcher;
546
 
  }
547
 
 
548
560
  rescan_queue_.remove(dir.id);
549
561
  watched_dirs_.remove(dir.id);
550
562
}
552
564
bool LibraryWatcher::FindSongByPath(const SongList& list, const QString& path, Song* out) {
553
565
  // TODO: Make this faster
554
566
  foreach (const Song& song, list) {
555
 
    if (song.filename() == path) {
 
567
    if (song.url().toLocalFile() == path) {
556
568
      *out = song;
557
569
      return true;
558
570
    }
562
574
 
563
575
void LibraryWatcher::DirectoryChanged(const QString &subdir) {
564
576
  // Find what dir it was in
565
 
  QFileSystemWatcher* watcher = qobject_cast<QFileSystemWatcher*>(sender());
566
 
  if (!watcher)
 
577
  QHash<QString, DirData>::const_iterator it = subdir_mapping_.constFind(subdir);
 
578
  if (it == subdir_mapping_.constEnd()) {
567
579
    return;
568
 
 
569
 
  Directory dir;
570
 
  foreach (const DirData& info, watched_dirs_) {
571
 
    if (info.watcher == watcher)
572
 
      dir = info.dir;
573
580
  }
 
581
  Directory dir = it->dir;
574
582
 
575
 
  qDebug() << "Subdir" << subdir << "changed under directory" << dir.path << "id" << dir.id;
 
583
  qLog(Debug) << "Subdir" << subdir << "changed under directory" << dir.path << "id" << dir.id;
576
584
 
577
585
  // Queue the subdir for rescanning
578
586
  if (!rescan_queue_[dir.id].contains(subdir))
676
684
  s.beginGroup(kSettingsGroup);
677
685
  scan_on_startup_ = s.value("startup_scan", true).toBool();
678
686
  monitor_ = s.value("monitor", true).toBool();
679
 
  
 
687
 
680
688
  best_image_filters_.clear();
681
689
  QStringList filters = s.value("cover_art_patterns",
682
690
      QStringList() << "front" << "cover").toStringList();
685
693
    if (!s.isEmpty())
686
694
      best_image_filters_ << s;
687
695
  }
688
 
  
 
696
 
689
697
  if (!monitor_ && was_monitoring_before) {
690
 
    // Remove all directories from all QFileSystemWatchers
691
 
    foreach (const DirData& data, watched_dirs_.values()) {
692
 
      data.watcher->removePaths(data.watcher->directories());
693
 
    }
 
698
    fs_watcher_->Clear();
694
699
  } else if (monitor_ && !was_monitoring_before) {
695
700
    // Add all directories to all QFileSystemWatchers again
696
701
    foreach (const DirData& data, watched_dirs_.values()) {
697
702
      SubdirectoryList subdirs = backend_->SubdirsInDirectory(data.dir.id);
698
703
      foreach (const Subdirectory& subdir, subdirs) {
699
 
        AddWatch(data.watcher, subdir.path);
 
704
        AddWatch(data, subdir.path);
700
705
      }
701
706
    }
702
707
  }