summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArno <arno@disconnect.de>2016-08-19 17:51:10 +0200
committerArno <arno@disconnect.de>2016-08-19 17:51:10 +0200
commit8ab990b7c6fb5348b09f451878a80e2c70695876 (patch)
tree8a90c848308c09e729d9256a6af921abfeb786b3
parentcead61f9598302a83fa72e99f82f7bfa2c0b19cb (diff)
downloadShemovCleaner-8ab990b7c6fb5348b09f451878a80e2c70695876.tar.gz
ShemovCleaner-8ab990b7c6fb5348b09f451878a80e2c70695876.tar.bz2
ShemovCleaner-8ab990b7c6fb5348b09f451878a80e2c70695876.zip
Added torrent support
The BEncode parser is loosely based on this: https://github.com/jif/Bencode/blob/master/bencode.cpp Not perfect, but enough to display all the essential data in the shiny new TorrentDisplay dialog.
-rw-r--r--ShemovCleaner.pro8
-rw-r--r--shemovcleaner.cpp21
-rw-r--r--shemovcleaner.h4
-rw-r--r--torrentdisplay.cpp149
-rw-r--r--torrentdisplay.h27
-rw-r--r--torrentparser.cpp103
-rw-r--r--torrentparser.h31
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