2011-09-14 05:10:51 +00:00
|
|
|
/**
|
2011-09-02 19:29:41 +00:00
|
|
|
* Copyright © Jordan Lee, Dave Perrett, Malcolm Jarvis and Bruno Bierbaumer
|
2011-09-14 05:10:51 +00:00
|
|
|
*
|
|
|
|
* This file is licensed under the GPLv2.
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
2011-09-02 19:29:41 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
function Inspector(controller) {
|
|
|
|
|
|
|
|
var data = {
|
|
|
|
controller: null,
|
|
|
|
elements: { },
|
|
|
|
torrents: [ ]
|
|
|
|
},
|
|
|
|
|
|
|
|
needsExtraInfo = function (torrents) {
|
|
|
|
var i, id, tor;
|
|
|
|
|
|
|
|
for (i = 0; tor = torrents[i]; i++)
|
|
|
|
if (!tor.hasExtraInfo())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
|
|
|
refreshTorrents = function () {
|
|
|
|
var fields,
|
|
|
|
ids = $.map(data.torrents.slice(0), function (t) {return t.getId();});
|
|
|
|
|
|
|
|
if (ids && ids.length)
|
|
|
|
{
|
|
|
|
fields = ['id'].concat(Torrent.Fields.StatsExtra);
|
|
|
|
|
|
|
|
if (needsExtraInfo(data.torrents))
|
|
|
|
$.merge(fields, Torrent.Fields.InfoExtra);
|
|
|
|
|
|
|
|
data.controller.updateTorrents(ids, fields);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2011-09-03 19:15:03 +00:00
|
|
|
onTabClicked = function (ev) {
|
|
|
|
var tab = ev.currentTarget;
|
|
|
|
|
2011-09-02 19:29:41 +00:00
|
|
|
if (isMobileDevice)
|
|
|
|
ev.stopPropagation();
|
|
|
|
|
|
|
|
// select this tab and deselect the others
|
|
|
|
$(tab).addClass('selected').siblings().removeClass('selected');
|
|
|
|
|
|
|
|
// show this tab and hide the others
|
2011-10-23 17:10:44 +00:00
|
|
|
$('#' + tab.id.replace('tab','page')).show().siblings('.inspector-page').hide();
|
2011-09-02 19:29:41 +00:00
|
|
|
|
|
|
|
updateInspector();
|
|
|
|
},
|
|
|
|
|
|
|
|
updateInspector = function () {
|
|
|
|
var e = data.elements,
|
|
|
|
torrents = data.torrents,
|
|
|
|
name;
|
|
|
|
|
|
|
|
// update the name, which is shown on all the pages
|
|
|
|
if (!torrents || !torrents.length)
|
|
|
|
name = 'No Selection';
|
|
|
|
else if(torrents.length === 1)
|
|
|
|
name = torrents[0].getName();
|
|
|
|
else
|
|
|
|
name = '' + torrents.length+' Transfers Selected';
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.name_lb, name || na);
|
2011-09-02 19:29:41 +00:00
|
|
|
|
|
|
|
// update the visible page
|
|
|
|
if ($(e.info_page).is(':visible'))
|
|
|
|
updateInfoPage();
|
|
|
|
else if ($(e.peers_page).is(':visible'))
|
|
|
|
updatePeersPage();
|
|
|
|
else if ($(e.trackers_page).is(':visible'))
|
|
|
|
updateTrackersPage();
|
|
|
|
else if ($(e.files_page).is(':visible'))
|
|
|
|
updateFilesPage();
|
|
|
|
},
|
|
|
|
|
|
|
|
/****
|
|
|
|
***** GENERAL INFO PAGE
|
|
|
|
****/
|
|
|
|
|
|
|
|
accumulateString = function (oldVal, newVal) {
|
|
|
|
if (!oldVal || !oldVal.length)
|
|
|
|
return newVal;
|
2011-09-05 07:46:55 +00:00
|
|
|
if (oldVal === newVal)
|
2011-09-02 19:29:41 +00:00
|
|
|
return newVal;
|
|
|
|
return 'Mixed';
|
|
|
|
},
|
|
|
|
|
|
|
|
updateInfoPage = function () {
|
|
|
|
var torrents = data.torrents,
|
|
|
|
e = data.elements,
|
|
|
|
fmt = Transmission.fmt,
|
2011-11-04 21:05:24 +00:00
|
|
|
none = 'None',
|
|
|
|
mixed = 'Mixed',
|
|
|
|
unknown = 'Unknown',
|
|
|
|
isMixed, allPaused, allFinished,
|
|
|
|
str,
|
2011-11-06 16:06:48 +00:00
|
|
|
baseline, it, s, i, t,
|
2011-09-02 19:29:41 +00:00
|
|
|
sizeWhenDone = 0,
|
2011-11-04 21:05:24 +00:00
|
|
|
leftUntilDone = 0,
|
|
|
|
available = 0,
|
|
|
|
haveVerified = 0,
|
|
|
|
haveUnverified = 0,
|
|
|
|
verifiedPieces = 0,
|
|
|
|
stateString,
|
|
|
|
latest,
|
|
|
|
pieces,
|
|
|
|
size,
|
|
|
|
pieceSize,
|
|
|
|
creator, mixed_creator,
|
|
|
|
date, mixed_date,
|
2011-11-06 16:06:48 +00:00
|
|
|
v, u, f, d, pct,
|
|
|
|
now = Date.now();
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// state_lb
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length <1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
isMixed = false;
|
|
|
|
allPaused = true;
|
|
|
|
allFinished = true;
|
|
|
|
|
|
|
|
baseline = torrents[0].getStatus();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
it = t.getStatus();
|
|
|
|
if(it != baseline)
|
|
|
|
isMixed = true;
|
|
|
|
if(!t.isStopped())
|
|
|
|
allPaused = allFinished = false;
|
|
|
|
if(!t.isFinished())
|
|
|
|
allFinished = false;
|
|
|
|
}
|
|
|
|
if( isMixed )
|
|
|
|
str = mixed;
|
|
|
|
else if( allFinished )
|
|
|
|
str = 'Finished';
|
|
|
|
else if( allPaused )
|
|
|
|
str = 'Paused';
|
|
|
|
else
|
|
|
|
str = torrents[0].getStateString();
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.state_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
stateString = str;
|
|
|
|
|
|
|
|
//
|
|
|
|
// have_lb
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
baseline = torrents[0].getStatus();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
if(!t.needsMetaData()) {
|
|
|
|
haveUnverified += t.getHaveUnchecked();
|
|
|
|
v = t.getHaveValid();
|
|
|
|
haveVerified += v;
|
|
|
|
if(t.getPieceSize())
|
|
|
|
verifiedPieces += v / t.getPieceSize();
|
|
|
|
sizeWhenDone += t.getSizeWhenDone();
|
|
|
|
leftUntilDone += t.getLeftUntilDone();
|
|
|
|
available += (t.getHave()) + t.getDesiredAvailable();
|
|
|
|
}
|
|
|
|
}
|
2011-09-02 19:29:41 +00:00
|
|
|
|
2011-11-04 21:05:24 +00:00
|
|
|
d = 100.0 * ( sizeWhenDone ? ( sizeWhenDone - leftUntilDone ) / sizeWhenDone : 1 );
|
|
|
|
str = fmt.percentString( d );
|
2011-09-02 19:29:41 +00:00
|
|
|
|
2011-11-04 21:05:24 +00:00
|
|
|
if( !haveUnverified && !leftUntilDone )
|
|
|
|
str = fmt.size(haveVerified) + ' (100%)';
|
|
|
|
else if( !haveUnverified )
|
|
|
|
str = fmt.size(haveVerified) + ' of ' + fmt.size(sizeWhenDone) + ' (' + str +'%)';
|
|
|
|
else
|
|
|
|
str = fmt.size(haveVerified) + ' of ' + fmt.size(sizeWhenDone) + ' (' + str +'%), ' + fmt.size(haveUnverified) + ' Unverified';
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.have_lb, str);
|
2011-09-02 19:29:41 +00:00
|
|
|
|
2011-11-04 21:05:24 +00:00
|
|
|
//
|
|
|
|
// availability_lb
|
|
|
|
//
|
2011-09-02 19:29:41 +00:00
|
|
|
|
2011-11-04 21:05:24 +00:00
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else if( sizeWhenDone == 0 )
|
|
|
|
str = none;
|
|
|
|
else
|
|
|
|
str = '' + fmt.percentString( ( 100.0 * available ) / sizeWhenDone ) + '%';
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.availability_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// downloaded_lb
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
d = f = 0;
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
2012-03-20 00:41:57 +00:00
|
|
|
d += t.getDownloadedEver();
|
|
|
|
f += t.getFailedEver();
|
2011-11-04 21:05:24 +00:00
|
|
|
}
|
|
|
|
if(f)
|
|
|
|
str = fmt.size(d) + ' (' + fmt.size(f) + ' corrupt)';
|
|
|
|
else
|
|
|
|
str = fmt.size(d);
|
2011-09-02 19:29:41 +00:00
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.downloaded_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// uploaded_lb
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
d = u = 0;
|
2012-03-20 00:41:57 +00:00
|
|
|
if(torrents.length == 1) {
|
|
|
|
d = torrents[0].getDownloadedEver();
|
|
|
|
u = torrents[0].getUploadedEver();
|
|
|
|
|
|
|
|
if (d == 0)
|
|
|
|
d = torrents[0].getHaveValid();
|
2011-11-04 21:05:24 +00:00
|
|
|
}
|
2012-03-20 00:41:57 +00:00
|
|
|
else {
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
d += t.getDownloadedEver();
|
|
|
|
u += t.getUploadedEver();
|
|
|
|
}
|
|
|
|
}
|
2011-11-04 21:05:24 +00:00
|
|
|
str = fmt.size(u) + ' (Ratio: ' + fmt.ratioString( Math.ratio(u,d))+')';
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.uploaded_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// running time
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
allPaused = true;
|
|
|
|
baseline = torrents[0].getStartDate();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
if(baseline != t.getStartDate())
|
|
|
|
baseline = 0;
|
|
|
|
if(!t.isStopped())
|
|
|
|
allPaused = false;
|
|
|
|
}
|
|
|
|
if(allPaused)
|
|
|
|
str = stateString; // paused || finished
|
|
|
|
else if(!baseline)
|
|
|
|
str = mixed;
|
|
|
|
else
|
2011-11-06 16:06:48 +00:00
|
|
|
str = fmt.timeInterval(now/1000 - baseline);
|
2011-11-04 21:05:24 +00:00
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.running_time_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// remaining time
|
|
|
|
//
|
|
|
|
|
|
|
|
str = '';
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
baseline = torrents[0].getETA();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
if(baseline != t.getETA()) {
|
|
|
|
str = mixed;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!str.length) {
|
|
|
|
if(baseline < 0)
|
|
|
|
str = unknown;
|
|
|
|
else
|
|
|
|
str = fmt.timeInterval(baseline);
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.remaining_time_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// last activity
|
|
|
|
//
|
|
|
|
|
|
|
|
latest = -1;
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
baseline = torrents[0].getLastActivity();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
d = t.getLastActivity();
|
|
|
|
if(latest < d)
|
|
|
|
latest = d;
|
|
|
|
}
|
2011-11-06 16:06:48 +00:00
|
|
|
d = now/1000 - latest; // seconds since last activity
|
2011-11-04 21:05:24 +00:00
|
|
|
if(d < 0)
|
|
|
|
str = none;
|
|
|
|
else if(d < 5)
|
|
|
|
str = 'Active now';
|
|
|
|
else
|
|
|
|
str = fmt.timeInterval(d) + ' ago';
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.last_activity_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// error
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
str = torrents[0].getErrorString();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
if(str != t.getErrorString()) {
|
|
|
|
str = mixed;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.error_lb, str || none);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// size
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
pieces = 0;
|
|
|
|
size = 0;
|
|
|
|
pieceSize = torrents[0].getPieceSize();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
pieces += t.getPieceCount();
|
|
|
|
size += t.getTotalSize();
|
|
|
|
if(pieceSize != t.getPieceSize())
|
|
|
|
pieceSize = 0;
|
|
|
|
}
|
|
|
|
if(!size)
|
|
|
|
str = none;
|
|
|
|
else if(pieceSize > 0)
|
|
|
|
str = fmt.size(size) + ' (' + pieces.toStringWithCommas() + ' pieces @ ' + fmt.mem(pieceSize) + ')';
|
|
|
|
else
|
|
|
|
str = fmt.size(size) + ' (' + pieces.toStringWithCommas() + ' pieces)';
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.size_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// hash
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
str = torrents[0].getHashString();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
if(str != t.getHashString()) {
|
|
|
|
str = mixed;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.hash_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// privacy
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
baseline = torrents[0].getPrivateFlag();
|
|
|
|
str = baseline ? 'Private to this tracker -- DHT and PEX disabled' : 'Public torrent';
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
if(baseline != t.getPrivateFlag()) {
|
|
|
|
str = mixed;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.privacy_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// comment
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
str = torrents[0].getComment();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
if(str != t.getComment()) {
|
|
|
|
str = mixed;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!str)
|
|
|
|
str = none;
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.comment_lb, str.replace(/(https?|ftp):\/\/([\w\-]+(\.[\w\-]+)*(\.[a-z]{2,4})?)(\d{1,5})?(\/([^<>\s]*))?/g, '<a target="_blank" href="$&">$&</a>'));
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// origin
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
mixed_creator = false;
|
|
|
|
mixed_date = false;
|
|
|
|
creator = torrents[0].getCreator();
|
|
|
|
date = torrents[0].getDateCreated();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
if(creator != t.getCreator())
|
|
|
|
mixed_creator = true;
|
|
|
|
if(date != t.getDateCreated())
|
|
|
|
mixed_date = true;
|
|
|
|
}
|
|
|
|
if(mixed_creator && mixed_date)
|
|
|
|
str = mixed;
|
|
|
|
else if(mixed_date && creator.length)
|
|
|
|
str = 'Created by ' + creator;
|
|
|
|
else if(mixed_creator && date)
|
|
|
|
str = 'Created on ' + (new Date(date*1000)).toDateString();
|
|
|
|
else
|
|
|
|
str = 'Created by ' + creator + ' on ' + (new Date(date*1000)).toDateString();
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.origin_lb, str);
|
2011-11-04 21:05:24 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// foldername
|
|
|
|
//
|
|
|
|
|
|
|
|
if(torrents.length < 1)
|
|
|
|
str = none;
|
|
|
|
else {
|
|
|
|
str = torrents[0].getDownloadDir();
|
|
|
|
for(i=0; t=torrents[i]; ++i) {
|
|
|
|
if(str != t.getDownloadDir()) {
|
|
|
|
str = mixed;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-07-20 17:37:50 +00:00
|
|
|
setTextContent(e.foldername_lb, str);
|
2011-09-02 19:29:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/****
|
|
|
|
***** FILES PAGE
|
|
|
|
****/
|
|
|
|
|
2011-09-03 04:33:04 +00:00
|
|
|
changeFileCommand = function(rows, command) {
|
2011-09-03 19:15:03 +00:00
|
|
|
var torrentId = data.file_torrent.getId();
|
|
|
|
var rowIndices = $.map(rows.slice(0),function (row) {return row.getIndex();});
|
2011-09-03 04:33:04 +00:00
|
|
|
data.controller.changeFileCommand(torrentId, rowIndices, command);
|
2011-09-02 19:29:41 +00:00
|
|
|
},
|
|
|
|
|
2012-02-03 22:59:33 +00:00
|
|
|
selectAllFiles = function() {
|
|
|
|
changeFileCommand([], 'files-wanted');
|
|
|
|
},
|
|
|
|
|
|
|
|
deselectAllFiles = function() {
|
|
|
|
changeFileCommand([], 'files-unwanted');
|
|
|
|
},
|
|
|
|
|
2011-09-03 19:15:03 +00:00
|
|
|
onFileWantedToggled = function(ev, row, want) {
|
2011-09-03 04:33:04 +00:00
|
|
|
changeFileCommand([row], want?'files-wanted':'files-unwanted');
|
2011-09-02 19:29:41 +00:00
|
|
|
},
|
|
|
|
|
2011-09-03 19:15:03 +00:00
|
|
|
onFilePriorityToggled = function(ev, row, priority) {
|
2011-09-02 19:29:41 +00:00
|
|
|
var command;
|
|
|
|
switch(priority) {
|
|
|
|
case -1: command = 'priority-low'; break;
|
|
|
|
case 1: command = 'priority-high'; break;
|
|
|
|
default: command = 'priority-normal'; break;
|
|
|
|
}
|
2011-09-03 04:33:04 +00:00
|
|
|
changeFileCommand([row], command);
|
2011-09-02 19:29:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
clearFileList = function() {
|
|
|
|
$(data.elements.file_list).empty();
|
|
|
|
delete data.file_torrent;
|
|
|
|
delete data.file_rows;
|
|
|
|
},
|
|
|
|
|
|
|
|
updateFilesPage = function() {
|
2012-09-23 17:08:27 +00:00
|
|
|
var i, j, n, sel, row, tor, fragment,
|
|
|
|
box, complete, conn, connections, e, from, heirarchy, item,
|
|
|
|
matches, parents, parentid, path, sum, subheirarchy, to, inner,
|
2011-09-02 19:29:41 +00:00
|
|
|
file_list = data.elements.file_list,
|
|
|
|
torrents = data.torrents;
|
|
|
|
|
|
|
|
if (torrents.length !== 1) {
|
|
|
|
clearFileList();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// build the file list
|
|
|
|
tor = torrents[0];
|
|
|
|
|
2012-08-18 15:04:06 +00:00
|
|
|
for (parentid in data.parents) {
|
|
|
|
data.parents[parentid] = $('#'+parentid).children('li').css('display')
|
|
|
|
}
|
2011-09-02 19:29:41 +00:00
|
|
|
clearFileList();
|
|
|
|
data.file_torrent = tor;
|
|
|
|
n = tor.getFileCount();
|
|
|
|
data.file_rows = [];
|
|
|
|
fragment = document.createDocumentFragment();
|
2012-09-23 17:21:19 +00:00
|
|
|
heirarchy = {'/':[]}
|
2012-08-18 15:04:06 +00:00
|
|
|
|
2011-09-02 19:29:41 +00:00
|
|
|
for (i=0; i<n; ++i) {
|
|
|
|
row = data.file_rows[i] = new FileRow(tor, i);
|
|
|
|
fragment.appendChild(row.getElement());
|
2011-09-03 19:15:03 +00:00
|
|
|
$(row).bind('wantedToggled',onFileWantedToggled);
|
|
|
|
$(row).bind('priorityToggled',onFilePriorityToggled);
|
2012-08-18 15:04:06 +00:00
|
|
|
path = row.getPath();
|
|
|
|
if (path.length == 1) {
|
|
|
|
heirarchy['/'].push(path[0]);
|
|
|
|
} else {
|
|
|
|
subheirarchy = heirarchy;
|
|
|
|
for (j=0; j<path.length; j++) {
|
|
|
|
if (j<(path.length-1)) {
|
|
|
|
subheirarchy[path[j]] = (subheirarchy[path[j]] == undefined) ? {'/':[]} : subheirarchy[path[j]];
|
|
|
|
subheirarchy[path[j]]['PARENT'] = (path[j-1] == undefined) ? [undefined] : [path[j-1].replace(/[\[\] ().]/g,'_')]
|
|
|
|
subheirarchy = subheirarchy[path[j]];
|
|
|
|
} else {
|
|
|
|
parentid = (path[j-1] == undefined) ? [undefined] : [path[j-1].replace(/[\[\] ().]/g,'_')]
|
|
|
|
subheirarchy['/'].push([path[j],parentid]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-02 19:29:41 +00:00
|
|
|
}
|
2012-09-23 17:21:19 +00:00
|
|
|
console.log(heirarchy);
|
2012-08-18 15:04:06 +00:00
|
|
|
/*
|
|
|
|
At this point we have a single object containing the whole
|
|
|
|
torrent heirarchy. The '/' key is file element ids as assigned above
|
|
|
|
for the current level. Any other keys are array objects which are
|
|
|
|
directories in the torrent heirarchy, this will also contain a '/'
|
|
|
|
key and potentially more keys for nested directories.
|
|
|
|
*/
|
|
|
|
connections = [];
|
|
|
|
parents = {};
|
|
|
|
var recursiveCreate = function(key,val) {
|
|
|
|
if (key == "PARENT") { return; }
|
|
|
|
if (typeof(val) == "object" &&! Array.isArray(val)) {
|
|
|
|
row = document.createElement('li');
|
|
|
|
row.id = key.replace(/[\[\] ().]/g,'_');
|
|
|
|
row.classname = 'inspector_torrent_file_list_entry odd';
|
|
|
|
|
|
|
|
e = document.createElement('input');
|
|
|
|
e.type = 'checkbox';
|
|
|
|
e.className = "file_wanted_control";
|
|
|
|
e.title = 'Download file';
|
|
|
|
e.checked = true;
|
|
|
|
$(e).change(function() { $($(this).parent()).children('li').children('input').click() });
|
|
|
|
row.appendChild(e);
|
|
|
|
|
|
|
|
e = document.createElement('div');
|
|
|
|
e.className = 'file-priority-radiobox';
|
|
|
|
box = e;
|
|
|
|
|
|
|
|
e = document.createElement('div');
|
|
|
|
e.className = 'low';
|
|
|
|
e.title = 'Low Priority';
|
|
|
|
$(e).click(function(){ $($(this).parent().parent()).children('li').children('div').children('.low').click() });
|
|
|
|
box.appendChild(e);
|
|
|
|
|
|
|
|
e = document.createElement('div');
|
|
|
|
e.className = 'normal';
|
|
|
|
e.title = 'Normal Priority';
|
|
|
|
$(e).click(function(){ $($(this).parent().parent()).children('li').children('div').children('.normal').click() });
|
|
|
|
box.appendChild(e);
|
|
|
|
|
|
|
|
e = document.createElement('div');
|
|
|
|
e.title = 'High Priority';
|
|
|
|
e.className = 'high';
|
|
|
|
$(e).click(function(){ $($(this).parent().parent()).children('li').children('div').children('.high').click() });
|
|
|
|
box.appendChild(e);
|
|
|
|
|
|
|
|
row.appendChild(box);
|
|
|
|
|
|
|
|
inner = document.createElement('div');
|
|
|
|
inner.className = "inspector_torrent_file_list_entry_name";
|
|
|
|
inner.innerHTML = key;
|
|
|
|
row.appendChild(inner);
|
|
|
|
|
|
|
|
complete = document.createElement('div');
|
|
|
|
complete.className = "inspector_torrent_file_list_entry_progress";
|
|
|
|
complete.innerHTML = " "
|
|
|
|
row.appendChild(complete)
|
|
|
|
|
|
|
|
fragment.appendChild(row);
|
|
|
|
connections.push([key.replace(/[\[\] ().]/g,'_'),val['PARENT'][0]])
|
|
|
|
} else {
|
|
|
|
for (item in val) {
|
|
|
|
parents[val[item][1][0]] = ""
|
|
|
|
}
|
|
|
|
connections.push.apply(connections,val)
|
|
|
|
}
|
|
|
|
if (!Array.isArray(val)) {
|
|
|
|
$.each(val,function(key,val) { recursiveCreate(key,val) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$.each(heirarchy,function(key,val) { recursiveCreate(key,val) })
|
2011-09-02 19:29:41 +00:00
|
|
|
file_list.appendChild(fragment);
|
2012-08-18 15:04:06 +00:00
|
|
|
for (conn in connections) {
|
|
|
|
from = connections[conn][0];
|
|
|
|
to = connections[conn][1];
|
|
|
|
if (to == undefined) { continue; }
|
|
|
|
$('#'+from).appendTo($('#'+to));
|
|
|
|
$('#'+from).css('margin-left','20px')
|
|
|
|
}
|
|
|
|
for (parentid in parents) {
|
|
|
|
$($('.inspector_torrent_file_list_entry_name',$('#'+parentid))[0]).click(function() { $($(this).parent()).children('li').toggle(); })
|
|
|
|
|
2012-09-23 17:08:27 +00:00
|
|
|
sum = 0;
|
2012-09-19 05:28:13 +00:00
|
|
|
matches = $('#'+parentid).children('li').text().match(/\([^\.]+\)/g)
|
2012-08-18 15:04:06 +00:00
|
|
|
if (matches == null) { continue; }
|
|
|
|
matches.map(function(word) {return parseFloat(word.slice(1,-2)) }).map(function(perc) {sum+=perc})
|
2012-09-19 05:28:13 +00:00
|
|
|
count = $('#'+parentid).children('li').text().match(/\([^\.]+\)/g).length
|
2012-08-18 15:04:06 +00:00
|
|
|
totalcomplete = (sum/count).toFixed(1)
|
|
|
|
|
|
|
|
$($('.inspector_torrent_file_list_entry_progress',$('#'+parentid))[0]).text('('+totalcomplete+'%)')
|
|
|
|
}
|
|
|
|
for (parentid in data.parents) {
|
|
|
|
$('#'+parentid).children('li').css('display',data.parents[parentid])
|
|
|
|
}
|
|
|
|
data.parents = parents;
|
2011-09-02 19:29:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/****
|
|
|
|
***** PEERS PAGE
|
|
|
|
****/
|
|
|
|
|
|
|
|
updatePeersPage = function() {
|
|
|
|
var i, k, tor, peers, peer, parity,
|
|
|
|
html = [],
|
|
|
|
fmt = Transmission.fmt,
|
|
|
|
peers_list = data.elements.peers_list,
|
|
|
|
torrents = data.torrents;
|
|
|
|
|
|
|
|
for (k=0; tor=torrents[k]; ++k)
|
|
|
|
{
|
|
|
|
peers = tor.getPeers();
|
|
|
|
html.push('<div class="inspector_group">');
|
|
|
|
if (torrents.length > 1) {
|
2012-07-20 17:37:50 +00:00
|
|
|
html.push('<div class="inspector_torrent_label">', sanitizeText(tor.getName()), '</div>');
|
2011-09-02 19:29:41 +00:00
|
|
|
}
|
|
|
|
if (!peers || !peers.length) {
|
|
|
|
html.push('<br></div>'); // firefox won't paint the top border if the div is empty
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
html.push('<table class="peer_list">',
|
|
|
|
'<tr class="inspector_peer_entry even">',
|
|
|
|
'<th class="encryptedCol"></th>',
|
|
|
|
'<th class="upCol">Up</th>',
|
|
|
|
'<th class="downCol">Down</th>',
|
|
|
|
'<th class="percentCol">%</th>',
|
|
|
|
'<th class="statusCol">Status</th>',
|
|
|
|
'<th class="addressCol">Address</th>',
|
|
|
|
'<th class="clientCol">Client</th>',
|
|
|
|
'</tr>');
|
|
|
|
for (i=0; peer=peers[i]; ++i) {
|
2011-09-05 07:46:55 +00:00
|
|
|
parity = (i%2) ? 'odd' : 'even';
|
2011-09-02 19:29:41 +00:00
|
|
|
html.push('<tr class="inspector_peer_entry ', parity, '">',
|
2011-10-20 00:10:06 +00:00
|
|
|
'<td>', (peer.isEncrypted ? '<div class="encrypted-peer-cell" title="Encrypted Connection">'
|
|
|
|
: '<div class="unencrypted-peer-cell">'), '</div>', '</td>',
|
2011-09-02 19:29:41 +00:00
|
|
|
'<td>', (peer.rateToPeer ? fmt.speedBps(peer.rateToPeer) : ''), '</td>',
|
|
|
|
'<td>', (peer.rateToClient ? fmt.speedBps(peer.rateToClient) : ''), '</td>',
|
|
|
|
'<td class="percentCol">', Math.floor(peer.progress*100), '%', '</td>',
|
|
|
|
'<td>', fmt.peerStatus(peer.flagStr), '</td>',
|
2012-07-20 17:37:50 +00:00
|
|
|
'<td>', sanitizeText(peer.address), '</td>',
|
|
|
|
'<td class="clientCol">', sanitizeText(peer.clientName), '</td>',
|
2011-09-02 19:29:41 +00:00
|
|
|
'</tr>');
|
|
|
|
}
|
|
|
|
html.push('</table></div>');
|
|
|
|
}
|
|
|
|
|
|
|
|
setInnerHTML(peers_list, html.join(''));
|
|
|
|
},
|
|
|
|
|
|
|
|
/****
|
|
|
|
***** TRACKERS PAGE
|
|
|
|
****/
|
|
|
|
|
|
|
|
getAnnounceState = function(tracker) {
|
|
|
|
var timeUntilAnnounce, s = '';
|
|
|
|
switch (tracker.announceState) {
|
|
|
|
case Torrent._TrackerActive:
|
|
|
|
s = 'Announce in progress';
|
|
|
|
break;
|
|
|
|
case Torrent._TrackerWaiting:
|
|
|
|
timeUntilAnnounce = tracker.nextAnnounceTime - ((new Date()).getTime() / 1000);
|
|
|
|
if (timeUntilAnnounce < 0) {
|
|
|
|
timeUntilAnnounce = 0;
|
|
|
|
}
|
|
|
|
s = 'Next announce in ' + Transmission.fmt.timeInterval(timeUntilAnnounce);
|
|
|
|
break;
|
|
|
|
case Torrent._TrackerQueued:
|
|
|
|
s = 'Announce is queued';
|
|
|
|
break;
|
|
|
|
case Torrent._TrackerInactive:
|
|
|
|
s = tracker.isBackup ?
|
|
|
|
'Tracker will be used as a backup' :
|
|
|
|
'Announce not scheduled';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
s = 'unknown announce state: ' + tracker.announceState;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
},
|
|
|
|
|
|
|
|
lastAnnounceStatus = function(tracker) {
|
|
|
|
|
|
|
|
var lastAnnounceLabel = 'Last Announce',
|
|
|
|
lastAnnounce = [ 'N/A' ],
|
|
|
|
lastAnnounceTime;
|
|
|
|
|
|
|
|
if (tracker.hasAnnounced) {
|
|
|
|
lastAnnounceTime = Transmission.fmt.timestamp(tracker.lastAnnounceTime);
|
|
|
|
if (tracker.lastAnnounceSucceeded) {
|
|
|
|
lastAnnounce = [ lastAnnounceTime, ' (got ', Transmission.fmt.plural(tracker.lastAnnouncePeerCount, 'peer'), ')' ];
|
|
|
|
} else {
|
|
|
|
lastAnnounceLabel = 'Announce error';
|
|
|
|
lastAnnounce = [ (tracker.lastAnnounceResult ? (tracker.lastAnnounceResult + ' - ') : ''), lastAnnounceTime ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return { 'label':lastAnnounceLabel, 'value':lastAnnounce.join('') };
|
|
|
|
},
|
|
|
|
|
|
|
|
lastScrapeStatus = function(tracker) {
|
|
|
|
|
|
|
|
var lastScrapeLabel = 'Last Scrape',
|
|
|
|
lastScrape = 'N/A',
|
|
|
|
lastScrapeTime;
|
|
|
|
|
|
|
|
if (tracker.hasScraped) {
|
|
|
|
lastScrapeTime = Transmission.fmt.timestamp(tracker.lastScrapeTime);
|
|
|
|
if (tracker.lastScrapeSucceeded) {
|
|
|
|
lastScrape = lastScrapeTime;
|
|
|
|
} else {
|
|
|
|
lastScrapeLabel = 'Scrape error';
|
|
|
|
lastScrape = (tracker.lastScrapeResult ? tracker.lastScrapeResult + ' - ' : '') + lastScrapeTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {'label':lastScrapeLabel, 'value':lastScrape};
|
|
|
|
},
|
|
|
|
|
|
|
|
updateTrackersPage = function() {
|
2011-09-03 05:12:14 +00:00
|
|
|
var i, j, tier, tracker, trackers, tor,
|
2011-09-02 19:29:41 +00:00
|
|
|
html, parity, lastAnnounceStatusHash,
|
|
|
|
announceState, lastScrapeStatusHash,
|
2011-09-03 05:12:14 +00:00
|
|
|
na = 'N/A',
|
2011-09-02 19:29:41 +00:00
|
|
|
trackers_list = data.elements.trackers_list,
|
|
|
|
torrents = data.torrents;
|
|
|
|
|
|
|
|
// By building up the HTML as as string, then have the browser
|
|
|
|
// turn this into a DOM tree, this is a fast operation.
|
|
|
|
html = [];
|
|
|
|
for (i=0; tor=torrents[i]; ++i)
|
|
|
|
{
|
|
|
|
html.push ('<div class="inspector_group">');
|
|
|
|
|
|
|
|
if (torrents.length > 1)
|
|
|
|
html.push('<div class="inspector_torrent_label">', tor.getName(), '</div>');
|
|
|
|
|
|
|
|
tier = -1;
|
|
|
|
trackers = tor.getTrackers();
|
|
|
|
for (j=0; tracker=trackers[j]; ++j)
|
|
|
|
{
|
|
|
|
if (tier != tracker.tier)
|
|
|
|
{
|
|
|
|
if (tier !== -1) // close previous tier
|
|
|
|
html.push('</ul></div>');
|
|
|
|
|
|
|
|
tier = tracker.tier;
|
|
|
|
|
|
|
|
html.push('<div class="inspector_group_label">',
|
|
|
|
'Tier ', tier, '</div>',
|
|
|
|
'<ul class="tier_list">');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Display construction
|
|
|
|
lastAnnounceStatusHash = lastAnnounceStatus(tracker);
|
|
|
|
announceState = getAnnounceState(tracker);
|
|
|
|
lastScrapeStatusHash = lastScrapeStatus(tracker);
|
2011-09-05 07:46:55 +00:00
|
|
|
parity = (j%2) ? 'odd' : 'even';
|
2012-07-20 17:37:50 +00:00
|
|
|
html.push('<li class="inspector_tracker_entry ', parity, '"><div class="tracker_host" title="', sanitizeText(tracker.announce), '">',
|
|
|
|
sanitizeText(tracker.host), '</div>',
|
2011-09-02 19:29:41 +00:00
|
|
|
'<div class="tracker_activity">',
|
|
|
|
'<div>', lastAnnounceStatusHash['label'], ': ', lastAnnounceStatusHash['value'], '</div>',
|
|
|
|
'<div>', announceState, '</div>',
|
|
|
|
'<div>', lastScrapeStatusHash['label'], ': ', lastScrapeStatusHash['value'], '</div>',
|
|
|
|
'</div><table class="tracker_stats">',
|
|
|
|
'<tr><th>Seeders:</th><td>', (tracker.seederCount > -1 ? tracker.seederCount : na), '</td></tr>',
|
|
|
|
'<tr><th>Leechers:</th><td>', (tracker.leecherCount > -1 ? tracker.leecherCount : na), '</td></tr>',
|
|
|
|
'<tr><th>Downloads:</th><td>', (tracker.downloadCount > -1 ? tracker.downloadCount : na), '</td></tr>',
|
|
|
|
'</table></li>');
|
|
|
|
}
|
|
|
|
if (tier !== -1) // close last tier
|
|
|
|
html.push('</ul></div>');
|
|
|
|
|
|
|
|
html.push('</div>'); // inspector_group
|
|
|
|
}
|
|
|
|
|
2012-07-20 17:37:50 +00:00
|
|
|
setInnerHTML (trackers_list, html.join(''));
|
2011-09-02 19:29:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
initialize = function (controller) {
|
|
|
|
|
|
|
|
var ti = '#torrent_inspector_';
|
|
|
|
|
|
|
|
data.controller = controller;
|
|
|
|
|
2011-10-23 17:10:44 +00:00
|
|
|
$('.inspector-tab').click(onTabClicked);
|
2011-09-02 19:29:41 +00:00
|
|
|
|
2011-10-23 17:10:44 +00:00
|
|
|
data.elements.info_page = $('#inspector-page-info')[0];
|
|
|
|
data.elements.files_page = $('#inspector-page-files')[0];
|
|
|
|
data.elements.peers_page = $('#inspector-page-peers')[0];
|
|
|
|
data.elements.trackers_page = $('#inspector-page-trackers')[0];
|
2011-09-02 19:29:41 +00:00
|
|
|
|
|
|
|
data.elements.file_list = $('#inspector_file_list')[0];
|
|
|
|
data.elements.peers_list = $('#inspector_peers_list')[0];
|
|
|
|
data.elements.trackers_list = $('#inspector_trackers_list')[0];
|
|
|
|
|
2011-11-04 21:05:24 +00:00
|
|
|
data.elements.have_lb = $('#inspector-info-have')[0];
|
|
|
|
data.elements.availability_lb = $('#inspector-info-availability')[0];
|
|
|
|
data.elements.downloaded_lb = $('#inspector-info-downloaded')[0];
|
|
|
|
data.elements.uploaded_lb = $('#inspector-info-uploaded')[0];
|
|
|
|
data.elements.state_lb = $('#inspector-info-state')[0];
|
|
|
|
data.elements.running_time_lb = $('#inspector-info-running-time')[0];
|
|
|
|
data.elements.remaining_time_lb = $('#inspector-info-remaining-time')[0];
|
|
|
|
data.elements.last_activity_lb = $('#inspector-info-last-activity')[0];
|
|
|
|
data.elements.error_lb = $('#inspector-info-error')[0];
|
|
|
|
data.elements.size_lb = $('#inspector-info-size')[0];
|
|
|
|
data.elements.foldername_lb = $('#inspector-info-location')[0];
|
|
|
|
data.elements.hash_lb = $('#inspector-info-hash')[0];
|
|
|
|
data.elements.privacy_lb = $('#inspector-info-privacy')[0];
|
|
|
|
data.elements.origin_lb = $('#inspector-info-origin')[0];
|
|
|
|
data.elements.comment_lb = $('#inspector-info-comment')[0];
|
|
|
|
data.elements.name_lb = $('#torrent_inspector_name')[0];
|
2011-09-15 03:13:50 +00:00
|
|
|
|
2012-02-03 22:59:33 +00:00
|
|
|
// file page's buttons
|
|
|
|
$('#select-all-files').click(selectAllFiles);
|
|
|
|
$('#deselect-all-files').click(deselectAllFiles);
|
|
|
|
|
2011-09-15 03:13:50 +00:00
|
|
|
// force initial 'N/A' updates on all the pages
|
|
|
|
updateInspector();
|
|
|
|
updateInfoPage();
|
|
|
|
updatePeersPage();
|
|
|
|
updateTrackersPage();
|
|
|
|
updateFilesPage();
|
2011-09-02 19:29:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/****
|
|
|
|
***** PUBLIC FUNCTIONS
|
|
|
|
****/
|
|
|
|
|
|
|
|
this.setTorrents = function (torrents) {
|
|
|
|
var d = data;
|
|
|
|
|
|
|
|
// update the inspector when a selected torrent's data changes.
|
|
|
|
$(d.torrents).unbind('dataChanged.inspector');
|
|
|
|
$(torrents).bind('dataChanged.inspector', $.proxy(updateInspector,this));
|
|
|
|
d.torrents = torrents;
|
|
|
|
|
|
|
|
// periodically ask for updates to the inspector's torrents
|
|
|
|
clearInterval(d.refreshInterval);
|
|
|
|
d.refreshInterval = setInterval($.proxy(refreshTorrents,this), 2000);
|
|
|
|
refreshTorrents();
|
|
|
|
|
|
|
|
// refresh the inspector's UI
|
|
|
|
updateInspector();
|
|
|
|
};
|
|
|
|
|
|
|
|
initialize (controller);
|
|
|
|
};
|