Select download folder from web client (diff attached)

Feature requests not specific to either the Mac OS X or GTK+ versions of Transmission
rampitec
Posts: 13
Joined: Wed Apr 28, 2010 8:17 pm
Location: Saint-Petersburg, Russia

Select download folder from web client (diff attached)

Post by rampitec »

Moving to transmission I found one major feature missing (and that seems to have a high demand, as google tell us) -- web client is unable to select destination folder for a torrent.

I've created diff for that (against svn revision 10530, as per `svn diff'), altogether 349 lines of code.

To support the feature a new rpc call is exposed: 'folders-get'.
Input parameter: 'path', string, required (should be a full pathname).
Output:
'folders' -- array of strings (list of folders existing in path to which transmission user has access).
'pathDelim' -- string, server path delimiter (/ or \).
'folderName' -- string, cleaned version of input path.
'parentFolder' -- string, contains a pathname of folder's parent (if path is root parameter is absent on output).

The change has been tested on Linux and MacOS both as server and client, Firefox and Safari. I have no Windows, but rpc should work (except for manual selection of alternative drive letter).

I would appreciate if diff will be integrated.

Screenshoots:

http://lh3.ggpht.com/_1LXhCJBcaMk/S9ihc ... 7%20AM.png
http://lh3.ggpht.com/_1LXhCJBcaMk/S9ihc ... 1%20AM.png

Code: Select all

Index: libtransmission/utils.c
===================================================================
--- libtransmission/utils.c	(revision 10530)
+++ libtransmission/utils.c	(working copy)
@@ -657,7 +657,10 @@
         const size_t elementLen = strlen( element );
         memcpy( pch, element, elementLen );
         pch += elementLen;
-        *pch++ = TR_PATH_DELIMITER;
+        if( elementLen > 1 && element[elementLen-1] != TR_PATH_DELIMITER )
+            *pch++ = TR_PATH_DELIMITER;
+        else
+            bufLen--;
         element = (const char*) va_arg( vl, const char* );
     }
     va_end( vl );
Index: libtransmission/rpcimpl.c
===================================================================
--- libtransmission/rpcimpl.c	(revision 10530)
+++ libtransmission/rpcimpl.c	(working copy)
@@ -16,8 +16,9 @@
 #include <stdlib.h> /* strtol */
 #include <string.h> /* strcmp */
 #include <unistd.h> /* unlink */
-
+#include <dirent.h> /* opendir */
 #include <event.h> /* evbuffer */
+#include <sys/stat.h>
 
 #include "transmission.h"
 #include "bencode.h"
@@ -30,6 +31,7 @@
 #include "utils.h"
 #include "version.h"
 #include "web.h"
+#include "platform.h"
 
 #define RPC_VERSION     9
 #define RPC_VERSION_MIN 1
@@ -1084,9 +1086,18 @@
 
         /* set the optional arguments */
 
-        if( tr_bencDictFindStr( args_in, TR_PREFS_KEY_DOWNLOAD_DIR, &str ) )
-            tr_ctorSetDownloadDir( ctor, TR_FORCE, str );
+        if( tr_bencDictFindStr( args_in, TR_PREFS_KEY_DOWNLOAD_DIR, &str ) ) {
+            char * path;
 
+            while ( isspace(*str) ) str++;
+            if( *str != TR_PATH_DELIMITER ) /* file path is not fully qualified */
+                path = tr_buildPath( tr_getDefaultDownloadDir(), str, NULL );
+            else /* otherwise still call tr_buildPath to strip possible unwanted training '/' */
+                path = tr_buildPath( str, NULL );
+            tr_ctorSetDownloadDir( ctor, TR_FORCE, path );
+            tr_free( path );
+        }
+
         if( tr_bencDictFindBool( args_in, "paused", &boolVal ) )
             tr_ctorSetPaused( ctor, TR_FORCE, boolVal );
 
@@ -1351,6 +1362,126 @@
     return NULL;
 }
 
