--- /dev/null
+#include "aniaddcli.h"
+
+#include <QCoreApplication>
+#include <QStringList>
+#include <QFileInfo>
+#include <iostream>
+
+AniAddCli::AniAddCli(QObject *parent) :
+ QObject(parent), printHash(false)
+{
+ AniDBUdpClient::Client::instance()->setIdlePolicy(AniDBUdpClient::ImmediateLogoutIdlePolicy);;
+ connect(AniDBUdpClient::Client::instance(), SIGNAL(connectionError()), this, SLOT(handleError()));
+
+ connect(this, SIGNAL(finished(int)), this, SLOT(exit(int)), Qt::QueuedConnection);
+}
+
+AniAddCli::~AniAddCli()
+{
+ AniDBUdpClient::Client::destroy();
+ qDeleteAll(m_files);
+}
+
+AniDBUdpClient::MyListState AniAddCli::state() const
+{
+ return m_state;
+}
+
+void AniAddCli::setState(const AniDBUdpClient::MyListState &state)
+{
+ m_state = state;
+}
+
+void AniAddCli::process(const QStringList &files, bool rename, bool add, bool setState, bool hash)
+{
+ foreach(const QString &fileName, files)
+ {
+ QFileInfo fileInfo(fileName);
+ if (!fileInfo.exists())
+ {
+ std::cout << "[FAIL] File " << fileInfo.absoluteFilePath().toUtf8().data() << " does not exist" << std::endl;
+ continue;
+ }
+
+ AniDBUdpClient::File *file = new AniDBUdpClient::File(fileInfo);
+ connect(file, SIGNAL(statusUpdate(AniDBUdpClient::File::Action,AniDBUdpClient::File::ActionState,int)), this, SLOT(handleStatusUpdate(AniDBUdpClient::File::Action,AniDBUdpClient::File::ActionState,int)));
+
+ file->setState(m_state);
+
+ if (hash)
+ {
+ file->hash();
+ printHash = true;
+ }
+ if (rename)
+ file->rename();
+ if (add)
+ file->addToMyList();
+ if (setState)
+ file->updateState();
+
+ m_files << file;
+ }
+
+ if (m_files.isEmpty())
+ {
+ std::cout << "No files to process" << std::endl;
+ emit finished(1);
+ return;
+ }
+ std::cout << "Processing " << m_files.count() << " files" << std::endl;
+}
+
+void AniAddCli::handleStatusUpdate(AniDBUdpClient::File::Action action, AniDBUdpClient::File::ActionState state, int progress)
+{
+ AniDBUdpClient::File *file = (AniDBUdpClient::File *) sender();
+ qDebug() << (action == AniDBUdpClient::File::All) << "ALLL";
+ if (state == AniDBUdpClient::File::InProgress && progress) // Just show once per InProgress
+ return;
+
+ if (action == AniDBUdpClient::File::All)
+ {
+ m_files.removeAll(file);
+ file->deleteLater();
+
+ if (!m_files.isEmpty())
+ return;
+
+ emit finished(0);
+ return;
+ }
+
+ switch (state)
+ {
+ case AniDBUdpClient::File::Success:
+ std::cout << "[WIN!] ";
+ break;
+ case AniDBUdpClient::File::Failure:
+ std::cout << "[FAIL] ";
+ break;
+ case AniDBUdpClient::File::InProgress:
+ default:
+ std::cout << "[INFO] ";
+ break;
+ }
+
+ switch (action)
+ {
+ case AniDBUdpClient::File::Hashing:
+ std::cout << "Hashing ";
+ break;
+ case AniDBUdpClient::File::Renaming:
+ std::cout << "Renaming ";
+ break;
+ case AniDBUdpClient::File::Adding:
+ std::cout << "Adding ";
+ break;
+ case AniDBUdpClient::File::SettingState:
+ std::cout << "Set State ";
+ break;
+ default:
+ std::cout << "Unknown Operation ";
+ break;
+ }
+ std::cout << "of file " << file->file().fileName().toUtf8().data();
+
+ switch (state)
+ {
+ case AniDBUdpClient::File::Success:
+ case AniDBUdpClient::File::Finished:
+ std::cout << " finished successfully!";
+ break;
+ case AniDBUdpClient::File::Failure:
+ std::cout << " failed";
+ break;
+ case AniDBUdpClient::File::InProgress:
+ default:
+ std::cout << " started";
+ break;
+ }
+ std::cout << std::endl;
+
+ if (printHash && action == AniDBUdpClient::File::Hashing && state == AniDBUdpClient::File::Success)
+ std::cout << "[HASH] " << file->file().fileName().toUtf8().constData() << " - " << file->ed2k().constData() << std::endl;
+}
+
+void AniAddCli::handleError()
+{
+ std::cout << "[FAIL] Connection error: " << AniDBUdpClient::Client::instance()->errorString().toUtf8().data()
+ << std::endl;
+ emit finished(1);
+}
+
+void AniAddCli::exit(int code)
+{
+ if (!code)
+ std::cout << "[INFO] Done" << std::endl;
+ qApp->exit(code);
+}
--- /dev/null
+#include <QtCore/QCoreApplication>
+
+#include <QTime>
+#include <QSettings>
+#include <QStringList>
+#include <iostream>
+#include <AniDBUdpClient/MyListState>
+#include <QxtCommandOptions>
+#include <QDebug>
+#include "aniaddcli.h"
+
+QString State2String(AniDBUdpClient::State state)
+{
+ using namespace AniDBUdpClient;
+
+ QMap<State, QString> map;
+ map[StateUnknown] = "unknown";
+ map[StateOnHdd] = "hdd";
+ map[StateOnCd] = "cd";
+ map[StateDeleted] = "deleted";
+
+ return map.value(state, "unknown");
+}
+
+AniDBUdpClient::State String2State(const QString &string)
+{
+ using namespace AniDBUdpClient;
+
+ QMap<QString, State> map;
+ map["unknown"] = StateUnknown;
+ map["hdd"] = StateOnHdd;
+ map["cd"] = StateOnCd;
+ map["deleted"] = StateDeleted;
+ return map.value(string, StateUnknown);
+}
+
+QString ViewedState2String(AniDBUdpClient::MyListState::ViewedState state)
+{
+ using namespace AniDBUdpClient;
+
+ QMap<MyListState::ViewedState, QString> map;
+ map[MyListState::Unset] = "unset";
+ map[MyListState::Viewed] = "watched";
+ map[MyListState::NotViewed] = "unwatched";
+
+ return map.value(state, "unknown");
+}
+
+AniDBUdpClient::MyListState::ViewedState String2ViewedState(const QString &string)
+{
+ using namespace AniDBUdpClient;
+
+ QMap<QString, MyListState::ViewedState> map;
+ map["unset"] = MyListState::Unset;
+ map["watched"] = MyListState::Viewed;
+ map["unwatched"] = MyListState::NotViewed;
+ return map.value(string, MyListState::Unset);
+}
+
+int main(int argc, char *argv[])
+{
+ qsrand(QTime().msecsTo(QTime::currentTime()));
+
+ QCoreApplication a(argc, argv);
+
+ QCoreApplication::setApplicationName(QLatin1String("AniAdd CLI"));
+ QCoreApplication::setOrganizationName(QLatin1String("APTX"));
+ QCoreApplication::setApplicationVersion(QLatin1String("1.0.0B1"));
+
+ QSettings::setDefaultFormat(QSettings::IniFormat);
+
+ AniDBUdpClient::MyListState state;
+ QxtCommandOptions opts;
+
+ opts.setFlagStyle(QxtCommandOptions::SingleDash);
+ opts.setParamStyle(QxtCommandOptions::SpaceAndEquals);
+
+ opts.addSection("Common options");
+ opts.add("help", "Print this message");
+ opts.alias("help", "h");
+// opts.add("config", "Use this config file", QxtCommandOptions::ValueRequired);
+// opts.alias("config", "c");
+ opts.add("no-config", "Do not read config file");
+ opts.add("print-settings", "Print currently used settings. This takes into account the config settings + commandline settings");
+ opts.alias("print-settings", "p");
+ opts.add("write-config", "Write config file based on command line settings and exit");
+ opts.alias("write-config", "w");
+
+ opts.addSection("Actions");
+ opts.add("add", "Add file to MyList", QxtCommandOptions::NoValue, 1);
+ opts.add("no-add", "No not add file to MyList", QxtCommandOptions::NoValue, 1);
+ opts.add("rename", "Rename file", QxtCommandOptions::NoValue, 2);
+ opts.add("no-rename", "Do not rename file", QxtCommandOptions::NoValue, 2);
+ opts.add("update-state", "Update state even if file already added to MyList", QxtCommandOptions::NoValue, 3);
+ opts.add("no-update-state", "Do not update state", QxtCommandOptions::NoValue, 3);
+ opts.add("hash", "Print hash", QxtCommandOptions::NoValue, 4);
+ opts.add("no-hash", "Do not print hash", QxtCommandOptions::NoValue, 4);
+
+ opts.addSection("Account settings");
+ opts.add("user", "AniDB user name", QxtCommandOptions::ValueRequired);
+ opts.add("pass", "AniDB password", QxtCommandOptions::ValueRequired);
+
+ opts.addSection("Connecton settings");
+ opts.add("host", "AniDB UDP API host name", QxtCommandOptions::ValueRequired);
+ opts.add("host-port", "AniDB UDP API host port", QxtCommandOptions::ValueRequired);
+ opts.add("local-port", "Local port. WARNING: DO NOT CHANGE!", QxtCommandOptions::ValueRequired);
+
+ opts.addSection("MyList settings");
+ opts.add("state", "File state: hdd, cd, deleted or unknown", QxtCommandOptions::ValueRequired);
+ opts.alias("state", "s");
+ opts.add("mark", "Mark file as watched, unwatched or unset", QxtCommandOptions::ValueRequired);
+ opts.alias("mark", "m");
+ opts.add("source", "File source", QxtCommandOptions::ValueRequired);
+ opts.add("storage", "File storage", QxtCommandOptions::ValueRequired);
+ opts.add("other", "Other file info", QxtCommandOptions::ValueRequired);
+
+ opts.parse(a.arguments());
+
+ if (opts.count("help")) {
+ std::cout << QCoreApplication::applicationName().toUtf8().constData() << " v" << QCoreApplication::applicationVersion().toUtf8().constData()
+ << " by " << QCoreApplication::organizationName().toUtf8().constData() << std::endl << std::endl;
+ opts.showUsage();
+ return -1;
+ }
+
+ bool rename = true;
+ bool add = true;
+ bool setState = true;
+ bool hash = false;
+
+ // Read settings from config
+ if (!opts.count("no-config"))
+ {
+ AniDBUdpClient::Client *c = AniDBUdpClient::Client::instance();
+ bool ok;
+ QSettings s;
+ s.beginGroup("actions");
+ rename = s.value("rename", rename).toBool();
+ add = s.value("add", add).toBool();
+ setState = s.value("setState", setState).toBool();
+ hash = s.value("hash", hash).toBool();
+ s.endGroup();
+ s.beginGroup("account");
+ c->setUser(s.value("user", "").toString());
+ c->setPass(s.value("pass", "").toString());
+ s.endGroup();
+ s.beginGroup("connection");
+ c->setHost(s.value("host", c->host()).toString());
+ uint hostPort = s.value("hostPort", c->hostPort()).toUInt(&ok);
+ if (ok)
+ c->setHostPort(quint16(hostPort));
+ uint localPort = s.value("localPort", c->localPort()).toUInt(&ok);
+ if (ok)
+ c->setLocalPort(quint16(localPort));
+ s.endGroup();
+ s.beginGroup("myListState");
+ state.setState(String2State(s.value("state", State2String(AniDBUdpClient::StateUnknown)).toString()));
+ state.setViewed(String2ViewedState(s.value("viewed", ViewedState2String(AniDBUdpClient::MyListState::Unset)).toString()));
+ state.setSource(s.value("source", QString()).toString());
+ state.setStorage(s.value("storage", QString()).toString());
+ state.setOther(s.value("other", QString()).toString());
+ s.endGroup();
+ }
+
+ // Read config from commandline
+ {
+ AniDBUdpClient::Client *c = AniDBUdpClient::Client::instance();
+ bool ok;
+
+ if (opts.count("add"))
+ add = true;
+ if (opts.count("no-add"))
+ add = false;
+ if (opts.count("rename"))
+ rename = true;
+ if (opts.count("no-rename"))
+ rename = false;
+ if (opts.count("update-state"))
+ setState = true;
+ if (opts.count("no-update-state"))
+ setState = false;
+ if (opts.count("hash"))
+ hash = true;
+ if (opts.count("no-hash"))
+ hash = false;
+
+ if (opts.count("user"))
+ c->setUser(opts.value("user").toString());
+ if (opts.count("pass"))
+ c->setPass(opts.value("pass").toString());
+ if (opts.count("host"))
+ c->setHost(opts.value("host").toString());
+ if (opts.count("host-port"))
+ {
+ uint hostPort = opts.value("hostPort").toUInt(&ok);
+ if (ok)
+ c->setHostPort(quint16(hostPort));
+ }
+ if (opts.count("local-port"))
+ {
+ uint localPort = opts.value("localPort").toUInt(&ok);
+ if (ok)
+ c->setLocalPort(quint16(localPort));
+ }
+ if (opts.count("state"))
+ {
+ state.setState(String2State(opts.value("state").toString()));
+ }
+ if (opts.count("mark"))
+ state.setViewed(String2ViewedState(opts.value("mark").toString()));
+ if (opts.count("source"))
+ state.setSource(opts.value("source").toString());
+ if (opts.count("storage"))
+ state.setStorage(opts.value("storage").toString());
+ if (opts.count("other"))
+ state.setOther(opts.value("other").toString());
+ }
+
+ if (opts.count("print-settings"))
+ {
+ AniDBUdpClient::Client *c = AniDBUdpClient::Client::instance();
+ using namespace std;
+ cout << "Actions:" << endl;
+ cout << " Add: " << (add ? "Yes" : "No") << endl;
+ cout << " Rename: " << (rename ? "Yes" : "No") << endl;
+ cout << " Update State: " << (setState ? "Yes" : "No") << endl;
+ cout << " Print Hash: " << (hash ? "Yes" : "No") << endl << endl;
+
+ cout << "Account settings:" << endl;
+ cout << " User: " << c->user().toUtf8().constData() << endl;
+ cout << " Pass: " << (c->pass().isEmpty() ? "" : "****") << endl << endl;
+
+ cout << "Connection settings:" << endl;
+ cout << " Host: " << c->host().toUtf8().constData() << endl;
+ cout << " Host port: " << c->hostPort() << endl;
+ cout << " Local port: " << c->localPort() << endl << endl;
+
+ cout << "MyList settings:" << endl;
+ cout << " State: " << State2String(state.state()).toUtf8().constData() << endl;
+ cout << " Watched: " << ViewedState2String(state.viewed()).toUtf8().constData() << endl;
+ cout << " Source: " << state.source().toUtf8().constData() << endl;
+ cout << " Storage: " << state.storage().toUtf8().constData() << endl;
+ cout << " Other: " << state.other().toUtf8().constData() << endl;
+ cout << endl;
+ }
+
+ if (opts.count("write-config"))
+ {
+ AniDBUdpClient::Client *c = AniDBUdpClient::Client::instance();
+ QSettings s;
+ s.beginGroup("actions");
+ s.setValue("rename", rename);
+ s.setValue("add", add);
+ s.setValue("setState", setState);
+ s.setValue("hash", hash);
+ s.endGroup();
+ s.beginGroup("account");
+ s.setValue("user", c->user());
+ s.setValue("pass", c->pass());
+ s.endGroup();
+ s.beginGroup("connection");
+ s.setValue("host", c->host());
+ s.setValue("hostPort", c->hostPort());
+ s.setValue("localPort", c->localPort());
+ s.endGroup();
+ s.beginGroup("myListState");
+ s.setValue("state", State2String(state.state()));
+ s.setValue("viewed", ViewedState2String(state.viewed()));
+ s.setValue("source", state.source());
+ s.setValue("storage", state.storage());
+ s.setValue("other", state.other());
+ s.endGroup();
+ return 0;
+ }
+
+ AniAddCli t;
+ t.setState(state);
+
+ t.process(opts.positional(), rename, add, setState, hash);
+
+ return a.exec();
+}