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"> <div class="content">
<h3>changelog</h3> <h3>changelog</h3>
<ul> <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> <li><h3>version 125</h3></li>
<ul> <ul>
<li>moved client splash screen and client boot to application event loop (i.e. your mouse won't hourglass over it now)</li> <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> <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> <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>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 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 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>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> <h3>backing up</h3>
<p>You <i>do</i> backup, right? <i>Right</i>?</p> <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> <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>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> <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> <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> <p class="right"><a href="getting_started_files.html">Let's import some files! ----></a></p>
</div> </div>
</body> </body>

View File

@ -5,13 +5,14 @@
<link href="style.css" rel="stylesheet" type="text/css" /> <link href="style.css" rel="stylesheet" type="text/css" />
</head> </head>
<body> <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="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="client_autism.png" title="an example search"><img src="client_autism_small.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="lib_gc.png" title="a well-tagged webcomic, sorted and viewed by chapter"><img src="lib_gc_small.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="client_fullscreen.png" title="reading the webcomic in fullscreen"><img src="client_fullscreen_small.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="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="screenshot_fullscreen_blame.png" title="fullscreen view is clean and fast"><img src="screenshot_fullscreen_blame_thumb.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="screenshot_video.png" title="many file formats are supported"><img src="screenshot_video_thumb.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_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> <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> <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> <ul>

View File

@ -8,23 +8,23 @@
<div class="content"> <div class="content">
<h3>on being anonymous</h3> <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>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>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 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>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>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> <p>I think we can do better.</p>
<h3>the hydrus network</h3> <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>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><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> <p>I'm working on adding peer-to-peer anonymous communication.</p>
<h3>statement of principles</h3> <h3>statement of principles</h3>
<ul class="bulletpoint"> <ul class="bulletpoint">
<li>No speech should be outlawed.</li> <li>No speech should be outlawed.</li>
<li>Everyone should be able to control their own media diet.</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> </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>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> <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[ '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[ 'default_tag_sort' ] = SORT_BY_LEXICOGRAPHIC_ASC
CLIENT_DEFAULT_OPTIONS[ 'pause_export_folders_sync' ] = False CLIENT_DEFAULT_OPTIONS[ 'pause_export_folders_sync' ] = False
@ -1160,7 +1160,7 @@ class LocalBooruCache( object ):
def _RefreshShares( self ): 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 = {} self._keys_to_infos = {}
@ -2293,6 +2293,8 @@ class Service( HC.HydrusYAMLBase ):
self._name = name self._name = name
self._info = info self._info = info
self._lock = threading.Lock()
HC.pubsub.sub( self, 'ProcessServiceUpdates', 'service_updates_data' ) HC.pubsub.sub( self, 'ProcessServiceUpdates', 'service_updates_data' )
@ -2565,29 +2567,14 @@ class ServiceManager( object ):
HC.pubsub.sub( self, 'RefreshServices', 'notify_new_services_data' ) 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 ): def GetService( self, service_key ):
with self._lock: return self._keys_to_services[ 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: with self._lock: return [ service for service in self._keys_to_services.values() if service.GetType() in types ]
service = self._keys_to_services[ service_key ]
return service.GetType()
def RefreshServices( self ): def RefreshServices( self ):

View File

@ -31,7 +31,7 @@ from twisted.internet import defer
ID_ANIMATED_EVENT_TIMER = wx.NewId() ID_ANIMATED_EVENT_TIMER = wx.NewId()
ID_MAINTENANCE_EVENT_TIMER = wx.NewId() ID_MAINTENANCE_EVENT_TIMER = wx.NewId()
MAINTENANCE_PERIOD = 12 * 60 MAINTENANCE_PERIOD = 5 * 60
class Controller( wx.App ): 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 ): 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 = {}
self._managers[ 'services' ] = CC.ServiceManager()
self._managers[ 'hydrus_sessions' ] = HydrusSessions.HydrusSessionManagerClient() self._managers[ 'hydrus_sessions' ] = HydrusSessions.HydrusSessionManagerClient()
self._managers[ 'local_booru' ] = CC.LocalBooruCache() self._managers[ 'local_booru' ] = CC.LocalBooruCache()
self._managers[ 'services' ] = CC.ServiceManager()
self._managers[ 'tag_censorship' ] = HydrusTags.TagCensorshipManager() self._managers[ 'tag_censorship' ] = HydrusTags.TagCensorshipManager()
self._managers[ 'tag_siblings' ] = HydrusTags.TagSiblingsManager() self._managers[ 'tag_siblings' ] = HydrusTags.TagSiblingsManager()
self._managers[ 'tag_parents' ] = HydrusTags.TagParentsManager() 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' ) 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() 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() else: return text.lower()
def Read( self, action, *args, **kwargs ): def Read( self, action, *args, **kwargs ): return self._Read( action, *args, **kwargs )
if action == 'media_results': self._timestamps[ 'last_user_db_use' ] = HC.GetNow()
return self._Read( action, *args, **kwargs )
def ReadDaemon( self, 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 return result
def ResetIdleTimer( self ): self._timestamps[ 'last_user_action' ] = HC.GetNow()
def RestartBooru( self ): 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() info = service.GetInfo()
@ -506,7 +504,7 @@ Once it is done, the client will restart.'''
try: 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 ) 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 ] 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 ) media_results.extend( more_media_results )
HC.pubsub.pub( 'set_num_query_results', len( media_results ), len( query_hash_ids ) ) 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 ) 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() self._timestamps[ 'last_check_idle_time' ] = HC.GetNow()
# this tests if we probably just woke up from a sleep # 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() 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 ) ) 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 ): def _AddService( self, c, service_key, service_type, name, info ):
service_key = service_identifier.GetServiceKey()
service_type = service_identifier.GetType()
name = service_identifier.GetName()
if service_type in HC.LOCAL_SERVICES: if service_type in HC.LOCAL_SERVICES:
@ -2497,10 +2493,6 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
service_type = service_identifier.GetType() service_type = service_identifier.GetType()
repository = self._GetService( c, service_id )
account = repository.GetInfo( 'account' )
if service_type == HC.TAG_REPOSITORY: if service_type == HC.TAG_REPOSITORY:
updates = [] updates = []
@ -2657,57 +2649,30 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
return reason_id 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 ): 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 return services
def _GetServiceId( self, c, parameter ): def _GetServiceId( self, c, parameter ):
if type( parameter ) in ( str, unicode ): if type( parameter ) == HC.ClientServiceIdentifier: service_key = parameter.GetServiceKey()
else: service_key = parameter
result = c.execute( 'SELECT service_id FROM services WHERE name = ?;', ( parameter, ) ).fetchone()
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' )
if result is None: raise Exception( 'Service id error in database' )
( service_id, ) = result
( 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
return service_id 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 _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 } 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 } 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() } 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: else:
if dump_type == YAML_DUMP_ID_LOCAL_BOORU: dump_name = dump_name.encode( 'hex' ) 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!' ) if result is None: raise Exception( dump_name + ' was not found!' )
else: else: ( result, ) = result
( result, ) = result
if dump_type == YAML_DUMP_ID_SUBSCRIPTION:
result[ 'advanced_tag_options' ] = dict( result[ 'advanced_tag_options' ] )
return result return result
@ -3827,14 +3776,12 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
def _ResetService( self, c, service_identifier ): def _ResetService( self, c, service_identifier ):
service_name = service_identifier.GetName() name = service_identifier.GetName()
service_type = service_identifier.GetType() service_type = service_identifier.GetType()
service_id = self._GetServiceId( c, service_identifier ) service_id = self._GetServiceId( c, service_identifier )
service = self._GetService( c, service_id ) ( info, ) = c.execute( 'SELECT info FROM services WHERE service_id = ?;', ( service_id, ) ).fetchone()
info = service.GetInfo()
c.execute( 'DELETE FROM services WHERE service_id = ?;', ( service_id, ) ) 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.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_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_pending' )
self.pub_after_commit( 'notify_new_services_data' ) self.pub_after_commit( 'notify_new_services_data' )
self.pub_after_commit( 'notify_new_services_gui' ) self.pub_after_commit( 'notify_new_services_gui' )
self.pub_after_commit( 'permissions_are_stale' ) self.pub_after_commit( 'permissions_are_stale' )
HC.ShowText( 'reset ' + service_name ) HC.ShowText( 'reset ' + name )
def _SetTagCensorship( self, c, info ): 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 ) ) 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 ) ) try: c.execute( 'INSERT INTO yaml_dumps ( dump_type, dump_name, dump ) VALUES ( ?, ?, ? );', ( dump_type, dump_name, data ) )
except: except:
@ -4290,11 +4237,10 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
server_admin_service_id = self._GetServiceId( c, server_admin_service_identifier ) 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_info[ 'host' ]
server_admin_port = server_admin_info[ 'port' ]
( host, server_admin_port ) = server_admin_credentials.GetAddress()
recalc_combined_mappings = False 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' ] ) 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, service_key, service_type, name, info )
self._AddService( c, client_service_identifier, info )
elif action == HC.DELETE: elif action == HC.DELETE:
@ -4406,7 +4350,11 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
( service_identifier, info ) = details ( 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: elif action == HC.DELETE:
@ -4570,10 +4518,10 @@ class DB( ServiceDB ):
raise raise
self._local_file_service_id = self._GetServiceId( c, HC.LOCAL_FILE_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_IDENTIFIER ) 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_IDENTIFIER ) 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_IDENTIFIER ) self._combined_tag_service_id = self._GetServiceId( c, HC.COMBINED_TAG_SERVICE_KEY )
options = self._GetOptions( c ) options = self._GetOptions( c )
@ -4820,9 +4768,12 @@ class DB( ServiceDB ):
for init_service_identifier in init_service_identifiers: 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 = {} 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() ) ) 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: 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 = {} info = {}
self._AddService( c, HC.LOCAL_BOORU_SERVICE_IDENTIFIER, 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 ) ) 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, ) ) c.execute( 'UPDATE version SET version = ?;', ( version + 1, ) )
HC.is_db_updated = True 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 == '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_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 == '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_identifiers': result = self._GetServiceIdentifiers( c, *args, **kwargs )
elif action == 'service_info': result = self._GetServiceInfo( c, *args, **kwargs ) elif action == 'service_info': result = self._GetServiceInfo( c, *args, **kwargs )
elif action == 'services': result = self._GetServices( 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 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 except: continue
HC.pubsub.pub( 'downloads_status', HC.ConvertIntToPrettyString( num_downloads ) + ' file downloads' ) HC.pubsub.pub( 'downloads_status', HC.ConvertIntToPrettyString( num_downloads ) + ' file downloads' )
@ -7611,7 +7593,7 @@ def DAEMONDownloadThumbnails():
if len( thumbnail_hashes_i_need ) > 0: 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 except: continue
if file_repository.CanDownload(): if file_repository.CanDownload():
@ -7711,7 +7693,7 @@ def DAEMONResizeThumbnails():
def DAEMONSynchroniseAccounts(): def DAEMONSynchroniseAccounts():
services = HC.app.ReadDaemon( 'services', HC.RESTRICTED_SERVICES ) services = HC.app.GetManager( 'services' ).GetServices( HC.RESTRICTED_SERVICES )
do_notify = False do_notify = False
@ -7771,7 +7753,7 @@ def DAEMONSynchroniseMessages():
service_type = service_identifier.GetType() 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 except: continue
if service.CanCheck(): if service.CanCheck():
@ -7794,7 +7776,7 @@ def DAEMONSynchroniseMessages():
HC.app.WriteSynchronous( 'contact_associated', service_identifier ) 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() contact = service.GetContact()
@ -7893,7 +7875,7 @@ def DAEMONSynchroniseMessages():
my_public_key = contact_from.GetPublicKey() my_public_key = contact_from.GetPublicKey()
my_contact_key = contact_from.GetContactKey() 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() from_connection = my_message_depot.GetConnection()
@ -7957,7 +7939,7 @@ def DAEMONSynchroniseRepositories():
service_type = service_identifier.GetType() service_type = service_identifier.GetType()
service_key = service_identifier.GetServiceKey() 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 except: continue
info = service.GetInfo() info = service.GetInfo()
@ -7966,19 +7948,34 @@ def DAEMONSynchroniseRepositories():
if service.CanDownloadUpdate(): 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 ) HC.pubsub.pub( 'message', message )
while service.CanDownloadUpdate(): 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' ]: while HC.options[ 'pause_repo_sync' ]:
message.SetInfo( 'text', 'Repository synchronisation paused' ) message.SetInfo( 'text', 'repository synchronisation paused' )
time.sleep( 5 ) 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: 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() now = HC.GetNow()
@ -8036,7 +8033,7 @@ def DAEMONSynchroniseRepositories():
time.sleep( 0.10 ) time.sleep( 0.10 )
try: service = HC.app.ReadDaemon( 'service', service_identifier ) try: service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
except: break except: break
@ -8045,19 +8042,34 @@ def DAEMONSynchroniseRepositories():
if service.CanProcessUpdate(): 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 ) HC.pubsub.pub( 'message', message )
while service.CanProcessUpdate(): 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' ]: while HC.options[ 'pause_repo_sync' ]:
message.SetInfo( 'text', 'Repository synchronisation paused' ) message.SetInfo( 'text', 'repository synchronisation paused' )
time.sleep( 5 ) 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: 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() now = HC.GetNow()
@ -8168,7 +8180,7 @@ def DAEMONSynchroniseRepositories():
time.sleep( 0.10 ) time.sleep( 0.10 )
try: service = HC.app.ReadDaemon( 'service', service_identifier ) try: service = HC.app.GetManager( 'services' ).GetService( service_identifier.GetServiceKey() )
except: break except: break
@ -8225,7 +8237,9 @@ def DAEMONSynchroniseSubscriptions():
try: 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 ) HC.pubsub.pub( 'message', message )
@ -8291,6 +8305,17 @@ def DAEMONSynchroniseSubscriptions():
while True: 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' ]: while HC.options[ 'pause_subs_sync' ]:
message.SetInfo( 'text', 'subscriptions paused' ) message.SetInfo( 'text', 'subscriptions paused' )
@ -8299,6 +8324,8 @@ def DAEMONSynchroniseSubscriptions():
if HC.shutdown: return if HC.shutdown: return
if message.IsClosed(): return
if HC.subs_changed: if HC.subs_changed:
message.Close() message.Close()
@ -8467,6 +8494,8 @@ def DAEMONSynchroniseSubscriptions():
message.SetInfo( 'hashes', successful_hashes ) message.SetInfo( 'hashes', successful_hashes )
message.SetInfo( 'mode', 'files' ) message.SetInfo( 'mode', 'files' )
job_key.SetPausable( False )
else: message.Close() else: message.Close()
last_checked = now last_checked = now
@ -8504,13 +8533,17 @@ def DAEMONSynchroniseSubscriptions():
def DAEMONUPnP(): 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() services = HC.app.GetManager( 'services' ).GetServices( ( HC.LOCAL_BOORU, ) )
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, ) )
for service in services: for service in services:

View File

@ -144,17 +144,17 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
try: 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 ) HC.pubsub.pub( 'message', message )
result = HC.app.Read( 'pending', service_identifier ) 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: if service_type == HC.FILE_REPOSITORY:
@ -172,7 +172,6 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
i = 1 i = 1
message.SetInfo( 'job_key', job_key )
message.SetInfo( 'range', gauge_range ) message.SetInfo( 'range', gauge_range )
message.SetInfo( 'value', i ) message.SetInfo( 'value', i )
message.SetInfo( 'text', 'connecting to repository' ) message.SetInfo( 'text', 'connecting to repository' )
@ -325,7 +324,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
subject_access_key = dlg.GetValue().decode( 'hex' ) 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' ) } ) 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 _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.' 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: with ClientGUIDialogs.DialogYesNo( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_YES: if dlg.ShowModal() == wx.ID_YES: HydrusThreading.CallToThread( 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!' )
def _AutoServerSetup( self ): def _AutoServerSetup( self ):
host = '127.0.0.1' def do_it():
port = HC.DEFAULT_SERVER_ADMIN_PORT
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.' 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: with ClientGUIDialogs.DialogYesNo( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_YES: if dlg.ShowModal() == wx.ID_YES: HydrusThreading.CallToThread( do_it )
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.' )
@ -521,7 +535,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
if dlg.ShowModal() == wx.ID_YES: 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' ) with wx.BusyCursor(): service.Request( HC.POST, 'backup' )
@ -611,7 +625,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
hash = dlg.GetValue().decode( 'hex' ) 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' ) } ) with wx.BusyCursor(): response = service.Request( HC.GET, 'ip', { 'hash' : hash.encode( 'hex' ) } )
@ -746,13 +760,13 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
def view(): 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 ) ] 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 ] 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 ) ] 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(): 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 ) ] 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 ) ] 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 ) ] 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: 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 ): 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: 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: 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' ) account = service.GetInfo( 'account' )
@ -1395,7 +1409,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
news = dlg.GetValue() 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 } ) 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 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 ) 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 ): 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' ) response = service.Request( HC.GET, 'stats' )
@ -2505,7 +2521,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
def _DisplayAccountInfo( self ): 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() service_type = self._service_identifier.GetType()
@ -2636,7 +2652,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
if service_type in HC.REPOSITORIES + HC.LOCAL_SERVICES: 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 ): 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] ( 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() info = self._service.GetInfo()
@ -2805,7 +2821,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
( name, text, timeout, ( num_hashes, hashes, share_key ) ) = shares[0] ( 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() info = self._service.GetInfo()

View File

@ -433,6 +433,19 @@ class Canvas( object ):
self.Bind( wx.EVT_PAINT, self.EventPaint ) 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 ): def _DrawBackgroundBitmap( self ):
( client_width, client_height ) = self.GetClientSize() ( 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 ] if service_identifier in self._service_identifiers_to_services: service = self._service_identifiers_to_services[ service_identifier ]
else: 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 self._service_identifiers_to_services[ service_identifier ] = service
@ -757,6 +770,8 @@ class Canvas( object ):
if media != self._current_media: if media != self._current_media:
HC.app.ResetIdleTimer()
with wx.FrozenWindow( self ): with wx.FrozenWindow( self ):
self._current_media = media 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 _ShowFirst( self ): self.SetMedia( self._GetFirst() )
def _ShowLast( self ): self.SetMedia( self._GetLast() ) def _ShowLast( self ): self.SetMedia( self._GetLast() )
@ -1459,6 +1498,7 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
if command == 'archive': self._Archive() if command == 'archive': self._Archive()
elif command == 'copy_files': elif command == 'copy_files':
with wx.BusyCursor(): HC.app.Write( 'copy_files', ( self._current_media.GetHash(), ) ) 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_local_url': self._CopyLocalUrlToClipboard()
elif command == 'copy_path': self._CopyPathToClipboard() elif command == 'copy_path': self._CopyPathToClipboard()
elif command == 'delete': self._Delete() elif command == 'delete': self._Delete()
@ -1481,6 +1521,7 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
elif command == 'pan_left': self._DoManualPan( -distance, 0 ) elif command == 'pan_left': self._DoManualPan( -distance, 0 )
elif command == 'pan_right': 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': self._StartSlideshow( data )
elif command == 'slideshow_pause_play': self._PausePlaySlideshow() elif command == 'slideshow_pause_play': self._PausePlaySlideshow()
elif command == 'zoom_in': self._ZoomIn() elif command == 'zoom_in': self._ZoomIn()
@ -1511,9 +1552,9 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
def EventShowMenu( self, event ): 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 i_can_post_ratings = len( local_ratings_services ) > 0
@ -1550,25 +1591,33 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
menu.AppendSeparator() 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() menu.AppendSeparator()
if self._current_media.HasInbox(): menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'archive' ), '&archive' ) 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' ) 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.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 = 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_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_path' ) , 'path' )
copy_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy_local_url' ) , 'local url' ) 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() 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', 80 ), 'william gibson' )
slideshow.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'slideshow' ), 'custom interval' ) 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' ) if self._timer_slideshow.IsRunning(): menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'slideshow_pause_play' ), 'stop slideshow' )
self._menu_open = True self._menu_open = True
@ -1838,6 +1887,7 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
if command == 'archive': self._Archive() if command == 'archive': self._Archive()
elif command == 'copy_files': elif command == 'copy_files':
with wx.BusyCursor(): HC.app.Write( 'copy_files', ( self._current_media.GetHash(), ) ) 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_local_url': self._CopyLocalUrlToClipboard()
elif command == 'copy_path': self._CopyPathToClipboard() elif command == 'copy_path': self._CopyPathToClipboard()
elif command == 'delete': self._Delete() elif command == 'delete': self._Delete()
@ -1851,6 +1901,7 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
elif command == 'inbox': self._Inbox() elif command == 'inbox': self._Inbox()
elif command == 'manage_ratings': self._ManageRatings() elif command == 'manage_ratings': self._ManageRatings()
elif command == 'manage_tags': self._ManageTags() elif command == 'manage_tags': self._ManageTags()
elif command == 'remove': self._Remove()
elif command == 'slideshow': self._StartSlideshow( data ) elif command == 'slideshow': self._StartSlideshow( data )
elif command == 'slideshow_pause_play': self._PausePlaySlideshow() elif command == 'slideshow_pause_play': self._PausePlaySlideshow()
elif command == 'zoom_in': self._ZoomIn() elif command == 'zoom_in': self._ZoomIn()
@ -1914,19 +1965,35 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
menu.AppendSeparator() 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.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' ) 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.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'delete', HC.LOCAL_FILE_SERVICE_IDENTIFIER ), '&delete' )
menu.AppendSeparator() menu.AppendSeparator()
share_menu = wx.Menu()
copy_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_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_path' ) , 'path' )
copy_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy_local_url' ) , 'local url' ) 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() menu.AppendSeparator()
@ -2578,7 +2645,7 @@ class RatingsFilterFrameLike( CanvasFullscreenMediaListFilter ):
CanvasFullscreenMediaListFilter.__init__( self, my_parent, page_key, HC.LOCAL_FILE_SERVICE_IDENTIFIER, [], media_results ) CanvasFullscreenMediaListFilter.__init__( self, my_parent, page_key, HC.LOCAL_FILE_SERVICE_IDENTIFIER, [], media_results )
self._rating_service_identifier = service_identifier 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 ) FullscreenPopoutFilterLike( self )
@ -2651,7 +2718,7 @@ class RatingsFilterFrameNumerical( ClientGUICommon.FrameThatResizes ):
if service_identifier.GetType() == HC.LOCAL_RATING_LIKE: self._score_gap = 1.0 if service_identifier.GetType() == HC.LOCAL_RATING_LIKE: self._score_gap = 1.0
else: 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() ( self._lower, self._upper ) = self._service.GetLowerUpper()

View File

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

View File

@ -63,7 +63,7 @@ def SelectServiceIdentifier( permission = None, service_types = HC.ALL_SERVICES,
if service_identifiers is None: 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 ) ] 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 ) 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' ) response = service.Request( HC.GET, 'account_types' )
@ -670,7 +670,7 @@ class DialogGenerateNewAccounts( Dialog ):
lifetime = self._lifetime.GetClientData( self._lifetime.GetSelection() ) 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: try:
@ -894,7 +894,7 @@ class DialogInputCustomFilterAction( Dialog ):
service_identifier = self._ratings_like_service_identifiers.GetClientData( selection ) 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 self._current_ratings_like_service = service
@ -918,7 +918,7 @@ class DialogInputCustomFilterAction( Dialog ):
service_identifier = self._ratings_numerical_service_identifiers.GetClientData( selection ) 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 self._current_ratings_numerical_service = service
@ -1535,8 +1535,8 @@ class DialogInputFileSystemPredicate( Dialog ):
def PopulateControls(): def PopulateControls():
self._local_numericals = HC.app.Read( 'services', ( HC.LOCAL_RATING_NUMERICAL, ) ) self._local_numericals = HC.app.GetManager( 'services' ).GetServices( ( HC.LOCAL_RATING_NUMERICAL, ) )
self._local_likes = HC.app.Read( 'services', ( HC.LOCAL_RATING_LIKE, ) ) 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 ) 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 ): 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() info = self._service.GetInfo()
@ -2125,7 +2125,7 @@ class DialogInputLocalBooruShare( Dialog ):
def EventCopyInternalShareURL( self, event ): 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() info = self._service.GetInfo()
@ -3550,7 +3550,7 @@ class DialogModifyAccounts( Dialog ):
Dialog.__init__( self, parent, 'modify account' ) 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 ) self._subject_identifiers = list( subject_identifiers )
InitialiseControls() InitialiseControls()
@ -3766,9 +3766,9 @@ class DialogPageChooser( Dialog ):
ArrangeControls() 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' ) self._InitButtons( 'home' )
@ -3975,7 +3975,7 @@ class DialogPathsToTagsRegex( Dialog ):
def PopulateControls(): def PopulateControls():
services = HC.app.Read( 'services', ( HC.TAG_REPOSITORY, ) ) services = HC.app.GetManager( 'services' ).GetServices( ( HC.TAG_REPOSITORY, ) )
for service in services: for service in services:
@ -3999,7 +3999,9 @@ class DialogPathsToTagsRegex( Dialog ):
self._tag_repositories.AddPage( page, name ) 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() ) self._tag_repositories.Select( default_tag_repository.GetName() )
@ -4890,6 +4892,8 @@ class DialogSelectYoutubeURL( Dialog ):
url_string = title + ' ' + resolution + ' ' + extension url_string = title + ' ' + resolution + ' ' + extension
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, url_string ) message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, url_string )
HydrusThreading.CallToThread( HydrusDownloading.THREADDownloadURL, message, url, url_string ) HydrusThreading.CallToThread( HydrusDownloading.THREADDownloadURL, message, url, url_string )

View File

@ -209,7 +209,7 @@ class DialogManageAccountTypes( ClientGUIDialogs.Dialog ):
def PopulateControls(): 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' ) response = service.Request( HC.GET, 'account_types' )
@ -383,7 +383,7 @@ class DialogManageAccountTypes( ClientGUIDialogs.Dialog ):
def EventOK( self, event ): 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 } ) 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 (desc)', CC.SORT_BY_INCIDENCE_DESC )
self._default_tag_sort.Append( 'incidence (asc)', CC.SORT_BY_INCIDENCE_ASC ) 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 ) 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_DESC: self._default_tag_sort.Select( 2 )
elif HC.options[ 'default_tag_sort' ] == CC.SORT_BY_INCIDENCE_ASC: self._default_tag_sort.Select( 3 ) 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' ] ) self._fullscreen_borderless.SetValue( HC.options[ 'fullscreen_borderless' ] )
@ -3644,7 +3646,7 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
HC.options[ 'shortcuts' ] = shortcuts 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() ) HC.options[ 'default_tag_sort' ] = self._default_tag_sort.GetClientData( self._default_tag_sort.GetSelection() )
new_local_port = self._local_port.GetValue() new_local_port = self._local_port.GetValue()
@ -3948,7 +3950,7 @@ class DialogManageRatings( ClientGUIDialogs.Dialog ):
wx.Panel.__init__( self, parent ) wx.Panel.__init__( self, parent )
self._service_identifier = service_identifier 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 self._media = media
@ -4290,7 +4292,7 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
self._service_identifier = service_identifier 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() InitialiseControls()
@ -4606,7 +4608,7 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
parent_listbook.AddPage( listbook, name ) 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: for service in services:
@ -5960,9 +5962,11 @@ class DialogManageTagCensorship( ClientGUIDialogs.Dialog ):
self._tag_services.AddPage( page, name ) 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(): def ArrangeControls():
@ -6130,7 +6134,7 @@ class DialogManageTagParents( ClientGUIDialogs.Dialog ):
def PopulateControls(): def PopulateControls():
services = HC.app.Read( 'services', ( HC.TAG_REPOSITORY, ) ) services = HC.app.GetManager( 'services' ).GetServices( ( HC.TAG_REPOSITORY, ) )
for service in services: for service in services:
@ -6154,9 +6158,11 @@ class DialogManageTagParents( ClientGUIDialogs.Dialog ):
self._tag_repositories.AddPage( page, name ) 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(): def ArrangeControls():
@ -6309,7 +6315,7 @@ class DialogManageTagParents( ClientGUIDialogs.Dialog ):
if self._service_identifier != HC.LOCAL_TAG_SERVICE_IDENTIFIER: 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' ) self._account = service.GetInfo( 'account' )
@ -6598,7 +6604,7 @@ class DialogManageTagSiblings( ClientGUIDialogs.Dialog ):
self._tag_repositories.AddPage( page, name ) 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: 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(): def ArrangeControls():
@ -6777,7 +6785,7 @@ class DialogManageTagSiblings( ClientGUIDialogs.Dialog ):
if self._service_identifier != HC.LOCAL_TAG_SERVICE_IDENTIFIER: 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' ) self._account = service.GetInfo( 'account' )
@ -7273,9 +7281,11 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
self._tag_repositories.AddPage( page_info, name ) 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(): def ArrangeControls():
@ -7449,7 +7459,7 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
if not self._i_am_local_tag_service: 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' ) self._account = service.GetInfo( 'account' )

View File

@ -639,10 +639,15 @@ class ManagementPanelDumper( ManagementPanel ):
advanced_tag_options = self._advanced_tag_options.GetInfo() 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() 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 ) current = tags_manager.GetCurrent( service_identifier )
pending = tags_manager.GetPending( 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 ) 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._can_ban = self._service.GetInfo( 'account' ).HasPermission( HC.MANAGE_USERS )
self._num_petitions = None 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, 'Collect', 'collect_media' )
HC.pubsub.sub( self, 'Sort', 'sort_media' ) HC.pubsub.sub( self, 'Sort', 'sort_media' )
HC.pubsub.sub( self, 'FileDumped', 'file_dumped' ) HC.pubsub.sub( self, 'FileDumped', 'file_dumped' )
HC.pubsub.sub( self, 'RemoveMedia', 'remove_media' )
self._PublishSelectionChange() 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 ): def SetFocussedMedia( self, page_key, media ):
if page_key == self._page_key: if page_key == self._page_key:
@ -1678,13 +1689,13 @@ class MediaPanelThumbnails( MediaPanel ):
multiple_selected = num_selected > 1 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 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 == 'read': status = 'read'
elif command == 'unread': status = 'sent' 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() connection = my_message_depot.GetConnection()
@ -1250,7 +1250,7 @@ class DraftPanel( wx.Panel ):
try: 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() connection = my_message_depot.GetConnection()

View File

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

View File

@ -56,7 +56,10 @@ def ConvertTagsToServiceIdentifiersToTags( tags, advanced_tag_options ):
siblings_manager = HC.app.GetManager( 'tag_siblings' ) siblings_manager = HC.app.GetManager( 'tag_siblings' )
parents_manager = HC.app.GetManager( 'tag_parents' ) 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: if len( namespaces ) > 0:
@ -1766,6 +1769,7 @@ def THREADDownloadURL( message, url, url_string ):
message.SetInfo( 'range', None ) message.SetInfo( 'range', None )
message.SetInfo( 'value', None ) message.SetInfo( 'value', None )
message.SetInfo( 'mode', 'gauge' ) message.SetInfo( 'mode', 'gauge' )
temp_path = HC.http.Request( HC.GET, url, response_to_path = True, report_hooks = [ hook ] ) temp_path = HC.http.Request( HC.GET, url, response_to_path = True, report_hooks = [ hook ] )
message.SetInfo( 'range', None ) message.SetInfo( 'range', None )

View File

@ -120,7 +120,7 @@ class HydrusSessionManagerClient( object ):
# session key expired or not found # 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 ) ( 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' ) 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' ] internal_port = options[ 'port' ]
upnp = options[ 'upnp' ] 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' ] internal_port = options[ 'port' ]
upnp = options[ 'upnp' ] 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 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 = self._read( 'services', ( HC.LOCAL_FILE, HC.LOCAL_TAG ) )
result_s_is = { service.GetServiceIdentifier() for service in result } 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 ) self.assertEqual( type( result ), dict )
@ -1055,18 +1047,7 @@ class TestClientDB( unittest.TestCase ):
self._write( 'update_services', edit_log ) self._write( 'update_services', edit_log )
with self.assertRaises( HydrusExceptions.DBException ): # update this ~sometime~ to test the new services manager object, which should update with these changes!
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 ) )
# #
@ -1076,10 +1057,7 @@ class TestClientDB( unittest.TestCase ):
self._write( 'update_services', edit_log ) self._write( 'update_services', edit_log )
with self.assertRaises( HydrusExceptions.DBException ): # update this ~sometime~ to test the new services manager object, which should update with these changes!
self._read( 'service', other_new_tag_repo )
# #

View File

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

View File

@ -52,6 +52,11 @@ class App( wx.App ):
self._reads[ 'messaging_sessions' ] = [] self._reads[ 'messaging_sessions' ] = []
self._reads[ 'tag_censorship' ] = [] self._reads[ 'tag_censorship' ] = []
self._reads[ 'options' ] = CC.CLIENT_DEFAULT_OPTIONS 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[ 'sessions' ] = []
self._reads[ 'tag_parents' ] = {} self._reads[ 'tag_parents' ] = {}
self._reads[ 'tag_service_precedence' ] = [] self._reads[ 'tag_service_precedence' ] = []
@ -65,6 +70,8 @@ class App( wx.App ):
self._managers = {} self._managers = {}
self._managers[ 'services' ] = CC.ServiceManager()
self._managers[ 'hydrus_sessions' ] = HydrusSessions.HydrusSessionManagerClient() self._managers[ 'hydrus_sessions' ] = HydrusSessions.HydrusSessionManagerClient()
self._managers[ 'tag_censorship' ] = HydrusTags.TagCensorshipManager() self._managers[ 'tag_censorship' ] = HydrusTags.TagCensorshipManager()
self._managers[ 'tag_siblings' ] = HydrusTags.TagSiblingsManager() self._managers[ 'tag_siblings' ] = HydrusTags.TagSiblingsManager()