#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "helper.h" #include "globals.h" namespace Helper { const QString md5Sum(const QString &path){ QFileInfo info(path); if(!info.exists() || !info.isFile()){ return QString(); } QString retval; QCryptographicHash h(QCryptographicHash::Md5); QFile file(path); file.open(QIODevice::ReadOnly); qint64 read = 0; if(info.size() < (5 * 1024 * 1024)){ QByteArray data(4096, '\0'); do { read = file.read(data.data(), 4096); if(read > 0){ h.addData(data.data(), read); } } while (read == 4096); QByteArray res = h.result(); retval = res.toHex().toLower(); }else{ QByteArray data(512, '\0'); int offset = info.size() / 3; file.seek(offset); int numBytes = 512 * 1024; int readBytes = 0; do { read = file.read(data.data(), 512); if(read > 0){ readBytes += read; }else{ return QString(); } h.addData(data.data(), read); } while(readBytes < numBytes); QByteArray res = h.result(); retval = res.toHex().toLower(); } return retval; } const QJsonDocument ffpmegData(const QString &path){ QSettings s; QString ffProbe = s.value("ext/ffprobe").toString(); QStringList args; args << "-v" << "quiet" << "-print_format" << "json" << "-show_format" << "-show_streams" << path; QProcess ffproc; ffproc.start(ffProbe, args); if(!ffproc.waitForStarted()){ return QJsonDocument(); } ffproc.waitForFinished(); QByteArray ffData = ffproc.readAllStandardOutput(); return QJsonDocument::fromJson(ffData); } const QPixmap preview(const QString &file){ QJsonDocument jDoc = ffpmegData(file); QJsonObject jObj = jDoc.object(); QJsonValue durationV = jObj["format"].toObject()["duration"]; int seconds = durationV.toVariant().toDouble(); int interval = seconds / 4; QImage img1 = snapshot(file, 60); QImage img2 = snapshot(file, interval * 2); QImage img3 = snapshot(file, interval * 3); QImage img4 = snapshot(file, seconds - 60); QImage retval(640 * 2 + 10, img1.height() * 2 + 10, QImage::Format_ARGB32); //retval.fill(Qt::red); QPainter p(&retval); p.drawImage(0, 0, img1); p.drawImage(650, 0, img2); p.drawImage(0, img1.height() + 10, img3); p.drawImage(650, img1.height() + 10, img4); return QPixmap::fromImage(retval); } const QImage snapshot(const QString &file, int offset){ const int fixedWith = 640; QSettings s; QString ffmpeg = s.value("ext/ffmpeg").toString(); QTemporaryFile tempFile; tempFile.open(); QStringList ffmpegArgs = QStringList() << "-y" << "-ss" << QString::number(offset) << "-i" << file << "-f" << "image2" << "-vframes" << "1" << tempFile.fileName(); QProcess ffproc; ffproc.start(ffmpeg, ffmpegArgs); if(!ffproc.waitForStarted()){ return QImage(); } if(ffproc.state() == QProcess::Running){ ffproc.waitForFinished(); } QImage retval(tempFile.fileName()); retval = retval.scaledToWidth(fixedWith); Duration dur(offset); QFont font("Monospace", 10); QFontMetrics fm(font); int width = fm.width(dur.toString()); int height = fm.height(); QPainter p(&retval); p.setBrush(QBrush(QColor(255, 255, 255, 70))); QRect durationRect(fixedWith / 2 - width / 2 - 4, retval.height() - height - 8, width + 4, height + 4); p.drawRect(durationRect); p.setPen(Qt::black); p.drawText(durationRect, Qt::AlignCenter, dur.toString()); return retval; } const QString appDataDir(){ QString retval = QStandardPaths::locate(QStandardPaths::HomeLocation, ".shemovcleaner", QStandardPaths::LocateDirectory); if(retval.isEmpty()){ QString homeDir = QStandardPaths::locate(QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory); QDir d(homeDir); if(d.mkdir(".shemovcleaner")){ retval = QString("%1/%2").arg(homeDir).arg(".shemovcleaner"); } } return retval; } const QIcon icon(const QColor &bg, const QChar c, bool bold){ QImage img(32, 32, QImage::Format_ARGB32); img.fill(QColor(0, 0, 0, 0)); QPainter *p = new QPainter(&img); p->setBrush(bg); p->setRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::TextAntialiasing); p->setRenderHint(QPainter::SmoothPixmapTransform); QFont f("courier new"); f.setPixelSize(30); f.setBold(bold); p->setPen(Qt::white); p->drawEllipse(img.rect()); p->setFont(f); p->drawText(img.rect(), Qt::AlignCenter, c); delete p; return QIcon(QPixmap::fromImage(img)); } void setAlternatingRowColors(){ QSettings s; bool alternate = s.value("alternatecolors").toBool(); if(alternate){ QColor b = s.value("basecolor").value(); QColor a = s.value("altcolor").value(); QString style = QString("QTreeView { background-color: rgb(%1,%2,%3);alternate-background-color: rgb(%4,%5,%6); }").arg(b.red()).arg(b.green()).arg(b.blue()).arg(a.red()).arg(a.green()).arg(a.blue()); QVector views = Globals::instance()->views(); for(QTreeView *v : views){ v->setAlternatingRowColors(true); v->setStyleSheet(style); } } } Duration::Duration() : mHours(0), mMinutes(0), mSeconds(0) {} Duration::Duration(qint64 seconds){ int sec(0), min(0), h(0); // get hours h = (seconds / 60 / 60); // remaining minutes min = (seconds / 60) % 60; // seconds sec = seconds % 60; mHours = h; mMinutes = min; mSeconds = sec; } Duration::Duration(const QString &dur) : mHours(0), mMinutes(0), mSeconds(0){ QStringList parts = dur.split(':'); if(parts.size() == 3){ mHours = parts.at(0).toInt(); mMinutes = parts.at(1).toInt(); mSeconds = parts.at(2).toInt(); } } Duration Duration::operator+(const Duration &dur) const{ Duration retval; retval.mSeconds = mSeconds + dur.mSeconds; retval.mMinutes = mMinutes + dur.mMinutes + retval.mSeconds / 60; retval.mSeconds %= 60; retval.mHours = mHours + dur.mHours + retval.mMinutes / 60; retval.mMinutes %= 60; return retval; } const QString Duration::toString() const { QString retval = QString("%1:%2:%3").arg(QString::number(mHours), 2, '0').arg(QString::number(mMinutes), 2, '0').arg(QString::number(mSeconds), 2, '0'); return retval; } bool Duration::isNull() const { return mHours == 0 && mMinutes == 0 && mSeconds == 0; } qint64 Duration::toSeconds() const { qint64 retval; retval = mHours * 60 * 60 + mMinutes * 60 + mSeconds; return retval; } }