00001 #include <qimage.h>
00002
00003 #include <set>
00004 #include <map>
00005
00006 #include <mythtv/mythcontext.h>
00007 #include <mythtv/mythdialogs.h>
00008
00009 #include "globals.h"
00010 #include "videoscan.h"
00011 #include "metadata.h"
00012
00013 #include "metadatalistmanager.h"
00014 #include "dbaccess.h"
00015 #include "dirscan.h"
00016
00017 class VideoScannerImp
00018 {
00019 public:
00020 VideoScannerImp();
00021 ~VideoScannerImp();
00022 void doScan(const QStringList &dirs);
00023
00024 private:
00025 typedef std::vector<std::pair<unsigned int, QString> > PurgeList;
00026 typedef std::map<QString, bool> FileCheckList;
00027
00028 private:
00029 bool m_ListUnknown;
00030 bool m_RemoveAll;
00031 bool m_KeepAll;
00032
00033 MetadataListManager *m_dbmetadata;
00034
00035 private:
00036 void promptForRemoval(unsigned int id, const QString &filename);
00037 void verifyFiles(FileCheckList &files, PurgeList &remove);
00038 void updateDB(const FileCheckList &add, const PurgeList &remove);
00039 void buildFileList(const QString &directory,
00040 const QStringList &imageExtensions,
00041 FileCheckList &filelist);
00042 };
00043
00044 VideoScanner::VideoScanner()
00045 {
00046 m_imp = new VideoScannerImp();
00047 }
00048
00049 VideoScanner::~VideoScanner()
00050 {
00051 delete m_imp;
00052 }
00053
00054 void VideoScanner::doScan(const QStringList &dirs)
00055 {
00056 m_imp->doScan(dirs);
00057 }
00058
00059 VideoScannerImp::VideoScannerImp() : m_RemoveAll(false), m_KeepAll(false)
00060 {
00061 m_dbmetadata = new MetadataListManager;
00062 MetadataListManager::metadata_list ml;
00063 MetadataListManager::loadAllFromDatabase(ml);
00064 m_dbmetadata->setList(ml);
00065
00066 m_ListUnknown = gContext->GetNumSetting("VideoListUnknownFileTypes", 1);
00067 }
00068
00069 VideoScannerImp::~VideoScannerImp()
00070 {
00071 delete m_dbmetadata;
00072 }
00073
00074 void VideoScannerImp::doScan(const QStringList &dirs)
00075 {
00076 MythProgressDialog *progressDlg =
00077 new MythProgressDialog(QObject::tr("Searching for video files"),
00078 dirs.size());
00079
00080 QStringList imageExtensions = QImage::inputFormatList();
00081 int counter = 0;
00082
00083 FileCheckList fs_files;
00084
00085 for (QStringList::const_iterator iter = dirs.begin(); iter != dirs.end();
00086 ++iter)
00087 {
00088 buildFileList(*iter, imageExtensions, fs_files);
00089 progressDlg->setProgress(++counter);
00090 }
00091
00092 progressDlg->close();
00093 progressDlg->deleteLater();
00094
00095 PurgeList db_remove;
00096 verifyFiles(fs_files, db_remove);
00097 updateDB(fs_files, db_remove);
00098 }
00099
00100 void VideoScannerImp::promptForRemoval(unsigned int id, const QString &filename)
00101 {
00102
00103 if (m_RemoveAll)
00104 m_dbmetadata->purgeByID(id);
00105
00106 if (m_KeepAll || m_RemoveAll)
00107 return;
00108
00109 QStringList buttonText;
00110 buttonText += QObject::tr("No");
00111 buttonText += QObject::tr("No to all");
00112 buttonText += QObject::tr("Yes");
00113 buttonText += QObject::tr("Yes to all");
00114
00115 DialogCode result = MythPopupBox::ShowButtonPopup(
00116 gContext->GetMainWindow(),
00117 QObject::tr("File Missing"),
00118 QObject::tr("%1 appears to be missing.\n"
00119 "Remove it from the database?").arg(filename),
00120 buttonText, kDialogCodeButton0);
00121
00122 switch (result)
00123 {
00124 case kDialogCodeRejected:
00125 case kDialogCodeButton0:
00126 default:
00127 break;
00128 case kDialogCodeButton1:
00129 m_KeepAll = true;
00130 break;
00131 case kDialogCodeButton2:
00132 m_dbmetadata->purgeByID(id);
00133 break;
00134 case kDialogCodeButton3:
00135 m_RemoveAll = true;
00136 m_dbmetadata->purgeByID(id);
00137 break;
00138 };
00139 }
00140
00141 void VideoScannerImp::updateDB(const FileCheckList &add,
00142 const PurgeList &remove)
00143 {
00144 int counter = 0;
00145 MythProgressDialog *progressDlg = new MythProgressDialog(
00146 QObject::tr("Updating video database"), add.size() + remove.size());
00147
00148 for (FileCheckList::const_iterator p = add.begin(); p != add.end(); ++p)
00149 {
00150
00151 if (!p->second)
00152 {
00153 Metadata newFile(p->first, VIDEO_COVERFILE_DEFAULT,
00154 Metadata::FilenameToTitle(p->first),
00155 VIDEO_YEAR_DEFAULT,
00156 VIDEO_INETREF_DEFAULT, VIDEO_DIRECTOR_DEFAULT,
00157 VIDEO_PLOT_DEFAULT, 0.0, VIDEO_RATING_DEFAULT,
00158 0, 0, ParentalLevel::plLowest);
00159
00160 newFile.dumpToDatabase();
00161 }
00162
00163 progressDlg->setProgress(++counter);
00164 }
00165
00166 for (PurgeList::const_iterator p = remove.begin(); p != remove.end(); ++p)
00167 {
00168 promptForRemoval(p->first, p->second);
00169
00170 progressDlg->setProgress(++counter);
00171 }
00172
00173 progressDlg->Close();
00174 progressDlg->deleteLater();
00175 }
00176
00177 void VideoScannerImp::verifyFiles(FileCheckList &files, PurgeList &remove)
00178 {
00179 int counter = 0;
00180 FileCheckList::iterator iter;
00181
00182 MythProgressDialog *progressDlg = new MythProgressDialog(
00183 QObject::tr("Verifying video files"), m_dbmetadata->getList().size());
00184
00185
00186 for (MetadataListManager::metadata_list::const_iterator p =
00187 m_dbmetadata->getList().begin();
00188 p != m_dbmetadata->getList().end(); ++p)
00189 {
00190 QString name = (*p)->Filename();
00191 if (name != QString::null)
00192 {
00193 iter = files.find(name);
00194 if (iter != files.end())
00195 {
00196
00197 iter->second = true;
00198 }
00199 else
00200 {
00201
00202
00203 remove.push_back(std::make_pair((*p)->ID(), name));
00204 }
00205 }
00206
00207 progressDlg->setProgress(++counter);
00208 }
00209
00210 progressDlg->Close();
00211 progressDlg->deleteLater();
00212 }
00213
00214 namespace
00215 {
00216 template <typename DirListType>
00217 class dirhandler : public DirectoryHandler
00218 {
00219 public:
00220 dirhandler(DirListType &video_files,
00221 const QStringList &image_extensions) :
00222 m_video_files(video_files)
00223 {
00224 for (QStringList::const_iterator p = image_extensions.begin();
00225 p != image_extensions.end(); ++p)
00226 {
00227 m_image_ext.insert((*p).lower());
00228 }
00229 }
00230
00231 DirectoryHandler *newDir(const QString &dir_name,
00232 const QString &fq_dir_name)
00233 {
00234 (void)dir_name;
00235 (void)fq_dir_name;
00236 return this;
00237 }
00238
00239 void handleFile(const QString &file_name,
00240 const QString &fq_file_name,
00241 const QString &extension)
00242
00243 {
00244 (void)file_name;
00245 if (m_image_ext.find(extension.lower()) == m_image_ext.end())
00246 m_video_files[fq_file_name] = false;
00247 }
00248
00249 private:
00250 typedef std::set<QString> image_ext;
00251 image_ext m_image_ext;
00252 DirListType &m_video_files;
00253 };
00254 }
00255
00256 void VideoScannerImp::buildFileList(const QString &directory,
00257 const QStringList &imageExtensions,
00258 FileCheckList &filelist)
00259 {
00260 FileAssociations::ext_ignore_list ext_list;
00261 FileAssociations::getFileAssociation().getExtensionIgnoreList(ext_list);
00262
00263 dirhandler<FileCheckList> dh(filelist, imageExtensions);
00264 ScanVideoDirectory(directory, &dh, ext_list, m_ListUnknown);
00265 }