+static const char*
+addFolders( const char *    path,
+            tr_benc *       folders )
+{
+    DIR * odir;
+    struct dirent *d;
+
+    odir = opendir ( path );
+    if ( odir == NULL ) return tr_strerror(errno);
+    for( d = readdir( odir ); d != NULL; d = readdir( odir ) )
+    {
+        if( d->d_name && strcmp(d->d_name,".") != 0 && strcmp(d->d_name,"..") != 0 )
+        {
+            char * buf = tr_buildPath( path, d->d_name, NULL );
+            struct stat sb;
+
+            if ( !stat( buf, &sb ) )
+            {
+                if( S_ISDIR( sb.st_mode ) && access( buf, R_OK|X_OK) == 0 )
+                    tr_bencListAddStr( folders, d->d_name );
+            }
+            tr_free(buf);
+        }
+    }
+    closedir( odir );
+    return NULL;
+}
+
+#ifdef WIN32
+# define IS_PATH_DELIM(c) (strchr("\\/", (c)))
+# define ROOT_PATH_LEN 3
+#else
+# define IS_PATH_DELIM(c) ((c) == TR_PATH_DELIMITER)
+# define ROOT_PATH_LEN 1
+#endif
+
+static const char*
+foldersGet( tr_session               * session UNUSED,
+            tr_benc                  * args_in,
+            tr_benc                  * args_out,
+            struct tr_rpc_idle_data  * idle_data UNUSED )
+{
+    tr_benc *    d = args_out;
+    const char * req_path = NULL;
+    const char * ret;
+    char * path;
+    size_t len;
+    int up_level = 0;
+
+    assert( idle_data == NULL );
+
+    tr_bencDictFindStr( args_in, "path", &req_path );
+    if( !req_path )
+        return "no path specified";
+
+    path = tr_strdup(req_path);
+    if( !path )
+        return strerror(errno);
+
+    len = strlen(path);
+
+    if( len < ROOT_PATH_LEN || 
+#ifdef WIN32
+        path[1] != ':' || 
+#endif
+        !IS_PATH_DELIM(path[ROOT_PATH_LEN-1]) )
+    {
+        tr_free(path);
+        path = tr_strdup(tr_getDefaultDownloadDir());
+        if( !path )
+            return strerror(errno);
+        len = strlen(path);
+    }
+
+    /* use of POSIX realpath() would easy all of that, but its availablity is unclear */
+    for(;;) {
+        /* strip possible multiple path delimiters at the end of pathname, except for root folder */
+        while ( len > ROOT_PATH_LEN && IS_PATH_DELIM(path[len-1]) )
+            path[--len] = '\0';
+
+        /* strip possible . and .. at the end of path */
+        if ( len > ROOT_PATH_LEN && path[len-1] == '.' && IS_PATH_DELIM(path[len-2]) ) /* trailing /. */
+        {
+            path[--len] = '\0';
+            continue;
+        }
+        else if ( len > ROOT_PATH_LEN + 1 && path[len-1] == '.' && path[len-2] == '.' && IS_PATH_DELIM(path[len-3]) ) /* trailing /.. */
+        {
+            len -= 2; /* strip .. */
+            if( len > ROOT_PATH_LEN ) len--; /* and path delimiter if not root */
+            path[len] = '\0';
+            up_level++;
+            continue;
+        }
+        else if ( up_level > 0 )
+        {
+            up_level--;
+            while( len > ROOT_PATH_LEN && !IS_PATH_DELIM(path[len-1]) ) len--; /* strip one parent folder name */
+            path[len] = '\0';
+            continue;
+        }
+        break;
+    }
+
+    tr_bencDictAddStr ( d, "pathDelim", TR_PATH_DELIMITER_STR );
+    tr_bencDictAddStr ( d, "folderName", path );
+    ret = addFolders( path, tr_bencDictAddList( d, "folders", 1 ) );
+    if( len > ROOT_PATH_LEN )
+    {
+        path = tr_dirname(path);
+        tr_bencDictAddStr ( d, "parentFolder", path );
+        tr_free(path);
+    }
+
+    return ret;
+}
+
+#undef ROOT_PATH_LEN
+#undef IS_PATH_DELIM
+
 /***
 ****
 ***/
@@ -1378,7 +1509,8 @@
     { "torrent-start",         TRUE,  torrentStart        },
     { "torrent-stop",          TRUE,  torrentStop         },
     { "torrent-verify",        TRUE,  torrentVerify       },
-    { "torrent-reannounce",    TRUE,  torrentReannounce   }
+    { "torrent-reannounce",    TRUE,  torrentReannounce   },
+    { "folders-get",           TRUE,  foldersGet          }
 };
 
 static void
Index: libtransmission/rpc-server.c
===================================================================
--- libtransmission/rpc-server.c	(revision 10530)
+++ libtransmission/rpc-server.c	(working copy)
@@ -212,8 +212,22 @@
         tr_ptrArray parts = TR_PTR_ARRAY_INIT;
 
         const char * query = strchr( req->uri, '?' );
