diff options
-rw-r--r-- | ShemovCleaner.pro | 8 | ||||
-rw-r--r-- | shemovcleaner.cpp | 21 | ||||
-rw-r--r-- | shemovcleaner.h | 4 | ||||
-rw-r--r-- | torrentdisplay.cpp | 149 | ||||
-rw-r--r-- | torrentdisplay.h | 27 | ||||
-rw-r--r-- | torrentparser.cpp | 103 | ||||
-rw-r--r-- | torrentparser.h | 31 |
7 files changed, 341 insertions, 2 deletions
diff --git a/ShemovCleaner.pro b/ShemovCleaner.pro index e246968..57893bb 100644 --- a/ShemovCleaner.pro +++ b/ShemovCleaner.pro @@ -16,10 +16,14 @@ TEMPLATE = app SOURCES += main.cpp\ shemovcleaner.cpp \ - filesorter.cpp + filesorter.cpp \ + torrentparser.cpp \ + torrentdisplay.cpp HEADERS += shemovcleaner.h \ - filesorter.h + filesorter.h \ + torrentparser.h \ + torrentdisplay.h DISTFILES += diff --git a/shemovcleaner.cpp b/shemovcleaner.cpp index 9625db1..beb5baf 100644 --- a/shemovcleaner.cpp +++ b/shemovcleaner.cpp @@ -22,6 +22,8 @@ #include "shemovcleaner.h" #include "filesorter.h" +#include "torrentparser.h" +#include "torrentdisplay.h" ShemovCleaner::ShemovCleaner(QWidget *parent) : QMainWindow(parent){ QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL", "shemovdb"); @@ -76,10 +78,13 @@ void ShemovCleaner::setupGui(){ connect(mDelete, SIGNAL(clicked()), this, SLOT(deleteFiles())); mMove = new QPushButton(tr("Move...")); connect(mMove, SIGNAL(clicked()), this, SLOT(moveFiles())); + mInfo = new QPushButton(tr("Torrent...")); + connect(mInfo, SIGNAL(clicked()), this, SLOT(torrentInfo())); QHBoxLayout *buttonL2 = new QHBoxLayout; buttonL2->addStretch(); buttonL2->addWidget(mMove); buttonL2->addWidget(mDelete); + buttonL2->addWidget(mInfo); buttonL2->addStretch(); QWidget *mainWidget = new QWidget; @@ -94,6 +99,7 @@ void ShemovCleaner::setupGui(){ setCentralWidget(mainWidget); createStatusbar(); + mTorrentDisplay = new TorrentDisplay(this); connect(mFileView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(fileSelectionChanged(QItemSelection,QItemSelection))); } @@ -189,6 +195,21 @@ void ShemovCleaner::moveFiles(){ } } +void ShemovCleaner::torrentInfo(){ + QModelIndexList sel = mFileView->selectionModel()->selectedRows(1); + if(sel.isEmpty()){ + return; + } + QString fn = sel.first().data(Qt::UserRole + 1).toString(); + TorrentParser p(fn, this); + QList<QVariant> tData = p.parse(); + tData.removeAll(QVariant()); + tData.removeAll(0); + mTorrentDisplay->setData(tData); + mTorrentDisplay->show(); + return; +} + void ShemovCleaner::selectDir(){ QString dir = QFileDialog::getExistingDirectory(this, tr("Select directory"), QDir::homePath()); mDir->setText(QDir::toNativeSeparators(dir)); diff --git a/shemovcleaner.h b/shemovcleaner.h index c2e0f32..fe02fc6 100644 --- a/shemovcleaner.h +++ b/shemovcleaner.h @@ -10,6 +10,7 @@ class QTreeView; class QStandardItemModel; class QLabel; class FileSorter; +class TorrentDisplay; class ShemovCleaner : public QMainWindow { Q_OBJECT @@ -23,6 +24,7 @@ class ShemovCleaner : public QMainWindow { void gatherData(); void deleteFiles(); void moveFiles(); + void torrentInfo(); private: void setupGui(); @@ -37,10 +39,12 @@ class ShemovCleaner : public QMainWindow { QPushButton *mSelExt; QPushButton *mMove; QPushButton *mDelete; + QPushButton *mInfo; QLabel *mSelected; QStandardItemModel *mModel; FileSorter *mProxy; QTreeView *mFileView; + TorrentDisplay *mTorrentDisplay; }; #endif // SHEMOVCLEANER_H diff --git a/torrentdisplay.cpp b/torrentdisplay.cpp new file mode 100644 index 0000000..e56343c --- /dev/null +++ b/torrentdisplay.cpp @@ -0,0 +1,149 @@ +#include <QGridLayout> +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QGroupBox> +#include <QLineEdit> +#include <QStandardItemModel> +#include <QTreeView> +#include <QStandardItem> +#include <QPushButton> +#include <QLabel> +#include <QDateTime> + +#include "torrentdisplay.h" + +TorrentDisplay::TorrentDisplay(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { + //windows doesn't like it after setting up the GUI + setMinimumWidth(600); + + //general info + QGridLayout *torGenLayout = new QGridLayout; + QLabel *l1 = new QLabel(tr("Created")); + mCreated = new QLineEdit; + mCreated->setReadOnly(true); + QLabel *l2 = new QLabel(tr("Created by")); + mCreatedBy = new QLineEdit; + mCreatedBy->setReadOnly(true); + QLabel *l3 = new QLabel(tr("Encoding")); + mEncoding = new QLineEdit; + mEncoding->setReadOnly(true); + QLabel *l4 = new QLabel(tr("Piece length")); + mPieceLength = new QLineEdit; + mPieceLength->setReadOnly(true); + torGenLayout->addWidget(l1, 0, 0); + torGenLayout->addWidget(mCreated, 0, 1); + torGenLayout->addWidget(l2, 1, 0); + torGenLayout->addWidget(mCreatedBy, 1, 1); + torGenLayout->addWidget(l3, 2, 0); + torGenLayout->addWidget(mEncoding, 2, 1); + torGenLayout->addWidget(l4, 3, 0); + torGenLayout->addWidget(mPieceLength, 3, 1); + QGroupBox *torGenGroup = new QGroupBox(tr("General")); + torGenGroup->setLayout(torGenLayout); + + //files + mFileModel = new QStandardItemModel; + mFileView = new QTreeView; + mFileView->setSortingEnabled(true); + mFileView->setModel(mFileModel); + QHBoxLayout *fileLayout = new QHBoxLayout; + fileLayout->addWidget(mFileView); + QGroupBox *fileGroup = new QGroupBox(tr("Files")); + fileGroup->setLayout(fileLayout); + + //announce list + mAnnounceModel = new QStandardItemModel; + mAnnounceView = new QTreeView; + mAnnounceView->setSortingEnabled(true); + mAnnounceView->setModel(mAnnounceModel); + QHBoxLayout *announceLayout = new QHBoxLayout; + announceLayout->addWidget(mAnnounceView); + QGroupBox *announceGroup = new QGroupBox(tr("Announce")); + announceGroup->setLayout(announceLayout); + + //close button + QHBoxLayout *buttonLayout = new QHBoxLayout; + QPushButton *closeBtn = new QPushButton(tr("Close")); + buttonLayout->addStretch(); + buttonLayout->addWidget(closeBtn); + buttonLayout->addStretch(); + connect(closeBtn, SIGNAL(clicked()), this, SLOT(hide())); + + //dialog layout + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(torGenGroup); + mainLayout->addWidget(fileGroup); + mainLayout->addWidget(announceGroup); + mainLayout->addLayout(buttonLayout); + setLayout(mainLayout); + setWindowTitle(tr("Torrent Info")); +} + +void TorrentDisplay::setData(const QList<QVariant> data) { + if(data.isEmpty()){ + return; + } + mFileModel->clear(); + mFileModel->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Length")); + mAnnounceModel->clear(); + mAnnounceModel->setHorizontalHeaderLabels(QStringList() << tr("Tracker")); + + foreach(QVariant cur, data){ + if(cur.canConvert<QVariantHash>()){ + QVariantHash h = cur.toHash(); + QHash<QString, QVariant>::const_iterator it = h.constBegin(); + while(it != h.constEnd()){ + if(it.key() == "info"){ + QVariantHash infoD = it.value().toHash(); + int piece_length = infoD.value("piece length").toInt(); + mPieceLength->setText(QString::number(piece_length)); + if(infoD.contains("name")){ + QString fn = infoD.value("name").toString(); + qint64 length = infoD.value("length").toLongLong(); + QStandardItem *i1 = new QStandardItem(fn); + QStandardItem *i2 = new QStandardItem(QString::number(length)); + i2->setData(length); + mFileModel->invisibleRootItem()->appendRow(QList<QStandardItem*>() << i1 << i2); + } + if(infoD.contains("files")){ + QVariantList fList = infoD.value("files").toList(); + foreach(QVariant fn, fList){ + QVariantHash curH = fn.toHash(); + QVariantList path = curH.value("path").toList(); + QStandardItem *i1 = new QStandardItem(path.last().toString()); + qint64 length = curH.value("length").toLongLong(); + QStandardItem *i2 = new QStandardItem(QString::number(length)); + i2->setData(length); + mFileModel->invisibleRootItem()->appendRow(QList<QStandardItem*>() << i1 << i2); + } + } + mFileView->resizeColumnToContents(0); + mFileView->resizeColumnToContents(1); + } + if(it.key() == "creation date"){ + qint64 secs = it.value().toLongLong(); + QDateTime when = QDateTime::fromTime_t(secs); + mCreated->setText(when.toString(Qt::RFC2822Date)); + } + if(it.key() == "encoding"){ + mEncoding->setText(it.value().toString()); + } + if(it.key() == "created by"){ + mCreatedBy->setText(it.value().toString()); + } + //this is a list of lists + if(it.key() == "announce-list"){ + QVariantList l1 = it.value().toList(); + foreach(QVariant l2, l1){ + QVariantList l3 = l2.toList(); + foreach(QVariant ann, l3){ + QStandardItem *i1 = new QStandardItem(ann.toString()); + mAnnounceModel->invisibleRootItem()->appendRow(QList<QStandardItem*>() << i1); + } + } + } + ++it; + } + } + } +} diff --git a/torrentdisplay.h b/torrentdisplay.h new file mode 100644 index 0000000..6305335 --- /dev/null +++ b/torrentdisplay.h @@ -0,0 +1,27 @@ +#ifndef TORRENTDISPLAY_H +#define TORRENTDISPLAY_H + +#include <QDialog> + +class QLineEdit; +class QStandardItemModel; +class QTreeView; + +class TorrentDisplay : public QDialog { + Q_OBJECT + public: + explicit TorrentDisplay(QWidget *parent = 0, Qt::WindowFlags f = 0); + void setData(const QList<QVariant> data); + + private: + QLineEdit *mCreated; + QLineEdit *mCreatedBy; + QLineEdit *mEncoding; + QLineEdit *mPieceLength; + QStandardItemModel *mFileModel; + QTreeView *mFileView; + QStandardItemModel *mAnnounceModel; + QTreeView *mAnnounceView; +}; + +#endif // TORRENTDISPLAY_H diff --git a/torrentparser.cpp b/torrentparser.cpp new file mode 100644 index 0000000..fc59233 --- /dev/null +++ b/torrentparser.cpp @@ -0,0 +1,103 @@ +#include <QFile> + +#include "torrentparser.h" + +TorrentParser::TorrentParser(const QString file, QObject *parent) : QObject(parent), mFile(file), mPos(0), mOk(true) {} + +const QList<QVariant> TorrentParser::parse(){ + QFile f(mFile); + QList<QVariant> retval; + if(f.size() > 4*1024*1024){ //this is an arbitray value + mLastError = tr("File is too big!"); + return retval; + } + f.open(QIODevice::ReadOnly); + mData = f.readAll(); + f.close(); + while(mPos < mData.size()){ + retval << parseObject(); + } + return retval; +} + +const QVariant TorrentParser::parseObject(){ + QChar cur = mData.at(mPos); + if(cur == 'i'){ + return parseInt(); + } + if(cur == 'l'){ + return parseList(); + } + if(cur == 'd'){ + return parseDict(); + } + if(cur.isNumber()){ + return parseString(); + } + ++mPos; + return QVariant(); +} + +const QByteArray TorrentParser::parseString(){ + int lenlen = mData.indexOf(':', mPos) - mPos; + if(lenlen <= 0){ + mOk = false; + return QByteArray(); + } + int len = mData.mid(mPos, lenlen).toInt(); + if(mPos + len > mData.size()){ + mOk = false; + return QByteArray(); + } + mPos = mPos + lenlen + 1; + QByteArray retval = mData.mid(mPos, len); + mPos += len; + return retval; +} + +int TorrentParser::parseInt(){ + if(mData.at(mPos) != 'i'){ + return 0; + } + ++mPos; + int len = mData.indexOf('e', mPos) - mPos; + if(len <= 0){ + return 0; + } + int retval = mData.mid(mPos, len).toInt(); + mPos = mPos + len + 1; + return retval; +} + +const QList<QVariant> TorrentParser::parseList(){ + if(mData.at(mPos) != 'l'){ + return QList<QVariant>(); + } + ++mPos; + QList<QVariant> retval; + while(mData.at(mPos) != 'e'){ + retval.append(parseObject()); + } + ++mPos; + return retval; +} + + + +const QHash<QString,QVariant> TorrentParser::parseDict(){ + QHash<QString,QVariant> retval; + if(mData.at(mPos) != 'd'){ + return retval; + } + ++mPos; + while(mData.at(mPos) != 'e'){ + QString key = parseString(); + QVariant value = parseObject(); + if(key.isEmpty() || value.isNull()){ + return retval; + } + retval.insert(key, value); + } + ++mPos; + return retval; +} diff --git a/torrentparser.h b/torrentparser.h new file mode 100644 index 0000000..02129fb --- /dev/null +++ b/torrentparser.h @@ -0,0 +1,31 @@ +#ifndef TORRENTPARSER_H +#define TORRENTPARSER_H + +#include <QObject> +#include <QString> +#include <QByteArray> +#include <QList> +#include <QVariant> +#include <QHash> + +class TorrentParser : public QObject { + Q_OBJECT + public: + TorrentParser(const QString file, QObject *parent = 0); + const QList<QVariant> parse(); + const QString lastError() const { return mLastError; } + + private: + const QVariant parseObject(); + const QByteArray parseString(); + int parseInt(); + const QList<QVariant> parseList(); + const QHash<QString,QVariant> parseDict(); + QString mFile; + QString mLastError; + QByteArray mData; + int mPos; + bool mOk; +}; + +#endif // TORRENTPARSER_H |