/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include #include #include #include #include "newmoviewizard.h" #include "movieinfopage.h" #include "moviemappingpage.h" #include "moviemetadatapage.h" #include "wizardtreemodel.h" #include "smglobals.h" #include "helper.h" NewMovieWizard::NewMovieWizard(QWidget *parent) : QWizard(parent){ mInfoPage = new MovieInfoPage; mActorPage = new MovieMappingPage("Actors"); mGenrePage = new MovieMappingPage("Genres"); mMetadataPage = new MovieMetadataPage; addPage(mInfoPage); addPage(mActorPage); addPage(mGenrePage); addPage(mMetadataPage); setOption(QWizard::IndependentPages, true); } void NewMovieWizard::reject(){ mInfoPage->saveData(); QWizard::reject(); } void NewMovieWizard::accept(){ QSqlDatabase db = QSqlDatabase::database("treedb"); db.open(); db.transaction(); QString seriesName = field("title").toString().toLower().trimmed(); QSqlQuery seriesIdQ(db); seriesIdQ.prepare("SELECT iseries_id FROM series WHERE tseries_name = :value"); seriesIdQ.bindValue(":value", seriesName); //see if we already have a series with this name int seriesId = 0; seriesIdQ.exec(); while(seriesIdQ.next()){ seriesId = seriesIdQ.value(0).toInt(); } //we don't have an id if(!seriesId){ QSqlQuery insertSeriesQ(db); insertSeriesQ.prepare("INSERT INTO series (tseries_name) VALUES(:name)"); insertSeriesQ.bindValue(":name", seriesName); if(insertSeriesQ.exec()){ QSqlQuery curval("SELECT currval('series_iseries_id__seq')", db); while(curval.next()){ seriesId = curval.value(0).toInt(); } db.commit(); db.transaction(); }else{ QMessageBox::critical(this, tr("Error"), tr("Failed to create series!")); db.rollback(); return; } } //now we have a series id, handle seriespart int partNo = field("seriesNo").toInt(); QString subtitle = field("subtitle").toString().toLower().trimmed(); QStringList subtitles = Helper::fuzzyCheck(subtitle); if(!subtitles.isEmpty()){ QString msg = QString(tr("%1:
    ")).arg(subtitle); for(int i = 0; i < subtitles.count() && i < 5; ++i){ msg = msg.append("
  • %1
  • ").arg(subtitles.at(i)); } msg.append("