-        const tr_bool paused = query && strstr( query + 1, "paused=true" );
+        tr_bool paused;
+        char * download_dir = NULL;
 
+        while( query != NULL ) {
+            query++;
+            if( strncmp(query, "paused=", 7) == 0 ) {
+                query += 7;
+                paused = ( strncmp(query, "true", 4) == 0 );
+            } else if( download_dir == NULL && strncmp(query, "download-dir=", 13) == 0 ) {
+                query += 13;
+                download_dir = strchr( query, '?' );
+                download_dir = tr_strndup( query, download_dir ? download_dir - query : (int)strlen(query) );
+            }
+            query = strchr( query, '?' );
+        }
+
         extract_parts_from_multipart( req->input_headers, req->input_buffer, &parts );
         n = tr_ptrArraySize( &parts );
 
@@ -254,6 +268,8 @@
                 b64 = tr_base64_encode( body, body_len, NULL );
                 tr_bencDictAddStr( args, "metainfo", b64 );
                 tr_bencDictAddBool( args, "paused", paused );
+                if( download_dir != NULL )
+                    tr_bencDictAddStr( args, "download-dir", download_dir );
                 tr_bencToBuf( &top, TR_FMT_JSON_LEAN, json );
                 tr_rpc_request_exec_json( server->session,
                                           EVBUFFER_DATA( json ),
@@ -267,6 +283,7 @@
         }
 
         tr_ptrArrayDestruct( &parts, (PtrArrayForeachFunc)tr_mimepart_free );
+        tr_free( download_dir );
 
         /* use xml here because json responses to file uploads is trouble.
          * see http://www.malsup.com/jquery/form/#sample7 for details */
Index: web/javascript/transmission.js
===================================================================
--- web/javascript/transmission.js	(revision 10530)
+++ web/javascript/transmission.js	(working copy)
@@ -58,6 +58,9 @@
 		$('#turtle_button').bind('click', function(e){ tr.toggleTurtleClicked(e); return false; });
 		$('#prefs_tab_general_tab').click(function(e){ changeTab(this, 'prefs_tab_general') });
 		$('#prefs_tab_speed_tab').click(function(e){ changeTab(this, 'prefs_tab_speed') });
+		$('#torrent_data_dir_browse').bind('click', function(e){ tr.openForlderClicked(e); });
+		$('#folder_confirm_button').bind('click', function(e){ tr.confirmFolderClicked(e); return false;});
+		$('#folder_cancel_button').bind('click', function(e){ tr.cancelFolderClicked(e); return false;});
 
 		if (iPhone) {
 			$('#inspector_close').bind('click', function(e){ tr.hideInspector(); });
@@ -117,7 +120,7 @@
 		
 		// Setup the prefs gui
 		this.initializeSettings( );
-		
+
 		// Get preferences & torrents from the daemon
 		var tr = this;
 		var async = false;
@@ -623,6 +626,30 @@
 		this.hideUploadDialog( );
 	},
 
+	confirmFolderClicked: function(event) {
+		var tr = this;
+		if( tr.isButtonEnabled( event ) ) {
+			var o = $('#folder_list').find('.selected');
+			if( o.length != 0 ) $('#torrent_data_dir').attr('value', o.find('a').attr('rel'));
+			$('#select_folder_container').hide();
+		}
+		tr.updateButtonStates();
+	},
+
+	cancelFolderClicked: function(event) {
+		$('#select_folder_container').hide();
+	},
+
+	openForlderClicked: function( event ) {
+		var tr = this;
+		if( tr.isButtonEnabled( event ) ) {
+			$('#folder_list').selectFolder({ root: $('#torrent_data_dir').val() }, tr.remote);
+			$('#select_folder_container').show();
+			$('#folder_list').scrollTop(0);
+		}
+		tr.updateButtonStates();
+	},
+
 	cancelPrefsClicked: function(event) {
 		this.hidePrefsDialog( );
 	},
