(RPC) add utility arguments for torrent-info: sort by (activity|age|id|name|progress|ratio|state|tracker), filter by (active|all|downloading|paused|seeding)
This commit is contained in:
parent
de6a87bfc9
commit
518f277e9f
|
@ -35,7 +35,7 @@ if test "x$GCC" = "xyes" ; then
|
|||
fi
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_TIME
|
||||
AC_CHECK_FUNCS([lrintf strlcpy daemon dirname basename daemon])
|
||||
AC_CHECK_FUNCS([lrintf strlcpy daemon dirname basename daemon strcasecmp])
|
||||
AC_CHECK_SIZEOF([void*])
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MAKE_SET
|
||||
|
|
|
@ -200,6 +200,7 @@ readargs( int argc, char ** argv )
|
|||
| TR_RPC_TORRENT_FIELD_ACTIVITY
|
||||
| TR_RPC_TORRENT_FIELD_SIZE;
|
||||
tr_bencDictAddInt( args, "fields", fields );
|
||||
tr_bencDictAddStr( args, "sort", "name" );
|
||||
break;
|
||||
case 'm': tr_bencDictAddStr( &top, "method", "session-set" );
|
||||
tr_bencDictAddInt( args, "port-forwarding-enabled", 1 );
|
||||
|
|
|
@ -79,12 +79,23 @@
|
|||
|
||||
Method name: "torrent-info".
|
||||
|
||||
The request takes two arguments: "ids", as described in section 3.1, and
|
||||
"fields", a bitwise-or'ed number which specifies which torrent information
|
||||
is being requested. (See libtransmission/rpc.h's enumeration)
|
||||
The response arguments are "fields" (identical to the request argument)
|
||||
and "torrent-info", a list of objects that each contain the pairs
|
||||
shown here:
|
||||
The request supports four arguments:
|
||||
|
||||
(1) "ids", as described in section 3.1.
|
||||
(2) A required "fields" number as described in the table below
|
||||
(3) An optional "sort" string whose value should be one of:
|
||||
"activity", "age", "id", "name", "progress", "ratio", "state", "tracker".
|
||||
(4) An optional "sort-ascending" 'boolean'.
|
||||
This is only used if "sort-method" is supplied.
|
||||
Its default value is 'true'.
|
||||
(5) An optional "filter" string whose value may be one of:
|
||||
"active", "all", "downloading", "paused", "seeding"
|
||||
|
||||
The respons supports two arguments:
|
||||
|
||||
(1) A required "fields" number identical to the request's
|
||||
(2) A "torrent-info" list of objects, each of which contains the
|
||||
response names described in the table below.
|
||||
|
||||
field and | response | response | source
|
||||
numeric value | type | name |
|
||||
|
@ -196,6 +207,7 @@
|
|||
"arguments": {
|
||||
"fields": 1056,
|
||||
"ids": [ 7, 10 ],
|
||||
"sort-method": "name"
|
||||
}
|
||||
"method": "torrent-info",
|
||||
"tag": 39693
|
||||
|
@ -205,17 +217,28 @@
|
|||
Response:
|
||||
|
||||
{
|
||||
"tag": 39693
|
||||
"result": "success",
|
||||
"arguments": {
|
||||
"fields": 1056,
|
||||
"torrent-info": [
|
||||
{
|
||||
"hashString": "sijioejisoefjiosejfioi",
|
||||
"haveUnchecked", 23023,
|
||||
"haveValid", 27986795145,
|
||||
"leftUntilDone", 0,
|
||||
"name": "Fedora x86_64 DVD",
|
||||
"percentComplete", "0.8010",
|
||||
"percentDone", "0.8010",
|
||||
"ratio", "0.604034",
|
||||
"sizeWhenDone", 34983493932,
|
||||
"totalSize", 34983493932,
|
||||
"uniqueId": 10,
|
||||
}
|
||||
{
|
||||
"hashString": "asdasiofjosejfoasjfiosj",
|
||||
"haveUnchecked", 0,
|
||||
"haveValid", 9923890123,
|
||||
"leftUntilDone", 0,
|
||||
"name": "Ubundu x86_64 DVD",
|
||||
"name": "Ubuntu x86_64 DVD",
|
||||
"percentComplete", "1.0000",
|
||||
"percentDone", "1.0000",
|
||||
"ratio", "2.23222",
|
||||
|
@ -223,21 +246,10 @@
|
|||
"totalSize", 9923890123,
|
||||
"uniqueId": 7,
|
||||
},
|
||||
{
|
||||
"hashString": "sijioejisoefjiosejfioi",
|
||||
"haveUnchecked", 23023,
|
||||
"haveValid", 27986795145,
|
||||
"leftUntilDone", 0,
|
||||
"name": "Fedora x86_64 DVD",
|
||||
"percentComplete", "1.0000",
|
||||
"percentDone", "0.8010",
|
||||
"ratio", "0.604034",
|
||||
"sizeWhenDone", 34983493932,
|
||||
"totalSize", 34983493932,
|
||||
"uniqueId": 10,
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"result": "success",
|
||||
"tag": 39693
|
||||
}
|
||||
|
||||
3.3. Adding a Torrent
|
||||
|
|
|
@ -47,15 +47,6 @@
|
|||
#include "tr-prefs.h"
|
||||
#include "util.h"
|
||||
|
||||
int
|
||||
tr_strcmp( const char * a, const char * b )
|
||||
{
|
||||
if( a && b ) return strcmp( a, b );
|
||||
if( a ) return 1;
|
||||
if( b ) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char*
|
||||
tr_strlratio( char * buf, double ratio, size_t buflen )
|
||||
{
|
||||
|
|
|
@ -33,9 +33,6 @@
|
|||
#define UNUSED G_GNUC_UNUSED
|
||||
#endif
|
||||
|
||||
/* NULL-safe version of strcmp */
|
||||
int tr_strcmp( const char*, const char * );
|
||||
|
||||
/* return number of items in array */
|
||||
#define ALEN(a) ((signed)G_N_ELEMENTS(a))
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ libtransmission_a_SOURCES = \
|
|||
resume.c \
|
||||
rpc.c \
|
||||
rpc-server.c \
|
||||
rpc-utils.c \
|
||||
session.c \
|
||||
stats.c \
|
||||
torrent.c \
|
||||
|
@ -77,6 +78,7 @@ noinst_HEADERS = \
|
|||
resume.h \
|
||||
rpc.h \
|
||||
rpc-server.h \
|
||||
rpc-utils.h \
|
||||
session.h \
|
||||
stats.h \
|
||||
torrent.h \
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* This file is licensed by the GPL version 2. Works owned by the
|
||||
* Transmission project are granted a special exemption to clause 2(b)
|
||||
* so that the bulk of its code can remain under the MIT license.
|
||||
* This exemption does not extend to derived works not owned by
|
||||
* the Transmission project.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stdlib.h> /* qsort */
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include "transmission.h"
|
||||
#include "rpc-utils.h"
|
||||
#include "torrent.h"
|
||||
#include "utils.h"
|
||||
|
||||
/****
|
||||
*****
|
||||
****/
|
||||
|
||||
static int
|
||||
compareTorrentsByActivity( const void * a, const void * b )
|
||||
{
|
||||
const tr_stat * sa = tr_torrentStatCached( (tr_torrent*) a );
|
||||
const tr_stat * sb = tr_torrentStatCached( (tr_torrent*) b );
|
||||
int i;
|
||||
if(( i = tr_compareDouble( sa->rateUpload + sa->rateDownload,
|
||||
sb->rateUpload + sb->rateDownload ) ))
|
||||
return i;
|
||||
if( sa->uploadedEver != sb->uploadedEver )
|
||||
return sa->uploadedEver < sa->uploadedEver ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
compareTorrentsByAge( const void * a, const void * b )
|
||||
{
|
||||
return tr_compareTime( tr_torrentStatCached( (tr_torrent*)a )->addedDate,
|
||||
tr_torrentStatCached( (tr_torrent*)b )->addedDate );
|
||||
}
|
||||
|
||||
static int
|
||||
compareTorrentsByID( const void * a, const void * b )
|
||||
{
|
||||
return ((tr_torrent*)a)->uniqueId - ((tr_torrent*)b)->uniqueId;
|
||||
}
|
||||
|
||||
static int
|
||||
compareTorrentsByName( const void * a, const void * b )
|
||||
{
|
||||
const tr_torrent * ta = a;
|
||||
const tr_torrent * tb = b;
|
||||
return tr_strcasecmp( ta->info.name, tb->info.name );
|
||||
}
|
||||
|
||||
static int
|
||||
compareRatio( double a, double b )
|
||||
{
|
||||
if( (int)a == TR_RATIO_INF && (int)b == TR_RATIO_INF ) return 0;
|
||||
if( (int)a == TR_RATIO_INF ) return 1;
|
||||
if( (int)b == TR_RATIO_INF ) return -1;
|
||||
return tr_compareDouble( a, b );
|
||||
}
|
||||
|
||||
static int
|
||||
compareTorrentsByProgress( const void * a, const void * b )
|
||||
{
|
||||
const tr_stat * sa = tr_torrentStatCached( (tr_torrent*) a );
|
||||
const tr_stat * sb = tr_torrentStatCached( (tr_torrent*) b );
|
||||
int ret = tr_compareDouble( sa->percentDone, sb->percentDone );
|
||||
if( !ret )
|
||||
ret = compareRatio( sa->ratio, sb->ratio );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
compareTorrentsByRatio( const void * a, const void * b )
|
||||
{
|
||||
const tr_stat * sa = tr_torrentStatCached( (tr_torrent*) a );
|
||||
const tr_stat * sb = tr_torrentStatCached( (tr_torrent*) b );
|
||||
return compareRatio( sa->ratio, sb->ratio );
|
||||
}
|
||||
|
||||
static int
|
||||
compareTorrentsByState( const void * a, const void * b )
|
||||
{
|
||||
const tr_stat * sa = tr_torrentStatCached( (tr_torrent*) a );
|
||||
const tr_stat * sb = tr_torrentStatCached( (tr_torrent*) b );
|
||||
int ret = sa->status - sb->status;
|
||||
if( !ret )
|
||||
ret = compareTorrentsByRatio( a, b );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
compareTorrentsByTracker( const void * a, const void * b )
|
||||
{
|
||||
const tr_stat * sa = tr_torrentStatCached( (tr_torrent*) a );
|
||||
const tr_stat * sb = tr_torrentStatCached( (tr_torrent*) b );
|
||||
return tr_strcmp( sa->announceURL, sb->announceURL );
|
||||
}
|
||||
|
||||
typedef int( *compareFunc )( const void *, const void * );
|
||||
|
||||
void
|
||||
tr_torrentSort( tr_torrent ** torrents,
|
||||
int torrentCount,
|
||||
tr_sort_method sortMethod,
|
||||
int isAscending )
|
||||
{
|
||||
compareFunc func = NULL;
|
||||
|
||||
switch( sortMethod )
|
||||
{
|
||||
case TR_SORT_ACTIVITY: func = &compareTorrentsByActivity; break;
|
||||
case TR_SORT_AGE: func = compareTorrentsByAge; break;
|
||||
case TR_SORT_NAME: func = compareTorrentsByName; break;
|
||||
case TR_SORT_PROGRESS: func = compareTorrentsByProgress; break;
|
||||
case TR_SORT_RATIO: func = compareTorrentsByRatio; break;
|
||||
case TR_SORT_STATE: func = compareTorrentsByState; break;
|
||||
case TR_SORT_TRACKER: func = compareTorrentsByTracker; break;
|
||||
default: func = compareTorrentsByID; break;
|
||||
}
|
||||
|
||||
qsort( torrents, torrentCount, sizeof(tr_torrent*), func );
|
||||
|
||||
if( !isAscending )
|
||||
{
|
||||
int left = 0;
|
||||
int right = torrentCount - 1;
|
||||
while( left < right ) {
|
||||
tr_torrent * tmp = torrents[left];
|
||||
torrents[left] = torrents[right];
|
||||
torrents[right] = tmp;
|
||||
++left;
|
||||
--right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
*****
|
||||
****/
|
||||
|
||||
static int
|
||||
testActive( const tr_torrent * tor )
|
||||
{
|
||||
const tr_stat * s = tr_torrentStatCached( ( tr_torrent * ) tor );
|
||||
return s->peersSendingToUs>0 || s->peersGettingFromUs>0;
|
||||
}
|
||||
static int
|
||||
testStatus( const tr_torrent * tor, cp_status_t status )
|
||||
{
|
||||
return tr_torrentGetStatus( ( tr_torrent * ) tor ) == status;
|
||||
}
|
||||
static int
|
||||
testDownloading( const tr_torrent * tor )
|
||||
{
|
||||
return testStatus( tor, TR_STATUS_DOWNLOAD );
|
||||
}
|
||||
static int
|
||||
testSeeding( const tr_torrent * tor )
|
||||
{
|
||||
return testStatus( tor, TR_STATUS_SEED );
|
||||
}
|
||||
static int
|
||||
testPaused( const tr_torrent * tor )
|
||||
{
|
||||
return testStatus( tor, TR_STATUS_STOPPED );
|
||||
}
|
||||
static int
|
||||
testTrue( const tr_torrent * tor UNUSED )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef int( *test_func )( const tr_torrent * );
|
||||
|
||||
void
|
||||
tr_torrentFilter( tr_torrent ** torrents,
|
||||
int * torrentCount,
|
||||
tr_filter_method filterMethod )
|
||||
{
|
||||
int i;
|
||||
int newCount = 0;
|
||||
test_func func;
|
||||
tr_torrent ** tmp = tr_new0( tr_torrent*, torrentCount );
|
||||
|
||||
switch( filterMethod ) {
|
||||
case TR_FILTER_ACTIVE: func = testActive; break;
|
||||
case TR_FILTER_DOWNLOADING: func = testDownloading; break;
|
||||
case TR_FILTER_PAUSED: func = testPaused; break;
|
||||
case TR_FILTER_SEEDING: func = testSeeding; break;
|
||||
default: func = testTrue; break;
|
||||
}
|
||||
|
||||
for( i=0; i<*torrentCount; ++i )
|
||||
if( func( torrents[i] ) )
|
||||
tmp[newCount++] = torrents[i];
|
||||
|
||||
memcpy( torrents, tmp, sizeof(tr_torrent*) * newCount );
|
||||
*torrentCount = newCount;
|
||||
tr_free( tmp );
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* This file is licensed by the GPL version 2. Works owned by the
|
||||
* Transmission project are granted a special exemption to clause 2(b)
|
||||
* so that the bulk of its code can remain under the MIT license.
|
||||
* This exemption does not extend to derived works not owned by
|
||||
* the Transmission project.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef RPC_UTILS_H
|
||||
#define RPC_UTILS_H
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TR_SORT_ACTIVITY,
|
||||
TR_SORT_AGE,
|
||||
TR_SORT_ID,
|
||||
TR_SORT_NAME,
|
||||
TR_SORT_PROGRESS,
|
||||
TR_SORT_RATIO,
|
||||
TR_SORT_STATE,
|
||||
TR_SORT_TRACKER
|
||||
}
|
||||
tr_sort_method;
|
||||
|
||||
void tr_torrentSort( tr_torrent ** torrents,
|
||||
int torrentCount,
|
||||
tr_sort_method sortMethod,
|
||||
int isAscending );
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TR_FILTER_ACTIVE,
|
||||
TR_FILTER_ALL,
|
||||
TR_FILTER_DOWNLOADING,
|
||||
TR_FILTER_PAUSED,
|
||||
TR_FILTER_SEEDING
|
||||
}
|
||||
tr_filter_method;
|
||||
|
||||
void tr_torrentFilter( tr_torrent ** torrents,
|
||||
int * torrentCount,
|
||||
tr_filter_method filterMethod );
|
||||
|
||||
#endif
|
|
@ -19,6 +19,7 @@
|
|||
#include "bencode.h"
|
||||
#include "ratecontrol.h"
|
||||
#include "rpc.h"
|
||||
#include "rpc-utils.h"
|
||||
#include "json.h"
|
||||
#include "session.h"
|
||||
#include "torrent.h"
|
||||
|
@ -44,11 +45,18 @@ notify( tr_handle * session, int type, tr_torrent * tor )
|
|||
static tr_torrent **
|
||||
getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount )
|
||||
{
|
||||
int64_t id;
|
||||
tr_torrent ** torrents = NULL;
|
||||
int method;
|
||||
int torrentCount = 0;
|
||||
int64_t id;
|
||||
int64_t sortAscending;
|
||||
tr_torrent ** torrents = NULL;
|
||||
const char * str;
|
||||
tr_benc * ids;
|
||||
|
||||
/***
|
||||
**** Build the array of torrents
|
||||
***/
|
||||
|
||||
if( tr_bencDictFindList( args, "ids", &ids ) )
|
||||
{
|
||||
int i;
|
||||
|
@ -87,6 +95,42 @@ getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount )
|
|||
torrents[torrentCount++] = tor;
|
||||
}
|
||||
|
||||
/***
|
||||
**** filter the torrents
|
||||
***/
|
||||
|
||||
method = TR_FILTER_ALL;
|
||||
if( tr_bencDictFindStr( args, "filter", &str ) ) {
|
||||
if( !strcmp( str, "active" ) ) method = TR_FILTER_ACTIVE;
|
||||
else if( !strcmp( str, "downloading" ) ) method = TR_FILTER_DOWNLOADING;
|
||||
else if( !strcmp( str, "paused" ) ) method = TR_FILTER_PAUSED;
|
||||
else if( !strcmp( str, "seeding" ) ) method = TR_FILTER_SEEDING;
|
||||
}
|
||||
if( method != TR_FILTER_ALL )
|
||||
tr_torrentFilter( torrents, &torrentCount, method );
|
||||
|
||||
/***
|
||||
**** sort the torrents
|
||||
***/
|
||||
|
||||
method = TR_SORT_ID;
|
||||
sortAscending = 1;
|
||||
tr_bencDictFindInt( args, "sort-ascending", &sortAscending );
|
||||
if( tr_bencDictFindStr( args, "sort", &str ) ) {
|
||||
if( !strcmp( str, "activity" ) ) method = TR_SORT_ACTIVITY;
|
||||
else if( !strcmp( str, "age" ) ) method = TR_SORT_AGE;
|
||||
else if( !strcmp( str, "name" ) ) method = TR_SORT_NAME;
|
||||
else if( !strcmp( str, "progress" ) ) method = TR_SORT_PROGRESS;
|
||||
else if( !strcmp( str, "ratio" ) ) method = TR_SORT_RATIO;
|
||||
else if( !strcmp( str, "state" ) ) method = TR_SORT_STATE;
|
||||
else if( !strcmp( str, "tracker" ) ) method = TR_SORT_TRACKER;
|
||||
}
|
||||
tr_torrentSort( torrents, torrentCount, method, sortAscending!=0 );
|
||||
|
||||
/***
|
||||
**** return the results
|
||||
***/
|
||||
|
||||
*setmeCount = torrentCount;
|
||||
return torrents;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h> /* isalpha */
|
||||
#include <ctype.h> /* isalpha, tolower */
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
@ -362,6 +362,47 @@ tr_compareUint64( uint64_t a, uint64_t b )
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tr_compareDouble( double a, double b )
|
||||
{
|
||||
if( a < b ) return -1;
|
||||
if( a > b ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tr_compareTime( time_t a, time_t b )
|
||||
{
|
||||
if( a < b ) return -1;
|
||||
if( a > b ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tr_strcmp( const void * a, const void * b )
|
||||
{
|
||||
if( a && b ) return strcmp( a, b );
|
||||
if( a ) return 1;
|
||||
if( b ) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tr_strcasecmp( const char * a, const char * b )
|
||||
{
|
||||
if( !a && !b ) return 0;
|
||||
if( !a ) return -1;
|
||||
if( !b ) return 1;
|
||||
#ifdef HAVE_STRCASECMP
|
||||
return strcasecmp( a, b );
|
||||
#else
|
||||
while( *a && ( tolower( *(uint8_t*)a ) == tolower( *(uint8_t*)b ) ) )
|
||||
++a, ++b;
|
||||
return tolower( *(uint8_t*)s1) - tolower(*(uint8_t*)s2 );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h> /* for size_t */
|
||||
#include <stdio.h> /* FILE* */
|
||||
#include <time.h> /* time_t* */
|
||||
|
||||
/***
|
||||
****
|
||||
|
@ -219,6 +220,11 @@ void tr_set_compare( const void * a, size_t aCount,
|
|||
int tr_compareUint16( uint16_t a, uint16_t b );
|
||||
int tr_compareUint32( uint32_t a, uint32_t b );
|
||||
int tr_compareUint64( uint64_t a, uint64_t b );
|
||||
int tr_compareDouble( double a, double b );
|
||||
int tr_compareTime( time_t a, time_t b );
|
||||
|
||||
int tr_strcmp( const void * a, const void * b );
|
||||
int tr_strcasecmp( const char * a, const char * b );
|
||||
|
||||
void tr_sha1_to_hex( char * out, const uint8_t * sha1 );
|
||||
|
||||
|
|
Loading…
Reference in New Issue