Version 148

This commit is contained in:
Hydrus 2015-02-25 13:34:30 -06:00
parent 7507e55c2d
commit 231c5f8252
24 changed files with 565 additions and 582 deletions

View File

@ -8,6 +8,26 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 148</h3></li>
<ul>
<li>rewrote thumbnail canvas and scrolling code from a crashtastic monolithic bmp to a lighter, faster, and more flexible page buffer</li>
<li>all custom gui elements should be less flickery</li>
<li>the manage tags dialog will now grow significantly taller if its parent window is also tall</li>
<li>dialogs launched by the media viewer will initially position themselves according to that, rather than the main gui</li>
<li>dialogs launched by controls will initially position themselves according the control's toplevelwindow, as originally intended</li>
<li>thumbnail download (for file repositories) no longer happens silently in the background; it will now occur in the repository sync daemon, reporting its progress in the normal repo sync popup</li>
<li>missing thumbnails are now replaced with the hydrus psi symbol silently, with a simple statement written to the log</li>
<li>fixed a tiny typo in update error code that was reporting version wrong</li>
<li>fixed a typo bug in gettagarchivetags</li>
<li>fixed a typo that had broken namespace sorting</li>
<li>numerous other single-line miscellaneous bug fixes</li>
<li>fixed a bug with displaying media with size (0,0)</li>
<li>fixed a bug with zooming in flash files</li>
<li>improved some buggy tag selection logic that was sometimes desyncing indices between menu popup and selection</li>
<li>tags will now stay selected even through changes to the tags list</li>
<li>any attempt to close the autocomplete dropdown floating frame should now bump the close event up to the whole program</li>
<li>linux release now includes source code alongside executables</li>
</ul>
<li><h3>version 147</h3></li>
<ul>
<li>fixed a problem when trying to do a multi-release update that contained the v146 update</li>

View File

@ -2681,8 +2681,7 @@ class ThumbnailCache( object ):
except Exception as e:
HC.ShowText( path )
HC.ShowException( e )
print( 'Could not find the thumbnail for ' + hash.encode( 'hex' ) + '!' )
return self._special_thumbs[ 'hydrus' ]

View File