@@ -1637,6 +1664,7 @@
 		if (! confirmed) {
 				$('input#torrent_upload_file').attr('value', '');
 				$('input#torrent_upload_url').attr('value', '');
+				$('input#torrent_data_dir').attr('value', $('#prefs_form #download_location')[0].value);
 				$('input#torrent_auto_start').attr('checked', $('#prefs_form #auto_start')[0].checked);
 				$('#upload_container').show();
 			if (!iPhone && Safari3) {
@@ -1649,9 +1677,9 @@
 			var args = { };
 			var paused = !$('#torrent_auto_start').is(':checked');
 			if ('' != $('#torrent_upload_url').val()) {
-				tr.remote.addTorrentByUrl($('#torrent_upload_url').val(), { paused: paused });
+				tr.remote.addTorrentByUrl($('#torrent_upload_url').val(), { paused: paused }, $('#torrent_data_dir').val());
 			} else {
-				args.url = '/transmission/upload?paused=' + paused;
+				args.url = '/transmission/upload?paused=' + paused + '?download-dir=' + $('#torrent_data_dir').val();
 				args.type = 'POST';
 				args.data = { 'X-Transmission-Session-Id' : tr.remote._token };
 				args.dataType = 'xml';
@@ -1865,3 +1893,48 @@
 		}
 	}
 };
+
+(function($){
+
+	$.extend($.fn, {
+		selectFolder: function(o, remote) {
+			if( !o ) var o = {};
+			if( o.root == undefined ) o.root = '/';
+			else o.root = o.root.replace(/^\s+|\s+$/g,"");
+			if( o.loadMessage == undefined ) o.loadMessage = 'Loading...';
+
+			function showFolder(c, t) {
+				$(c).html('<ul><li>' + o.loadMessage + '</li></ul>');
+
+				remote.getFolders( t, function(data){
+					var args = data.arguments;
+					var body = '<ul>';
+					body = body + '<li class="this_link selected"><a href="#" rel="'+args.folderName+'">'+args.folderName+'</a></li>';
+					if( args.parentFolder != undefined ) body = body + '<li class="parent_link"><a href="#" rel="'+args.parentFolder+'">..</a></li>';
+					jQuery.each( args.folders.sort(), function() {
+						body = body + '<li><a href="#" rel="' + args.folderName;
+						if( args.parentFolder != undefined ) body = body + args.pathDelim;
+						body = body + this + '">' + this + '</a></li>';
+					});
+					body = body + '</ul>';
+					$(c).html(body);
+					$(c).scrollTop(0);
+					$(c).find('li a').bind('dblclick', function() {
+						showFolder( $(c), $(this).attr('rel') );
+						return false;
+					});
+					$(c).find('li a').bind('click', function() {
+						$(c).parent().find('.selected').removeClass('selected');
+						$(this).parent().addClass('selected');
+						return false;
+					});
+				});
+
+			}
+
+			showFolder( $(this), o.root );
+		}
+	});
+
+})(jQuery);
+
Index: web/javascript/transmission.remote.js
===================================================================
--- web/javascript/transmission.remote.js	(revision 10530)
+++ web/javascript/transmission.remote.js	(working copy)
@@ -227,12 +227,13 @@
 	verifyTorrents: function( torrent_ids, callback ) {
 		this.sendTorrentActionRequests( 'torrent-verify', torrent_ids, callback );
 	},
-	addTorrentByUrl: function( url, options ) {
+	addTorrentByUrl: function( url, options, download_dir ) {
 		var remote = this;
 		var o = {
 			method: 'torrent-add',
 			arguments: {
 				paused: (options.paused),
+				'download-dir': download_dir,
 				filename: url
 			}
 		};
@@ -256,5 +257,14 @@
 	},
 	filesDeselectAll: function( torrent_ids, files, callback ) {
 		this.sendTorrentSetRequests( 'torrent-set', torrent_ids, { 'files-unwanted': files }, callback );
+	},
+	getFolders: function(path, callback) {
+		var o = {
+			method: 'folders-get',
+			arguments: {
+				path: path
+			}
+		};
+		this.sendRequest( o, callback, false );
 	}
 };
Index: web/index.html
===================================================================
--- web/index.html	(revision 10530)
+++ web/index.html	(working copy)
@@ -385,7 +385,12 @@
 						<label for="torrent_upload_file">Please select a torrent file to upload:</label>
 							<input type="file" name="torrent_files[]" id="torrent_upload_file" multiple="multiple" />
 						<label for="torrent_upload_url">Or enter a URL:</label>
-							<input type="text" id="torrent_upload_url"/>
+							<input type="text" id="torrent_upload_url" />
+						<div class="dialog_input_group">
+							<label for="torrent_data_dir">Download directory:</label>
+								<input type="text" id="torrent_data_dir" />
+							<input type="button" id="torrent_data_dir_browse" value="Browse..." />
+						</div>
 							<input type="checkbox" id="torrent_auto_start" />
 						<label for="torrent_auto_start" id="auto_start_label">Start when added</label>
 					</div>
@@ -394,6 +399,19 @@
 				</form>
 			</div>
 		</div>
+
+		<div class="dialog_container" id="select_folder_container" style="display:none;">
+			<div class="dialog_top_bar"></div>
+			<div class="dialog_window">
+				<h2 class="dialog_heading">Select target folder</h2>
+				<form action="#" method="post" id="select_folder_form" target="select_folder_frame">
+					<div id="folder_list"></div>
+					<a href="#select" id="folder_confirm_button">Select</a>
+					<a href="#cancel" id="folder_cancel_button">Cancel</a>
+				</form>
+			</div>
+		</div>
+
 		<div class="torrent_footer">	
 			<div id="disk_space_container"></div>	
 			<ul id="settings_menu">
@@ -480,5 +498,7 @@
 		</div>
 		
 		<iframe name="torrent_upload_frame" id="torrent_upload_frame" src="about:blank" ></iframe>
+		<iframe name="select_folder_frame" id="select_folder_frame" src="about:blank" ></iframe>
+
 	</body>
 </html>
Index: web/stylesheets/common.css
===================================================================
--- web/stylesheets/common.css	(revision 10530)
+++ web/stylesheets/common.css	(working copy)
@@ -970,6 +970,26 @@
 	display: inline;
 }
 
+div#upload_container div.dialog_window div.dialog_message div.dialog_input_group {
+	width: 245px;
+	margin: 3px 0 0 0;
+	display: table-row;
+}
+
+div#upload_container div.dialog_window div.dialog_message div.dialog_input_group input[type=text] {
+	width: 161px;
+	padding: 0px;
+	display: inline;
+}
+
+div#upload_container div.dialog_window div.dialog_message div.dialog_input_group input[type=button] {
+	width: 80px;
+	padding: 0px;
+	margin-right: 0px;
+	margin-left: 4px;
+	display: inline;
+}
+
 div.dialog_container div.dialog_window form {
 	margin: 0;
 	padding: 0px;
@@ -987,6 +1007,62 @@
 	margin: 0;
 }
 
+div#select_folder_container div.dialog_window {
+	height: 310px;
+}
+
+div#select_folder_container div.dialog_window h2.dialog_heading {
+	display: block;
+	float: none;
+	margin-top: 20px;
+	margin-left: 20px;
+}
+
+div#select_folder_container div.dialog_window div#folder_list {
+	display: block;
+	height: 210px;
+	margin-left: 0px;
+	margin-right: 5px;
+	overflow: auto;
+}
+
+div#select_folder_container div.dialog_window ul li {
+	list-style: none;
+	padding: 0px;
+	padding-left: 0px;
+	margin: 0px;
+	white-space: nowrap;
+	width: 100%;
+	border: none;
+}
+
+div#select_folder_container div.dialog_window ul li a {
+	float: none;
+	text-align: left;
+	font-weight: normal;
+	text-decoration: none;
+	border: none;
+	padding: 0;
+	width: 100%;
+	-webkit-appearance: none;
+}
+
+div#select_folder_container div.dialog_window ul li.selected a {
+	background: #BDF;
+}
+
+iframe#select_folder_frame {
+	display: block;
+	position: absolute;
+	top: -1000px;
+	left: -1000px;
+	width: 0px;
+	height: 0px;
+	border: none;
+	padding: 0;
+	margin: 0;
+}
+
 div#prefs_container label {
 	display: block;
 	margin: 0 0 0 2px;
lazybones
Posts: 220
Joined: Sun Jan 24, 2010 12:41 am

Re: Select download folder from web client (diff attached)

Post by lazybones »

I wonder if it will work on the iPhone Mobile Interface as well. The layout is significantly different from the default UI.

Did you submit this as a ticket, I think that is the preferred method of submitting changes like this.

I am looking forward to this feature if it is accepted.
Jordan
Transmission Developer
Posts: 2312
Joined: Sat May 26, 2007 3:39 pm
Location: Titania's Room

Re: Select download folder from web client (diff attached)

Post by Jordan »

rampitec: this patch looks very interesting! Thanks very much writing that code.

The larger issue is that the web client is in the process of being replaced by [url=ttp://github.com/endor/kettu]kettu[/url]. So the question would be, how much work would it take to apply your patch to kettu?
rampitec
Posts: 13
Joined: Wed Apr 28, 2010 8:17 pm
Location: Saint-Petersburg, Russia

Re: Select download folder from web client (diff attached)

Post by rampitec »

lazybones wrote:I wonder if it will work on the iPhone Mobile Interface as well. The layout is significantly different from the default UI.
I have no iPhone, so cannot verify that. It might require several more lines of css to make it pretty though.
lazybones wrote:Did you submit this as a ticket, I think that is the preferred method of submitting changes like this.
I would like to, but apparently unable to do so. There is no way to submit a ticket as unregistered user, and there is no option to register.
rampitec
Posts: 13
Joined: Wed Apr 28, 2010 8:17 pm
Location: Saint-Petersburg, Russia

Re: Select download folder from web client (diff attached)

Post by rampitec »

Jordan wrote:rampitec: this patch looks very interesting! Thanks very much writing that code.

The larger issue is that the web client is in the process of being replaced by [url=ttp://github.com/endor/kettu]kettu[/url]. So the question would be, how much work would it take to apply your patch to kettu?
Thanks! Looking forward to see it integrated. Surely I can help with the integration after web client changes, if needed (though I will be AFK first two weeks of May).
Jordan
Transmission Developer
Posts: 2312
Joined: Sat May 26, 2007 3:39 pm
Location: Titania's Room

Re: Select download folder from web client (diff attached)

Post by Jordan »

rampitec wrote:
lazybones wrote:Did you submit this as a ticket, I think that is the preferred method of submitting changes like this.
I would like to, but apparently unable to do so. There is no way to submit a ticket as unregistered user, and there is no option to register.
http://trac.transmissionbt.com/register
rampitec
Posts: 13
Joined: Wed Apr 28, 2010 8:17 pm
Location: Saint-Petersburg, Russia

Re: Select download folder from web client (diff attached)

Post by rampitec »

Thanks a lot!
rampitec
Posts: 13
Joined: Wed Apr 28, 2010 8:17 pm
Location: Saint-Petersburg, Russia

Re: Select download folder from web client (diff attached)

Post by rampitec »

Diff is added to ticket #1496: http://trac.transmissionbt.com/ticket/1496

Thanks, guys, for helping to register on trac :)
Gaahl
Posts: 1
Joined: Wed Nov 04, 2009 1:07 pm

Re: Select download folder from web client (diff attached)

Post by Gaahl »

Does this still work with the lastest version?
bobcote
Posts: 2
Joined: Sun Oct 24, 2010 6:04 am

Re: Select download folder from web client (diff attached)

Post by bobcote »

Yeah, will it work?
rampitec
Posts: 13
Joined: Wed Apr 28, 2010 8:17 pm
Location: Saint-Petersburg, Russia

Re: Select download folder from web client (diff attached)

Post by rampitec »

bobcote wrote:Yeah, will it work?
You can try. I did not. Obviously, the farer Transmisson goes the less chances it will work and the more work will be needed to adjust the patch.
lazybones
Posts: 220
Joined: Sun Jan 24, 2010 12:41 am

Re: Select download folder from web client (diff attached)

Post by lazybones »

I really wish this feature was in the standard web client as it is the only way I have to control transmission from my iPhone..

On my PC both the Google Chrome plugin and "Transmission remote GUI" provide a way to set a download location.
djhomeless
Posts: 4
Joined: Sun Feb 20, 2011 11:15 am

Re: Select download folder from web client (diff attached)

Post by djhomeless »

Was anyone able to apply this patch? I agree that this is pretty vital functionality for the web client, but unfortunately I get errors when trying to apply it.

I'm currently on 2.12 but even tried downgrading to 1.92.

Hope this gets merged someday...!
d0m1nation
Posts: 2
Joined: Mon Apr 04, 2011 5:30 pm

Re: Select download folder from web client (diff attached)

Post by d0m1nation »

I can't get this to work with 2.22 either..

This is a vital feature to the web interface and I hope this will get implemented soon!
hamfratv
Posts: 3
Joined: Fri Jul 08, 2011 11:10 am

Re: Select download folder from web client (diff attached)

Post by hamfratv »

THIS IS GENIUS! Thanks a lot!!

Got it to work with 2.32 with a few modifications :)
Post Reply