"); int res = QMessageBox::question(this, tr("Fuzzy search"), msg, QMessageBox::Cancel | QMessageBox::Ignore, QMessageBox::Cancel); if(res == QMessageBox::Cancel){ db.rollback(); return; } } QSqlQuery savePoint("SAVEPOINT before_parts", db); QSqlQuery insertPartQ(db); insertPartQ.prepare("INSERT INTO seriesparts (iseries_id, iseriespart, tsubtitle) VALUES(:sid, :pid, :tsub)"); insertPartQ.bindValue(":sid", seriesId); insertPartQ.bindValue(":pid", partNo); insertPartQ.bindValue(":tsub", subtitle); int seriesPartId = 0; if(!insertPartQ.exec()){ int res = QMessageBox::question(this, tr("Question"), tr("We already have that part of the series. Continue anyway?")); if(res == QMessageBox::No){ db.rollback(); return; }else{ QSqlQuery rollbackSave("ROLLBACK TO SAVEPOINT before_parts", db); } } QSqlQuery partNoQ(db); partNoQ.prepare("SELECT iseriesparts_id FROM seriesparts WHERE iseries_id = :sid AND iseriespart = :pid AND tsubtitle = :tsub"); partNoQ.bindValue(":sid", seriesId); partNoQ.bindValue(":pid", partNo); partNoQ.bindValue(":tsub", subtitle); if(!partNoQ.exec()){ db.rollback(); return; } while(partNoQ.next()){ seriesPartId = partNoQ.value(0).toInt(); } //since we're in a transaction, we have to have a valid seriespart //handle files MovieInfoPage *movieInfoPage = qobject_cast(page(0)); WizardTreeModel *wizardModel = movieInfoPage->model(); QSqlQuery insertFilesQ(db); insertFilesQ.prepare("INSERT INTO files (iseriespart_id, tfilename, cmd5sum, bisize, sifiletype, sifileno, siquality, cpicsize, iduration) VALUES(:ipid, :tfn, :md5, :size, :ft, :fno, :qual, :psize, :dur)"); QSqlQuery insertOriginQ(db); insertOriginQ.prepare("INSERT INTO files_origin (ifiles_id, tname, cmd5sum, bisize, ibitrate) VALUES(:oid, :oname, :omd5, :osize, :obitrate)"); QHash md5Sums; for(int i = 0; i < wizardModel->rowCount(QModelIndex()); ++i){ QModelIndex curIdx = wizardModel->index(i, 0, QModelIndex()); QList fData = wizardModel->fileData(curIdx); QString fullPath = fData.value(WizardTreeModel::FullPath).toString(); QFileInfo fi(fullPath); qint64 size = fi.size(); QString md5 = Helper::md5Sum(fullPath); md5Sums.insert(fullPath, md5); qint64 secs = 0; QString picSize; int type = fData.value(WizardTreeModel::FileType).toInt(); QVariant quality; QString oName, oMD5; qint64 oSize = 0, oldBitrate = 0; bool hasOrigin = false; if(type == FT_MOVIE){ QVariantMap m = Helper::ffmpegData(fullPath); secs = static_cast(m.value("duration").toDouble()); quality = field("quality").toInt(); //check for origin QModelIndex oIdx = wizardModel->index(0, 0, curIdx); if(oIdx.isValid()){ QList oData = wizardModel->fileData(oIdx); QString oFullPath = oData.value(WizardTreeModel::FullPath).toString(); QFileInfo oFi(oFullPath); oName = oFi.fileName(); oSize = oFi.size(); oMD5 = Helper::md5Sum(oFullPath); QVariantMap oldFfmpeg = Helper::ffmpegData(oFullPath); oldBitrate = oldFfmpeg.value("bit_rate").toLongLong(); oldBitrate /= 1000; hasOrigin = true; } }else{ QPixmap pix(fullPath); picSize = QString("%1x%2").arg(QString::number(pix.width()), QString::number(pix.height())); } insertFilesQ.bindValue(":ipid", seriesPartId); insertFilesQ.bindValue(":tfn", fi.fileName()); insertFilesQ.bindValue(":md5", md5); insertFilesQ.bindValue(":size", size); insertFilesQ.bindValue(":ft", type); insertFilesQ.bindValue(":fno", fData.value(WizardTreeModel::FilePart)); insertFilesQ.bindValue(":qual", quality); insertFilesQ.bindValue(":psize", picSize); insertFilesQ.bindValue(":dur", secs); if(insertFilesQ.exec()){ if(hasOrigin){ int curFileId = -1; QSqlQuery curval("SELECT currval('files_ifiles_id__seq')", db); while(curval.next()){ curFileId= curval.value(0).toInt(); } insertOriginQ.bindValue(":oid", curFileId); insertOriginQ.bindValue(":oname", oName); insertOriginQ.bindValue(":omd5", oMD5); insertOriginQ.bindValue(":osize", oSize); insertOriginQ.bindValue(":obitrate", oldBitrate); if(!insertOriginQ.exec()){ QMessageBox::critical(this, tr("Error"), tr("Failed to insert old!")); db.rollback(); return; } } }else{ QMessageBox::critical(this, tr("Error"), tr("Craptastic... Something went wrong archiving files.")); db.rollback(); return; } } //files have landed //handle actors MovieMappingPage *actorPage = qobject_cast(page(1)); QStringList actors = actorPage->widget()->items(); QSqlQuery actorIdQ(db); actorIdQ.prepare("SELECT iactors_id FROM actors WHERE tactorname = :name"); QSqlQuery insertActorQ(db); insertActorQ.prepare("INSERT INTO actors (tactorname) VALUES(:name)"); QSqlQuery actorMapQ(db); actorMapQ.prepare("INSERT INTO seriesparts_actormap (iseriesparts_id, iactors_id) VALUES(:pid, :aid)"); for(QString a : actors){ a = a.toLower().trimmed(); int actorId = 0; actorIdQ.bindValue(":name", a); actorIdQ.exec(); while(actorIdQ.next()){ actorId = actorIdQ.value(0).toInt(); } if(!actorId){ insertActorQ.bindValue(":name", a); insertActorQ.exec(); actorIdQ.bindValue(":name", a); actorIdQ.exec(); while(actorIdQ.next()){ actorId = actorIdQ.value(0).toInt(); } } actorMapQ.bindValue(":pid", seriesPartId); actorMapQ.bindValue(":aid", actorId); if(!actorMapQ.exec()){ QMessageBox::critical(this, tr("Error"), tr("Failed to handle actors.")); db.rollback(); return; } } //actors are in place! //handle genres MovieMappingPage *genrePage = qobject_cast(page(2)); QStringList genres = genrePage->widget()->items(); QSqlQuery genreIdQ(db); genreIdQ.prepare("SELECT igenres_id FROM genres WHERE tgenrename = :name"); QSqlQuery insertGenreQ(db); insertGenreQ.prepare("INSERT INTO genres (tgenrename) VALUES(:name)"); QSqlQuery genreMapQ(db); genreMapQ.prepare("INSERT INTO seriesparts_genremap (iseriesparts_id, igenres_id) VALUES(:pid, :gid)"); for(QString g : genres){ g = g.toLower().trimmed(); int genreId = 0; genreIdQ.bindValue(":name", g); genreIdQ.exec(); while(genreIdQ.next()){ genreId = genreIdQ.value(0).toInt(); } if(!genreId){ insertGenreQ.bindValue(":name", g); insertGenreQ.exec(); genreIdQ.bindValue(":name", g); genreIdQ.exec(); while(genreIdQ.next()){ genreId = genreIdQ.value(0).toInt(); } } genreMapQ.bindValue(":pid", seriesPartId); genreMapQ.bindValue(":gid", genreId); if(!genreMapQ.exec()){ QMessageBox::critical(this, tr("Error"), tr("Failed to handle genres.")); db.rollback(); return; } } //genres done! //now handle metadata QSqlQuery savePoint2("SAVEPOINT before_metadata", db); QSqlQuery insertMetadataQ(db); insertMetadataQ.prepare("INSERT INTO metadata (iseriespart_id, sireleaseyear, tsourcemedium, tsubject, treleasegroup, tencoderopts, tcomment, sipasses) VALUES(:pid, :rely, :source, :sub, :group, :encopts, :comment, :passes)"); MovieMetadataPage *metadataPage = qobject_cast(page(3)); QList metadata = metadataPage->widget()->metadata(); insertMetadataQ.bindValue(":pid", seriesPartId); insertMetadataQ.bindValue(":rely", metadata.at(ArchiveModel::ReleaseYear)); insertMetadataQ.bindValue(":source", metadata.at(ArchiveModel::Source)); insertMetadataQ.bindValue(":sub", metadata.at(ArchiveModel::Subject)); insertMetadataQ.bindValue(":group", metadata.at(ArchiveModel::ReleaseGroup)); insertMetadataQ.bindValue(":encopts", metadata.at(ArchiveModel::EncoderOpts)); insertMetadataQ.bindValue(":comment", metadata.at(ArchiveModel::Comment)); insertMetadataQ.bindValue(":passes", metadata.at(ArchiveModel::Passes)); if(!insertMetadataQ.exec()){ int res = QMessageBox::question(this, tr("Question"), tr("Failed to insert metadata. Continue anyway?")); if(res == QMessageBox::No){ db.rollback(); return; }else{ QSqlQuery rollbackSave("ROLLBACK TO SAVEPOINT before_metadata", db); } } //we're still here, good //now actually move the files for(int i = 0; i < wizardModel->rowCount(QModelIndex()); ++i){ QModelIndex curIdx = wizardModel->index(i, 0, QModelIndex()); QList fData = wizardModel->fileData(curIdx); QString fullPath = fData.value(WizardTreeModel::FullPath).toString(); QString md5 = md5Sums.value(fullPath); Helper::moveToArchive(fullPath, md5); } db.commit(); mInfoPage->saveData(); const QStringList &origins = mInfoPage->origins(); if(!origins.isEmpty()){ QString q = QString("

Also delete origins?

    "); for(const QString &o : origins){ q.append(QString("
  • %1
  • ").arg(o)); } q.append("
"); int qRes = QMessageBox::question(this, tr("Delete other files"), q); if(qRes == QMessageBox::Yes){ for(const QString &o : origins){ QFile::remove(o); } } } QWizard::accept(); }