@ -247,7 +247,7 @@ class MessageDB( object ):
temp_path = HC.GetTempPath()
with open( temp_path, 'wb' ) as f: f.write( temp_path )
with open( temp_path, 'wb' ) as f: f.write( file )
try:
@ -3262,7 +3262,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
for ( archive_name, hta ) in self._tag_archives.items():
hash_type == hta.GetHashType()
hash_type = hta.GetHashType()
sha256_to_archive_hashes = {}
@ -3654,7 +3654,6 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
notify_new_pending = False
notify_new_parents = False
notify_new_siblings = False
notify_new_thumbnails = False
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
@ -3690,8 +3689,6 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
self._AddFile( service_id, hash_id, size, mime, timestamp, width, height, duration, num_frames, num_words )
notify_new_thumbnails = True
elif action == HC.CONTENT_UPDATE_PENDING:
hashes = row
@ -4114,7 +4111,6 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
self.pub_after_commit( 'notify_new_siblings' )
self.pub_after_commit( 'notify_new_parents' )
if notify_new_thumbnails: self.pub_after_commit( 'notify_new_thumbnails' )
self.pub_content_updates_after_commit( service_keys_to_content_updates )
@ -4898,7 +4894,7 @@ class DB( ServiceDB ):
self._c.execute( 'ROLLBACK' )
raise Exception( 'Updating the client db to version ' + HC.u( version ) + ' caused this error:' + os.linesep + traceback.format_exc() )
raise Exception( 'Updating the client db to version ' + HC.u( version + 1 ) + ' caused this error:' + os.linesep + traceback.format_exc() )
( version, ) = self._c.execute( 'SELECT version FROM version;' ).fetchone()
@ -6182,7 +6178,6 @@ class DB( ServiceDB ):
HydrusThreading.DAEMONWorker( 'CheckImportFolders', DAEMONCheckImportFolders, ( 'notify_restart_import_folders_daemon', 'notify_new_import_folders' ), period = 180 )
HydrusThreading.DAEMONWorker( 'CheckExportFolders', DAEMONCheckExportFolders, ( 'notify_restart_export_folders_daemon', 'notify_new_export_folders' ), period = 180 )
HydrusThreading.DAEMONWorker( 'DownloadFiles', DAEMONDownloadFiles, ( 'notify_new_downloads', 'notify_new_permissions' ) )
HydrusThreading.DAEMONWorker( 'DownloadThumbnails', DAEMONDownloadThumbnails, ( 'notify_new_permissions', 'notify_new_thumbnails' ) )
HydrusThreading.DAEMONWorker( 'ResizeThumbnails', DAEMONResizeThumbnails, period = 3600 * 24, init_wait = 600 )
HydrusThreading.DAEMONWorker( 'SynchroniseAccounts', DAEMONSynchroniseAccounts, ( 'permissions_are_stale', ) )
HydrusThreading.DAEMONWorker( 'SynchroniseRepositories', DAEMONSynchroniseRepositories, ( 'notify_restart_repo_sync_daemon', 'notify_new_permissions' ) )
@ -6475,62 +6470,6 @@ def DAEMONDownloadFiles():
if num_downloads == 0: HC.pubsub.pub( 'downloads_status', 'no file downloads' )
elif num_downloads > 0: HC.pubsub.pub( 'downloads_status', HC.ConvertIntToPrettyString( num_downloads ) + ' inactive file downloads' )
def DAEMONDownloadThumbnails():
services = HC.app.ReadDaemon( 'services', ( HC.FILE_REPOSITORY, ) )
thumbnail_hashes_i_have = CC.GetAllThumbnailHashes()
for service in services:
service_key = service.GetServiceKey()
thumbnail_hashes_i_should_have = HC.app.ReadDaemon( 'thumbnail_hashes_i_should_have', service_key )
thumbnail_hashes_i_need = list( thumbnail_hashes_i_should_have - thumbnail_hashes_i_have )
if len( thumbnail_hashes_i_need ) > 0:
try: file_repository = HC.app.GetManager( 'services' ).GetService( service_key )
except: continue
if file_repository.CanDownload():
try:
num_per_round = 50
for i in range( 0, len( thumbnail_hashes_i_need ), num_per_round ):
if HC.shutdown: return
thumbnails = []
for hash in thumbnail_hashes_i_need[ i : i + num_per_round ]:
request_args = { 'hash' : hash.encode( 'hex' ) }
thumbnail = file_repository.Request( HC.GET, 'thumbnail', request_args = request_args )
thumbnails.append( ( hash, thumbnail ) )
HC.app.WaitUntilGoodTimeToUseGUIThread()
HC.app.WriteSynchronous( 'thumbnails', thumbnails )
HC.pubsub.pub( 'add_thumbnail_count', service_key, len( thumbnails ) )
thumbnail_hashes_i_have.update( { hash for ( hash, thumbnail ) in thumbnails } )
time.sleep( 0.25 )
except: pass # if bad download, the repo gets dinged an error. no need to do anything here
def DAEMONFlushServiceUpdates( list_of_service_keys_to_service_updates ):
service_keys_to_service_updates = HC.MergeKeyToListDicts( list_of_service_keys_to_service_updates )
@ -7105,6 +7044,89 @@ def DAEMONSynchroniseRepositories():
job_key.DeleteVariable( 'popup_message_text_2' )
job_key.DeleteVariable( 'popup_message_gauge_2' )
if service_type == HC.FILE_REPOSITORY and service.CanDownload():
job_key.SetVariable( 'popup_message_text_1', 'reviewing existing thumbnails' )
thumbnail_hashes_i_have = CC.GetAllThumbnailHashes()
job_key.SetVariable( 'popup_message_text_1', 'reviewing service thumbnails' )
thumbnail_hashes_i_should_have = HC.app.ReadDaemon( 'thumbnail_hashes_i_should_have', service_key )
thumbnail_hashes_i_need = thumbnail_hashes_i_should_have.difference( thumbnail_hashes_i_have )
if len( thumbnail_hashes_i_need ) > 0:
while job_key.IsPaused() or job_key.IsCancelled() or HC.options[ 'pause_repo_sync' ] or HC.shutdown:
time.sleep( 0.1 )
if job_key.IsPaused(): job_key.SetVariable( 'popup_message_text_1', 'paused' )
if HC.options[ 'pause_repo_sync' ]: job_key.SetVariable( 'popup_message_text_1', 'repository synchronisation paused' )
if HC.shutdown: raise Exception( 'application shutting down!' )
if job_key.IsCancelled():
job_key.SetVariable( 'popup_message_text_1', 'cancelled' )
print( HC.ConvertJobKeyToString( job_key ) )
return
if HC.repos_changed:
job_key.SetVariable( 'popup_message_text_1', 'repositories were changed during processing; this job was abandoned' )
print( HC.ConvertJobKeyToString( job_key ) )
HC.pubsub.pub( 'notify_restart_repo_sync_daemon' )
return
def SaveThumbnails( batch_of_thumbnails ):
job_key.SetVariable( 'popup_message_text_1', 'saving thumbnails to database' )
HC.app.WriteSynchronous( 'thumbnails', batch_of_thumbnails )
HC.pubsub.pub( 'add_thumbnail_count', service_key, len( batch_of_thumbnails ) )
thumbnails = []
for ( i, hash ) in enumerate( thumbnail_hashes_i_need ):
job_key.SetVariable( 'popup_message_text_1', 'downloading thumbnail ' + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( thumbnail_hashes_i_need ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( thumbnail_hashes_i_need ) ) )
request_args = { 'hash' : hash.encode( 'hex' ) }
thumbnail = service.Request( HC.GET, 'thumbnail', request_args = request_args )
thumbnails.append( ( hash, thumbnail ) )
if i % 50 == 0:
SaveThumbnails( thumbnails )
thumbnails = []
HC.app.WaitUntilGoodTimeToUseGUIThread()
if len( thumbnails ) > 0: SaveThumbnails( thumbnails )
job_key.DeleteVariable( 'popup_message_gauge_1' )
job_key.SetVariable( 'popup_message_title', 'repository synchronisation - ' + name + ' - finished' )
updates_text = HC.ConvertIntToPrettyString( num_updates_downloaded ) + ' updates downloaded, ' + HC.ConvertIntToPrettyString( num_updates_processed ) + ' updates processed'

View File

@ -1925,7 +1925,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
def ImportFiles( self, paths ): self._ImportFiles( paths )
'''
def NewCompose( self, identity ):
draft_key = os.urandom( 32 )
@ -1941,7 +1941,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
FrameComposeMessage( empty_draft_message )
'''
def NewPageImportGallery( self, gallery_name, gallery_type ): self._NewPageImportGallery( gallery_name, gallery_type )
def NewPageImportHDD( self, paths_info, advanced_import_options = {}, paths_to_tags = {}, delete_after_success = False ):
@ -2126,7 +2126,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
for page in [ self._notebook.GetPage( i ) for i in range( self._notebook.GetPageCount() ) ]: page.TestAbleToClose()
'''
class FrameComposeMessage( ClientGUICommon.Frame ):
def __init__( self, empty_draft_message ):
@ -2158,7 +2158,7 @@ class FrameComposeMessage( ClientGUICommon.Frame ):
if draft_key == self._draft_panel.GetDraftKey(): self.Close()
'''
class FrameReviewServices( ClientGUICommon.Frame ):
def __init__( self ):
@ -2974,6 +2974,7 @@ class FrameSplash( ClientGUICommon.Frame ):
self.Bind( wx.EVT_MOTION, self.EventDrag )
self.Bind( wx.EVT_LEFT_DOWN, self.EventDragBegin )
self.Bind( wx.EVT_LEFT_UP, self.EventDragEnd )
self.Bind( wx.EVT_ERASE_BACKGROUND, self.EventEraseBackground )
if action == 'boot':
@ -3074,6 +3075,8 @@ class FrameSplash( ClientGUICommon.Frame ):
event.Skip()
def EventEraseBackground( self, event ): pass
def EventPaint( self, event ): wx.BufferedPaintDC( self, self._bmp )
def ExitApp( self ):

View File

@ -63,6 +63,8 @@ def CalculateCanvasZoom( media, ( canvas_width, canvas_height ) ):
( media_width, media_height ) = media.GetResolution()
if media_width == 0 or media_height == 0: return 1.0
if ShouldHaveAnimationBar( media ): canvas_height -= ANIMATED_SCANBAR_HEIGHT
if media.GetMime() in NON_LARGABLY_ZOOMABLE_MIMES: canvas_width -= 2
@ -143,6 +145,7 @@ class Animation( wx.Window ):
self.Bind( wx.EVT_TIMER, self.TIMEREventVideo, id = ID_TIMER_VIDEO )
self.Bind( wx.EVT_MOUSE_EVENTS, self.EventPropagateMouse )
self.Bind( wx.EVT_KEY_UP, self.EventPropagateKey )
self.Bind( wx.EVT_ERASE_BACKGROUND, self.EventEraseBackground )
self.EventResize( None )
@ -199,6 +202,8 @@ class Animation( wx.Window ):
def CurrentFrame( self ): return self._current_frame_index
def EventEraseBackground( self, event ): pass
def EventPaint( self, event ): wx.BufferedPaintDC( self, self._canvas_bmp )
def EventPropagateKey( self, event ):
@ -350,6 +355,7 @@ class AnimationBar( wx.Window ):
self.Bind( wx.EVT_TIMER, self.TIMEREventUpdate, id = ID_TIMER_ANIMATION_BAR_UPDATE )
self.Bind( wx.EVT_PAINT, self.EventPaint )
self.Bind( wx.EVT_SIZE, self.EventResize )
self.Bind( wx.EVT_ERASE_BACKGROUND, self.EventEraseBackground )
self._timer_update = wx.Timer( self, id = ID_TIMER_ANIMATION_BAR_UPDATE )
self._timer_update.Start( 100, wx.TIMER_CONTINUOUS )
@ -388,6 +394,8 @@ class AnimationBar( wx.Window ):
dc.DrawText( s, my_width - x - 3, 3 )
def EventEraseBackground( self, event ): pass
def EventMouse( self, event ):
CC.CAN_HIDE_MOUSE = False
@ -503,6 +511,7 @@ class Canvas( object ):
self.Bind( wx.EVT_SIZE, self.EventResize )
self.Bind( wx.EVT_PAINT, self.EventPaint )
self.Bind( wx.EVT_ERASE_BACKGROUND, self.EventEraseBackground )
def _CopyHashToClipboard( self ):
@ -659,6 +668,8 @@ class Canvas( object ):
# because of the event passing under mouse, we want to preserve whitespace around flash
( my_width, my_height ) = self.GetClientSize()
( new_media_width, new_media_height ) = CalculateMediaContainerSize( self._current_display_media, zoom )
if new_media_width >= my_width or new_media_height >= my_height: return
@ -749,7 +760,9 @@ class Canvas( object ):
def EventPaint( self, event ): wx.BufferedPaintDC( self, self._canvas_bmp, wx.BUFFER_VIRTUAL_AREA )
def EventEraseBackground( self, event ): pass
def EventPaint( self, event ): wx.BufferedPaintDC( self, self._canvas_bmp )
def EventResize( self, event ):
@ -3138,7 +3151,7 @@ class RatingsFilterFrameNumerical( ClientGUICommon.FrameThatResizes ):
def _Skip( self ):
if len( self._media_still_to_rate ) == 0: self.EventClose()
if len( self._media_still_to_rate ) == 0: self.EventClose( None )
else: self._ShowNewMedia()
@ -3821,6 +3834,7 @@ class EmbedButton( wx.Window ):
self.Bind( wx.EVT_PAINT, self.EventPaint )
self.Bind( wx.EVT_SIZE, self.EventResize )
self.Bind( wx.EVT_ERASE_BACKGROUND, self.EventEraseBackground )
def _Redraw( self ):
@ -3864,6 +3878,8 @@ class EmbedButton( wx.Window ):
dc.DrawPolygon( points )
def EventEraseBackground( self, event ): pass
def EventPaint( self, event ): wx.BufferedPaintDC( self, self._canvas_bmp )
def EventResize( self, event ):
@ -4014,6 +4030,7 @@ class StaticImage( wx.Window ):
self.Bind( wx.EVT_SIZE, self.EventResize )
self.Bind( wx.EVT_TIMER, self.TIMEREventRenderWait, id = ID_TIMER_RENDER_WAIT )
self.Bind( wx.EVT_MOUSE_EVENTS, self.EventPropagateMouse )
self.Bind( wx.EVT_ERASE_BACKGROUND, self.EventEraseBackground )
self.EventResize( None )
@ -4056,6 +4073,8 @@ class StaticImage( wx.Window ):
def EventEraseBackground( self, event ): pass
def EventPaint( self, event ): wx.BufferedPaintDC( self, self._canvas_bmp )
def EventPropagateMouse( self, event ):

View File

@ -140,6 +140,8 @@ class AutoCompleteDropdown( wx.Panel ):
self._dropdown_window.Show()
self._dropdown_window.Bind( wx.EVT_CLOSE, self.EventCloseDropdown )
self._dropdown_hidden = True
self._list_height = 250
@ -237,6 +239,11 @@ class AutoCompleteDropdown( wx.Panel ):
def _UpdateList( self ): pass
def EventCloseDropdown( self, event ):
HC.app.GetGUI().EventExit( event )
def EventKeyDown( self, event ):
if event.KeyCode in ( wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER ) and self._text_ctrl.GetValue() == '' and len( self._dropdown_list ) == 0: self._BroadcastChoice( None )
@ -997,11 +1004,14 @@ class BufferedWindow( wx.Window ):
self.Bind( wx.EVT_PAINT, self.EventPaint )
self.Bind( wx.EVT_SIZE, self.EventResize )
self.Bind( wx.EVT_ERASE_BACKGROUND, self.EventEraseBackground )
def GetDC( self ): return wx.BufferedDC( wx.ClientDC( self ), self._canvas_bmp )
def EventEraseBackground( self, event ): pass
def EventPaint( self, event ): wx.BufferedPaintDC( self, self._canvas_bmp )
def EventResize( self, event ):
@ -1773,6 +1783,7 @@ class ListBox( wx.ScrolledWindow ):
self._canvas_bmp = wx.EmptyBitmap( 0, 0, 24 )
self._current_selected_index = None
self._current_selected_term = None
dc = self._GetScrolledDC()
@ -1788,6 +1799,7 @@ class ListBox( wx.ScrolledWindow ):
self.Bind( wx.EVT_PAINT, self.EventPaint )
self.Bind( wx.EVT_SIZE, self.EventResize )
self.Bind( wx.EVT_ERASE_BACKGROUND, self.EventEraseBackground )
self.Bind( wx.EVT_LEFT_DOWN, self.EventMouseSelect )
self.Bind( wx.EVT_LEFT_DCLICK, self.EventDClick )
@ -1935,9 +1947,13 @@ class ListBox( wx.ScrolledWindow ):
self._current_selected_index = index
if old_index is not None: self._DrawText( old_index )
if self._current_selected_index is not None: self._DrawText( self._current_selected_index )
if self._current_selected_index is not None:
if self._current_selected_index is None: self._current_selected_term = None
else:
self._current_selected_term = self._strings_to_terms[ self._ordered_strings[ self._current_selected_index ] ]
self._DrawText( self._current_selected_index )
# scroll to index, if needed
@ -1971,8 +1987,24 @@ class ListBox( wx.ScrolledWindow ):
def _TextsHaveChanged( self ):
self._drawn_up_to = 0
self._current_selected_index = None
if self._current_selected_term is not None:
for ( s, term ) in self._strings_to_terms.items():
if term == self._current_selected_term:
self._current_selected_index = self._ordered_strings.index( s )
break
if self._current_selected_index is None: self._current_selected_term = None
total_height = self._text_y * len( self._ordered_strings )
( my_x, my_y ) = self._canvas_bmp.GetSize()
@ -1995,6 +2027,8 @@ class ListBox( wx.ScrolledWindow ):
def EventEraseBackground( self, event ): pass
def EventKeyDown( self, event ):
key_code = event.GetKeyCode()

View File

@ -99,7 +99,10 @@ class Dialog( wx.Dialog ):
if parent is not None and position == 'topleft':
( pos_x, pos_y ) = HC.app.GetGUI().GetPositionTuple()
if issubclass( type( parent ), wx.TopLevelWindow ): parent_tlp = parent
else: parent_tlp = parent.GetTopLevelParent()
( pos_x, pos_y ) = parent_tlp.GetPositionTuple()
pos = ( pos_x + 50, pos_y + 100 )

View File

@ -5968,7 +5968,7 @@ class DialogManageSubscriptions( ClientGUIDialogs.Dialog ):
panel = self._listbook.GetCurrentPage()
if sub_panel is not None:
if panel is not None:
( name, info ) = panel.GetSubscription()
@ -7690,7 +7690,9 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x + 200, 500 ) )
( parent_width, parent_height ) = parent.GetSize()
self.SetInitialSize( ( x + 200, max( 500, parent_height - 200 ) ) )
self._file_service_key = file_service_key

File diff suppressed because it is too large Load Diff

View File

@ -389,7 +389,7 @@ class ListeningMediaList( MediaList ):
if self._collect_by is not None:
keys_to_medias = self._CalculateCollectionKeysToMedias( collect_by, new_media )
keys_to_medias = self._CalculateCollectionKeysToMedias( self._collect_by, new_media )
new_media = []
@ -548,17 +548,6 @@ class MediaCollection( MediaList, Media ):
def GetHashes( self, discriminant = None, not_uploaded_to = None ):
if discriminant is not None:
if ( discriminant == CC.DISCRIMINANT_INBOX and not self._inbox ) or ( discriminant == CC.DISCRIMINANT_ARCHIVE and not self._archive ) or ( discriminant == CC.DISCRIMINANT_LOCAL and not self._locations_manager().HasLocal() ) or ( discriminant == CC.DISCRIMINANT_NOT_LOCAL and self._locations_manager().HasLocal() ): return set()
if not_uploaded_to is not None:
if not_uploaded_to in self._locations_manager.GetCurrentRemote(): return set()
return self._hashes
def GetLocationsManager( self ): return self._locations_manager
def GetMime( self ): return HC.APPLICATION_HYDRUS_CLIENT_COLLECTION

View File

@ -66,7 +66,7 @@ options = {}
# Misc
NETWORK_VERSION = 15
SOFTWARE_VERSION = 147
SOFTWARE_VERSION = 148
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
@ -2691,7 +2691,7 @@ class ServerToClientUpdate( HydrusYAMLBase ):
def GetHashes( self ): return set( hash_ids_to_hashes.values() )
def GetHashes( self ): return set( self._hash_ids_to_hashes.values() )
def GetTags( self ):

View File

@ -113,6 +113,8 @@ class Downloader( object ):
return HC.http.Request( HC.GET, url, request_headers = request_headers, report_hooks = report_hooks, response_to_path = response_to_path )
def _GetNextGalleryPageURL( self ): return ''
def _GetNextGalleryPageURLs( self ): return ( self._GetNextGalleryPageURL(), )
def AddReportHook( self, hook ): self._report_hooks.append( hook )
@ -1449,7 +1451,7 @@ class ImportController( object ):
with self._lock:
if s in self._pending_import_queue_jobs:
if job in self._pending_import_queue_jobs:
index = self._pending_import_queue_jobs.index( job )

View File

@ -88,7 +88,7 @@ def EfficientlyThumbnailPILImage( pil_image, ( target_x, target_y ) ):
def GenerateNumpyImage( path ):
numpy_image = cv2.imread( self._path, flags = -1 ) # flags = -1 loads alpha channel, if present
numpy_image = cv2.imread( path, flags = -1 ) # flags = -1 loads alpha channel, if present
( y, x, depth ) = numpy_image.shape

View File

@ -1,6 +1,7 @@
import HydrusConstants as HC
import HydrusExceptions
import httplib
import os
import threading
import time
import urllib
@ -51,7 +52,7 @@ def CheckHydrusVersion( service_key, service_type, response_headers ):
if network_version > HC.NETWORK_VERSION: message = 'Your client is out of date; please download the latest release.'
else: message = 'The server is out of date; please ask its admin to update to the latest release.'
raise HydrusExceptions.NetworkVersionException( 'Network version mismatch! The server\'s network version was ' + u( network_version ) + ', whereas your client\'s is ' + u( HC.NETWORK_VERSION ) + '! ' + message )
raise HydrusExceptions.NetworkVersionException( 'Network version mismatch! The server\'s network version was ' + HC.u( network_version ) + ', whereas your client\'s is ' + HC.u( HC.NETWORK_VERSION ) + '! ' + message )
def ConvertHydrusGETArgsToQuery( request_args ):
@ -325,7 +326,7 @@ class HTTPConnection( object ):
elif content_type in HC.mime_enum_lookup and HC.mime_enum_lookup[ content_type ] == HC.APPLICATION_YAML:
try: parsed_response = yaml.safe_load( data )
except Exception as e: raise HydrusExceptions.NetworkVersionException( 'Failed to parse a response object!' + os.linesep + u( e ) )
except Exception as e: raise HydrusExceptions.NetworkVersionException( 'Failed to parse a response object!' + os.linesep + HC.u( e ) )
elif content_type == 'text/html':

View File

@ -28,7 +28,7 @@ class HydrusMessagingSessionManagerServer( object ):
for ( service_key, session_tuples ) in existing_sessions:
self._service_keys_to_sessions[ service_key ] = { session_key : ( account, name, expires ) for ( session_Key, account, name, expires ) in session_tuples }
self._service_keys_to_sessions[ service_key ] = { session_key : ( account, name, expires ) for ( session_key, account, name, expires ) in session_tuples }
self._lock = threading.Lock()

View File

@ -324,7 +324,7 @@ class TagsManagerSimple( object ):
tags = [ tag for tag in combined if tag.startswith( namespace + ':' ) ]
if collapse: tags = list( siblings_manager.CollapseTags( tags ) )
if collapse_siblings: tags = list( siblings_manager.CollapseTags( tags ) )
tags = [ tag.split( ':', 1 )[1] for tag in tags ]

View File

@ -693,9 +693,9 @@ class GIFRenderer( object ):
if self._pil_image.palette == self._pil_global_palette: # for some reason, when pil falls back from local palette to global palette, a bunch of important variables reset!
pil_image.palette.dirty = self._pil_dirty
pil_image.palette.mode = self._pil_mode
pil_image.palette.rawmode = self._pil_rawmode
self._pil_image.palette.dirty = self._pil_dirty
self._pil_image.palette.mode = self._pil_mode
self._pil_image.palette.rawmode = self._pil_rawmode

View File

@ -957,7 +957,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
if len( mappings_dict ) > 0:
for ( tag_id, hash_ids ) in mappings_dict.items(): self._DeleteMappings( admin_account_id, tag_id, hash_ids, reason_id )
for ( tag_id, hash_ids ) in mappings_dict.items(): self._DeleteMappings( service_id, admin_account_id, tag_id, hash_ids, reason_id )
@ -1359,7 +1359,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
self._c.execute( 'DELETE FROM messaging_sessions WHERE ? > expiry;', ( now, ) )
existing_session_ids = HC.BuildKeyToListDict( [ ( service_id, ( session_key, account_id, identifier, name, expires ) ) for ( service_id, identifier, name, expires ) in self._c.execute( 'SELECT service_id, session_key, account_id, identifier, name, expiry FROM messaging_sessions;' ) ] )
existing_session_ids = HC.BuildKeyToListDict( [ ( service_id, ( session_key, account_id, identifier, name, expires ) ) for ( service_id, session_key, account_id, identifier, name, expires ) in self._c.execute( 'SELECT service_id, session_key, account_id, identifier, name, expiry FROM messaging_sessions;' ) ] )
existing_sessions = {}
@ -1594,13 +1594,15 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
reason_id = self._GetReasonId( reason )
if lifetime in request_args: lifetime = kwargs[ 'lifetime' ]
if 'lifetime' in kwargs: lifetime = kwargs[ 'lifetime' ]
else: lifetime = None
self._Ban( service_id, action, admin_account_id, subject_account_ids, reason_id, lifetime ) # fold ban and superban together, yo
else:
admin_account = self._GetAccount( admin_account_key )
admin_account.CheckPermission( HC.GENERAL_ADMIN ) # special case, don't let manage_users people do these:
if action == HC.CHANGE_ACCOUNT_TYPE:

View File

@ -6,6 +6,7 @@ import os
import random
import threading
import weakref
import wx
tinest_gif = '\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x00\xFF\x00\x2C\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x00\x3B'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB