mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-31 12:00:16 -07:00
Merge pull request #2389 from buinsky/WebUI3
Web API: Implement sync/maindata request
This commit is contained in:
commit
f2c6981711
10 changed files with 451 additions and 208 deletions
|
@ -37,53 +37,53 @@ struct WebSession;
|
||||||
|
|
||||||
class AbstractRequestHandler
|
class AbstractRequestHandler
|
||||||
{
|
{
|
||||||
friend class WebApplication;
|
friend class WebApplication;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AbstractRequestHandler(
|
AbstractRequestHandler(
|
||||||
const HttpRequest& request, const HttpEnvironment& env,
|
const HttpRequest& request, const HttpEnvironment& env,
|
||||||
WebApplication* app);
|
WebApplication* app);
|
||||||
|
|
||||||
HttpResponse run();
|
HttpResponse run();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void processRequest() = 0;
|
virtual void processRequest() = 0;
|
||||||
|
|
||||||
void status(uint code, const QString& text);
|
void status(uint code, const QString& text);
|
||||||
void header(const QString& name, const QString& value);
|
void header(const QString& name, const QString& value);
|
||||||
void print(const QString& text, const QString& type = CONTENT_TYPE_HTML);
|
void print(const QString& text, const QString& type = CONTENT_TYPE_HTML);
|
||||||
void print(const QByteArray& data, const QString& type = CONTENT_TYPE_HTML);
|
void print(const QByteArray& data, const QString& type = CONTENT_TYPE_HTML);
|
||||||
void printFile(const QString& path);
|
void printFile(const QString& path);
|
||||||
|
|
||||||
// Session management
|
// Session management
|
||||||
bool sessionActive() const { return session_ != 0; }
|
bool sessionActive() const { return session_ != 0; }
|
||||||
void sessionInitialize();
|
void sessionInitialize();
|
||||||
void sessionStart();
|
void sessionStart();
|
||||||
void sessionEnd();
|
void sessionEnd();
|
||||||
|
|
||||||
// Ban management
|
// Ban management
|
||||||
bool isBanned() const;
|
bool isBanned() const;
|
||||||
int failedAttempts() const;
|
int failedAttempts() const;
|
||||||
void resetFailedAttempts();
|
void resetFailedAttempts();
|
||||||
void increaseFailedAttempts();
|
void increaseFailedAttempts();
|
||||||
|
|
||||||
bool isAuthNeeded();
|
bool isAuthNeeded();
|
||||||
|
|
||||||
// save data to temporary file on disk and return its name (or empty string if fails)
|
// save data to temporary file on disk and return its name (or empty string if fails)
|
||||||
static QString saveTmpFile(const QByteArray& data);
|
static QString saveTmpFile(const QByteArray& data);
|
||||||
|
|
||||||
inline WebSession* session() { return session_; }
|
inline WebSession* session() { return session_; }
|
||||||
inline HttpRequest request() const { return request_; }
|
inline HttpRequest request() const { return request_; }
|
||||||
inline HttpEnvironment env() const { return env_; }
|
inline HttpEnvironment env() const { return env_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WebApplication* app_;
|
WebApplication* app_;
|
||||||
WebSession* session_;
|
WebSession* session_;
|
||||||
const HttpRequest request_;
|
const HttpRequest request_;
|
||||||
const HttpEnvironment env_;
|
const HttpEnvironment env_;
|
||||||
HttpResponse response_;
|
HttpResponse response_;
|
||||||
|
|
||||||
void print_impl(const QByteArray& data, const QString& type);
|
void print_impl(const QByteArray& data, const QString& type);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ABSTRACTREQUESTHANDLER_H
|
#endif // ABSTRACTREQUESTHANDLER_H
|
||||||
|
|
|
@ -101,6 +101,7 @@ static const char KEY_TORRENT_ETA[] = "eta";
|
||||||
static const char KEY_TORRENT_STATE[] = "state";
|
static const char KEY_TORRENT_STATE[] = "state";
|
||||||
static const char KEY_TORRENT_SEQUENTIAL_DOWNLOAD[] = "seq_dl";
|
static const char KEY_TORRENT_SEQUENTIAL_DOWNLOAD[] = "seq_dl";
|
||||||
static const char KEY_TORRENT_FIRST_LAST_PIECE_PRIO[] = "f_l_piece_prio";
|
static const char KEY_TORRENT_FIRST_LAST_PIECE_PRIO[] = "f_l_piece_prio";
|
||||||
|
static const char KEY_TORRENT_LABEL[] = "label";
|
||||||
|
|
||||||
// Tracker keys
|
// Tracker keys
|
||||||
static const char KEY_TRACKER_URL[] = "url";
|
static const char KEY_TRACKER_URL[] = "url";
|
||||||
|
@ -143,6 +144,17 @@ static const char KEY_TRANSFER_UPRATELIMIT[] = "up_rate_limit";
|
||||||
static const char KEY_TRANSFER_DHT_NODES[] = "dht_nodes";
|
static const char KEY_TRANSFER_DHT_NODES[] = "dht_nodes";
|
||||||
static const char KEY_TRANSFER_CONNECTION_STATUS[] = "connection_status";
|
static const char KEY_TRANSFER_CONNECTION_STATUS[] = "connection_status";
|
||||||
|
|
||||||
|
static const char KEY_FULL_UPDATE[] = "full_update";
|
||||||
|
static const char KEY_RESPONSE_ID[] = "rid";
|
||||||
|
static const char KEY_SUFFIX_REMOVED[] = "_removed";
|
||||||
|
|
||||||
|
QVariantMap getTranserInfoMap();
|
||||||
|
QVariantMap toMap(const QTorrentHandle& h);
|
||||||
|
void processMap(QVariantMap prevData, QVariantMap data, QVariantMap &syncData);
|
||||||
|
void processHash(QVariantHash prevData, QVariantHash data, QVariantHash &syncData, QVariantList &removedItems);
|
||||||
|
void processList(QVariantList prevData, QVariantList data, QVariantList &syncData, QVariantList &removedItems);
|
||||||
|
QVariantMap generateSyncData(int acceptedResponseId, QVariantMap data, QVariantMap &lastAcceptedData, QVariantMap &lastData);
|
||||||
|
|
||||||
class QTorrentCompare
|
class QTorrentCompare
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -195,36 +207,6 @@ private:
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static QVariantMap toMap(const QTorrentHandle& h)
|
|
||||||
{
|
|
||||||
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters);
|
|
||||||
|
|
||||||
QVariantMap ret;
|
|
||||||
ret[KEY_TORRENT_HASH] = h.hash();
|
|
||||||
ret[KEY_TORRENT_NAME] = h.name();
|
|
||||||
ret[KEY_TORRENT_SIZE] = static_cast<qlonglong>(status.total_wanted);
|
|
||||||
ret[KEY_TORRENT_PROGRESS] = h.progress(status);
|
|
||||||
ret[KEY_TORRENT_DLSPEED] = status.download_payload_rate;
|
|
||||||
ret[KEY_TORRENT_UPSPEED] = status.upload_payload_rate;
|
|
||||||
if (QBtSession::instance()->isQueueingEnabled() && h.queue_position(status) >= 0)
|
|
||||||
ret[KEY_TORRENT_PRIORITY] = h.queue_position(status);
|
|
||||||
else
|
|
||||||
ret[KEY_TORRENT_PRIORITY] = -1;
|
|
||||||
ret[KEY_TORRENT_SEEDS] = status.num_seeds;
|
|
||||||
ret[KEY_TORRENT_NUM_COMPLETE] = status.num_complete;
|
|
||||||
ret[KEY_TORRENT_LEECHS] = status.num_peers - status.num_seeds;
|
|
||||||
ret[KEY_TORRENT_NUM_INCOMPLETE] = status.num_incomplete;
|
|
||||||
const qreal ratio = QBtSession::instance()->getRealRatio(status);
|
|
||||||
ret[KEY_TORRENT_RATIO] = (ratio > QBtSession::MAX_RATIO) ? -1 : ratio;
|
|
||||||
ret[KEY_TORRENT_STATE] = h.torrentState().toString();
|
|
||||||
ret[KEY_TORRENT_ETA] = h.eta();
|
|
||||||
ret[KEY_TORRENT_SEQUENTIAL_DOWNLOAD] = status.sequential_download;
|
|
||||||
if (h.has_metadata())
|
|
||||||
ret[KEY_TORRENT_FIRST_LAST_PIECE_PRIO] = h.first_last_piece_first();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all the torrents in JSON format.
|
* Returns all the torrents in JSON format.
|
||||||
*
|
*
|
||||||
|
@ -257,7 +239,7 @@ QByteArray btjson::getTorrents(QString filter, QString label,
|
||||||
std::vector<torrent_handle>::const_iterator end = torrents.end();
|
std::vector<torrent_handle>::const_iterator end = torrents.end();
|
||||||
|
|
||||||
QTorrentFilter torrentFilter(filter, label);
|
QTorrentFilter torrentFilter(filter, label);
|
||||||
for(; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
QTorrentHandle torrent = QTorrentHandle(*it);
|
QTorrentHandle torrent = QTorrentHandle(*it);
|
||||||
|
|
||||||
if (torrentFilter.apply(torrent))
|
if (torrentFilter.apply(torrent))
|
||||||
|
@ -281,6 +263,76 @@ QByteArray btjson::getTorrents(QString filter, QString label,
|
||||||
return json::toJson(torrent_list);
|
return json::toJson(torrent_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function returns the changed data from the server to synchronize with the web client.
|
||||||
|
* Return value is map in JSON format.
|
||||||
|
* Map contain the key:
|
||||||
|
* - "Rid": ID response
|
||||||
|
* Map can contain the keys:
|
||||||
|
* - "full_update": full data update flag
|
||||||
|
* - "torrents": dictionary contains information about torrents.
|
||||||
|
* - "torrents_removed": a list of hashes of removed torrents
|
||||||
|
* - "labels": list of labels
|
||||||
|
* - "labels_removed": list of removed labels
|
||||||
|
* - "queueing": priority system usage flag
|
||||||
|
* - "server_state": map contains information about the status of the server
|
||||||
|
* The keys of the 'torrents' dictionary are hashes of torrents.
|
||||||
|
* Each value of the 'torrents' dictionary contains map. The map can contain following keys:
|
||||||
|
* - "name": Torrent name
|
||||||
|
* - "size": Torrent size
|
||||||
|
* - "progress: Torrent progress
|
||||||
|
* - "dlspeed": Torrent download speed
|
||||||
|
* - "upspeed": Torrent upload speed
|
||||||
|
* - "priority": Torrent priority (-1 if queuing is disabled)
|
||||||
|
* - "num_seeds": Torrent seeds connected to
|
||||||
|
* - "num_complete": Torrent seeds in the swarm
|
||||||
|
* - "num_leechs": Torrent leechers connected to
|
||||||
|
* - "num_incomplete": Torrent leechers in the swarm
|
||||||
|
* - "ratio": Torrent share ratio
|
||||||
|
* - "eta": Torrent ETA
|
||||||
|
* - "state": Torrent state
|
||||||
|
* - "seq_dl": Torrent sequential download state
|
||||||
|
* - "f_l_piece_prio": Torrent first last piece priority state
|
||||||
|
* Server state map may contain the following keys:
|
||||||
|
* - "connection_status": conection status
|
||||||
|
* - "dht_nodes": DHT nodes count
|
||||||
|
* - "dl_info_data": bytes downloaded
|
||||||
|
* - "dl_info_speed": download speed
|
||||||
|
* - "dl_rate_limit: downlaod rate limit
|
||||||
|
* - "up_info_data: bytes uploaded
|
||||||
|
* - "up_info_speed: upload speed
|
||||||
|
* - "up_rate_limit: upload speed limit
|
||||||
|
*/
|
||||||
|
QByteArray btjson::getSyncMainData(int acceptedResponseId, QVariantMap &lastData, QVariantMap &lastAcceptedData)
|
||||||
|
{
|
||||||
|
QVariantMap data;
|
||||||
|
|
||||||
|
QVariantHash torrents;
|
||||||
|
|
||||||
|
std::vector<torrent_handle> torrentsList = QBtSession::instance()->getTorrents();
|
||||||
|
std::vector<torrent_handle>::const_iterator it = torrentsList.begin();
|
||||||
|
std::vector<torrent_handle>::const_iterator end = torrentsList.end();
|
||||||
|
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
QTorrentHandle torrent = QTorrentHandle(*it);
|
||||||
|
QVariantMap map = toMap(torrent);
|
||||||
|
map.remove(KEY_TORRENT_HASH);
|
||||||
|
torrents[torrent.hash()] = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
data["torrents"] = torrents;
|
||||||
|
data["queueing"] = QBtSession::instance()->isQueueingEnabled();
|
||||||
|
|
||||||
|
QVariantList labels;
|
||||||
|
foreach (QString s, Preferences::instance()->getTorrentLabels())
|
||||||
|
labels << s;
|
||||||
|
|
||||||
|
data["labels"] = labels;
|
||||||
|
data["server_state"] = getTranserInfoMap();
|
||||||
|
|
||||||
|
return json::toJson(generateSyncData(acceptedResponseId, data, lastAcceptedData, lastData));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the trackers for a torrent in JSON format.
|
* Returns the trackers for a torrent in JSON format.
|
||||||
*
|
*
|
||||||
|
@ -322,7 +374,7 @@ QByteArray btjson::getTrackersForTorrent(const QString& hash)
|
||||||
tracker_list.append(tracker_dict);
|
tracker_list.append(tracker_dict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << misc::toQStringU(e.what());
|
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << misc::toQStringU(e.what());
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
@ -384,7 +436,7 @@ QByteArray btjson::getPropertiesForTorrent(const QString& hash)
|
||||||
const qreal ratio = QBtSession::instance()->getRealRatio(status);
|
const qreal ratio = QBtSession::instance()->getRealRatio(status);
|
||||||
data[KEY_PROP_RATIO] = ratio > QBtSession::MAX_RATIO ? -1 : ratio;
|
data[KEY_PROP_RATIO] = ratio > QBtSession::MAX_RATIO ? -1 : ratio;
|
||||||
}
|
}
|
||||||
catch(const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << misc::toQStringU(e.what());
|
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << misc::toQStringU(e.what());
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
@ -454,21 +506,214 @@ QByteArray btjson::getFilesForTorrent(const QString& hash)
|
||||||
*/
|
*/
|
||||||
QByteArray btjson::getTransferInfo()
|
QByteArray btjson::getTransferInfo()
|
||||||
{
|
{
|
||||||
QVariantMap info;
|
return json::toJson(getTranserInfoMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap getTranserInfoMap()
|
||||||
|
{
|
||||||
|
QVariantMap map;
|
||||||
session_status sessionStatus = QBtSession::instance()->getSessionStatus();
|
session_status sessionStatus = QBtSession::instance()->getSessionStatus();
|
||||||
session_settings sessionSettings = QBtSession::instance()->getSession()->settings();
|
session_settings sessionSettings = QBtSession::instance()->getSession()->settings();
|
||||||
info[KEY_TRANSFER_DLSPEED] = sessionStatus.payload_download_rate;
|
map[KEY_TRANSFER_DLSPEED] = sessionStatus.payload_download_rate;
|
||||||
info[KEY_TRANSFER_DLDATA] = static_cast<qlonglong>(sessionStatus.total_payload_download);
|
map[KEY_TRANSFER_DLDATA] = static_cast<qlonglong>(sessionStatus.total_payload_download);
|
||||||
info[KEY_TRANSFER_UPSPEED] = sessionStatus.payload_upload_rate;
|
map[KEY_TRANSFER_UPSPEED] = sessionStatus.payload_upload_rate;
|
||||||
info[KEY_TRANSFER_UPDATA] = static_cast<qlonglong>(sessionStatus.total_payload_upload);
|
map[KEY_TRANSFER_UPDATA] = static_cast<qlonglong>(sessionStatus.total_payload_upload);
|
||||||
if (sessionSettings.download_rate_limit)
|
map[KEY_TRANSFER_DLRATELIMIT] = sessionSettings.download_rate_limit;
|
||||||
info[KEY_TRANSFER_DLRATELIMIT] = sessionSettings.download_rate_limit;
|
map[KEY_TRANSFER_UPRATELIMIT] = sessionSettings.upload_rate_limit;
|
||||||
if (sessionSettings.upload_rate_limit)
|
map[KEY_TRANSFER_DHT_NODES] = sessionStatus.dht_nodes;
|
||||||
info[KEY_TRANSFER_UPRATELIMIT] = sessionSettings.upload_rate_limit;
|
|
||||||
info[KEY_TRANSFER_DHT_NODES] = sessionStatus.dht_nodes;
|
|
||||||
if (!QBtSession::instance()->getSession()->is_listening())
|
if (!QBtSession::instance()->getSession()->is_listening())
|
||||||
info[KEY_TRANSFER_CONNECTION_STATUS] = "disconnected";
|
map[KEY_TRANSFER_CONNECTION_STATUS] = "disconnected";
|
||||||
else
|
else
|
||||||
info[KEY_TRANSFER_CONNECTION_STATUS] = sessionStatus.has_incoming_connections ? "connected" : "firewalled";
|
map[KEY_TRANSFER_CONNECTION_STATUS] = sessionStatus.has_incoming_connections ? "connected" : "firewalled";
|
||||||
return json::toJson(info);
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap toMap(const QTorrentHandle& h)
|
||||||
|
{
|
||||||
|
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters);
|
||||||
|
|
||||||
|
QVariantMap ret;
|
||||||
|
ret[KEY_TORRENT_HASH] = h.hash();
|
||||||
|
ret[KEY_TORRENT_NAME] = h.name();
|
||||||
|
ret[KEY_TORRENT_SIZE] = static_cast<qlonglong>(status.total_wanted);
|
||||||
|
ret[KEY_TORRENT_PROGRESS] = h.progress(status);
|
||||||
|
ret[KEY_TORRENT_DLSPEED] = status.download_payload_rate;
|
||||||
|
ret[KEY_TORRENT_UPSPEED] = status.upload_payload_rate;
|
||||||
|
if (QBtSession::instance()->isQueueingEnabled() && h.queue_position(status) >= 0)
|
||||||
|
ret[KEY_TORRENT_PRIORITY] = h.queue_position(status);
|
||||||
|
else
|
||||||
|
ret[KEY_TORRENT_PRIORITY] = -1;
|
||||||
|
ret[KEY_TORRENT_SEEDS] = status.num_seeds;
|
||||||
|
ret[KEY_TORRENT_NUM_COMPLETE] = status.num_complete;
|
||||||
|
ret[KEY_TORRENT_LEECHS] = status.num_peers - status.num_seeds;
|
||||||
|
ret[KEY_TORRENT_NUM_INCOMPLETE] = status.num_incomplete;
|
||||||
|
const qreal ratio = QBtSession::instance()->getRealRatio(status);
|
||||||
|
ret[KEY_TORRENT_RATIO] = (ratio > QBtSession::MAX_RATIO) ? -1 : ratio;
|
||||||
|
ret[KEY_TORRENT_STATE] = h.torrentState().toString();
|
||||||
|
ret[KEY_TORRENT_ETA] = h.eta();
|
||||||
|
ret[KEY_TORRENT_SEQUENTIAL_DOWNLOAD] = status.sequential_download;
|
||||||
|
if (h.has_metadata())
|
||||||
|
ret[KEY_TORRENT_FIRST_LAST_PIECE_PRIO] = h.first_last_piece_first();
|
||||||
|
ret[KEY_TORRENT_LABEL] = TorrentPersistentData::getLabel(h.hash());
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two structures (prevData, data) and calculate difference (syncData).
|
||||||
|
// Structures encoded as map.
|
||||||
|
void processMap(QVariantMap prevData, QVariantMap data, QVariantMap &syncData)
|
||||||
|
{
|
||||||
|
// initialize output variable
|
||||||
|
syncData.clear();
|
||||||
|
|
||||||
|
QVariantList removedItems;
|
||||||
|
foreach (QString key, data.keys()) {
|
||||||
|
removedItems.clear();
|
||||||
|
|
||||||
|
switch (data[key].type()) {
|
||||||
|
case QVariant::Map: {
|
||||||
|
QVariantMap map;
|
||||||
|
processMap(prevData[key].toMap(), data[key].toMap(), map);
|
||||||
|
if (!map.isEmpty())
|
||||||
|
syncData[key] = map;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QVariant::Hash: {
|
||||||
|
QVariantHash hash;
|
||||||
|
processHash(prevData[key].toHash(), data[key].toHash(), hash, removedItems);
|
||||||
|
if (!hash.isEmpty())
|
||||||
|
syncData[key] = hash;
|
||||||
|
if (!removedItems.isEmpty())
|
||||||
|
syncData[key + KEY_SUFFIX_REMOVED] = removedItems;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QVariant::List: {
|
||||||
|
QVariantList list;
|
||||||
|
processList(prevData[key].toList(), data[key].toList(), list, removedItems);
|
||||||
|
if (!list.isEmpty())
|
||||||
|
syncData[key] = list;
|
||||||
|
if (!removedItems.isEmpty())
|
||||||
|
syncData[key + KEY_SUFFIX_REMOVED] = removedItems;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QVariant::String:
|
||||||
|
case QVariant::LongLong:
|
||||||
|
case QMetaType::Float:
|
||||||
|
case QVariant::Int:
|
||||||
|
case QVariant::Bool:
|
||||||
|
case QVariant::Double:
|
||||||
|
case QVariant::ULongLong:
|
||||||
|
if (prevData[key] != data[key])
|
||||||
|
syncData[key] = data[key];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Q_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two lists of structures (prevData, data) and calculate difference (syncData, removedItems).
|
||||||
|
// Structures encoded as map.
|
||||||
|
// Lists are encoded as hash table (indexed by structure key value) to improve ease of searching for removed items.
|
||||||
|
void processHash(QVariantHash prevData, QVariantHash data, QVariantHash &syncData, QVariantList &removedItems)
|
||||||
|
{
|
||||||
|
// initialize output variables
|
||||||
|
syncData.clear();
|
||||||
|
removedItems.clear();
|
||||||
|
|
||||||
|
if (prevData.isEmpty()) {
|
||||||
|
// If list was empty before, then difference is a whole new list.
|
||||||
|
syncData = data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach (QString key, data.keys()) {
|
||||||
|
switch (data[key].type()) {
|
||||||
|
case QVariant::Map:
|
||||||
|
if (!prevData.contains(key)) {
|
||||||
|
// new list item found - append it to syncData
|
||||||
|
syncData[key] = data[key];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QVariantMap map;
|
||||||
|
processMap(prevData[key].toMap(), data[key].toMap(), map);
|
||||||
|
// existing list item found - remove it from prevData
|
||||||
|
prevData.remove(key);
|
||||||
|
if (!map.isEmpty())
|
||||||
|
// changed list item found - append its changes to syncData
|
||||||
|
syncData[key] = map;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Q_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prevData.isEmpty()) {
|
||||||
|
// prevData contains only items that are missing now -
|
||||||
|
// put them in removedItems
|
||||||
|
foreach (QString s, prevData.keys())
|
||||||
|
removedItems << s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two lists of simple value (prevData, data) and calculate difference (syncData, removedItems).
|
||||||
|
void processList(QVariantList prevData, QVariantList data, QVariantList &syncData, QVariantList &removedItems)
|
||||||
|
{
|
||||||
|
// initialize output variables
|
||||||
|
syncData.clear();
|
||||||
|
removedItems.clear();
|
||||||
|
|
||||||
|
if (prevData.isEmpty()) {
|
||||||
|
// If list was empty before, then difference is a whole new list.
|
||||||
|
syncData = data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach (QVariant item, data) {
|
||||||
|
if (!prevData.contains(item))
|
||||||
|
// new list item found - append it to syncData
|
||||||
|
syncData.append(item);
|
||||||
|
else
|
||||||
|
// unchanged list item found - remove it from prevData
|
||||||
|
prevData.removeOne(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prevData.isEmpty())
|
||||||
|
// prevData contains only items that are missing now -
|
||||||
|
// put them in removedItems
|
||||||
|
removedItems = prevData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap generateSyncData(int acceptedResponseId, QVariantMap data, QVariantMap &lastAcceptedData, QVariantMap &lastData)
|
||||||
|
{
|
||||||
|
QVariantMap syncData;
|
||||||
|
bool fullUpdate = true;
|
||||||
|
int lastResponseId = 0;
|
||||||
|
if (acceptedResponseId > 0) {
|
||||||
|
lastResponseId = lastData[KEY_RESPONSE_ID].toInt();
|
||||||
|
|
||||||
|
if (lastResponseId == acceptedResponseId)
|
||||||
|
lastAcceptedData = lastData;
|
||||||
|
|
||||||
|
int lastAcceptedResponseId = lastAcceptedData[KEY_RESPONSE_ID].toInt();
|
||||||
|
|
||||||
|
if (lastAcceptedResponseId == acceptedResponseId) {
|
||||||
|
processMap(lastAcceptedData, data, syncData);
|
||||||
|
fullUpdate = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullUpdate) {
|
||||||
|
lastAcceptedData.clear();
|
||||||
|
syncData = data;
|
||||||
|
syncData[KEY_FULL_UPDATE] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastResponseId = lastResponseId % 1000000 + 1; // cycle between 1 and 1000000
|
||||||
|
lastData = data;
|
||||||
|
lastData[KEY_RESPONSE_ID] = lastResponseId;
|
||||||
|
syncData[KEY_RESPONSE_ID] = lastResponseId;
|
||||||
|
|
||||||
|
return syncData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
class QTorrentHandle;
|
class QTorrentHandle;
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ private:
|
||||||
public:
|
public:
|
||||||
static QByteArray getTorrents(QString filter = "all", QString label = QString(),
|
static QByteArray getTorrents(QString filter = "all", QString label = QString(),
|
||||||
QString sortedColumn = "name", bool reverse = false, int limit = 0, int offset = 0);
|
QString sortedColumn = "name", bool reverse = false, int limit = 0, int offset = 0);
|
||||||
|
static QByteArray getSyncMainData(int acceptedResponseId, QVariantMap &lastData, QVariantMap &lastAcceptedData);
|
||||||
static QByteArray getTrackersForTorrent(const QString& hash);
|
static QByteArray getTrackersForTorrent(const QString& hash);
|
||||||
static QByteArray getPropertiesForTorrent(const QString& hash);
|
static QByteArray getPropertiesForTorrent(const QString& hash);
|
||||||
static QByteArray getFilesForTorrent(const QString& hash);
|
static QByteArray getFilesForTorrent(const QString& hash);
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "prefjson.h"
|
#include "prefjson.h"
|
||||||
#include "qbtsession.h"
|
#include "qbtsession.h"
|
||||||
#include "requesthandler.h"
|
#include "requesthandler.h"
|
||||||
|
#include "webapplication.h"
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
@ -82,6 +83,7 @@ QMap<QString, QMap<QString, RequestHandler::Action> > RequestHandler::initialize
|
||||||
ADD_ACTION(json, propertiesGeneral);
|
ADD_ACTION(json, propertiesGeneral);
|
||||||
ADD_ACTION(json, propertiesTrackers);
|
ADD_ACTION(json, propertiesTrackers);
|
||||||
ADD_ACTION(json, propertiesFiles);
|
ADD_ACTION(json, propertiesFiles);
|
||||||
|
ADD_ACTION(sync, maindata);
|
||||||
ADD_ACTION(command, shutdown);
|
ADD_ACTION(command, shutdown);
|
||||||
ADD_ACTION(command, download);
|
ADD_ACTION(command, download);
|
||||||
ADD_ACTION(command, upload);
|
ADD_ACTION(command, upload);
|
||||||
|
@ -261,6 +263,14 @@ void RequestHandler::action_json_propertiesFiles()
|
||||||
print(btjson::getFilesForTorrent(args_.front()), CONTENT_TYPE_JS);
|
print(btjson::getFilesForTorrent(args_.front()), CONTENT_TYPE_JS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET param:
|
||||||
|
// - rid (int): last response id
|
||||||
|
void RequestHandler::action_sync_maindata()
|
||||||
|
{
|
||||||
|
CHECK_URI(0);
|
||||||
|
print(btjson::getSyncMainData(request().gets["rid"].toInt(), session()->syncMainDataLastResponse, session()->syncMainDataLastAcceptedResponse));
|
||||||
|
}
|
||||||
|
|
||||||
void RequestHandler::action_version_api()
|
void RequestHandler::action_version_api()
|
||||||
{
|
{
|
||||||
CHECK_URI(0);
|
CHECK_URI(0);
|
||||||
|
|
|
@ -56,6 +56,7 @@ private:
|
||||||
void action_json_propertiesGeneral();
|
void action_json_propertiesGeneral();
|
||||||
void action_json_propertiesTrackers();
|
void action_json_propertiesTrackers();
|
||||||
void action_json_propertiesFiles();
|
void action_json_propertiesFiles();
|
||||||
|
void action_sync_maindata();
|
||||||
void action_command_shutdown();
|
void action_command_shutdown();
|
||||||
void action_command_download();
|
void action_command_download();
|
||||||
void action_command_upload();
|
void action_command_upload();
|
||||||
|
|
|
@ -33,12 +33,14 @@
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include "httptypes.h"
|
#include "httptypes.h"
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
struct WebSession
|
struct WebSession
|
||||||
{
|
{
|
||||||
const QString id;
|
const QString id;
|
||||||
|
QVariantMap syncMainDataLastResponse;
|
||||||
WebSession(const QString& id): id(id) {}
|
QVariantMap syncMainDataLastAcceptedResponse;
|
||||||
|
WebSession(const QString& id): id(id) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
const QString C_SID = "SID"; // name of session id cookie
|
const QString C_SID = "SID"; // name of session id cookie
|
||||||
|
@ -49,39 +51,39 @@ class AbstractRequestHandler;
|
||||||
|
|
||||||
class WebApplication: public QObject
|
class WebApplication: public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_DISABLE_COPY(WebApplication)
|
Q_DISABLE_COPY(WebApplication)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WebApplication(QObject* parent = 0);
|
WebApplication(QObject* parent = 0);
|
||||||
virtual ~WebApplication();
|
virtual ~WebApplication();
|
||||||
|
|
||||||
static WebApplication* instance();
|
static WebApplication* instance();
|
||||||
|
|
||||||
bool isBanned(const AbstractRequestHandler* _this) const;
|
bool isBanned(const AbstractRequestHandler* _this) const;
|
||||||
int failedAttempts(const AbstractRequestHandler *_this) const;
|
int failedAttempts(const AbstractRequestHandler *_this) const;
|
||||||
void resetFailedAttempts(AbstractRequestHandler* _this);
|
void resetFailedAttempts(AbstractRequestHandler* _this);
|
||||||
void increaseFailedAttempts(AbstractRequestHandler* _this);
|
void increaseFailedAttempts(AbstractRequestHandler* _this);
|
||||||
|
|
||||||
bool sessionStart(AbstractRequestHandler* _this);
|
bool sessionStart(AbstractRequestHandler* _this);
|
||||||
bool sessionEnd(AbstractRequestHandler* _this);
|
bool sessionEnd(AbstractRequestHandler* _this);
|
||||||
bool sessionInitialize(AbstractRequestHandler* _this);
|
bool sessionInitialize(AbstractRequestHandler* _this);
|
||||||
|
|
||||||
bool readFile(const QString &path, QByteArray& data, QString& type);
|
bool readFile(const QString &path, QByteArray& data, QString& type);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void UnbanTimerEvent();
|
void UnbanTimerEvent();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMap<QString, WebSession*> sessions_;
|
QMap<QString, WebSession*> sessions_;
|
||||||
QHash<QHostAddress, int> clientFailedAttempts_;
|
QHash<QHostAddress, int> clientFailedAttempts_;
|
||||||
QMap<QString, QByteArray> translatedFiles_;
|
QMap<QString, QByteArray> translatedFiles_;
|
||||||
|
|
||||||
QString generateSid();
|
QString generateSid();
|
||||||
static void translateDocument(QString& data);
|
static void translateDocument(QString& data);
|
||||||
|
|
||||||
static const QStringMap CONTENT_TYPE_BY_EXT;
|
static const QStringMap CONTENT_TYPE_BY_EXT;
|
||||||
static QStringMap initializeContentTypeByExtMap();
|
static QStringMap initializeContentTypeByExtMap();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WEBAPPLICATION_H
|
#endif // WEBAPPLICATION_H
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
'limit': limit
|
'limit': limit
|
||||||
},
|
},
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
window.parent.updateTransferInfo();
|
window.parent.updateMainData();
|
||||||
window.parent.closeWindows();
|
window.parent.closeWindows();
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
|
|
|
@ -25,8 +25,7 @@
|
||||||
myTable = new dynamicTable();
|
myTable = new dynamicTable();
|
||||||
|
|
||||||
var updatePropertiesPanel = function(){};
|
var updatePropertiesPanel = function(){};
|
||||||
var updateTransferInfo = function(){};
|
var updateMainData = function(){};
|
||||||
var updateTransferList = function(){};
|
|
||||||
var alternativeSpeedLimits = false;
|
var alternativeSpeedLimits = false;
|
||||||
|
|
||||||
selected_filter = getLocalStorageItem('selected_filter', 'all');
|
selected_filter = getLocalStorageItem('selected_filter', 'all');
|
||||||
|
@ -49,7 +48,6 @@ var saveSelectedLabel = function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window.addEvent('load', function () {
|
window.addEvent('load', function () {
|
||||||
|
|
||||||
var saveColumnSizes = function () {
|
var saveColumnSizes = function () {
|
||||||
|
@ -104,7 +102,7 @@ window.addEvent('load', function () {
|
||||||
localStorage.setItem('selected_filter', f);
|
localStorage.setItem('selected_filter', f);
|
||||||
// Reload torrents
|
// Reload torrents
|
||||||
if (typeof myTable.table != 'undefined')
|
if (typeof myTable.table != 'undefined')
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
}
|
}
|
||||||
|
|
||||||
new MochaUI.Panel({
|
new MochaUI.Panel({
|
||||||
|
@ -131,114 +129,99 @@ window.addEvent('load', function () {
|
||||||
if (!speedInTitle)
|
if (!speedInTitle)
|
||||||
$('speedInBrowserTitleBarLink').firstChild.style.opacity = '0';
|
$('speedInBrowserTitleBarLink').firstChild.style.opacity = '0';
|
||||||
|
|
||||||
var loadTorrentsInfoTimer;
|
var syncMainDataLastResponseId = 0;
|
||||||
var loadTorrentsInfo = function () {
|
var serverState = {};
|
||||||
var url = new URI('json/torrents');
|
|
||||||
|
var syncMainDataTimer;
|
||||||
|
var syncMainData = function () {
|
||||||
|
var url = new URI('sync/maindata');
|
||||||
|
url.setData('rid', syncMainDataLastResponseId);
|
||||||
var request = new Request.JSON({
|
var request = new Request.JSON({
|
||||||
url : url,
|
url : url,
|
||||||
noCache : true,
|
noCache : true,
|
||||||
method : 'get',
|
method : 'get',
|
||||||
onFailure : function () {
|
onFailure : function () {
|
||||||
$('error_div').set('html', 'QBT_TR(qBittorrent client is not reachable)QBT_TR');
|
$('error_div').set('html', 'QBT_TR(qBittorrent client is not reachable)QBT_TR');
|
||||||
clearTimeout(loadTorrentsInfoTimer);
|
clearTimeout(syncMainDataTimer);
|
||||||
loadTorrentsInfoTimer = loadTorrentsInfo.delay(2000);
|
syncMainDataTimer = syncMainData.delay(2000);
|
||||||
},
|
},
|
||||||
onSuccess : function (response) {
|
onSuccess : function (response) {
|
||||||
$('error_div').set('html', '');
|
$('error_div').set('html', '');
|
||||||
if (response) {
|
if (response) {
|
||||||
var queueing_enabled = false;
|
var full_update = (response['full_update'] == true);
|
||||||
var torrents_hashes = new Array();
|
if (full_update)
|
||||||
for (var i = 0; i < response.length; i++) {
|
myTable.rows.erase();
|
||||||
torrents_hashes.push(response[i].hash);
|
if (response['rid'])
|
||||||
if (response[i].priority > -1)
|
syncMainDataLastResponseId = response['rid'];
|
||||||
queueing_enabled = true;
|
if ('queueing' in response) {
|
||||||
myTable.updateRowData(response[i])
|
var queueing_enabled = response['queueing'];
|
||||||
|
myTable.columns['priority'].force_hide = !queueing_enabled;
|
||||||
|
myTable.updateColumn('priority');
|
||||||
|
if (queueing_enabled) {
|
||||||
|
$('queueingButtons').removeClass('invisible');
|
||||||
|
$('queueingMenuItems').removeClass('invisible');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('queueingButtons').addClass('invisible');
|
||||||
|
$('queueingMenuItems').addClass('invisible');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (response['torrents'])
|
||||||
var keys = myTable.rows.getKeys();
|
for (var key in response['torrents']) {
|
||||||
for (var i = 0; i < keys.length; i++) {
|
response['torrents'][key]['hash'] = key;
|
||||||
if (!torrents_hashes.contains(keys[i]))
|
myTable.updateRowData(response['torrents'][key]);
|
||||||
myTable.rows.erase(keys[i]);
|
}
|
||||||
}
|
myTable.updateTable(full_update);
|
||||||
|
if (response['torrents_removed'])
|
||||||
myTable.columns['priority'].force_hide = !queueing_enabled;
|
response['torrents_removed'].each(function (hash) {
|
||||||
myTable.updateColumn('priority');
|
myTable.removeRow(hash);
|
||||||
if (queueing_enabled) {
|
});
|
||||||
$('queueingButtons').removeClass('invisible');
|
|
||||||
$('queueingMenuItems').removeClass('invisible');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$('queueingButtons').addClass('invisible');
|
|
||||||
$('queueingMenuItems').addClass('invisible');
|
|
||||||
}
|
|
||||||
|
|
||||||
myTable.updateTable(true);
|
|
||||||
myTable.altRow();
|
myTable.altRow();
|
||||||
|
if (response['server_state']) {
|
||||||
|
var tmp = response['server_state'];
|
||||||
|
for(var key in tmp)
|
||||||
|
serverState[key] = tmp[key];
|
||||||
|
processServerState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
clearTimeout(loadTorrentsInfoTimer);
|
clearTimeout(syncMainDataTimer);
|
||||||
loadTorrentsInfoTimer = loadTorrentsInfo.delay(1500);
|
syncMainDataTimer = syncMainData.delay(1500);
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
};
|
};
|
||||||
|
|
||||||
updateTransferList = function() {
|
updateMainData = function() {
|
||||||
myTable.updateTable();
|
myTable.updateTable();
|
||||||
clearTimeout(loadTorrentsInfoTimer);
|
clearTimeout(syncMainDataTimer);
|
||||||
loadTorrentsInfoTimer = loadTorrentsInfo.delay(30);
|
syncMainDataTimer = syncMainData.delay(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
var loadTransferInfoTimer;
|
var processServerState = function () {
|
||||||
var loadTransferInfo = function () {
|
var transfer_info = "";
|
||||||
var url = 'json/transferInfo';
|
if (serverState.dl_rate_limit > 0)
|
||||||
var request = new Request.JSON({
|
transfer_info += "[" + friendlyUnit(serverState.dl_rate_limit, true) + "] ";
|
||||||
url : url,
|
transfer_info += friendlyUnit(serverState.dl_info_speed, true);
|
||||||
noCache : true,
|
transfer_info += " (" + friendlyUnit(serverState.dl_info_data, false) + ")"
|
||||||
method : 'get',
|
$("DlInfos").set('html', transfer_info);
|
||||||
onFailure : function () {
|
transfer_info = "";
|
||||||
$('error_div').set('html', 'QBT_TR(qBittorrent client is not reachable)QBT_TR');
|
if (serverState.up_rate_limit > 0)
|
||||||
clearTimeout(loadTransferInfoTimer);
|
transfer_info += "[" + friendlyUnit(serverState.up_rate_limit, true) + "] ";
|
||||||
loadTransferInfoTimer = loadTransferInfo.delay(4000);
|
transfer_info += friendlyUnit(serverState.up_info_speed, true)
|
||||||
},
|
transfer_info += " (" + friendlyUnit(serverState.up_info_data, false) + ")"
|
||||||
onSuccess : function (info) {
|
$("UpInfos").set('html', transfer_info);
|
||||||
if (info) {
|
if (speedInTitle)
|
||||||
var transfer_info = "";
|
document.title = "QBT_TR(D:%1 U:%2)QBT_TR".replace("%1", friendlyUnit(serverState.dl_info_speed, true)).replace("%2", friendlyUnit(serverState.up_info_speed, true));
|
||||||
if (info.dl_rate_limit != undefined)
|
else
|
||||||
transfer_info += "[" + friendlyUnit(info.dl_rate_limit, true) + "] ";
|
document.title = "QBT_TR(qBittorrent web User Interface)QBT_TR";
|
||||||
transfer_info += friendlyUnit(info.dl_info_speed, true);
|
$('DHTNodes').set('html', 'QBT_TR(DHT: %1 nodes)QBT_TR'.replace("%1", serverState.dht_nodes));
|
||||||
transfer_info += " (" + friendlyUnit(info.dl_info_data, false) + ")"
|
if (serverState.connection_status == "connected")
|
||||||
$("DlInfos").set('html', transfer_info);
|
$('connectionStatus').src = 'images/skin/connected.png';
|
||||||
transfer_info = "";
|
else if (serverState.connection_status == "firewalled")
|
||||||
if (info.up_rate_limit != undefined)
|
$('connectionStatus').src = 'images/skin/firewalled.png';
|
||||||
transfer_info += "[" + friendlyUnit(info.up_rate_limit, true) + "] ";
|
else
|
||||||
transfer_info += friendlyUnit(info.up_info_speed, true)
|
$('connectionStatus').src = 'images/skin/disconnected.png';
|
||||||
transfer_info += " (" + friendlyUnit(info.up_info_data, false) + ")"
|
|
||||||
$("UpInfos").set('html', transfer_info);
|
|
||||||
if (speedInTitle)
|
|
||||||
document.title = "QBT_TR(D:%1 U:%2)QBT_TR".replace("%1", friendlyUnit(info.dl_info_speed, true)).replace("%2", friendlyUnit(info.up_info_speed, true));
|
|
||||||
else
|
|
||||||
document.title = "QBT_TR(qBittorrent web User Interface)QBT_TR";
|
|
||||||
$('DHTNodes').set('html', 'QBT_TR(DHT: %1 nodes)QBT_TR'.replace("%1", info.dht_nodes));
|
|
||||||
if (info.connection_status == "connected")
|
|
||||||
$('connectionStatus').src = 'images/skin/connected.png';
|
|
||||||
else if (info.connection_status == "firewalled")
|
|
||||||
$('connectionStatus').src = 'images/skin/firewalled.png';
|
|
||||||
else
|
|
||||||
$('connectionStatus').src = 'images/skin/disconnected.png';
|
|
||||||
clearTimeout(loadTransferInfoTimer);
|
|
||||||
loadTransferInfoTimer = loadTransferInfo.delay(3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).send();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
updateTransferInfo = function() {
|
|
||||||
clearTimeout(loadTransferInfoTimer);
|
|
||||||
loadTransferInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start fetching data now
|
|
||||||
loadTransferInfo();
|
|
||||||
|
|
||||||
var updateAltSpeedIcon = function(enabled) {
|
var updateAltSpeedIcon = function(enabled) {
|
||||||
if (enabled)
|
if (enabled)
|
||||||
$('alternativeSpeedLimits').src = "images/slow.png";
|
$('alternativeSpeedLimits').src = "images/slow.png";
|
||||||
|
@ -264,7 +247,7 @@ window.addEvent('load', function () {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
alternativeSpeedLimits = !alternativeSpeedLimits;
|
alternativeSpeedLimits = !alternativeSpeedLimits;
|
||||||
updateTransferInfo();
|
updateMainData();
|
||||||
},
|
},
|
||||||
onFailure: function() {
|
onFailure: function() {
|
||||||
// Restore icon in case of failure
|
// Restore icon in case of failure
|
||||||
|
@ -278,7 +261,7 @@ window.addEvent('load', function () {
|
||||||
|
|
||||||
setSortedColumn = function (column) {
|
setSortedColumn = function (column) {
|
||||||
myTable.setSortedColumn(column);
|
myTable.setSortedColumn(column);
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
};
|
};
|
||||||
|
|
||||||
$('speedInBrowserTitleBarLink').addEvent('click', function(e) {
|
$('speedInBrowserTitleBarLink').addEvent('click', function(e) {
|
||||||
|
@ -288,7 +271,7 @@ window.addEvent('load', function () {
|
||||||
$('speedInBrowserTitleBarLink').firstChild.style.opacity = '1';
|
$('speedInBrowserTitleBarLink').firstChild.style.opacity = '1';
|
||||||
else
|
else
|
||||||
$('speedInBrowserTitleBarLink').firstChild.style.opacity = '0';
|
$('speedInBrowserTitleBarLink').firstChild.style.opacity = '0';
|
||||||
updateTransferInfo();
|
updateMainData();
|
||||||
});
|
});
|
||||||
|
|
||||||
new MochaUI.Panel({
|
new MochaUI.Panel({
|
||||||
|
@ -304,7 +287,7 @@ window.addEvent('load', function () {
|
||||||
loadMethod : 'xhr',
|
loadMethod : 'xhr',
|
||||||
contentURL : 'transferlist.html',
|
contentURL : 'transferlist.html',
|
||||||
onContentLoaded : function () {
|
onContentLoaded : function () {
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
},
|
},
|
||||||
column : 'mainColumn',
|
column : 'mainColumn',
|
||||||
onResize : saveColumnSizes,
|
onResize : saveColumnSizes,
|
||||||
|
|
|
@ -55,7 +55,7 @@ initializeWindows = function() {
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 300
|
height: 300
|
||||||
});
|
});
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
});
|
});
|
||||||
|
|
||||||
addClickEvent('preferences', function(e) {
|
addClickEvent('preferences', function(e) {
|
||||||
|
@ -95,7 +95,7 @@ initializeWindows = function() {
|
||||||
width: 600,
|
width: 600,
|
||||||
height: 130
|
height: 130
|
||||||
});
|
});
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
});
|
});
|
||||||
|
|
||||||
globalUploadLimitFN = function() {
|
globalUploadLimitFN = function() {
|
||||||
|
@ -144,7 +144,7 @@ initializeWindows = function() {
|
||||||
hashes: h.join("|")
|
hashes: h.join("|")
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ initializeWindows = function() {
|
||||||
hashes: h.join("|")
|
hashes: h.join("|")
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ initializeWindows = function() {
|
||||||
width: 424,
|
width: 424,
|
||||||
height: 140
|
height: 140
|
||||||
});
|
});
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ initializeWindows = function() {
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
});
|
});
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ initializeWindows = function() {
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
});
|
});
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -288,7 +288,7 @@ initializeWindows = function() {
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
});
|
});
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -317,7 +317,7 @@ initializeWindows = function() {
|
||||||
hashes: h.join("|")
|
hashes: h.join("|")
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
updateTransferList();
|
updateMainData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
'limit': limit
|
'limit': limit
|
||||||
},
|
},
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
window.parent.updateTransferInfo();
|
window.parent.updateMainData();
|
||||||
window.parent.closeWindows();
|
window.parent.closeWindows();
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue