Version 126

This commit is contained in:
Hydrus 2014-08-13 17:18:12 -05:00
parent 4125ced999
commit 799e75bba3
38 changed files with 664 additions and 471 deletions

View File

@ -8,6 +8,24 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 126</h3></li>
<ul>
<li>restored a dll that I thought was no longer needed, but was actually doing some weirder gif rendering</li>
<li>added 'remove' to fullscreen menu</li>
<li>harmonised thumbnail and fullscreen right click menus a bit more</li>
<li>added pause button to popup messages for repo update and subscription processing</li>
<li>moved service_identifier switchover forward</li>
<li>moved all service fetching to streamlined and non-laggy manager</li>
<li>changed client options to store default tag repository in a better way</li>
<li>changed subscriptions to store their advanced tag options in a better way</li>
<li>fixed a 'missing service' bug in advanced tag options</li>
<li>remade idle calculation into a much better gui-based rather than db-based test</li>
<li>fiddled more with maintenance timing, hopefully for the good</li>
<li>new screenshots in the help index pages!</li>
<li>improved how auto repo and server setup work and report their status</li>
<li>the client's UPnP daemon will no longer spam errors if your IGD doesn't support UPnP</li>
<li>fixed a bad db call in server's UPnP daemon</li>
</ul>
<li><h3>version 125</h3></li>
<ul>
<li>moved client splash screen and client boot to application event loop (i.e. your mouse won't hourglass over it now)</li>

View File

@ -18,11 +18,11 @@
<p>Because hydrus stores everything inside itself, it is entirely portable. You can extract it to a usb stick, move it from one place to another, have multiple installs for multiple purposes, wrap it all up inside a truecrypt volume, whatever you like. The .exe installer will write some unavoidable uninstall registry stuff to windows that'll mess with this, but the client itself will run fine in a different location.</p>
<h3>updating</h3>
<p>You don't <i>have</i> to update every week, but I generally recommend it. The different versions of client and server can talk with each other until I increment the private <i>network protocol version</i> (which happens every couple of months), at which point you will get polite error messages if you try to connect to a newer server with an older client or <i>vice versa</i>. Read my tumblr posts and judge for yourself what you want to do.</p>
<p>All your files and settings and synchronisation progress will be remembered after the update. Unless the update specifically disables something, nothing will be deleted or lost.</p>
<p>Whenever you start the client, it checks the version of its database. If the database is old, it makes the appropriate changes, in sequential order (i.e. to do v70->v75, the client would first apply v70->v71, then v71->v72 and so on), until the database is caught up.</p>
<p>If the client you want to update is running, remember to close it first!</p>
<p>If you use the installer, just download the new installer and run it. It should detect where the last install was and overwrite everything automatically.</p>
<p>If you extract, then just extract right on top of your current install and overwrite manually. Then run client.exe as normal.</p>
<p>All your files and settings and synchronisation progress will be remembered after the update. Unless the update specifically disables something, nothing will be deleted or lost.</p>
<p>Whenever you start the client, it checks the version of its database. If the database is old, it makes the appropriate changes, in sequential order (i.e. to do v70->v75, the client would first apply v70->v71, then v71->v72 and so on), until the database is caught up. If this process will take a while (like an hour, sometimes!) I will say so in my tumblr post.</p>
<h3>backing up</h3>
<p>You <i>do</i> backup, right? <i>Right</i>?</p>
<p>I run a backup every week so that if my computer blows up, I'll at worst have lost a few days' work. Before I had a backup regime, I once lost an entire drive with tens of thousands of files, and it didn't feel great at all. I only push backups so hard so you might avoid what I felt. ;_;</p>
@ -30,7 +30,7 @@
<p>If you want to backup hydrus, you can either go <i>database->create database backup</i> or just shut the client down and copy the entire install directory somewhere.</p>
<p>I recommend you do it before you update, just in case there is a problem with my code that breaks your database. If that happens, please <a href="contact.html">contact me</a>, describing the problem, and revert to the functioning older version. I'll get on any problems like that immediately.</p>
<h3>linux and os x</h3>
<p>I now make an OS X release, although it is very prototype. A linux release should follow in a few weeks.</p>
<p>I now make OS X and Linux releases. They are not as good as the Windows releases because I am not as experienced in their OSs' weirdnesses. When I find time, I improve them.</p>
<p class="right"><a href="getting_started_files.html">Let's import some files! ----></a></p>
</div>
</body>

View File

@ -5,13 +5,14 @@
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<a class="screenshot" href="client_empty.png" title="the main screen, just after you start up"><img src="client_empty_small.png" /></a>
<a class="screenshot" href="client_autism.png" title="an example search"><img src="client_autism_small.png" /></a>
<a class="screenshot" href="lib_gc.png" title="a well-tagged webcomic, sorted and viewed by chapter"><img src="lib_gc_small.png" /></a>
<a class="screenshot" href="client_fullscreen.png" title="reading the webcomic in fullscreen"><img src="client_fullscreen_small.png" /></a>
<a class="screenshot" href="lib_rec.png" title="file repository view, with some files local and some not"><img src="lib_rec_small.png" /></a>
<a class="screenshot" href="lib_party_hard.png" title="now with swf support!"><img src="lib_party_hard_small.png" /></a>
<a class="screenshot" href="client_auto.png" title="an example of tag-autocomplete, which only displays results applicable to the current query"><img src="client_auto_small.png" /></a>
<a class="screenshot" href="screenshot_empty.png" title="an empty page. you can search in many ways, not just tags"><img src="screenshot_empty_thumb.png" /></a>
<a class="screenshot" href="screenshot_general_search.png" title="a normal tag search"><img src="screenshot_general_search_thumb.png" /></a>
<a class="screenshot" href="screenshot_big_search.png" title="the client can easily search, display and manage thousands of files"><img src="screenshot_big_search_thumb.png" /></a>
<a class="screenshot" href="screenshot_gunnerkrigg_collect.png" title="files can be sorted and collected by their tags"><img src="screenshot_gunnerkrigg_collect_thumb.png" /></a>
<a class="screenshot" href="screenshot_fullscreen_blame.png" title="fullscreen view is clean and fast"><img src="screenshot_fullscreen_blame_thumb.png" /></a>
<a class="screenshot" href="screenshot_video.png" title="many file formats are supported"><img src="screenshot_video_thumb.png" /></a>
<a class="screenshot" href="screenshot_booru.png" title="you can run your own (simple!) booru"><img src="screenshot_booru_thumb.png" /></a>
<a class="screenshot" href="screenshot_advanced_autocomplete.png" title="the tag autocomplete is a powerful tool that can get complicated if you want it to. this screenshot shows a tag sibling, where one tag is immediately swapped with another, and a non-local search, where results that are known but not on the computer are shown"><img src="screenshot_advanced_autocomplete_thumb.png" /></a>
<h3>hydrus help</h3>
<p>Although I've tried to make hydrus's interface simple, its underlying concepts are not. Please read the introduction and skim the getting started guide at the least, and if you want to get started with my server, you'll probably want to check out the access keys section.</p>
<ul>

View File

@ -8,23 +8,23 @@
<div class="content">
<h3>on being anonymous</h3>
<p>I am convinced that having the option of anonymous speech is extremely valuable to the modern development of free culture and society.</p>
<p>When people have no fear of personal repercussion, they can reveal corruptions and admit truths they otherwise never would. Their words are insightful and stupid, convincing and hurtful, hilarious and ridiculous. Try it; it's fun!</p>
<p>Nearly all forums and social networking platforms use the same pseudonymous username/password archetype, and nearly all of them have the same problems with drama, sockpuppets, and egotistical mods. Sometimes the price is worth it, and sometimes it is not.</p>
<p>When people do not have to fear personal repercussion, they can reveal corruptions and admit truths they otherwise never would. Their words are insightful and stupid, convincing and hurtful, hilarious and ridiculous. It's fun!</p>
<p>Nearly all forums and social networking platforms use the same pseudonymous username/password system, and nearly all of them have the same problems with drama, sockpuppets, and egotistical mods. Sometimes the price is worth it, and sometimes it is not.</p>
<p>I think people should have the <i>option</i> to interact with others anonymously if they wish, and further should always have the choice to filter or entirely block anonymously submitted content (or anything else!). I want people to decide for themselves what they see, not anyone else.</p>
<p>There are several online platforms that support anonymity, usually through a web browser, but most have terribly inefficient code, and their actual anonymity is often impotent window dressing, an afterthought. Logs of IP addresses are kept routinely, available for any admin (or anyone else who gains access to the server) to peruse.</p>
<p>There are several online platforms that support anonymity, usually through a web browser, but most have terribly inefficient code, and their actual anonymity is unreliable. Logs of IP addresses are kept routinely, available for any admin (or anyone else who gains access to the server) to peruse.</p>
<p>I think we can do better.</p>
<h3>the hydrus network</h3>
<p>So! I'm developing a program that helps people manage their files together anonymously. My primary concern is in enabling you to do what you want with your stuff, and that's it. You can share tags and files with other people, but you don't have to connect to anything if you don't want to. I don't plan to ever record metrics on users, nor serve ads, nor charge for my software.</p>
<p>So! I'm developing a program that helps people manage their files together anonymously. I want to help you do what you want with your stuff, and that's it. You can share tags and files with other people, but you don't have to connect to anything if you don't want to. The default is <b>no sharing</b>. I don't plan to ever record metrics on users, nor serve ads, nor charge for my software.</p>
<p>There are a number of new concepts involved, and it can get as complicated as you like. If you are totally new to the idea of personal media collections and tagging, I advise you start slow, walk through the getting started guides, and experiment doing different things. You'll be importing thousands of files and applying <i>tens</i> of thousands of tags in no time.</p>
<p>The client is chiefly a file database. It manages your media far better than an explorer window. Here's a screenshot of one of my test installs with a very general search:</p>
<p>The client is chiefly a file database. It manages your media far better than an explorer window or some online gallery. Here's a screenshot of one of my test installs with a very general search:</p>
<p><a href="example_client.png"><img src="example_client.png" width="960" height="540" title="WELCOME TO INTERNET" /></a></p>
<p>There is also a server that anyone can run to store files or tags for sharing between many users. I run a tag service with several million tags that you are welcome to access and contribute to.</p>
<p>As well as the client, there is also a server that anyone can run to store files or tags for sharing between many users. I run a tag service with several million tags that you are welcome to access and contribute to.</p>
<p>I'm working on adding peer-to-peer anonymous communication.</p>
<h3>statement of principles</h3>
<ul class="bulletpoint">
<li>No speech should be outlawed.</li>
<li>Everyone should be able to control their own media diet.</li>
<li>The data on someone's computer and the logs of their network activity should be absolutely private.</li>
<li>Computer data and network logs should be absolutely private.</li>
</ul>
<p>None of the above are currently true, but I would love to live in a world where they were. My software is an attempt to move us a little closer.</p>
<p>I try to side with the person over the authority, the distributed over the centralised. I still use gmail and youtube just like pretty much everyone, but I would rather be using different systems, especially in ten years. No one seemed to be making what I wanted, so I decided to do it myself, and here we are.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
help/screenshot_booru.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

BIN
help/screenshot_empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
help/screenshot_video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -283,7 +283,7 @@ CLIENT_DEFAULT_OPTIONS[ 'shortcuts' ] = shortcuts
CLIENT_DEFAULT_OPTIONS[ 'confirm_client_exit' ] = False
CLIENT_DEFAULT_OPTIONS[ 'default_tag_repository' ] = HC.LOCAL_TAG_SERVICE_IDENTIFIER
CLIENT_DEFAULT_OPTIONS[ 'default_tag_repository' ] = HC.LOCAL_TAG_SERVICE_KEY
CLIENT_DEFAULT_OPTIONS[ 'default_tag_sort' ] = SORT_BY_LEXICOGRAPHIC_ASC
CLIENT_DEFAULT_OPTIONS[ 'pause_export_folders_sync' ] = False
@ -1160,7 +1160,7 @@ class LocalBooruCache( object ):
def _RefreshShares( self ):
self._local_booru_service = HC.app.Read( 'service', HC.LOCAL_BOORU_SERVICE_IDENTIFIER )
self._local_booru_service = HC.app.GetManager( 'services' ).GetService( HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetServiceKey() )
self._keys_to_infos = {}
@ -2293,6 +2293,8 @@ class Service( HC.HydrusYAMLBase ):
self._name = name
self._info = info
self._lock = threading.Lock()
HC.pubsub.sub( self, 'ProcessServiceUpdates', 'service_updates_data' )
@ -2565,29 +2567,14 @@ class ServiceManager( object ):
HC.pubsub.sub( self, 'RefreshServices', 'notify_new_services_data' )
def GetName( self, service_key ):
with self._lock:
service = self._keys_to_services[ service_key ]
return service.GetName()
def GetService( self, service_key ):
with self._lock: return self._keys_to_services[ service_key ]
def GetType( self, service_key ):
def GetServices( self, types = HC.ALL_SERVICES ):
with self._lock:
service = self._keys_to_services[ service_key ]
return service.GetType()
with self._lock: return [ service for service in self._keys_to_services.values() if service.GetType() in types ]
def RefreshServices( self ):

View File

@ -31,7 +31,7 @@ from twisted.internet import defer
ID_ANIMATED_EVENT_TIMER = wx.NewId()
ID_MAINTENANCE_EVENT_TIMER = wx.NewId()
MAINTENANCE_PERIOD = 12 * 60
MAINTENANCE_PERIOD = 5 * 60
class Controller( wx.App ):
@ -112,7 +112,7 @@ The database will be locked while the backup occurs, which may lock up your gui
def CurrentlyIdle( self ): return HC.GetNow() - self._timestamps[ 'last_user_db_use' ] > 30 * 60 # 30 mins since last user-initiated media_results query
def CurrentlyIdle( self ): return HC.GetNow() - self._timestamps[ 'last_user_action' ] > 30 * 60 # 30 mins since last canvas media swap
def EventPubSub( self, event ):
@ -208,9 +208,10 @@ The database will be locked while the backup occurs, which may lock up your gui
self._managers = {}
self._managers[ 'services' ] = CC.ServiceManager()
self._managers[ 'hydrus_sessions' ] = HydrusSessions.HydrusSessionManagerClient()
self._managers[ 'local_booru' ] = CC.LocalBooruCache()
self._managers[ 'services' ] = CC.ServiceManager()
self._managers[ 'tag_censorship' ] = HydrusTags.TagCensorshipManager()
self._managers[ 'tag_siblings' ] = HydrusTags.TagSiblingsManager()
self._managers[ 'tag_parents' ] = HydrusTags.TagParentsManager()
@ -265,9 +266,9 @@ The database will be locked while the backup occurs, which may lock up your gui
HC.pubsub.pub( 'set_splash_text', 'fattening service info' )
service_identifiers = self.Read( 'service_identifiers' )
services = self.GetManager( 'services' ).GetServices()
for service_identifier in service_identifiers: self.Read( 'service_info', service_identifier )
for service in services: self.Read( 'service_info', service.GetKey() )
self._timestamps[ 'service_info_cache_fatten' ] = HC.GetNow()
@ -314,12 +315,7 @@ The database will be locked while the backup occurs, which may lock up your gui
else: return text.lower()
def Read( self, action, *args, **kwargs ):
if action == 'media_results': self._timestamps[ 'last_user_db_use' ] = HC.GetNow()
return self._Read( action, *args, **kwargs )
def Read( self, action, *args, **kwargs ): return self._Read( action, *args, **kwargs )
def ReadDaemon( self, action, *args, **kwargs ):
@ -330,9 +326,11 @@ The database will be locked while the backup occurs, which may lock up your gui
return result
def ResetIdleTimer( self ): self._timestamps[ 'last_user_action' ] = HC.GetNow()
def RestartBooru( self ):
service = self.Read( 'service', HC.LOCAL_BOORU_SERVICE_IDENTIFIER )
service = self.GetManager( 'services' ).GetService( HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetServiceKey() )
info = service.GetInfo()
@ -506,7 +504,7 @@ Once it is done, the client will restart.'''
try:
query_hash_ids = HC.app.Read( 'file_query_ids', search_context )
query_hash_ids = self.Read( 'file_query_ids', search_context )
query_hash_ids = list( query_hash_ids )
@ -537,13 +535,13 @@ Once it is done, the client will restart.'''
sub_query_hash_ids = query_hash_ids[ last_i : i ]
more_media_results = HC.app.Read( 'media_results_from_ids', file_service_identifier, sub_query_hash_ids )
more_media_results = self.Read( 'media_results_from_ids', file_service_identifier, sub_query_hash_ids )
media_results.extend( more_media_results )
HC.pubsub.pub( 'set_num_query_results', len( media_results ), len( query_hash_ids ) )
HC.app.WaitUntilGoodTimeToUseGUIThread()
self.WaitUntilGoodTimeToUseGUIThread()
HC.pubsub.pub( 'file_query_done', query_key, media_results )
@ -558,7 +556,7 @@ Once it is done, the client will restart.'''
self._timestamps[ 'last_check_idle_time' ] = HC.GetNow()
# this tests if we probably just woke up from a sleep
if HC.GetNow() - last_time_this_ran > MAINTENANCE_PERIOD * 1.2: return
if HC.GetNow() - last_time_this_ran > MAINTENANCE_PERIOD + ( 5 * 60 ): return
if self.CurrentlyIdle(): self.MaintainDB()

View File

@ -1316,11 +1316,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
c.execute( 'REPLACE INTO hydrus_sessions ( service_id, session_key, expiry ) VALUES ( ?, ?, ? );', ( service_id, sqlite3.Binary( session_key ), expiry ) )
def _AddService( self, c, service_identifier, info ):
service_key = service_identifier.GetServiceKey()
service_type = service_identifier.GetType()
name = service_identifier.GetName()
def _AddService( self, c, service_key, service_type, name, info ):
if service_type in HC.LOCAL_SERVICES:
@ -2497,10 +2493,6 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
service_type = service_identifier.GetType()
repository = self._GetService( c, service_id )
account = repository.GetInfo( 'account' )
if service_type == HC.TAG_REPOSITORY:
updates = []
@ -2657,57 +2649,30 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
return reason_id
def _GetService( self, c, parameter ):
try:
if type( parameter ) == int: service_id = parameter
elif type( parameter ) == HC.ClientServiceIdentifier: service_id = self._GetServiceId( c, parameter )
except: raise Exception( 'Service error in database.' )
result = c.execute( 'SELECT service_key, service_type, name, info FROM services WHERE service_id = ?;', ( service_id, ) ).fetchone()
if result is None: raise Exception( 'Service error in database.' )
( service_key, service_type, name, info ) = result
service = CC.Service( service_key, service_type, name, info )
return service
def _GetServices( self, c, limited_types = HC.ALL_SERVICES ):
service_ids = [ service_id for ( service_id, ) in c.execute( 'SELECT service_id FROM services WHERE service_type IN ' + HC.SplayListForDB( limited_types ) + ';' ) ]
services = []
services = [ self._GetService( c, service_id ) for service_id in service_ids ]
for result in c.execute( 'SELECT service_key, service_type, name, info FROM services WHERE service_type IN ' + HC.SplayListForDB( limited_types ) + ';' ):
( service_key, service_type, name, info ) = result
services.append( CC.Service( service_key, service_type, name, info ) )
return services
def _GetServiceId( self, c, parameter ):
if type( parameter ) in ( str, unicode ):
result = c.execute( 'SELECT service_id FROM services WHERE name = ?;', ( parameter, ) ).fetchone()
if result is None: raise Exception( 'Service id error in database' )
( service_id, ) = result
elif type( parameter ) == HC.ClientServiceIdentifier:
service_type = parameter.GetType()
service_key = parameter.GetServiceKey()
result = c.execute( 'SELECT service_id FROM services WHERE service_key = ?;', ( sqlite3.Binary( service_key ), ) ).fetchone()
if result is None: raise Exception( 'Service id error in database' )
( service_id, ) = result
if type( parameter ) == HC.ClientServiceIdentifier: service_key = parameter.GetServiceKey()
else: service_key = parameter
result = c.execute( 'SELECT service_id FROM services WHERE service_key = ?;', ( sqlite3.Binary( service_key ), ) ).fetchone()
if result is None: raise Exception( 'Service id error in database' )
( service_id, ) = result
return service_id
@ -2727,11 +2692,11 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
def _GetServiceIdentifiers( self, c, limited_types = HC.ALL_SERVICES ): return { HC.ClientServiceIdentifier( service_key, service_type, name ) for ( service_key, service_type, name ) in c.execute( 'SELECT service_key, service_type, name FROM services WHERE service_type IN ' + HC.SplayListForDB( limited_types ) + ';' ) }
def _GetServiceInfo( self, c, service_identifier ):
def _GetServiceInfo( self, c, service_key ):
service_id = self._GetServiceId( c, service_identifier )
service_id = self._GetServiceId( c, service_key )
service_type = service_identifier.GetType()
service_type = self._GetServiceType( c, service_id )
if service_type == HC.LOCAL_FILE: info_types = { HC.SERVICE_INFO_NUM_FILES, HC.SERVICE_INFO_TOTAL_SIZE, HC.SERVICE_INFO_NUM_DELETED_FILES }
elif service_type == HC.FILE_REPOSITORY: info_types = { HC.SERVICE_INFO_NUM_FILES, HC.SERVICE_INFO_TOTAL_SIZE, HC.SERVICE_INFO_NUM_DELETED_FILES, HC.SERVICE_INFO_NUM_THUMBNAILS, HC.SERVICE_INFO_NUM_THUMBNAILS_LOCAL }
@ -3022,14 +2987,6 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
result = { dump_name.decode( 'hex' ) : data for ( dump_name, data ) in result.items() }
if dump_type == YAML_DUMP_ID_SUBSCRIPTION:
for ( dump_name, data ) in result.items():
data[ 'advanced_tag_options' ] = dict( data[ 'advanced_tag_options' ] )
else:
if dump_type == YAML_DUMP_ID_LOCAL_BOORU: dump_name = dump_name.encode( 'hex' )
@ -3046,15 +3003,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
if result is None: raise Exception( dump_name + ' was not found!' )
else:
( result, ) = result
if dump_type == YAML_DUMP_ID_SUBSCRIPTION:
result[ 'advanced_tag_options' ] = dict( result[ 'advanced_tag_options' ] )
else: ( result, ) = result
return result
@ -3827,14 +3776,12 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
def _ResetService( self, c, service_identifier ):
service_name = service_identifier.GetName()
name = service_identifier.GetName()
service_type = service_identifier.GetType()
service_id = self._GetServiceId( c, service_identifier )
service = self._GetService( c, service_id )
info = service.GetInfo()
( info, ) = c.execute( 'SELECT info FROM services WHERE service_id = ?;', ( service_id, ) ).fetchone()
c.execute( 'DELETE FROM services WHERE service_id = ?;', ( service_id, ) )
@ -3852,14 +3799,16 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
self.pub_after_commit( 'notify_restart_repo_sync_daemon' )
self._AddService( c, service_identifier, info )
service_key = service_identifier.GetServiceKey()
self._AddService( c, service_key, service_type, name, info )
self.pub_service_updates_after_commit( { service_identifier : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_RESET ) ] } )
self.pub_after_commit( 'notify_new_pending' )
self.pub_after_commit( 'notify_new_services_data' )
self.pub_after_commit( 'notify_new_services_gui' )
self.pub_after_commit( 'permissions_are_stale' )
HC.ShowText( 'reset ' + service_name )
HC.ShowText( 'reset ' + name )
def _SetTagCensorship( self, c, info ):
@ -3901,8 +3850,6 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
c.execute( 'DELETE FROM yaml_dumps WHERE dump_type = ? AND dump_name = ?;', ( dump_type, dump_name ) )
if dump_type == YAML_DUMP_ID_SUBSCRIPTION: data[ 'advanced_tag_options' ] = data[ 'advanced_tag_options' ].items()
try: c.execute( 'INSERT INTO yaml_dumps ( dump_type, dump_name, dump ) VALUES ( ?, ?, ? );', ( dump_type, dump_name, data ) )
except:
@ -4290,11 +4237,10 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
server_admin_service_id = self._GetServiceId( c, server_admin_service_identifier )
server_admin = self._GetService( c, server_admin_service_id )
( server_admin_info, ) = c.execute( 'SELECT info FROM services WHERE service_id = ?;', ( server_admin_service_id, ) ).fetchone()
server_admin_credentials = server_admin.GetCredentials()
( host, server_admin_port ) = server_admin_credentials.GetAddress()
host = server_admin_info[ 'host' ]
server_admin_port = server_admin_info[ 'port' ]
recalc_combined_mappings = False
@ -4315,9 +4261,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
name = HC.service_string_lookup[ service_type ] + ' at ' + host + ':' + HC.u( info[ 'port' ] )
client_service_identifier = HC.ClientServiceIdentifier( service_key, service_type, name )
self._AddService( c, client_service_identifier, info )
self._AddService( c, service_key, service_type, name, info )
elif action == HC.DELETE:
@ -4406,7 +4350,11 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
( service_identifier, info ) = details
self._AddService( c, service_identifier, info )
service_key = service_identifier.GetServiceKey()
service_type = service_identifier.GetType()
name = service_identifier.GetName()
self._AddService( c, service_key, service_type, name, info )
elif action == HC.DELETE:
@ -4570,10 +4518,10 @@ class DB( ServiceDB ):
raise
self._local_file_service_id = self._GetServiceId( c, HC.LOCAL_FILE_SERVICE_IDENTIFIER )
self._local_tag_service_id = self._GetServiceId( c, HC.LOCAL_TAG_SERVICE_IDENTIFIER )
self._combined_file_service_id = self._GetServiceId( c, HC.COMBINED_FILE_SERVICE_IDENTIFIER )
self._combined_tag_service_id = self._GetServiceId( c, HC.COMBINED_TAG_SERVICE_IDENTIFIER )
self._local_file_service_id = self._GetServiceId( c, HC.LOCAL_FILE_SERVICE_KEY )
self._local_tag_service_id = self._GetServiceId( c, HC.LOCAL_TAG_SERVICE_KEY )
self._combined_file_service_id = self._GetServiceId( c, HC.COMBINED_FILE_SERVICE_KEY )
self._combined_tag_service_id = self._GetServiceId( c, HC.COMBINED_TAG_SERVICE_KEY )
options = self._GetOptions( c )
@ -4820,9 +4768,12 @@ class DB( ServiceDB ):
for init_service_identifier in init_service_identifiers:
service_key = init_service_identifier.GetServiceKey()
service_type = init_service_identifier.GetType()
name = init_service_identifier.GetName()
info = {}
self._AddService( c, init_service_identifier, info )
self._AddService( c, service_key, service_type, name, info )
c.executemany( 'INSERT INTO yaml_dumps VALUES ( ?, ?, ? );', ( ( YAML_DUMP_ID_REMOTE_BOORU, name, booru ) for ( name, booru ) in CC.DEFAULT_BOORUS.items() ) )
@ -4940,6 +4891,9 @@ class DB( ServiceDB ):
if version == 114:
service_key = HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetServiceKey()
service_type = HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetType()
name = HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetName()
info = {}
self._AddService( c, HC.LOCAL_BOORU_SERVICE_IDENTIFIER, info )
@ -5064,6 +5018,35 @@ class DB( ServiceDB ):
c.execute( 'UPDATE services SET info = ? WHERE service_id = ?;', ( info, service_id ) )
if version == 125:
( HC.options, ) = c.execute( 'SELECT options FROM options;' ).fetchone()
HC.options[ 'default_tag_repository' ] = HC.options[ 'default_tag_repository' ].GetServiceKey()
c.execute( 'UPDATE options SET options = ?;', ( HC.options, ) )
#
results = c.execute( 'SELECT * FROM yaml_dumps WHERE dump_type = ?;', ( YAML_DUMP_ID_SUBSCRIPTION, ) ).fetchall()
for ( dump_type, dump_name, dump ) in results:
advanced_tag_options = dump[ 'advanced_tag_options' ]
new_advanced_tag_options = {}
for ( service_identifier, namespaces ) in advanced_tag_options:
new_advanced_tag_options[ service_identifier.GetServiceKey() ] = namespaces
dump[ 'advanced_tag_options' ] = new_advanced_tag_options
c.execute( 'UPDATE yaml_dumps SET dump = ? WHERE dump_type = ? and dump_name = ?;', ( dump, dump_type, dump_name ) )
c.execute( 'UPDATE version SET version = ?;', ( version + 1, ) )
HC.is_db_updated = True
@ -7096,7 +7079,6 @@ class DB( ServiceDB ):
elif action == 'ratings_media_result': result = self._GetRatingsMediaResult( c, *args, **kwargs )
elif action == 'remote_booru': result = self._GetYAMLDump( c, YAML_DUMP_ID_REMOTE_BOORU, *args, **kwargs )
elif action == 'remote_boorus': result = self._GetYAMLDump( c, YAML_DUMP_ID_REMOTE_BOORU )
elif action == 'service': result = self._GetService( c, *args, **kwargs )
elif action == 'service_identifiers': result = self._GetServiceIdentifiers( c, *args, **kwargs )
elif action == 'service_info': result = self._GetServiceInfo( c, *args, **kwargs )
elif action == 'services': result = self._GetServices( c, *args, **kwargs )
@ -7557,7 +7539,7 @@ def DAEMONDownloadFiles():
if service_identifier == HC.LOCAL_FILE_SERVICE_IDENTIFIER: break
try: file_repository = HC.app.ReadDaemon( 'service', service_identifier )
try: file_repository = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
except: continue
HC.pubsub.pub( 'downloads_status', HC.ConvertIntToPrettyString( num_downloads ) + ' file downloads' )
@ -7611,7 +7593,7 @@ def DAEMONDownloadThumbnails():
if len( thumbnail_hashes_i_need ) > 0:
try: file_repository = HC.app.ReadDaemon( 'service', service_identifier )
try: file_repository = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
except: continue
if file_repository.CanDownload():
@ -7711,7 +7693,7 @@ def DAEMONResizeThumbnails():
def DAEMONSynchroniseAccounts():
services = HC.app.ReadDaemon( 'services', HC.RESTRICTED_SERVICES )
services = HC.app.GetManager( 'services' ).GetServices( HC.RESTRICTED_SERVICES )
do_notify = False
@ -7771,7 +7753,7 @@ def DAEMONSynchroniseMessages():
service_type = service_identifier.GetType()
try: service = HC.app.ReadDaemon( 'service', service_identifier )
try: service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
except: continue
if service.CanCheck():
@ -7794,7 +7776,7 @@ def DAEMONSynchroniseMessages():
HC.app.WriteSynchronous( 'contact_associated', service_identifier )
service = HC.app.ReadDaemon( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
contact = service.GetContact()
@ -7893,7 +7875,7 @@ def DAEMONSynchroniseMessages():
my_public_key = contact_from.GetPublicKey()
my_contact_key = contact_from.GetContactKey()
my_message_depot = HC.app.ReadDaemon( 'service', contact_from )
my_message_depot = HC.app.GetManager( 'services' ).GetService( contact_from.GetServiceKey() )
from_connection = my_message_depot.GetConnection()
@ -7957,7 +7939,7 @@ def DAEMONSynchroniseRepositories():
service_type = service_identifier.GetType()
service_key = service_identifier.GetServiceKey()
try: service = HC.app.ReadDaemon( 'service', service_identifier )
try: service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
except: continue
info = service.GetInfo()
@ -7966,19 +7948,34 @@ def DAEMONSynchroniseRepositories():
if service.CanDownloadUpdate():
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'checking ' + name + ' repository' )
job_key = HC.JobKey( pausable = True, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'checking ' + name + ' repository', job_key )
HC.pubsub.pub( 'message', message )
while service.CanDownloadUpdate():
while job_key.IsPaused():
message.SetInfo( 'text', 'paused' )
time.sleep( 1 )
if HC.shutdown: raise Exception( 'application shutting down!' )
if message.IsClosed(): return
while HC.options[ 'pause_repo_sync' ]:
message.SetInfo( 'text', 'Repository synchronisation paused' )
message.SetInfo( 'text', 'repository synchronisation paused' )
time.sleep( 5 )
if HC.shutdown: raise Exception( 'Application shutting down!' )
if HC.shutdown: raise Exception( 'application shutting down!' )
if message.IsClosed(): return
if HC.repos_changed:
@ -7990,7 +7987,7 @@ def DAEMONSynchroniseRepositories():
if HC.shutdown: raise Exception( 'Application shutting down!' )
if HC.shutdown: raise Exception( 'application shutting down!' )
now = HC.GetNow()
@ -8036,7 +8033,7 @@ def DAEMONSynchroniseRepositories():
time.sleep( 0.10 )
try: service = HC.app.ReadDaemon( 'service', service_identifier )
try: service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
except: break
@ -8045,19 +8042,34 @@ def DAEMONSynchroniseRepositories():
if service.CanProcessUpdate():
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'processing ' + name + ' repository' )
job_key = HC.JobKey( pausable = True, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'processing ' + name + ' repository', job_key )
HC.pubsub.pub( 'message', message )
while service.CanProcessUpdate():
while job_key.IsPaused():
message.SetInfo( 'text', 'paused' )
time.sleep( 1 )
if HC.shutdown: raise Exception( 'application shutting down!' )
if message.IsClosed(): return
while HC.options[ 'pause_repo_sync' ]:
message.SetInfo( 'text', 'Repository synchronisation paused' )
message.SetInfo( 'text', 'repository synchronisation paused' )
time.sleep( 5 )
if HC.shutdown: raise Exception( 'Application shutting down!' )
if HC.shutdown: raise Exception( 'application shutting down!' )
if message.IsClosed(): return
if HC.repos_changed:
@ -8069,7 +8081,7 @@ def DAEMONSynchroniseRepositories():
if HC.shutdown: raise Exception( 'Application shutting down!' )
if HC.shutdown: raise Exception( 'application shutting down!' )
now = HC.GetNow()
@ -8168,7 +8180,7 @@ def DAEMONSynchroniseRepositories():
time.sleep( 0.10 )
try: service = HC.app.ReadDaemon( 'service', service_identifier )
try: service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
except: break
@ -8225,7 +8237,9 @@ def DAEMONSynchroniseSubscriptions():
try:
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'checking ' + name + ' subscription' )
job_key = HC.JobKey( pausable = True, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'checking ' + name + ' subscription', job_key )
HC.pubsub.pub( 'message', message )
@ -8291,6 +8305,17 @@ def DAEMONSynchroniseSubscriptions():
while True:
while job_key.IsPaused():
message.SetInfo( 'text', 'paused' )
time.sleep( 1 )
if HC.shutdown: return
if message.IsClosed(): return
while HC.options[ 'pause_subs_sync' ]:
message.SetInfo( 'text', 'subscriptions paused' )
@ -8299,6 +8324,8 @@ def DAEMONSynchroniseSubscriptions():
if HC.shutdown: return
if message.IsClosed(): return
if HC.subs_changed:
message.Close()
@ -8467,6 +8494,8 @@ def DAEMONSynchroniseSubscriptions():
message.SetInfo( 'hashes', successful_hashes )
message.SetInfo( 'mode', 'files' )
job_key.SetPausable( False )
else: message.Close()
last_checked = now
@ -8504,13 +8533,17 @@ def DAEMONSynchroniseSubscriptions():
def DAEMONUPnP():
local_ip = HydrusNATPunch.GetLocalIP()
try:
local_ip = HydrusNATPunch.GetLocalIP()
current_mappings = HydrusNATPunch.GetUPnPMappings()
our_mappings = { ( internal_client, internal_port ) : external_port for ( description, internal_client, internal_port, external_ip_address, external_port, protocol, enabled ) in current_mappings }
except: return # This IGD probably doesn't support UPnP, so don't spam the user with errors they can't fix!
current_mappings = HydrusNATPunch.GetUPnPMappings()
our_mappings = { ( internal_client, internal_port ) : external_port for ( description, internal_client, internal_port, external_ip_address, external_port, protocol, enabled ) in current_mappings }
services = HC.app.ReadDaemon( 'services', ( HC.LOCAL_BOORU, ) )
services = HC.app.GetManager( 'services' ).GetServices( ( HC.LOCAL_BOORU, ) )
for service in services:

View File

@ -144,17 +144,17 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
try:
job_key = HC.JobKey()
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'gathering pending and petitioned' )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'gathering pending and petitioned', job_key )
HC.pubsub.pub( 'message', message )
result = HC.app.Read( 'pending', service_identifier )
service_type = service_identifier.GetType()
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
service = HC.app.Read( 'service', service_identifier )
service_type = service.GetType()
if service_type == HC.FILE_REPOSITORY:
@ -172,7 +172,6 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
i = 1
message.SetInfo( 'job_key', job_key )
message.SetInfo( 'range', gauge_range )
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'connecting to repository' )
@ -325,7 +324,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
subject_access_key = dlg.GetValue().decode( 'hex' )
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
response = service.Request( HC.GET, 'account_info', { 'subject_access_key' : subject_access_key.encode( 'hex' ) } )
@ -338,178 +337,193 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
def _AutoRepoSetup( self ):
def do_it():
edit_log = []
tag_repo_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), HC.TAG_REPOSITORY, 'public tag repository' )
tag_repo_info = {}
tag_repo_info[ 'host' ] = 'hydrus.no-ip.org'
tag_repo_info[ 'port' ] = 45871
tag_repo_info[ 'access_key' ] = '4a285629721ca442541ef2c15ea17d1f7f7578b0c3f4f5f2a05f8f0ab297786f'.decode( 'hex' )
edit_log.append( ( HC.ADD, ( tag_repo_identifier, tag_repo_info ) ) )
file_repo_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), HC.FILE_REPOSITORY, 'read-only art file repository' )
file_repo_info = {}
file_repo_info[ 'host' ] = 'hydrus.no-ip.org'
file_repo_info[ 'port' ] = 45872
file_repo_info[ 'access_key' ] = '8f8a3685abc19e78a92ba61d84a0482b1cfac176fd853f46d93fe437a95e40a5'.decode( 'hex' )
edit_log.append( ( HC.ADD, ( file_repo_identifier, file_repo_info ) ) )
HC.app.Write( 'update_services', edit_log )
HC.ShowText( 'Auto repo setup done! Check services->review services to see your new services.' )
message = 'This will attempt to set up your client with my repositories\' credentials, letting you tag on the public tag repository and see some files.'
with ClientGUIDialogs.DialogYesNo( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_YES:
edit_log = []
tag_repo_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), HC.TAG_REPOSITORY, 'public tag repository' )
tag_repo_info = {}
tag_repo_info[ 'host' ] = 'hydrus.no-ip.org'
tag_repo_info[ 'port' ] = 45871
tag_repo_info[ 'access_key' ] = '4a285629721ca442541ef2c15ea17d1f7f7578b0c3f4f5f2a05f8f0ab297786f'.decode( 'hex' )
edit_log.append( ( HC.ADD, ( tag_repo_identifier, tag_repo_info ) ) )
file_repo_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), HC.FILE_REPOSITORY, 'read-only art file repository' )
file_repo_info = {}
file_repo_info[ 'host' ] = 'hydrus.no-ip.org'
file_repo_info[ 'port' ] = 45872
file_repo_info[ 'access_key' ] = '8f8a3685abc19e78a92ba61d84a0482b1cfac176fd853f46d93fe437a95e40a5'.decode( 'hex' )
edit_log.append( ( HC.ADD, ( file_repo_identifier, file_repo_info ) ) )
HC.app.Write( 'update_services', edit_log )
HC.ShowText( 'Auto repo setup done!' )
if dlg.ShowModal() == wx.ID_YES: HydrusThreading.CallToThread( do_it )
def _AutoServerSetup( self ):
host = '127.0.0.1'
port = HC.DEFAULT_SERVER_ADMIN_PORT
def do_it():
host = '127.0.0.1'
port = HC.DEFAULT_SERVER_ADMIN_PORT
try:
connection = httplib.HTTPConnection( '127.0.0.1', HC.DEFAULT_SERVER_ADMIN_PORT, timeout = 20 )
connection.connect()
connection.close()
already_running = True
except:
already_running = False
if already_running:
HC.ShowText( 'The server appears to be already running. Either that, or something else is using port ' + HC.u( HC.DEFAULT_SERVER_ADMIN_PORT ) + '.' )
return
else:
try:
HC.ShowText( 'starting server' )
my_scriptname = sys.argv[0]
if my_scriptname.endswith( 'pyw' ): subprocess.Popen( [ 'pythonw', HC.BASE_DIR + os.path.sep + 'server.pyw' ] )
else:
# The problem here is that, for mystical reasons, a PyInstaller exe can't launch another using subprocess, so we do it via explorer.
subprocess.Popen( [ 'explorer', HC.BASE_DIR + os.path.sep + 'server.exe' ] )
time.sleep( 10 ) # give it time to init its db
except:
HC.ShowText( 'I tried to start the server, but something failed!' )
HC.ShowText( traceback.format_exc() )
return
HC.ShowText( 'creating admin service' )
edit_log = []
admin_service_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), HC.SERVER_ADMIN, 'local server admin' )
admin_service_info = {}
admin_service_info[ 'host' ] = host
admin_service_info[ 'port' ] = port
admin_service_info[ 'access_key' ] = ''
edit_log.append( ( HC.ADD, ( admin_service_identifier, admin_service_info ) ) )
HC.app.Write( 'update_services', edit_log )
time.sleep( 5 )
i = 0
while True:
time.sleep( i + 1 )
try:
service = HC.app.GetManager( 'services' ).GetService( admin_service_identifier.GetServiceKey() )
break
except: pass
i += 1
if i > 5:
HC.ShowText( 'For some reason, I could not add the new server to the db! Perhaps it is very busy. Please email the hydrus developer, or sort it out yourself!' )
return
#
response = service.Request( HC.GET, 'init' )
access_key = response[ 'access_key' ]
update = { 'access_key' : access_key }
edit_log = [ ( HC.EDIT, ( admin_service_identifier, ( admin_service_identifier, update ) ) ) ]
HC.app.Write( 'update_services', edit_log )
HC.ShowText( 'admin service initialised' )
wx.CallAfter( ClientGUICommon.ShowKeys, 'access', ( access_key, ) )
time.sleep( 5 )
service = HC.app.GetManager( 'services' ).GetService( admin_service_identifier.GetServiceKey() )
#
HC.ShowText( 'creating tag and file services' )
tag_server_service_identifier = HC.ServerServiceIdentifier( os.urandom( 32 ), HC.TAG_REPOSITORY )
tag_options = HC.DEFAULT_OPTIONS[ HC.TAG_REPOSITORY ]
tag_options[ 'port' ] = HC.DEFAULT_SERVICE_PORT
file_server_service_identifier = HC.ServerServiceIdentifier( os.urandom( 32 ), HC.FILE_REPOSITORY )
file_options = HC.DEFAULT_OPTIONS[ HC.FILE_REPOSITORY ]
file_options[ 'port' ] = HC.DEFAULT_SERVICE_PORT + 1
edit_log = []
edit_log.append( ( HC.ADD, ( tag_server_service_identifier, tag_options ) ) )
edit_log.append( ( HC.ADD, ( file_server_service_identifier, file_options ) ) )
response = service.Request( HC.POST, 'services', { 'edit_log' : edit_log } )
service_identifiers_to_access_keys = dict( response[ 'service_identifiers_to_access_keys' ] )
HC.app.Write( 'update_server_services', admin_service_identifier, edit_log, service_identifiers_to_access_keys )
HC.ShowText( 'Done! Check services->review services to see your new server and its services.' )
message = 'This will attempt to start the server in the same install directory as this client, initialise it, and store the resultant admin accounts in the client.'
with ClientGUIDialogs.DialogYesNo( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_YES:
try:
connection = httplib.HTTPConnection( '127.0.0.1', HC.DEFAULT_SERVER_ADMIN_PORT, timeout = 20 )
connection.connect()
connection.close()
already_running = True
except:
already_running = False
if already_running:
message = 'The server appears to be already running. Either that, or something else is using port ' + HC.u( HC.DEFAULT_SERVER_ADMIN_PORT ) + '.' + os.linesep + 'Would you like to try to initialise the server that is already running?'
with ClientGUIDialogs.DialogYesNo( self, message ) as dlg:
if dlg.ShowModal() != wx.ID_YES: return
else:
try:
my_scriptname = sys.argv[0]
if my_scriptname.endswith( 'pyw' ): subprocess.Popen( [ 'pythonw', HC.BASE_DIR + os.path.sep + 'server.pyw' ] )
else:
# The problem here is that, for mystical reasons, a PyInstaller exe can't launch another using subprocess, so we do it via explorer.
subprocess.Popen( [ 'explorer', HC.BASE_DIR + os.path.sep + 'server.exe' ] )
time.sleep( 10 ) # give it time to init its db
except:
wx.MessageBox( 'I tried to start the server, but something failed!' )
wx.MessageBox( traceback.format_exc() )
return
edit_log = []
admin_service_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), HC.SERVER_ADMIN, 'local server admin' )
admin_service_info = {}
admin_service_info[ 'host' ] = host
admin_service_info[ 'port' ] = port
admin_service_info[ 'access_key' ] = ''
edit_log.append( ( HC.ADD, ( admin_service_identifier, admin_service_info ) ) )
HC.app.Write( 'update_services', edit_log )
i = 0
while True:
time.sleep( i + 1 )
try:
service = HC.app.Read( 'service', admin_service_identifier )
break
except: pass
i += 1
if i > 5:
wx.MessageBox( 'For some reason, I could not add the new server to the db! Perhaps it is very busy. Please contact the administrator, or sort it out yourself!' )
return
#
response = service.Request( HC.GET, 'init' )
access_key = response[ 'access_key' ]
update = { 'access_key' : access_key }
edit_log = [ ( HC.EDIT, ( admin_service_identifier, ( admin_service_identifier, update ) ) ) ]
HC.app.Write( 'update_services', edit_log )
ClientGUICommon.ShowKeys( 'access', ( access_key, ) )
#
tag_server_service_identifier = HC.ServerServiceIdentifier( os.urandom( 32 ), HC.TAG_REPOSITORY )
tag_options = HC.DEFAULT_OPTIONS[ HC.TAG_REPOSITORY ]
tag_options[ 'port' ] = HC.DEFAULT_SERVICE_PORT
file_server_service_identifier = HC.ServerServiceIdentifier( os.urandom( 32 ), HC.FILE_REPOSITORY )
file_options = HC.DEFAULT_OPTIONS[ HC.FILE_REPOSITORY ]
file_options[ 'port' ] = HC.DEFAULT_SERVICE_PORT + 1
edit_log = []
edit_log.append( ( HC.ADD, ( tag_server_service_identifier, tag_options ) ) )
edit_log.append( ( HC.ADD, ( file_server_service_identifier, file_options ) ) )
response = service.Request( HC.POST, 'services', { 'edit_log' : edit_log } )
service_identifiers_to_access_keys = dict( response[ 'service_identifiers_to_access_keys' ] )
HC.app.Write( 'update_server_services', admin_service_identifier, edit_log, service_identifiers_to_access_keys )
wx.MessageBox( 'Done! Check services->review services to see your new server and its services.' )
if dlg.ShowModal() == wx.ID_YES: HydrusThreading.CallToThread( do_it )
@ -521,7 +535,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
if dlg.ShowModal() == wx.ID_YES:
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
with wx.BusyCursor(): service.Request( HC.POST, 'backup' )
@ -611,7 +625,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
hash = dlg.GetValue().decode( 'hex' )
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
with wx.BusyCursor(): response = service.Request( HC.GET, 'ip', { 'hash' : hash.encode( 'hex' ) } )
@ -746,13 +760,13 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
def view():
services = HC.app.Read( 'services' )
services = HC.app.GetManager( 'services' ).GetServices()
tag_repositories = [ service for service in services if service.GetServiceIdentifier().GetType() == HC.TAG_REPOSITORY ]
tag_repositories = [ service for service in services if service.GetType() == HC.TAG_REPOSITORY ]
petition_resolve_tag_service_identifiers = [ repository.GetServiceIdentifier() for repository in tag_repositories if repository.GetInfo( 'account' ).HasPermission( HC.RESOLVE_PETITIONS ) ]
file_repositories = [ service for service in services if service.GetServiceIdentifier().GetType() == HC.FILE_REPOSITORY ]
file_repositories = [ service for service in services if service.GetType() == HC.FILE_REPOSITORY ]
file_service_identifiers = [ repository.GetServiceIdentifier() for repository in file_repositories ]
petition_resolve_file_service_identifiers = [ repository.GetServiceIdentifier() for repository in file_repositories if repository.GetInfo( 'account' ).HasPermission( HC.RESOLVE_PETITIONS ) ]
@ -897,15 +911,15 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
def admin():
services = HC.app.Read( 'services' )
services = HC.app.GetManager( 'services' ).GetServices()
tag_repositories = [ service for service in services if service.GetServiceIdentifier().GetType() == HC.TAG_REPOSITORY ]
tag_repositories = [ service for service in services if service.GetType() == HC.TAG_REPOSITORY ]
admin_tag_service_identifiers = [ repository.GetServiceIdentifier() for repository in tag_repositories if repository.GetInfo( 'account' ).HasPermission( HC.GENERAL_ADMIN ) ]
file_repositories = [ service for service in services if service.GetServiceIdentifier().GetType() == HC.FILE_REPOSITORY ]
file_repositories = [ service for service in services if service.GetType() == HC.FILE_REPOSITORY ]
admin_file_service_identifiers = [ repository.GetServiceIdentifier() for repository in file_repositories if repository.GetInfo( 'account' ).HasPermission( HC.GENERAL_ADMIN ) ]
servers_admin = [ service for service in services if service.GetServiceIdentifier().GetType() == HC.SERVER_ADMIN ]
servers_admin = [ service for service in services if service.GetType() == HC.SERVER_ADMIN ]
server_admin_identifiers = [ service.GetServiceIdentifier() for service in servers_admin if service.GetInfo( 'account' ).HasPermission( HC.GENERAL_ADMIN ) ]
if len( admin_tag_service_identifiers ) > 0 or len( admin_file_service_identifiers ) > 0 or len( server_admin_identifiers ) > 0:
@ -1227,7 +1241,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
def _ModifyAccount( self, service_identifier ):
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
with ClientGUIDialogs.DialogTextEntry( self, 'Enter the access key for the account to be modified.' ) as dlg:
@ -1313,7 +1327,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
if service_identifier is not None:
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
account = service.GetInfo( 'account' )
@ -1395,7 +1409,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
news = dlg.GetValue()
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
with wx.BusyCursor(): service.Request( HC.POST, 'news', { 'news' : news } )
@ -1592,7 +1606,9 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
url_string = url
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, url_string )
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, url_string, job_key )
HC.pubsub.pub( 'message', message )
@ -1620,7 +1636,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
def _Stats( self, service_identifier ):
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
response = service.Request( HC.GET, 'stats' )
@ -2505,7 +2521,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
def _DisplayAccountInfo( self ):
self._service = HC.app.Read( 'service', self._service_identifier )
self._service = HC.app.GetManager( 'services' ).GetService( self._service_identifier.GetServiceKey() )
service_type = self._service_identifier.GetType()
@ -2636,7 +2652,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
if service_type in HC.REPOSITORIES + HC.LOCAL_SERVICES:
service_info = HC.app.Read( 'service_info', self._service_identifier )
service_info = HC.app.Read( 'service_info', self._service_identifier.GetServiceKey() )
if service_type in ( HC.LOCAL_FILE, HC.FILE_REPOSITORY ):
@ -2781,7 +2797,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
( name, text, timeout, ( num_hashes, hashes, share_key ) ) = shares[0]
self._service = HC.app.Read( 'service', HC.LOCAL_BOORU_SERVICE_IDENTIFIER )
self._service = HC.app.GetManager( 'services' ).GetService( HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetServiceKey() )
info = self._service.GetInfo()
@ -2805,7 +2821,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
( name, text, timeout, ( num_hashes, hashes, share_key ) ) = shares[0]
self._service = HC.app.Read( 'service', HC.LOCAL_BOORU_SERVICE_IDENTIFIER )
self._service = HC.app.GetManager( 'services' ).GetService( HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetServiceKey() )
info = self._service.GetInfo()

View File

@ -433,6 +433,19 @@ class Canvas( object ):
self.Bind( wx.EVT_PAINT, self.EventPaint )
def _CopyHashToClipboard( self ):
if wx.TheClipboard.Open():
data = wx.TextDataObject( self._current_display_media.GetHash().encode( 'hex' ) )
wx.TheClipboard.SetData( data )
wx.TheClipboard.Close()
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
def _DrawBackgroundBitmap( self ):
( client_width, client_height ) = self.GetClientSize()
@ -539,7 +552,7 @@ class Canvas( object ):
if service_identifier in self._service_identifiers_to_services: service = self._service_identifiers_to_services[ service_identifier ]
else:
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
self._service_identifiers_to_services[ service_identifier ] = service
@ -757,6 +770,8 @@ class Canvas( object ):
if media != self._current_media:
HC.app.ResetIdleTimer()
with wx.FrozenWindow( self ):
self._current_media = media
@ -1051,6 +1066,30 @@ class CanvasFullscreenMediaList( ClientGUIMixins.ListeningMediaList, Canvas, Cli
def _Remove( self ):
next_media = self._GetNext( self._current_media )
if next_media == self._current_media: next_media = None
hashes = { self._current_display_media.GetHash() }
HC.pubsub.pub( 'remove_media', self._page_key, hashes )
singleton_media = { self._current_display_media }
ClientGUIMixins.ListeningMediaList._RemoveMedia( self, singleton_media, {} )
if self.HasNoMedia(): self.EventClose( None )
elif self.HasMedia( self._current_media ):
self._DrawBackgroundBitmap()
self._DrawCurrentMedia()
else: self.SetMedia( next_media )
def _ShowFirst( self ): self.SetMedia( self._GetFirst() )
def _ShowLast( self ): self.SetMedia( self._GetLast() )
@ -1459,6 +1498,7 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
if command == 'archive': self._Archive()
elif command == 'copy_files':
with wx.BusyCursor(): HC.app.Write( 'copy_files', ( self._current_media.GetHash(), ) )
elif command == 'copy_hash': self._CopyHashToClipboard()
elif command == 'copy_local_url': self._CopyLocalUrlToClipboard()
elif command == 'copy_path': self._CopyPathToClipboard()
elif command == 'delete': self._Delete()
@ -1481,6 +1521,7 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
elif command == 'pan_left': self._DoManualPan( -distance, 0 )
elif command == 'pan_right': self._DoManualPan( distance, 0 )
elif command == 'remove': self._Remove()
elif command == 'slideshow': self._StartSlideshow( data )
elif command == 'slideshow_pause_play': self._PausePlaySlideshow()
elif command == 'zoom_in': self._ZoomIn()
@ -1511,9 +1552,9 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
def EventShowMenu( self, event ):
services = HC.app.Read( 'services' )
services = HC.app.GetManager( 'services' ).GetServices()
local_ratings_services = [ service for service in services if service.GetServiceIdentifier().GetType() in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) ]
local_ratings_services = [ service for service in services if service.GetType() in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) ]
i_can_post_ratings = len( local_ratings_services ) > 0
@ -1550,25 +1591,33 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
menu.AppendSeparator()
menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'manage_tags' ), 'manage tags' )
manage_menu = wx.Menu()
if i_can_post_ratings: menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'manage_ratings' ), 'manage ratings' )
manage_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'manage_tags' ), 'tags' )
if i_can_post_ratings: manage_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'manage_ratings' ), 'ratings' )
menu.AppendMenu( CC.ID_NULL, 'manage', manage_menu )
menu.AppendSeparator()
if self._current_media.HasInbox(): menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'archive' ), '&archive' )
if self._current_media.HasArchive(): menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'inbox' ), 'return to &inbox' )
menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'remove', HC.LOCAL_FILE_SERVICE_IDENTIFIER ), '&remove' )
menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'delete', HC.LOCAL_FILE_SERVICE_IDENTIFIER ), '&delete' )
menu.AppendSeparator()
share_menu = wx.Menu()
copy_menu = wx.Menu()
copy_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy_files' ) , 'file' )
copy_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy_hash' ) , 'hash' )
copy_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy_path' ) , 'path' )
copy_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy_local_url' ) , 'local url' )
menu.AppendMenu( CC.ID_NULL, 'copy', copy_menu )
share_menu.AppendMenu( CC.ID_NULL, 'copy', copy_menu )
menu.AppendMenu( CC.ID_NULL, 'share', share_menu )
menu.AppendSeparator()
@ -1582,7 +1631,7 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
slideshow.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'slideshow', 80 ), 'william gibson' )
slideshow.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'slideshow' ), 'custom interval' )
menu.AppendMenu( CC.ID_NULL, 'Start Slideshow', slideshow )
menu.AppendMenu( CC.ID_NULL, 'start slideshow', slideshow )
if self._timer_slideshow.IsRunning(): menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'slideshow_pause_play' ), 'stop slideshow' )
self._menu_open = True
@ -1838,6 +1887,7 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
if command == 'archive': self._Archive()
elif command == 'copy_files':
with wx.BusyCursor(): HC.app.Write( 'copy_files', ( self._current_media.GetHash(), ) )
elif command == 'copy_hash': self._CopyHashToClipboard()
elif command == 'copy_local_url': self._CopyLocalUrlToClipboard()
elif command == 'copy_path': self._CopyPathToClipboard()
elif command == 'delete': self._Delete()
@ -1851,6 +1901,7 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
elif command == 'inbox': self._Inbox()
elif command == 'manage_ratings': self._ManageRatings()
elif command == 'manage_tags': self._ManageTags()
elif command == 'remove': self._Remove()
elif command == 'slideshow': self._StartSlideshow( data )
elif command == 'slideshow_pause_play': self._PausePlaySlideshow()
elif command == 'zoom_in': self._ZoomIn()
@ -1914,19 +1965,35 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
menu.AppendSeparator()
manage_menu = wx.Menu()
manage_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'manage_tags' ), 'tags' )
if i_can_post_ratings: manage_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'manage_ratings' ), 'ratings' )
menu.AppendMenu( CC.ID_NULL, 'manage', manage_menu )
menu.AppendSeparator()
if self._current_media.HasInbox(): menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'archive' ), '&archive' )
if self._current_media.HasArchive(): menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'inbox' ), 'return to &inbox' )
menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'remove', HC.LOCAL_FILE_SERVICE_IDENTIFIER ), '&remove' )
menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'delete', HC.LOCAL_FILE_SERVICE_IDENTIFIER ), '&delete' )
menu.AppendSeparator()
share_menu = wx.Menu()
copy_menu = wx.Menu()
copy_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy_files' ) , 'file' )
copy_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy_hash' ) , 'hash' )
copy_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy_path' ) , 'path' )
copy_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy_local_url' ) , 'local url' )
menu.AppendMenu( CC.ID_NULL, 'copy', copy_menu )
share_menu.AppendMenu( CC.ID_NULL, 'copy', copy_menu )
menu.AppendMenu( CC.ID_NULL, 'share', share_menu )
menu.AppendSeparator()
@ -2578,7 +2645,7 @@ class RatingsFilterFrameLike( CanvasFullscreenMediaListFilter ):
CanvasFullscreenMediaListFilter.__init__( self, my_parent, page_key, HC.LOCAL_FILE_SERVICE_IDENTIFIER, [], media_results )
self._rating_service_identifier = service_identifier
self._service = HC.app.Read( 'service', service_identifier )
self._service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
FullscreenPopoutFilterLike( self )
@ -2651,7 +2718,7 @@ class RatingsFilterFrameNumerical( ClientGUICommon.FrameThatResizes ):
if service_identifier.GetType() == HC.LOCAL_RATING_LIKE: self._score_gap = 1.0
else:
self._service = HC.app.Read( 'service', service_identifier )
self._service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
( self._lower, self._upper ) = self._service.GetLowerUpper()

View File

@ -2607,6 +2607,8 @@ class PopupMessageGauge( PopupMessage ):
PopupMessage.__init__( self, parent, message )
self._job_key = self._message.GetJobKey()
self._done = False
vbox = wx.BoxSizer( wx.VERTICAL )
@ -2620,11 +2622,16 @@ class PopupMessageGauge( PopupMessage ):
self._gauge = Gauge( self, size = ( 380, -1 ) )
self._gauge.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._pause_button = wx.Button( self, label = 'pause' )
self._pause_button.Bind( wx.EVT_BUTTON, self.EventPauseButton )
self._pause_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._cancel_button = wx.Button( self, label = 'cancel' )
self._cancel_button.Bind( wx.EVT_BUTTON, self.EventCancelButton )
self._cancel_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
hbox.AddF( self._gauge, FLAGS_EXPAND_BOTH_WAYS )
hbox.AddF( self._pause_button, FLAGS_MIXED )
hbox.AddF( self._cancel_button, FLAGS_MIXED )
self._show_file_button = wx.Button( self )
@ -2637,6 +2644,8 @@ class PopupMessageGauge( PopupMessage ):
self.SetSizer( vbox )
self._created = HC.GetNow()
def Dismiss( self ):
@ -2653,6 +2662,8 @@ class PopupMessageGauge( PopupMessage ):
if self._job_key.IsPaused(): self._job_key.Cancel()
PopupMessage.Dismiss( self )
@ -2660,14 +2671,28 @@ class PopupMessageGauge( PopupMessage ):
if self._message.GetInfo( 'mode' ) == 'cancelable gauge':
job_key = self._message.GetInfo( 'job_key' )
job_key.Cancel()
self._job_key.Cancel()
self._cancel_button.Disable()
def EventPauseButton( self, event ):
if self._job_key.IsPaused():
self._job_key.Resume()
self._pause_button.SetLabel( 'pause' )
else:
self._job_key.Pause()
self._pause_button.SetLabel( 'resume' )
def EventShowFileButton( self, event ):
hashes = self._message.GetInfo( 'hashes' )
@ -2681,6 +2706,9 @@ class PopupMessageGauge( PopupMessage ):
mode = self._message.GetInfo( 'mode' )
text = self._message.GetInfo( 'text' )
if self._job_key.IsPausable(): self._pause_button.Show()
else: self._pause_button.Hide()
if mode == 'files':
@ -3667,7 +3695,7 @@ class AdvancedTagOptions( AdvancedOptions ):
self._namespaces = namespaces
self._initial_settings = initial_settings
self._service_identifiers_to_checkbox_info = {}
self._service_keys_to_checkbox_info = {}
AdvancedOptions.__init__( self, parent, 'advanced tag options' )
@ -3678,21 +3706,23 @@ class AdvancedTagOptions( AdvancedOptions ):
self._vbox.Clear( True )
self._service_identifiers_to_checkbox_info = {}
self._service_keys_to_checkbox_info = {}
service_identifiers = HC.app.Read( 'service_identifiers', ( HC.TAG_REPOSITORY, HC.LOCAL_TAG ) )
services = HC.app.GetManager( 'services' ).GetServices( ( HC.TAG_REPOSITORY, HC.LOCAL_TAG ) )
if len( service_identifiers ) > 0:
if len( services ) > 0:
outer_gridbox = wx.FlexGridSizer( 0, 2 )
outer_gridbox.AddGrowableCol( 1, 1 )
for service_identifier in service_identifiers:
for service in services:
self._service_identifiers_to_checkbox_info[ service_identifier ] = []
service_key = service.GetKey()
outer_gridbox.AddF( wx.StaticText( panel, label = service_identifier.GetName() ), FLAGS_MIXED )
self._service_keys_to_checkbox_info[ service_key ] = []
outer_gridbox.AddF( wx.StaticText( panel, label = service.GetName() ), FLAGS_MIXED )
vbox = wx.BoxSizer( wx.VERTICAL )
@ -3703,12 +3733,12 @@ class AdvancedTagOptions( AdvancedOptions ):
namespace_checkbox = wx.CheckBox( panel, label = label )
if service_identifier in self._initial_settings and namespace in self._initial_settings[ service_identifier ]: namespace_checkbox.SetValue( True )
if service_key in self._initial_settings and namespace in self._initial_settings[ service_key ]: namespace_checkbox.SetValue( True )
else: namespace_checkbox.SetValue( False )
namespace_checkbox.Bind( wx.EVT_CHECKBOX, self.EventChecked )
self._service_identifiers_to_checkbox_info[ service_identifier ].append( ( namespace, namespace_checkbox ) )
self._service_keys_to_checkbox_info[ service_key ].append( ( namespace, namespace_checkbox ) )
vbox.AddF( namespace_checkbox, FLAGS_EXPAND_BOTH_WAYS )
@ -3746,11 +3776,11 @@ class AdvancedTagOptions( AdvancedOptions ):
result = {}
for ( service_identifier, checkbox_info ) in self._service_identifiers_to_checkbox_info.items():
for ( service_key, checkbox_info ) in self._service_keys_to_checkbox_info.items():
namespaces = [ namespace for ( namespace, checkbox ) in checkbox_info if checkbox.GetValue() == True ]
result[ service_identifier ] = namespaces
result[ service_key ] = namespaces
return result
@ -3767,13 +3797,13 @@ class AdvancedTagOptions( AdvancedOptions ):
def SetInfo( self, info ):
for ( service_identifier, checkbox_info ) in self._service_identifiers_to_checkbox_info.items():
for ( service_key, checkbox_info ) in self._service_keys_to_checkbox_info.items():
if service_identifier in info:
if service_key in info:
for ( namespace, checkbox ) in checkbox_info:
if namespace in info[ service_identifier ]: checkbox.SetValue( True )
if namespace in info[ service_key ]: checkbox.SetValue( True )
else: checkbox.SetValue( False )

View File

@ -63,7 +63,7 @@ def SelectServiceIdentifier( permission = None, service_types = HC.ALL_SERVICES,
if service_identifiers is None:
services = HC.app.Read( 'services', service_types )
services = HC.app.GetManager( 'services' ).GetServices( service_types )
if permission is not None: services = [ service for service in services if service.GetInfo( 'account' ).HasPermission( permission ) ]
@ -608,7 +608,7 @@ class DialogGenerateNewAccounts( Dialog ):
self._num.SetValue( 1 )
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
response = service.Request( HC.GET, 'account_types' )
@ -670,7 +670,7 @@ class DialogGenerateNewAccounts( Dialog ):
lifetime = self._lifetime.GetClientData( self._lifetime.GetSelection() )
service = HC.app.Read( 'service', self._service_identifier )
service = HC.app.GetManager( 'services' ).GetService( self._service_identifier.GetServiceKey() )
try:
@ -894,7 +894,7 @@ class DialogInputCustomFilterAction( Dialog ):
service_identifier = self._ratings_like_service_identifiers.GetClientData( selection )
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
self._current_ratings_like_service = service
@ -918,7 +918,7 @@ class DialogInputCustomFilterAction( Dialog ):
service_identifier = self._ratings_numerical_service_identifiers.GetClientData( selection )
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
self._current_ratings_numerical_service = service
@ -1535,8 +1535,8 @@ class DialogInputFileSystemPredicate( Dialog ):
def PopulateControls():
self._local_numericals = HC.app.Read( 'services', ( HC.LOCAL_RATING_NUMERICAL, ) )
self._local_likes = HC.app.Read( 'services', ( HC.LOCAL_RATING_LIKE, ) )
self._local_numericals = HC.app.GetManager( 'services' ).GetServices( ( HC.LOCAL_RATING_NUMERICAL, ) )
self._local_likes = HC.app.GetManager( 'services' ).GetServices( ( HC.LOCAL_RATING_LIKE, ) )
for service in self._local_numericals: self._service_numerical.Append( service.GetServiceIdentifier().GetName(), service )
@ -2108,7 +2108,7 @@ class DialogInputLocalBooruShare( Dialog ):
def EventCopyExternalShareURL( self, event ):
self._service = HC.app.Read( 'service', HC.LOCAL_BOORU_SERVICE_IDENTIFIER )
self._service = HC.app.GetManager( 'services' ).GetService( HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetServiceKey() )
info = self._service.GetInfo()
@ -2125,7 +2125,7 @@ class DialogInputLocalBooruShare( Dialog ):
def EventCopyInternalShareURL( self, event ):
self._service = HC.app.Read( 'service', HC.LOCAL_BOORU_SERVICE_IDENTIFIER )
self._service = HC.app.GetManager( 'services' ).GetService( HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetServiceKey() )
info = self._service.GetInfo()
@ -3550,7 +3550,7 @@ class DialogModifyAccounts( Dialog ):
Dialog.__init__( self, parent, 'modify account' )
self._service = HC.app.Read( 'service', service_identifier )
self._service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
self._subject_identifiers = list( subject_identifiers )
InitialiseControls()
@ -3766,9 +3766,9 @@ class DialogPageChooser( Dialog ):
ArrangeControls()
self._services = HC.app.Read( 'services' )
self._services = HC.app.GetManager( 'services' ).GetServices()
self._petition_service_identifiers = [ service.GetServiceIdentifier() for service in self._services if service.GetServiceIdentifier().GetType() in HC.REPOSITORIES and service.GetInfo( 'account' ).HasPermission( HC.RESOLVE_PETITIONS ) ]
self._petition_service_identifiers = [ service.GetServiceIdentifier() for service in self._services if service.GetType() in HC.REPOSITORIES and service.GetInfo( 'account' ).HasPermission( HC.RESOLVE_PETITIONS ) ]
self._InitButtons( 'home' )
@ -3975,7 +3975,7 @@ class DialogPathsToTagsRegex( Dialog ):
def PopulateControls():
services = HC.app.Read( 'services', ( HC.TAG_REPOSITORY, ) )
services = HC.app.GetManager( 'services' ).GetServices( ( HC.TAG_REPOSITORY, ) )
for service in services:
@ -3999,7 +3999,9 @@ class DialogPathsToTagsRegex( Dialog ):
self._tag_repositories.AddPage( page, name )
default_tag_repository = HC.options[ 'default_tag_repository' ]
default_tag_repository_key = HC.options[ 'default_tag_repository' ]
default_tag_repository = HC.app.GetManager( 'services' ).GetService( default_tag_repository_key )
self._tag_repositories.Select( default_tag_repository.GetName() )
@ -4890,6 +4892,8 @@ class DialogSelectYoutubeURL( Dialog ):
url_string = title + ' ' + resolution + ' ' + extension
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, url_string )
HydrusThreading.CallToThread( HydrusDownloading.THREADDownloadURL, message, url, url_string )

View File

@ -209,7 +209,7 @@ class DialogManageAccountTypes( ClientGUIDialogs.Dialog ):
def PopulateControls():
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
response = service.Request( HC.GET, 'account_types' )
@ -383,7 +383,7 @@ class DialogManageAccountTypes( ClientGUIDialogs.Dialog ):
def EventOK( self, event ):
service = HC.app.Read( 'service', self._service_identifier )
service = HC.app.GetManager( 'services' ).GetService( self._service_identifier.GetServiceKey() )
service.Request( HC.POST, 'account_types', { 'edit_log' : self._edit_log } )
@ -2845,7 +2845,7 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
self._default_tag_sort.Append( 'incidence (desc)', CC.SORT_BY_INCIDENCE_DESC )
self._default_tag_sort.Append( 'incidence (asc)', CC.SORT_BY_INCIDENCE_ASC )
self._default_tag_repository = wx.Choice( self._gui_page )
self._default_tag_repository = ClientGUICommon.BetterChoice( self._gui_page )
self._fullscreen_borderless = wx.CheckBox( self._gui_page )
@ -3050,11 +3050,13 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
elif HC.options[ 'default_tag_sort' ] == CC.SORT_BY_INCIDENCE_DESC: self._default_tag_sort.Select( 2 )
elif HC.options[ 'default_tag_sort' ] == CC.SORT_BY_INCIDENCE_ASC: self._default_tag_sort.Select( 3 )
service_identifiers = HC.app.Read( 'service_identifiers', ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ) )
services = HC.app.GetManager( 'services' ).GetServices( ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ) )
for service_identifier in service_identifiers: self._default_tag_repository.Append( service_identifier.GetName(), service_identifier )
for service in services: self._default_tag_repository.Append( service.GetName(), service.GetKey() )
self._default_tag_repository.SetStringSelection( HC.options[ 'default_tag_repository' ].GetName() )
default_tag_repository_key = HC.options[ 'default_tag_repository' ]
self._default_tag_repository.SelectClientData( default_tag_repository_key )
self._fullscreen_borderless.SetValue( HC.options[ 'fullscreen_borderless' ] )
@ -3644,7 +3646,7 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
HC.options[ 'shortcuts' ] = shortcuts
HC.options[ 'default_tag_repository' ] = self._default_tag_repository.GetClientData( self._default_tag_repository.GetSelection() )
HC.options[ 'default_tag_repository' ] = self._default_tag_repository.GetChoice()
HC.options[ 'default_tag_sort' ] = self._default_tag_sort.GetClientData( self._default_tag_sort.GetSelection() )
new_local_port = self._local_port.GetValue()
@ -3948,7 +3950,7 @@ class DialogManageRatings( ClientGUIDialogs.Dialog ):
wx.Panel.__init__( self, parent )
self._service_identifier = service_identifier
self._service = HC.app.Read( 'service', service_identifier )
self._service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
self._media = media
@ -4290,7 +4292,7 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
self._service_identifier = service_identifier
self._service = HC.app.Read( 'service', self._service_identifier )
self._service = HC.app.GetManager( 'services' ).GetService( self._service_identifier.GetServiceKey() )
InitialiseControls()
@ -4606,7 +4608,7 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
parent_listbook.AddPage( listbook, name )
services = HC.app.Read( 'services', manageable_service_types )
services = HC.app.GetManager( 'services' ).GetServices( manageable_service_types )
for service in services:
@ -5960,9 +5962,11 @@ class DialogManageTagCensorship( ClientGUIDialogs.Dialog ):
self._tag_services.AddPage( page, name )
default_tag_repository = HC.options[ 'default_tag_repository' ]
default_tag_repository_key = HC.options[ 'default_tag_repository' ]
self._tag_services.Select( default_tag_repository.GetName() )
service = HC.app.GetManager( 'services' ).GetService( default_tag_repository_key )
self._tag_services.Select( service.GetName() )
def ArrangeControls():
@ -6130,7 +6134,7 @@ class DialogManageTagParents( ClientGUIDialogs.Dialog ):
def PopulateControls():
services = HC.app.Read( 'services', ( HC.TAG_REPOSITORY, ) )
services = HC.app.GetManager( 'services' ).GetServices( ( HC.TAG_REPOSITORY, ) )
for service in services:
@ -6154,9 +6158,11 @@ class DialogManageTagParents( ClientGUIDialogs.Dialog ):
self._tag_repositories.AddPage( page, name )
default_tag_repository = HC.options[ 'default_tag_repository' ]
default_tag_repository_key = HC.options[ 'default_tag_repository' ]
self._tag_repositories.Select( default_tag_repository.GetName() )
service = HC.app.GetManager( 'services' ).GetService( default_tag_repository_key )
self._tag_repositories.Select( service.GetName() )
def ArrangeControls():
@ -6309,7 +6315,7 @@ class DialogManageTagParents( ClientGUIDialogs.Dialog ):
if self._service_identifier != HC.LOCAL_TAG_SERVICE_IDENTIFIER:
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
self._account = service.GetInfo( 'account' )
@ -6598,7 +6604,7 @@ class DialogManageTagSiblings( ClientGUIDialogs.Dialog ):
self._tag_repositories.AddPage( page, name )
services = HC.app.Read( 'services', ( HC.TAG_REPOSITORY, ) )
services = HC.app.GetManager( 'services' ).GetServices( ( HC.TAG_REPOSITORY, ) )
for service in services:
@ -6616,9 +6622,11 @@ class DialogManageTagSiblings( ClientGUIDialogs.Dialog ):
default_tag_repository = HC.options[ 'default_tag_repository' ]
default_tag_repository_key = HC.options[ 'default_tag_repository' ]
self._tag_repositories.Select( default_tag_repository.GetName() )
service = HC.app.GetManager( 'services' ).GetService( default_tag_repository_key )
self._tag_repositories.Select( service.GetName() )
def ArrangeControls():
@ -6777,7 +6785,7 @@ class DialogManageTagSiblings( ClientGUIDialogs.Dialog ):
if self._service_identifier != HC.LOCAL_TAG_SERVICE_IDENTIFIER:
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
self._account = service.GetInfo( 'account' )
@ -7273,9 +7281,11 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
self._tag_repositories.AddPage( page_info, name )
default_tag_repository = HC.options[ 'default_tag_repository' ]
default_tag_repository_key = HC.options[ 'default_tag_repository' ]
self._tag_repositories.Select( default_tag_repository.GetName() )
service = HC.app.GetManager( 'services' ).GetService( default_tag_repository_key )
self._tag_repositories.Select( service.GetName() )
def ArrangeControls():
@ -7449,7 +7459,7 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
if not self._i_am_local_tag_service:
service = HC.app.Read( 'service', tag_service_identifier )
service = HC.app.GetManager( 'services' ).GetService( tag_service_identifier.GetServiceKey() )
self._account = service.GetInfo( 'account' )

View File

@ -639,10 +639,15 @@ class ManagementPanelDumper( ManagementPanel ):
advanced_tag_options = self._advanced_tag_options.GetInfo()
for ( service_identifier, namespaces ) in advanced_tag_options.items():
for ( service_key, namespaces ) in advanced_tag_options.items():
tags_manager = media.GetTagsManager()
try: service = HC.app.GetManager( 'services' ).GetService( service_key )
except: continue
service_identifier = service.GetKey()
current = tags_manager.GetCurrent( service_identifier )
pending = tags_manager.GetPending( service_identifier )
@ -1820,7 +1825,7 @@ class ManagementPanelPetitions( ManagementPanel ):
ManagementPanel.__init__( self, parent, page, page_key, file_service_identifier, starting_from_session = starting_from_session )
self._service = HC.app.Read( 'service', self._petition_service_identifier )
self._service = HC.app.GetManager( 'services' ).GetService( self._petition_service_identifier.GetServiceKey() )
self._can_ban = self._service.GetInfo( 'account' ).HasPermission( HC.MANAGE_USERS )
self._num_petitions = None

View File

@ -91,6 +91,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
HC.pubsub.sub( self, 'Collect', 'collect_media' )
HC.pubsub.sub( self, 'Sort', 'sort_media' )
HC.pubsub.sub( self, 'FileDumped', 'file_dumped' )
HC.pubsub.sub( self, 'RemoveMedia', 'remove_media' )
self._PublishSelectionChange()
@ -815,6 +816,16 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
def RemoveMedia( self, page_key, hashes ):
if page_key == self._page_key:
media = self._GetMedia( hashes )
self._RemoveMedia( media, {} )
def SetFocussedMedia( self, page_key, media ):
if page_key == self._page_key:
@ -1678,13 +1689,13 @@ class MediaPanelThumbnails( MediaPanel ):
multiple_selected = num_selected > 1
services = HC.app.Read( 'services' )
services = HC.app.GetManager( 'services' ).GetServices()
tag_repositories = [ service for service in services if service.GetServiceIdentifier().GetType() == HC.TAG_REPOSITORY ]
tag_repositories = [ service for service in services if service.GetType() == HC.TAG_REPOSITORY ]
file_repositories = [ service for service in services if service.GetServiceIdentifier().GetType() == HC.FILE_REPOSITORY ]
file_repositories = [ service for service in services if service.GetType() == HC.FILE_REPOSITORY ]
local_ratings_services = [ service for service in services if service.GetServiceIdentifier().GetType() in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) ]
local_ratings_services = [ service for service in services if service.GetType() in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) ]
i_can_post_ratings = len( local_ratings_services ) > 0

View File

@ -626,7 +626,7 @@ class DestinationPanel( wx.Panel ):
elif command == 'read': status = 'read'
elif command == 'unread': status = 'sent'
my_message_depot = HC.app.Read( 'service', self._identity )
my_message_depot = HC.app.GetManager( 'services' ).GetService( self._identity.GetServiceKey() )
connection = my_message_depot.GetConnection()
@ -1250,7 +1250,7 @@ class DraftPanel( wx.Panel ):
try:
my_message_depot = HC.app.Read( 'service', self._contact_from )
my_message_depot = HC.app.GetManager( 'services' ).GetService( self._contact_from.GetServiceKey() )
connection = my_message_depot.GetConnection()

View File

@ -64,7 +64,7 @@ options = {}
# Misc
NETWORK_VERSION = 13
SOFTWARE_VERSION = 125
SOFTWARE_VERSION = 126
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
@ -1522,12 +1522,17 @@ class ClientServiceIdentifier( HydrusYAMLBase ):
def GetType( self ): return self._type
LOCAL_FILE_SERVICE_IDENTIFIER = ClientServiceIdentifier( 'local files', LOCAL_FILE, 'local files' )
LOCAL_TAG_SERVICE_IDENTIFIER = ClientServiceIdentifier( 'local tags', LOCAL_TAG, 'local tags' )
LOCAL_BOORU_SERVICE_IDENTIFIER = ClientServiceIdentifier( 'local booru', LOCAL_BOORU, 'local booru' )
COMBINED_FILE_SERVICE_IDENTIFIER = ClientServiceIdentifier( 'all known files', COMBINED_FILE, 'all known files' )
COMBINED_TAG_SERVICE_IDENTIFIER = ClientServiceIdentifier( 'all known tags', COMBINED_TAG, 'all known tags' )
NULL_SERVICE_IDENTIFIER = ClientServiceIdentifier( '', NULL_SERVICE, 'no service' )
LOCAL_FILE_SERVICE_KEY = 'local files'
LOCAL_TAG_SERVICE_KEY = 'local tags'
LOCAL_BOORU_SERVICE_KEY = 'local booru'
COMBINED_FILE_SERVICE_KEY = 'all known files'
COMBINED_TAG_SERVICE_KEY = 'all known tags'
LOCAL_FILE_SERVICE_IDENTIFIER = ClientServiceIdentifier( LOCAL_FILE_SERVICE_KEY, LOCAL_FILE, 'local files' )
LOCAL_TAG_SERVICE_IDENTIFIER = ClientServiceIdentifier( LOCAL_TAG_SERVICE_KEY, LOCAL_TAG, 'local tags' )
LOCAL_BOORU_SERVICE_IDENTIFIER = ClientServiceIdentifier( LOCAL_BOORU_SERVICE_KEY, LOCAL_BOORU, 'local booru' )
COMBINED_FILE_SERVICE_IDENTIFIER = ClientServiceIdentifier( COMBINED_FILE_SERVICE_KEY, COMBINED_FILE, 'all known files' )
COMBINED_TAG_SERVICE_IDENTIFIER = ClientServiceIdentifier( COMBINED_TAG_SERVICE_KEY, COMBINED_TAG, 'all known tags' )
class ClientToServerUpdate( HydrusYAMLBase ):
@ -1742,10 +1747,13 @@ class JobDatabase( object ):
class JobKey( object ):
def __init__( self ):
def __init__( self, pausable = True, cancellable = True ):
self._key = os.urandom( 32 )
self._pausable = pausable
self._cancellable = cancellable
self._begun = threading.Event()
self._done = threading.Event()
self._cancelled = threading.Event()
@ -1770,6 +1778,11 @@ class JobKey( object ):
self.Finish()
def DeleteVariable( self, name ):
with self._variable_lock: del self._variables[ name ]
def Finish( self ): self._done.set()
def GetKey( self ): return self._key
@ -1786,10 +1799,14 @@ class JobKey( object ):
def IsBegun( self ): return self._begun.is_set()
def IsCancellable( self ): return self._cancellable
def IsCancelled( self ): return shutdown or self._cancelled.is_set()
def IsDone( self ): return shutdown or self._done.is_set()
def IsPausable( self ): return self._pausable
def IsPaused( self ): return self._paused.is_set()
def IsWorking( self ): return self.IsBegun() and not self.IsDone()
@ -1804,6 +1821,10 @@ class JobKey( object ):
def Resume( self ): self._paused.clear()
def SetCancellable( self, value ): self._cancellable = value
def SetPausable( self, value ): self._pausable = value
def SetVariable( self, name, value ):
with self._variable_lock: self._variables[ name ] = value
@ -1906,16 +1927,18 @@ class Message( object ):
class MessageGauge( Message ):
def __init__( self, message_type, text ):
def __init__( self, message_type, text, job_key ):
info = {}
Message.__init__( self, message_type, {} )
info[ 'mode' ] = 'text'
info[ 'text' ] = text
self._info[ 'mode' ] = 'text'
self._info[ 'text' ] = text
Message.__init__( self, message_type, info )
self._job_key = job_key
def GetJobKey( self ): return self._job_key
class Predicate( HydrusYAMLBase ):
yaml_tag = u'!Predicate'
@ -2224,7 +2247,8 @@ class ServerServiceIdentifier( HydrusYAMLBase ):
def GetType( self ): return self._type
SERVER_ADMIN_IDENTIFIER = ServerServiceIdentifier( 'server admin', SERVER_ADMIN )
SERVER_ADMIN_KEY = 'server admin'
SERVER_ADMIN_IDENTIFIER = ServerServiceIdentifier( SERVER_ADMIN_KEY, SERVER_ADMIN )
class ServiceUpdate( object ):

View File

@ -56,7 +56,10 @@ def ConvertTagsToServiceIdentifiersToTags( tags, advanced_tag_options ):
siblings_manager = HC.app.GetManager( 'tag_siblings' )
parents_manager = HC.app.GetManager( 'tag_parents' )
for ( service_identifier, namespaces ) in advanced_tag_options.items():
for ( service_key, namespaces ) in advanced_tag_options.items():
try: service_identifier = HC.app.GetManager( 'services' ).GetService( service_key ).GetServiceIdentifier()
except: continue
if len( namespaces ) > 0:
@ -1766,6 +1769,7 @@ def THREADDownloadURL( message, url, url_string ):
message.SetInfo( 'range', None )
message.SetInfo( 'value', None )
message.SetInfo( 'mode', 'gauge' )
temp_path = HC.http.Request( HC.GET, url, response_to_path = True, report_hooks = [ hook ] )
message.SetInfo( 'range', None )

View File

@ -120,7 +120,7 @@ class HydrusSessionManagerClient( object ):
# session key expired or not found
service = HC.app.Read( 'service', service_identifier )
service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
( response, cookies ) = service.Request( HC.GET, 'session_key', return_cookies = True )

View File

@ -2884,9 +2884,9 @@ def DAEMONUPnP():
service_identifiers = HC.app.ReadDaemon( 'service_identifiers' )
all_options = { service_identifier : HC.app.ReadDaemon( 'options', service_identifier ) for service_identifier in service_identifiers }
all_infos = HC.app.ReadDaemon( 'services' )
for ( service_identifier, options ) in all_options.items():
for ( service_identifier, options ) in all_infos:
internal_port = options[ 'port' ]
upnp = options[ 'upnp' ]
@ -2899,12 +2899,12 @@ def DAEMONUPnP():
for ( service_identifier, options ) in all_options.items():
for ( service_identifier, options ) in all_infos:
internal_port = options[ 'port' ]
upnp = options[ 'upnp' ]
if ( local_ip, internal_port ) not in our_mappings:
if upnp is not None and ( local_ip, internal_port ) not in our_mappings:
external_port = upnp

View File

@ -961,14 +961,6 @@ class TestClientDB( unittest.TestCase ):
#
result = self._read( 'service', HC.LOCAL_FILE_SERVICE_IDENTIFIER )
self.assertEqual( result.GetServiceIdentifier(), HC.LOCAL_FILE_SERVICE_IDENTIFIER )
result = self._read( 'service', HC.LOCAL_TAG_SERVICE_IDENTIFIER )
self.assertEqual( result.GetServiceIdentifier(), HC.LOCAL_TAG_SERVICE_IDENTIFIER )
result = self._read( 'services', ( HC.LOCAL_FILE, HC.LOCAL_TAG ) )
result_s_is = { service.GetServiceIdentifier() for service in result }
@ -977,7 +969,7 @@ class TestClientDB( unittest.TestCase ):
#
result = self._read( 'service_info', HC.LOCAL_FILE_SERVICE_IDENTIFIER )
result = self._read( 'service_info', HC.LOCAL_FILE_SERVICE_IDENTIFIER.GetServiceKey() )
self.assertEqual( type( result ), dict )
@ -1055,18 +1047,7 @@ class TestClientDB( unittest.TestCase ):
self._write( 'update_services', edit_log )
with self.assertRaises( HydrusExceptions.DBException ):
self._read( 'service', new_local_like )
result = self._read( 'service', other_new_tag_repo )
host = other_new_tag_repo_info_updated[ 'host' ]
port = other_new_tag_repo_info_updated[ 'port' ]
access_key = other_new_tag_repo_info_updated[ 'access_key' ]
self.assertEqual( result.GetCredentials(), CC.Credentials( host, port, access_key ) )
# update this ~sometime~ to test the new services manager object, which should update with these changes!
#
@ -1076,10 +1057,7 @@ class TestClientDB( unittest.TestCase ):
self._write( 'update_services', edit_log )
with self.assertRaises( HydrusExceptions.DBException ):
self._read( 'service', other_new_tag_repo )
# update this ~sometime~ to test the new services manager object, which should update with these changes!
#

View File

@ -58,8 +58,8 @@ class TestHydrusDownloadingFunctions( unittest.TestCase ):
advanced_tag_options = {}
advanced_tag_options[ local ] = [ '', 'character' ]
advanced_tag_options[ remote ] = [ '', 'character' ]
advanced_tag_options[ local.GetServiceKey() ] = [ '', 'character' ]
advanced_tag_options[ remote.GetServiceKey() ] = [ '', 'character' ]
tags = [ 'a', 'character:b', 'series:c' ]

View File

@ -52,6 +52,11 @@ class App( wx.App ):
self._reads[ 'messaging_sessions' ] = []
self._reads[ 'tag_censorship' ] = []
self._reads[ 'options' ] = CC.CLIENT_DEFAULT_OPTIONS
services = []
services.append( CC.Service( HC.LOCAL_BOORU_SERVICE_KEY, HC.LOCAL_BOORU, 'local booru', {} ) )
self._reads[ 'services' ] = services
self._reads[ 'sessions' ] = []
self._reads[ 'tag_parents' ] = {}
self._reads[ 'tag_service_precedence' ] = []
@ -65,6 +70,8 @@ class App( wx.App ):
self._managers = {}
self._managers[ 'services' ] = CC.ServiceManager()
self._managers[ 'hydrus_sessions' ] = HydrusSessions.HydrusSessionManagerClient()
self._managers[ 'tag_censorship' ] = HydrusTags.TagCensorshipManager()
self._managers[ 'tag_siblings' ] = HydrusTags.TagSiblingsManager()