diff --git a/doc/rpc-spec.txt b/doc/rpc-spec.txt index 35059edd8..51d43823d 100644 --- a/doc/rpc-spec.txt +++ b/doc/rpc-spec.txt @@ -155,6 +155,7 @@ id | number | tr_torrent isPrivate | boolean | tr_torrent leftUntilDone | number | tr_stat + magnetLink | number | n/a manualAnnounceTime | number | tr_stat maxConnectedPeers | number | tr_torrent metadataPercentComplete | double | tr_stat @@ -562,6 +563,7 @@ | | NO | torrent-get | removed arg "seeders" | | NO | torrent-get | removed arg "timesCompleted" | | NO | torrent-get | removed arg "swarmSpeed" + | | yes | torrent-get | new arg "magnetLink" | | yes | torrent-get | new arg "metadataPercentComplete" | | yes | torrent-get | new arg "trackerStats" | | yes | session-set | new arg "incomplete-dir" diff --git a/libtransmission/rpcimpl.c b/libtransmission/rpcimpl.c index ed0d81fc4..76f8d709c 100644 --- a/libtransmission/rpcimpl.c +++ b/libtransmission/rpcimpl.c @@ -500,6 +500,11 @@ addField( const tr_torrent * tor, tr_benc * d, const char * key ) tr_bencDictAddInt( d, key, st->manualAnnounceTime ); else if( tr_streq( key, keylen, "maxConnectedPeers" ) ) tr_bencDictAddInt( d, key, tr_torrentGetPeerLimit( tor ) ); + else if( tr_streq( key, keylen, "magnetLink" ) ) { + char * str = tr_torrentGetMagnetLink( tor ); + tr_bencDictAddStr( d, key, str ); + tr_free( str ); + } else if( tr_streq( key, keylen, "metadataPercentComplete" ) ) tr_bencDictAddReal( d, key, st->metadataPercentComplete ); else if( tr_streq( key, keylen, "name" ) ) diff --git a/qt/mainwin.cc b/qt/mainwin.cc index e1ee32a98..2b67d3d97 100644 --- a/qt/mainwin.cc +++ b/qt/mainwin.cc @@ -159,6 +159,7 @@ TrMainWindow :: TrMainWindow( Session& session, Prefs& prefs, TorrentModel& mode connect( ui.action_About, SIGNAL(triggered()), myAboutDialog, SLOT(show())); connect( ui.action_Contents, SIGNAL(triggered()), this, SLOT(openHelp())); connect( ui.action_OpenFolder, SIGNAL(triggered()), this, SLOT(openFolder())); + connect( ui.action_CopyMagnetToClipboard, SIGNAL(triggered()), this, SLOT(copyMagnetLinkToClipboard())); connect( ui.action_SetLocation, SIGNAL(triggered()), this, SLOT(setLocation())); connect( ui.action_Properties, SIGNAL(triggered()), this, SLOT(openProperties())); connect( ui.action_SessionDialog, SIGNAL(triggered()), mySessionDialog, SLOT(show())); @@ -166,17 +167,21 @@ TrMainWindow :: TrMainWindow( Session& session, Prefs& prefs, TorrentModel& mode QAction * sep2 = new QAction( this ); sep2->setSeparator( true ); + QAction * sep3 = new QAction( this ); + sep3->setSeparator( true ); // context menu QList actions; actions << ui.action_Properties << ui.action_OpenFolder - << ui.action_SetLocation << sep2 << ui.action_Start - << ui.action_Pause - << ui.action_Verify << ui.action_Announce + << ui.action_Pause + << ui.action_CopyMagnetToClipboard + << sep3 + << ui.action_Verify + << ui.action_SetLocation << sep << ui.action_Remove << ui.action_Delete; @@ -652,6 +657,13 @@ TrMainWindow :: openFolder( ) QDesktopServices :: openUrl( QUrl::fromLocalFile( path ) ); } +void +TrMainWindow :: copyMagnetLinkToClipboard( ) +{ + const int id( *getSelectedTorrents().begin() ); + mySession.copyMagnetLinkToClipboard( id ); +} + void TrMainWindow :: openHelp( ) { @@ -766,6 +778,7 @@ TrMainWindow :: refreshActionSensitivity( ) const bool oneSelection( selected == 1 ); ui.action_OpenFolder->setEnabled( oneSelection && mySession.isLocal( ) ); + ui.action_CopyMagnetToClipboard->setEnabled( oneSelection ); ui.action_SelectAll->setEnabled( selected < rowCount ); ui.action_StartAll->setEnabled( paused > 0 ); diff --git a/qt/mainwin.h b/qt/mainwin.h index 66f4b3b58..b5437d0e3 100644 --- a/qt/mainwin.h +++ b/qt/mainwin.h @@ -116,6 +116,7 @@ class TrMainWindow: public QMainWindow void addTorrents( const QStringList& filenames ); void openHelp( ); void openFolder( ); + void copyMagnetLinkToClipboard( ); void setLocation( ); void openProperties( ); void toggleSpeedMode( ); diff --git a/qt/mainwin.ui b/qt/mainwin.ui index 5a118f75a..4300b3812 100644 --- a/qt/mainwin.ui +++ b/qt/mainwin.ui @@ -51,7 +51,7 @@ 0 0 792 - 25 + 23 @@ -65,24 +65,19 @@ &Torrent - - - - + + + + - - - - - @@ -127,8 +122,21 @@ - + + + &File + + + + + + + + + + + @@ -536,6 +544,11 @@ Set &Location... + + + &Copy Magnet Link to Clipboard + + diff --git a/qt/session.cc b/qt/session.cc index b0f5903a6..d130c5221 100644 --- a/qt/session.cc +++ b/qt/session.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,7 @@ namespace TAG_BLOCKLIST_UPDATE, TAG_ADD_TORRENT, TAG_PORT_TEST, + TAG_MAGNET_LINK, FIRST_UNIQUE_TAG }; @@ -106,6 +108,21 @@ Session :: portTest( ) tr_bencFree( &top ); } +void +Session :: copyMagnetLinkToClipboard( int torrentId ) +{ + tr_benc top; + tr_bencInitDict( &top, 3 ); + tr_bencDictAddStr( &top, "method", "torrent-get" ); + tr_bencDictAddInt( &top, "tag", TAG_MAGNET_LINK ); + tr_benc * args = tr_bencDictAddDict( &top, "arguments", 2 ); + tr_bencListAddInt( tr_bencDictAddList( args, "ids", 1 ), torrentId ); + tr_bencListAddStr( tr_bencDictAddList( args, "fields", 1 ), "magnetLink" ); + + exec( &top ); + tr_bencFree( &top ); +} + void Session :: updatePref( int key ) { @@ -680,6 +697,19 @@ Session :: parseResponse( const char * json, size_t jsonLength ) emit portTested( (bool)isOpen ); } + case TAG_MAGNET_LINK: { + tr_benc * args; + tr_benc * torrents; + tr_benc * child; + const char * str; + if( tr_bencDictFindDict( &top, "arguments", &args ) + && tr_bencDictFindList( args, "torrents", &torrents ) + && (( child = tr_bencListChild( torrents, 0 ))) + && tr_bencDictFindStr( child, "magnetLink", &str ) ) + QApplication::clipboard()->setText( str ); + break; + } + case TAG_ADD_TORRENT: str = ""; if( tr_bencDictFindStr( &top, "result", &str ) && strcmp( str, "success" ) ) { diff --git a/qt/session.h b/qt/session.h index dfac8979a..bc9e6972a 100644 --- a/qt/session.h +++ b/qt/session.h @@ -58,6 +58,7 @@ class Session: public QObject void setBlocklistSize( int64_t i ); void updateBlocklist( ); void portTest( ); + void copyMagnetLinkToClipboard( int torrentId ); public: