Version 79

This commit is contained in:
Hydrus 2013-07-31 16:26:38 -05:00
parent 46cff89b35
commit ee159f8675
44 changed files with 7846 additions and 3566 deletions

View File

@ -21,7 +21,7 @@ from include import ClientController
initial_sys_stdout = sys.stdout
initial_sys_stderr = sys.stderr
with open( HC.LOGS_DIR + os.path.sep + 'client.log', 'a' ) as f:
with HC.o( HC.LOGS_DIR + os.path.sep + 'client.log', 'a' ) as f:
sys.stdout = f
sys.stderr = f

View File

@ -8,6 +8,52 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 79</h3></li>
<ul>
<li>popup messages will now report whenever a subscription or import folder successfully imports some files, with a button to show them in a new search</li>
<li>popup messages now wrap</li>
<li>slightly better error popup</li>
<li>many more errors reported through error popup</li>
<li>old logging system switched over to new messaging system</li>
<li>popup message manager will only show ten messages at once, now</li>
<li>selectfromlistofstrings now supports enter key to select</li>
<li>completely reworked how dialog cancel works; absolutely all dialogs should now close with escape key</li>
<li>reworked how a bunch of dialogs do ok</li>
<li>a huge amount of dialog refactoring</li>
<li>made ok button initial focus of all dialogs</li>
<li>couple of bugs in service options dialog fixed</li>
<li>rejiggered some button names and focus behaviour a bit more</li>
<li>some classname refactoring</li>
<li>muchly improved string->unicode handling</li>
<li>improved timestamp generation</li>
<li>fixed a clientserviceidentifier->text bug</li>
<li>reworked how namespace cache in tagsmanager object is calculated</li>
<li>improved instantiation of noneablespinctrls</li>
<li>fixed a bug in the thumbnails download daemon</li>
<li>changed the way daemons wait for the db, much to the better</li>
<li>moved daemons out of the db object</li>
<li>rejiggered writedaemon synchrony so exceptions work</li>
<li>fiddled around with some help links</li>
<li>default, non-maximised size of client is a little more comfortable</li>
<li>custom filter now has a popup that'll let you change the custom actions mid-filter</li>
<li>server now uses new synchronous logging system</li>
<li>fixed an options save bug for server</li>
<li>updated server diagram in help</li>
<li>added test for dialog selectfromlistofstrings</li>
<li>added test for dialogyesno</li>
<li>made a framework for testing that requires network stuff</li>
<li>made a newgrounds test</li>
<li>fixed newgrounds swf parsing</li>
<li>made a framework for testing that requires file reads and writes</li>
<li>fixed a graceful-exception bug in mime parsing</li>
<li>added test for synchronous import_folders</li>
<li>added test for delete import_folders</li>
<li>wrote a test for importfolders daemon</li>
<li>import folders no longer delete or reattempt failed imports; they'll just ignore them</li>
<li>import folders are deleted on update, since old objects are obselete</li>
<li>import folders won't try to do zips any more; they'll just ignore them</li>
<li>rejiggered how import folders does its path parsing to remove mime calc cpu usage</li>
</ul>
<li><h3>version 78</h3></li>
<ul>
<li>expanded parents testing with a namespace example</li>
@ -15,7 +61,7 @@
<li>refactored ManageDialogs to their own file</li>
<li>refactored Exceptions to their own file</li>
<li>improved my testing framework so it can do wx gui elements</li>
<li>added test for dialogchoosenewservicemethod, fixed a tuypo</li>
<li>added test for dialogchoosenewservicemethod, fixed a typo</li>
<li>added test for dialogfinishfiltering</li>
<li>added test for dialogfinishratingfiltering</li>
<li>those two finish filter dialogs are a little simpler, now</li>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 153 KiB

View File

@ -112,14 +112,6 @@ field_string_lookup[ FIELD_FILE ] = 'file'
field_string_lookup[ FIELD_THREAD_ID ] = 'thread id'
field_string_lookup[ FIELD_PASSWORD ] = 'password'
LOG_ERROR = 0
LOG_MESSAGE = 1
log_string_lookup = {}
log_string_lookup[ LOG_ERROR ] = 'error'
log_string_lookup[ LOG_MESSAGE ] = 'message'
RESTRICTION_MIN_RESOLUTION = 0
RESTRICTION_MAX_RESOLUTION = 1
RESTRICTION_MAX_FILE_SIZE = 2
@ -245,7 +237,7 @@ def GenerateDumpMultipartFormDataCTAndBody( fields ):
for ( name, type, value ) in fields:
if type in ( FIELD_TEXT, FIELD_COMMENT, FIELD_PASSWORD, FIELD_VERIFICATION_RECAPTCHA, FIELD_THREAD_ID ): m.field( name, str( value ) )
if type in ( FIELD_TEXT, FIELD_COMMENT, FIELD_PASSWORD, FIELD_VERIFICATION_RECAPTCHA, FIELD_THREAD_ID ): m.field( name, HC.u( value ) )
elif type == FIELD_CHECKBOX:
if value:
@ -269,7 +261,7 @@ def GenerateMultipartFormDataCTAndBodyFromDict( fields ):
m = multipart.Multipart()
for ( name, value ) in fields.items(): m.field( name, str( value ) )
for ( name, value ) in fields.items(): m.field( name, HC.u( value ) )
return m.get()
@ -292,6 +284,79 @@ def GetAllFileHashes():
return file_hashes
def GetAllPaths( raw_paths, quiet = False ):
file_paths = []
title = 'Parsing files and subdirectories'
if not quiet: progress = wx.ProgressDialog( title, u'Preparing', 1000, HC.app.GetTopWindow(), style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE | wx.PD_CAN_ABORT | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME )
try:
paths_to_process = raw_paths
total_paths_to_process = len( paths_to_process )
num_processed = 0
while len( paths_to_process ) > 0:
next_paths_to_process = []
for path in paths_to_process:
if not quiet:
# would rather use progress.SetRange( total_paths_to_process ) here, but for some reason wx python doesn't support it!
permill = int( 1000 * ( float( num_processed ) / float( total_paths_to_process ) ) )
( should_continue, skip ) = progress.Update( permill, 'Done ' + HC.u( num_processed ) + '/' + HC.u( total_paths_to_process ) )
if not should_continue:
progress.Destroy()
return []
if os.path.isdir( path ):
subpaths = [ path + os.path.sep + filename for filename in dircache.listdir( path ) ]
total_paths_to_process += len( subpaths )
next_paths_to_process.extend( subpaths )
else: file_paths.append( path )
num_processed += 1
paths_to_process = next_paths_to_process
except:
message = 'While parsing files, encountered this error:' + os.linesep + traceback.format_exc()
if not quiet:
wx.MessageBox( message )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, Exception( message ) ) )
print( message )
if not quiet: progress.Destroy()
gc.collect()
return file_paths
def GetAllThumbnailHashes():
thumbnail_hashes = set()
@ -387,74 +452,9 @@ def IntersectTags( tags_managers, service_identifier = HC.COMBINED_TAG_SERVICE_I
return ( current, deleted, pending, petitioned )
def ParseImportablePaths( raw_paths, include_subdirs = True, quiet = False ):
def ParseImportablePaths( raw_paths, quiet = False ):
file_paths = []
if include_subdirs: title = 'Parsing files and subdirectories'
else: title = 'Parsing files'
if not quiet: progress = wx.ProgressDialog( title, u'Preparing', 1000, HC.app.GetTopWindow(), style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE | wx.PD_CAN_ABORT | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME )
try:
paths_to_process = raw_paths
total_paths_to_process = len( paths_to_process )
num_processed = 0
while len( paths_to_process ) > 0:
next_paths_to_process = []
for path in paths_to_process:
if not quiet:
# would rather use progress.SetRange( total_paths_to_process ) here, but for some reason wx python doesn't support it!
permill = int( 1000 * ( float( num_processed ) / float( total_paths_to_process ) ) )
( should_continue, skip ) = progress.Update( permill, 'Done ' + str( num_processed ) + '/' + str( total_paths_to_process ) )
if not should_continue:
progress.Destroy()
return []
if os.path.isdir( path ):
if include_subdirs:
subpaths = [ path + os.path.sep + filename for filename in dircache.listdir( path ) ]
total_paths_to_process += len( subpaths )
next_paths_to_process.extend( subpaths )
else: file_paths.append( path )
num_processed += 1
paths_to_process = next_paths_to_process
except:
if not quiet: wx.MessageBox( traceback.format_exc() )
print( traceback.format_exc() )
if not quiet: progress.Destroy()
gc.collect()
file_paths = GetAllPaths( raw_paths, quiet )
good_paths_info = []
odd_paths = []
@ -469,7 +469,7 @@ def ParseImportablePaths( raw_paths, include_subdirs = True, quiet = False ):
if not quiet:
( should_continue, skip ) = progress.Update( i, 'Done ' + str( i ) + '/' + str( num_file_paths ) )
( should_continue, skip ) = progress.Update( i, 'Done ' + HC.u( i ) + '/' + HC.u( num_file_paths ) )
if not should_continue: break
@ -505,7 +505,7 @@ def ParseImportablePaths( raw_paths, include_subdirs = True, quiet = False ):
if os.path.exists( potential_key_path ):
with open( potential_key_path, 'rb' ) as f: key_text = f.read()
with HC.o( potential_key_path, 'rb' ) as f: key_text = f.read()
( aes_key, iv ) = HydrusEncryption.AESTextToKey( key_text )
@ -514,7 +514,9 @@ def ParseImportablePaths( raw_paths, include_subdirs = True, quiet = False ):
message = 'Tried to read a key, but did not understand it.'
if not quiet: wx.MessageBox( message )
if not quiet:
wx.MessageBox( message )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, Exception( message ) ) )
print( message )
@ -598,11 +600,17 @@ def ParseImportablePaths( raw_paths, include_subdirs = True, quiet = False ):
else:
print( odd_path + ' could not be imported because of this error:' )
print( unicode( e ) )
print( HC.u( e ) )
if not quiet: wx.MessageBox( str( len( odd_paths ) ) + ' files could not be added. Their paths and exact errors have been written to the log.' )
if not quiet:
message = HC.u( len( odd_paths ) ) + ' files could not be added. Their paths and exact errors have been written to the log.'
wx.MessageBox( message )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, Exception( message ) ) )
return good_paths_info
@ -936,7 +944,7 @@ class ConnectionToService():
( host, port ) = self._credentials.GetAddress()
self._connection = HC.AdvancedHTTPConnection( host = host, port = port, service_identifier = self._service_identifier, accept_cookies = True )
self._connection = HC.get_connection( host = host, port = port, service_identifier = self._service_identifier, accept_cookies = True )
self._connection.connect()
@ -1023,7 +1031,7 @@ class ConnectionToService():
request_args[ 'title' ] = request_args[ 'title' ].encode( 'hex' )
if len( request_args ) > 0: request_string += '?' + '&'.join( [ key + '=' + str( value ) for ( key, value ) in request_args.items() ] )
if len( request_args ) > 0: request_string += '?' + '&'.join( [ key + '=' + HC.u( value ) for ( key, value ) in request_args.items() ] )
body = None
@ -1044,7 +1052,7 @@ class ConnectionToService():
try: response = self._connection.request( request_type_string, request_string, headers = headers, body = body )
except HydrusExceptions.ForbiddenException as e:
if unicode( e ) == 'Session not found!':
if HC.u( e ) == 'Session not found!':
HC.app.DeleteSessionKey( self._service_identifier )
@ -1095,7 +1103,7 @@ class ConnectionToService():
if dlg.ShowModal() == wx.ID_OK:
with open( dlg.GetPath(), 'wb' ) as f: f.write( body )
with HC.o( dlg.GetPath(), 'wb' ) as f: f.write( body )
@ -1204,7 +1212,7 @@ class Credentials( HC.HydrusYAMLBase ):
def __ne__( self, other ): return self.__hash__() != other.__hash__()
def __repr__( self ): return 'Credentials: ' + str( ( self._host, self._port, self._access_key.encode( 'hex' ) ) )
def __repr__( self ): return 'Credentials: ' + HC.u( ( self._host, self._port, self._access_key.encode( 'hex' ) ) )
def GetAccessKey( self ): return self._access_key
@ -1216,7 +1224,7 @@ class Credentials( HC.HydrusYAMLBase ):
if self._access_key is not None: connection_string += self._access_key.encode( 'hex' ) + '@'
connection_string += self._host + ':' + str( self._port )
connection_string += self._host + ':' + HC.u( self._port )
return connection_string
@ -1544,7 +1552,7 @@ class FileSystemPredicates():
( operator, years, months, days, hours ) = info
timestamp = int( time.time() ) - ( ( ( ( ( ( ( years * 12 ) + months ) * 30 ) + days ) * 24 ) + hours ) * 3600 )
timestamp = HC.GetNow() - ( ( ( ( ( ( ( years * 12 ) + months ) * 30 ) + days ) * 24 ) + hours ) * 3600 )
# this is backwards because we are talking about age, not timestamp
@ -1957,15 +1965,12 @@ class Log():
self._entries = []
HC.pubsub.sub( self, 'AddMessage', 'log_message' )
HC.pubsub.sub( self, 'AddError', 'log_error' )
HC.pubsub.sub( self, 'AddMessage', 'message' )
def __iter__( self ): return self._entries.__iter__()
def AddError( self, source, message ): self._entries.append( ( LOG_ERROR, source, message, time.time() ) )
def AddMessage( self, source, message ): self._entries.append( ( LOG_MESSAGE, source, message, time.time() ) )
def AddMessage( self, message ): self._entries.append( ( message, HC.GetNow() ) )
class MediaResult():
@ -2018,9 +2023,7 @@ class MediaResult():
service_type = service_identifier.GetType()
if service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
try: tags_manager.ProcessContentUpdate( service_identifier, content_update )
except: print( traceback.format_exc() )
if service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ): tags_manager.ProcessContentUpdate( service_identifier, content_update )
elif service_type in ( HC.FILE_REPOSITORY, HC.LOCAL_FILE ):
if service_type == HC.LOCAL_FILE:
@ -2127,6 +2130,8 @@ class RenderedImageCache():
print( traceback.format_exc() )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, Exception( traceback.format_exc() ) ) )
raise
@ -2215,7 +2220,7 @@ class ServiceRemote( Service ):
def GetRecentErrorPending( self ): return HC.ConvertTimestampToPrettyPending( self._last_error + 600 )
def HasRecentError( self ): return self._last_error + 600 > int( time.time() )
def HasRecentError( self ): return self._last_error + 600 > HC.GetNow()
def SetCredentials( self, credentials ): self._credentials = credentials
@ -2229,7 +2234,7 @@ class ServiceRemote( Service ):
( action, row ) = service_update.ToTuple()
if action == HC.SERVICE_UPDATE_ERROR: self._last_error = int( time.time() )
if action == HC.SERVICE_UPDATE_ERROR: self._last_error = HC.GetNow()
elif action == HC.SERVICE_UPDATE_RESET:
self._service_identifier = row
@ -2266,8 +2271,8 @@ class ServiceRemoteRestricted( ServiceRemote ):
def HasRecentError( self ):
if self._account.HasPermission( HC.GENERAL_ADMIN ): return self._last_error + 600 > int( time.time() )
else: return self._last_error + 3600 * 4 > int( time.time() )
if self._account.HasPermission( HC.GENERAL_ADMIN ): return self._last_error + 600 > HC.GetNow()
else: return self._last_error + 3600 * 4 > HC.GetNow()
def IsInitialised( self ):
@ -2340,7 +2345,7 @@ class ServiceRemoteRestrictedRepository( ServiceRemoteRestricted ):
def HasUpdateDue( self ): return self._next_begin + HC.UPDATE_DURATION + 1800 < int( time.time() )
def HasUpdateDue( self ): return self._next_begin + HC.UPDATE_DURATION + 1800 < HC.GetNow()
def SetNextBegin( self, next_begin ):
@ -2444,7 +2449,7 @@ class ServiceRemoteRestrictedDepot( ServiceRemoteRestricted ):
def HasCheckDue( self ): return self._last_check + self._check_period + 5 < int( time.time() )
def HasCheckDue( self ): return self._last_check + self._check_period + 5 < HC.GetNow()
def ProcessServiceUpdates( self, service_identifiers_to_service_updates ):
@ -2521,7 +2526,7 @@ class ThumbnailCache():
for name in names:
with open( HC.STATIC_DIR + os.path.sep + name + '.png', 'rb' ) as f: file = f.read()
with HC.o( HC.STATIC_DIR + os.path.sep + name + '.png', 'rb' ) as f: file = f.read()
thumbnail = HydrusImageHandling.GenerateHydrusBitmapFromFile( HydrusImageHandling.GenerateThumbnailFileFromFile( file, self._options[ 'thumbnail_dimensions' ] ) )
@ -2816,7 +2821,7 @@ class WebSessionManagerClient():
def GetCookies( self, name ):
now = int( time.time() )
now = HC.GetNow()
with self._lock:
@ -2832,7 +2837,7 @@ class WebSessionManagerClient():
if name == 'hentai foundry':
connection = HC.AdvancedHTTPConnection( url = 'http://www.hentai-foundry.com', accept_cookies = True )
connection = HC.get_connection( url = 'http://www.hentai-foundry.com', accept_cookies = True )
# this establishes the php session cookie, the csrf cookie, and tells hf that we are 18 years of age
connection.request( 'GET', '/?enterAgree=1' )
@ -2850,7 +2855,7 @@ class WebSessionManagerClient():
raise Exception( 'You need to set up your pixiv credentials in services->manage pixiv account.' )
connection = HC.AdvancedHTTPConnection( url = 'http://www.pixiv.net', accept_cookies = True )
connection = HC.get_connection( url = 'http://www.pixiv.net', accept_cookies = True )
form_fields = {}

View File

@ -454,7 +454,7 @@ class MessageSystemPredicates():
days = int( days )
timestamp = int( time.time() ) - ( ( ( ( ( years * 12 ) + months ) * 30 ) + days ) * 86400 )
timestamp = HC.GetNow() - ( ( ( ( ( years * 12 ) + months ) * 30 ) + days ) * 86400 )
# this is backwards because we are talking about age, not timestamp

View File

@ -30,7 +30,7 @@ class Controller( wx.App ):
else: return self._db.Read( action, HC.HIGH_PRIORITY, *args, **kwargs )
def _Write( self, action, priority, *args, **kwargs ): self._db.Write( action, priority, *args, **kwargs )
def _Write( self, action, priority, synchronous, *args, **kwargs ): return self._db.Write( action, priority, synchronous, *args, **kwargs )
def ClearCaches( self ):
@ -93,12 +93,12 @@ class Controller( wx.App ):
def EventMaintenanceTimer( self, event ):
if int( time.time() ) - self._last_idle_time > 60 * 60: # a long time, so we probably just woke up from a sleep
if HC.GetNow() - self._last_idle_time > 60 * 60: # a long time, so we probably just woke up from a sleep
self._last_idle_time = int( time.time() )
self._last_idle_time = HC.GetNow()
if int( time.time() ) - self._last_idle_time > 20 * 60: # 20 mins since last user-initiated db request
if HC.GetNow() - self._last_idle_time > 20 * 60: # 20 mins since last user-initiated db request
self.MaintainDB()
@ -115,8 +115,10 @@ class Controller( wx.App ):
except TypeError: pass
except Exception as e:
print( type( e ) )
print( traceback.format_exc() )
message = type( e ).__name__ + os.linesep + traceback.format_exc()
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, Exception( message ) ) )
print( message )
pubsubs_queue.task_done()
@ -147,7 +149,7 @@ class Controller( wx.App ):
gc.collect()
now = int( time.time() )
now = HC.GetNow()
shutdown_timestamps = self.Read( 'shutdown_timestamps' )
@ -185,7 +187,7 @@ class Controller( wx.App ):
except HydrusExceptions.DBAccessException as e:
print( unicode( e ) )
print( HC.u( e ) )
message = 'This instance of the client had a problem connecting to the database, which probably means an old instance is still closing.'
message += os.linesep + os.linesep
@ -247,10 +249,8 @@ class Controller( wx.App ):
self._maintenance_event_timer.Start( 20 * 60000, wx.TIMER_CONTINUOUS )
except sqlite3.OperationalError as e:
print( traceback.format_exc() )
message = 'Database error!'
message += os.linesep + os.linesep
message += unicode( e )
message = 'Database error!' + os.linesep + os.linesep + traceback.format_exc()
print message
@ -284,12 +284,19 @@ class Controller( wx.App ):
def Read( self, action, *args, **kwargs ):
self._last_idle_time = int( time.time() )
self._last_idle_time = HC.GetNow()
return self._Read( action, *args, **kwargs )
def ReadDaemon( self, action, *args, **kwargs ): return self._Read( action, *args, **kwargs )
def ReadDaemon( self, action, *args, **kwargs ):
result = self._Read( action, *args, **kwargs )
time.sleep( 0.1 )
return result
def SetSplashText( self, text ):
@ -311,14 +318,21 @@ class Controller( wx.App ):
def Write( self, action, *args, **kwargs ):
self._last_idle_time = int( time.time() )
self._last_idle_time = HC.GetNow()
if False and action == 'content_updates': self._undo_manager.AddCommand( 'content_updates', *args, **kwargs )
self._Write( action, HC.HIGH_PRIORITY, *args, **kwargs )
return self._Write( action, HC.HIGH_PRIORITY, False, *args, **kwargs )
def WriteDaemon( self, action, *args, **kwargs ): self._Write( action, HC.LOW_PRIORITY, *args, **kwargs )
def WriteDaemon( self, action, *args, **kwargs ):
result = self._Write( action, HC.LOW_PRIORITY, True, *args, **kwargs )
time.sleep( 0.1 )
return result
def WriteLowPriority( self, action, *args, **kwargs ): self._Write( action, HC.LOW_PRIORITY, *args, **kwargs )
def WriteLowPriority( self, action, *args, **kwargs ): return self._Write( action, HC.LOW_PRIORITY, False, *args, **kwargs )

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -574,7 +574,14 @@ class CanvasFullscreenMediaList( ClientGUIMixins.ListeningMediaList, Canvas, Cli
siblings_manager = HC.app.GetTagSiblingsManager()
( creators, series, titles, volumes, chapters, pages ) = self._current_media.GetDisplayMedia().GetTagsManager().GetCSTVCP()
namespaces = self._current_media.GetDisplayMedia().GetTagsManager().GetCombinedNamespaces( ( 'creator', 'series', 'title', 'volume', 'chapter', 'page' ) )
creators = namespaces[ 'creator' ]
series = namespaces[ 'series' ]
titles = namespaces[ 'title' ]
volumes = namespaces[ 'volume' ]
chapters = namespaces[ 'chapter' ]
pages = namespaces[ 'page' ]
if len( creators ) > 0:
@ -612,9 +619,9 @@ class CanvasFullscreenMediaList( ClientGUIMixins.ListeningMediaList, Canvas, Cli
( volume, ) = volumes
collections_string_append = 'volume ' + str( volume )
collections_string_append = 'volume ' + HC.u( volume )
else: collections_string_append = 'volumes ' + str( min( volumes ) ) + '-' + str( max( volumes ) )
else: collections_string_append = 'volumes ' + HC.u( min( volumes ) ) + '-' + HC.u( max( volumes ) )
if len( collections_string ) > 0: collections_string += ' - ' + collections_string_append
else: collections_string = collections_string_append
@ -626,9 +633,9 @@ class CanvasFullscreenMediaList( ClientGUIMixins.ListeningMediaList, Canvas, Cli
( chapter, ) = chapters
collections_string_append = 'chapter ' + str( chapter )
collections_string_append = 'chapter ' + HC.u( chapter )
else: collections_string_append = 'chapters ' + str( min( chapters ) ) + '-' + str( max( chapters ) )
else: collections_string_append = 'chapters ' + HC.u( min( chapters ) ) + '-' + HC.u( max( chapters ) )
if len( collections_string ) > 0: collections_string += ' - ' + collections_string_append
else: collections_string = collections_string_append
@ -640,9 +647,9 @@ class CanvasFullscreenMediaList( ClientGUIMixins.ListeningMediaList, Canvas, Cli
( page, ) = pages
collections_string_append = 'page ' + str( page )
collections_string_append = 'page ' + HC.u( page )
else: collections_string_append = 'pages ' + str( min( pages ) ) + '-' + str( max( pages ) )
else: collections_string_append = 'pages ' + HC.u( min( pages ) ) + '-' + HC.u( max( pages ) )
if len( collections_string ) > 0: collections_string += ' - ' + collections_string_append
else: collections_string = collections_string_append
@ -1141,8 +1148,9 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
except Exception as e:
wx.MessageBox( unicode( e ) )
print( unicode( e ) )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
wx.MessageBox( HC.u( e ) )
print( HC.u( e ) )
@ -1274,6 +1282,8 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
self.SetMedia( self._GetFirst() )
FullscreenPopoutFilterCustom( self )
HC.pubsub.sub( self, 'AddMediaResult', 'add_media_result' )
@ -1317,6 +1327,14 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
def _Inbox( self ): HC.app.Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_INBOX, ( self._current_media.GetHash(), ) ) ] } )
def EventActions( self, event ):
with ClientGUIDialogs.DialogSetupCustomFilterActions( self ) as dlg:
if dlg.ShowModal() == wx.ID_OK: self._actions = dlg.GetActions()
def EventKeyDown( self, event ):
if self._ShouldSkipInputDueToFlash(): event.Skip()
@ -1471,8 +1489,9 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
except Exception as e:
wx.MessageBox( unicode( e ) )
print( unicode( e ) )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
wx.MessageBox( HC.u( e ) )
print( HC.u( e ) )
@ -1659,8 +1678,9 @@ class CanvasFullscreenMediaListFilter( CanvasFullscreenMediaList ):
self._kept = set()
self._deleted = set()
except:
except Exception as e:
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
wx.MessageBox( traceback.format_exc() )
print( traceback.format_exc() )
@ -1762,8 +1782,9 @@ class CanvasFullscreenMediaListFilter( CanvasFullscreenMediaList ):
except Exception as e:
wx.MessageBox( unicode( e ) )
print( unicode( e ) )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
wx.MessageBox( HC.u( e ) )
print( HC.u( e ) )
@ -1941,6 +1962,30 @@ class FullscreenPopout( wx.Frame ):
event.Skip()
class FullscreenPopoutFilterCustom( FullscreenPopout ):
def _InitialisePopoutWindow( self, sizer ):
window = wx.Window( self )
vbox = wx.BoxSizer( wx.VERTICAL )
parent = self.GetParent()
actions = wx.Button( window, label = 'actions' )
actions.Bind( wx.EVT_BUTTON, parent.EventActions )
done = wx.Button( window, label = 'done' )
done.Bind( wx.EVT_BUTTON, parent.EventClose )
vbox.AddF( actions, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( done, FLAGS_EXPAND_PERPENDICULAR )
window.SetSizer( vbox )
return window
class FullscreenPopoutFilterInbox( FullscreenPopout ):
def _InitialisePopoutWindow( self, sizer ):
@ -2213,8 +2258,9 @@ class RatingsFilterFrameLike( CanvasFullscreenMediaListFilter ):
self._kept = set()
self._deleted = set()
except:
except Exception as e:
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
wx.MessageBox( traceback.format_exc() )
print( traceback.format_exc() )
@ -2399,7 +2445,7 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
else: against_string += ' - like'
center_string = str( len( self._media_to_initial_scores_dict ) ) + ' files being rated. after ' + str( len( self._decision_log ) ) + ' decisions, ' + str( len( certain_ratings ) ) + ' are certain'
center_string = HC.u( len( self._media_to_initial_scores_dict ) ) + ' files being rated. after ' + HC.u( len( self._decision_log ) ) + ' decisions, ' + HC.u( len( certain_ratings ) ) + ' are certain'
elif service_type == HC.LOCAL_RATING_NUMERICAL:
@ -2433,7 +2479,7 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
against_string += ' - ' + HC.ConvertNumericalRatingToPrettyString( self._lower, self._upper, rating )
center_string = str( len( self._media_to_initial_scores_dict ) ) + ' files being rated. after ' + str( len( self._decision_log ) ) + ' decisions, ' + str( len( certain_ratings ) ) + ' are certain and ' + str( len( uncertain_ratings ) ) + ' are uncertain'
center_string = HC.u( len( self._media_to_initial_scores_dict ) ) + ' files being rated. after ' + HC.u( len( self._decision_log ) ) + ' decisions, ' + HC.u( len( certain_ratings ) ) + ' are certain and ' + HC.u( len( uncertain_ratings ) ) + ' are uncertain'
if self._unrated_is_on_the_left:
@ -2810,8 +2856,9 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
HC.app.Write( 'content_updates', { self._service_identifier : content_updates } )
except:
except Exception as e:
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
wx.MessageBox( traceback.format_exc() )
print( traceback.format_exc() )
@ -2852,8 +2899,9 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
except Exception as e:
wx.MessageBox( unicode( e ) )
print( unicode( e ) )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
wx.MessageBox( HC.u( e ) )
print( HC.u( e ) )
@ -3193,8 +3241,9 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
except Exception as e:
wx.MessageBox( unicode( e ) )
print( unicode( e ) )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
wx.MessageBox( HC.u( e ) )
print( HC.u( e ) )

View File

@ -50,7 +50,7 @@ class AnimatedStaticTextTimestamp( wx.StaticText ):
self._timestamp = timestamp
self._suffix = suffix
self._last_tick = int( time.time() )
self._last_tick = HC.GetNow()
wx.StaticText.__init__( self, parent, label = self._prefix + self._rendering_function( self._timestamp ) + self._suffix )
@ -61,7 +61,7 @@ class AnimatedStaticTextTimestamp( wx.StaticText ):
update = False
now = int( time.time() )
now = HC.GetNow()
difference = abs( now - self._timestamp )
@ -471,7 +471,7 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
except Exception as e:
wx.MessageBox( unicode( e ) )
wx.MessageBox( HC.u( e ) )
wx.MessageBox( traceback.format_exc() )
@ -1281,7 +1281,7 @@ class ListBook( wx.Panel ):
except Exception as e:
wx.MessageBox( unicode( e ) )
wx.MessageBox( HC.u( e ) )
wx.MessageBox( traceback.format_exc() )
@ -1658,7 +1658,7 @@ class ListBox( wx.ScrolledWindow ):
except Exception as e:
wx.MessageBox( unicode( e ) )
wx.MessageBox( HC.u( e ) )
wx.MessageBox( traceback.format_exc() )
@ -1853,7 +1853,7 @@ class ListBoxMessagesPredicates( ListBoxMessages ):
class NoneableSpinCtrl( wx.Panel ):
def __init__( self, parent, message, value, none_phrase = 'no limit', max = 1000000, multiplier = 1, num_dimensions = 1 ):
def __init__( self, parent, message, none_phrase = 'no limit', max = 1000000, multiplier = 1, num_dimensions = 1 ):
wx.Panel.__init__( self, parent )
@ -1863,36 +1863,12 @@ class NoneableSpinCtrl( wx.Panel ):
self._checkbox = wx.CheckBox( self, label = none_phrase )
self._checkbox.Bind( wx.EVT_CHECKBOX, self.EventCheckBox )
if value is None:
self._one = wx.SpinCtrl( self, initial = 0, max = max, size = ( 80, -1 ) )
self._one.Disable()
if num_dimensions == 2:
self._two = wx.SpinCtrl( self, initial = 0, max = max, size = ( 80, -1 ) )
self._two.Disable()
self._checkbox.SetValue( True )
else:
if num_dimensions == 2:
( value, value_2 ) = value
self._two = wx.SpinCtrl( self, max = max, size = ( 80, -1 ) )
self._two.SetValue( value_2 / multiplier )
self._one = wx.SpinCtrl( self, max = max, size = ( 80, -1 ) )
self._one.SetValue( value / multiplier )
self._checkbox.SetValue( False )
self._one = wx.SpinCtrl( self, max = max, size = ( 80, -1 ) )
if num_dimensions == 2: self._two = wx.SpinCtrl( self, initial = 0, max = max, size = ( 80, -1 ) )
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( wx.StaticText( self, label=message + ': ' ), FLAGS_MIXED )
hbox.AddF( self._one, FLAGS_MIXED )
@ -1944,16 +1920,17 @@ class NoneableSpinCtrl( wx.Panel ):
self._checkbox.SetValue( False )
self._one.Enable()
if self._num_dimensions == 2: self._two.Enable()
if self._num_dimensions == 2:
self._two.Enable()
( value, y ) = value
self._two.SetValue( y / self._multiplier )
self._one.Enable()
self._one.SetValue( value / self._multiplier )
@ -2026,16 +2003,17 @@ class PopupMessage( wx.Window ):
class PopupMessageError( PopupMessage ):
def __init__( self, parent, message_string ):
def __init__( self, parent, exception ):
PopupMessage.__init__( self, parent )
vbox = wx.BoxSizer( wx.VERTICAL )
error = wx.StaticText( self, label = 'error', style = wx.ALIGN_CENTER )
error = wx.StaticText( self, label = type( exception ).__name__, style = wx.ALIGN_CENTER )
error.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
text = wx.StaticText( self, label = message_string ) # make this multi-line. There's an easy way to do that, right? A func that takes a pixel width, I think
text = wx.StaticText( self, label = HC.u( exception ) )
text.Wrap( 380 )
text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
vbox.AddF( error, FLAGS_EXPAND_PERPENDICULAR )
@ -2054,7 +2032,8 @@ class PopupMessageFiles( PopupMessage ):
vbox = wx.BoxSizer( wx.VERTICAL )
text = wx.StaticText( self, label = message_string ) # make this multi-line. There's an easy way to do that, right? A func that takes a pixel width, I think
text = wx.StaticText( self, label = message_string )
text.Wrap( 380 )
text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
button = wx.Button( self, label = 'show files in new page' )
@ -2086,6 +2065,7 @@ class PopupMessageText( PopupMessage ):
vbox = wx.BoxSizer( wx.VERTICAL )
text = wx.StaticText( self, label = message_string ) # make this multi-line. There's an easy way to do that, right? A func that takes a pixel width, I think
text.Wrap( 380 )
text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
vbox.AddF( text, FLAGS_EXPAND_PERPENDICULAR )
@ -2101,10 +2081,13 @@ class PopupMessageManager( wx.Frame ):
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
self._max_messages_to_display = 10
vbox = wx.BoxSizer( wx.VERTICAL )
self.SetSizer( vbox )
self._pending_messages = []
self._message_windows = []
top_level_parent.Bind( wx.EVT_SIZE, self.EventMove )
@ -2115,7 +2098,23 @@ class PopupMessageManager( wx.Frame ):
HC.pubsub.sub( self, 'AddMessage', 'message' )
# maybe make a ding noise when a new message arrives
# on right mouse click, dismiss relevant message and refit
def _CheckPending( self ):
if len( self._pending_messages ) > 0 and len( self._message_windows ) < self._max_messages_to_display:
message = self._pending_messages.pop( 0 )
window = self._CreateMessageWindow( message )
self._message_windows.append( window )
vbox = self.GetSizer()
vbox.AddF( window, FLAGS_EXPAND_PERPENDICULAR )
self._SizeAndPositionAndShow()
def _CreateMessageWindow( self, message ):
@ -2135,11 +2134,11 @@ class PopupMessageManager( wx.Frame ):
exception = info
message_string = str( exception )
message_string = HC.u( exception )
print( 'error: ' + message_string )
window = PopupMessageError( self, message_string )
window = PopupMessageError( self, exception )
elif message_type == HC.MESSAGE_TYPE_FILES:
@ -2172,15 +2171,9 @@ class PopupMessageManager( wx.Frame ):
def AddMessage( self, message ):
window = self._CreateMessageWindow( message )
self._pending_messages.append( message )
self._message_windows.append( window )
vbox = self.GetSizer()
vbox.AddF( window, FLAGS_EXPAND_PERPENDICULAR )
self._SizeAndPositionAndShow()
self._CheckPending()
def Dismiss( self, window ):
@ -2195,6 +2188,8 @@ class PopupMessageManager( wx.Frame ):
self._SizeAndPositionAndShow()
self._CheckPending()
def EventMove( self, event ):
@ -2766,9 +2761,11 @@ class AdvancedImportOptions( AdvancedOptions ):
self._exclude_deleted = wx.CheckBox( panel )
self._min_size = NoneableSpinCtrl( panel, 'minimum size (KB): ', 5120, multiplier = 1024 )
self._min_size = NoneableSpinCtrl( panel, 'minimum size (KB): ', multiplier = 1024 )
self._min_size.SetValue( 5120 )
self._min_resolution = NoneableSpinCtrl( panel, 'minimum resolution: ', ( 50, 50 ), num_dimensions = 2 )
self._min_resolution = NoneableSpinCtrl( panel, 'minimum resolution: ', num_dimensions = 2 )
self._min_resolution.SetValue( ( 50, 50 ) )
hbox1 = wx.BoxSizer( wx.HORIZONTAL )
@ -3073,7 +3070,7 @@ class TagsBox( ListBox ):
except Exception as e:
wx.MessageBox( unicode( e ) )
wx.MessageBox( HC.u( e ) )
wx.MessageBox( traceback.format_exc() )

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -222,7 +222,7 @@ class CaptchaControl( wx.Panel ):
def EnableWithValues( self, challenge, bitmap, captcha_runs_out, entry, ready ):
if int( time.time() ) > captcha_runs_out: self.Enable()
if HC.GetNow() > captcha_runs_out: self.Enable()
else:
self._captcha_challenge = challenge
@ -249,7 +249,7 @@ class CaptchaControl( wx.Panel ):
try:
connection = HC.AdvancedHTTPConnection( scheme = 'http', host = 'www.google.com', port = 80 )
connection = HC.get_connection( scheme = 'http', host = 'www.google.com', port = 80 )
javascript_string = connection.request( 'GET', '/recaptcha/api/challenge?k=' + self._captcha_key )
@ -261,7 +261,7 @@ class CaptchaControl( wx.Panel ):
self._bitmap = HydrusImageHandling.GenerateHydrusBitmapFromFile( jpeg )
self._captcha_runs_out = int( time.time() ) + 5 * 60 - 15
self._captcha_runs_out = HC.GetNow() + 5 * 60 - 15
self._DrawMain()
self._DrawEntry( '' )
@ -277,7 +277,7 @@ class CaptchaControl( wx.Panel ):
def EventTimer( self, event ):
if int( time.time() ) > self._captcha_runs_out: self.Enable()
if HC.GetNow() > self._captcha_runs_out: self.Enable()
else: self._DrawMain()
@ -402,7 +402,7 @@ class ManagementPanelDumper( ManagementPanel ):
( self._4chan_token, pin, timeout ) = HC.app.Read( '4chan_pass' )
self._have_4chan_pass = timeout > int( time.time() )
self._have_4chan_pass = timeout > HC.GetNow()
self._imageboard = imageboard
@ -584,13 +584,13 @@ class ManagementPanelDumper( ManagementPanel ):
try:
connection = HC.AdvancedHTTPConnection( scheme = self._post_scheme, host = self._post_host, port = self._post_port )
connection = HC.get_connection( scheme = self._post_scheme, host = self._post_host, port = self._post_port )
data = connection.request( 'POST', self._post_request, headers = headers, body = body )
( status, phrase ) = ClientParsers.Parse4chanPostScreen( data )
except Exception as e: ( status, phrase ) = ( 'big error', unicode( e ) )
except Exception as e: ( status, phrase ) = ( 'big error', HC.u( e ) )
wx.CallAfter( self.CALLBACKDoneDump, media_to_dump, post_field_info, status, phrase )
@ -622,11 +622,11 @@ class ManagementPanelDumper( ManagementPanel ):
total_size = sum( [ m.GetSize() for m in self._media_list.GetSortedMedia() ] )
initial = 'Hydrus Network Client is starting a dump of ' + str( num_files ) + ' files, totalling ' + HC.ConvertIntToBytes( total_size ) + ':' + os.linesep + os.linesep
initial = 'Hydrus Network Client is starting a dump of ' + HC.u( num_files ) + ' files, totalling ' + HC.ConvertIntToBytes( total_size ) + ':' + os.linesep + os.linesep
else: initial = ''
initial += str( index + 1 ) + '/' + str( num_files )
initial += HC.u( index + 1 ) + '/' + HC.u( num_files )
advanced_tag_options = self._advanced_tag_options.GetInfo()
@ -674,7 +674,7 @@ class ManagementPanelDumper( ManagementPanel ):
index = self._media_list.GetMediaIndex( self._current_media )
self._post_info.SetLabel( str( index + 1 ) + '/' + str( num_files ) + ': ' + dump_status_string )
self._post_info.SetLabel( HC.u( index + 1 ) + '/' + HC.u( num_files ) + ': ' + dump_status_string )
for ( name, type, value ) in post_field_info:
@ -763,7 +763,7 @@ class ManagementPanelDumper( ManagementPanel ):
if self._current_media == media_to_dump: HC.pubsub.pub( 'set_focus', self._page_key, None )
self._next_dump_time = int( time.time() ) + self._flood_time
self._next_dump_time = HC.GetNow() + self._flood_time
self._num_dumped += 1
@ -776,7 +776,7 @@ class ManagementPanelDumper( ManagementPanel ):
dump_status_enum = CC.DUMPER_RECOVERABLE_ERROR
dump_status_string = 'captcha was incorrect'
self._next_dump_time = int( time.time() ) + 10
self._next_dump_time = HC.GetNow() + 10
new_post_field_info = []
@ -802,7 +802,7 @@ class ManagementPanelDumper( ManagementPanel ):
self._progress_info.SetLabel( 'Flood limit hit, retrying.' )
self._next_dump_time = int( time.time() ) + self._flood_time
self._next_dump_time = HC.GetNow() + self._flood_time
elif status == 'big error':
@ -833,7 +833,7 @@ class ManagementPanelDumper( ManagementPanel ):
if self._current_media == media_to_dump: HC.pubsub.pub( 'set_focus', self._page_key, None )
self._next_dump_time = int( time.time() ) + self._flood_time
self._next_dump_time = HC.GetNow() + self._flood_time
self._next_dump_index += 1
@ -846,7 +846,7 @@ class ManagementPanelDumper( ManagementPanel ):
if self._next_dump_index == len( self._media_list.GetSortedMedia() ):
self._progress_info.SetLabel( 'done - ' + str( self._num_dumped ) + ' dumped' )
self._progress_info.SetLabel( 'done - ' + HC.u( self._num_dumped ) + ' dumped' )
self._start_button.Disable()
@ -882,7 +882,7 @@ class ManagementPanelDumper( ManagementPanel ):
except Exception as e:
wx.MessageBox( unicode( e ) )
wx.MessageBox( HC.u( e ) )
@ -910,7 +910,7 @@ class ManagementPanelDumper( ManagementPanel ):
self._dumping = True
self._start_button.SetLabel( 'pause' )
if self._next_dump_time == 0: self._next_dump_time = int( time.time() ) + 5
if self._next_dump_time == 0: self._next_dump_time = HC.GetNow() + 5
# disable thread fields here
@ -931,7 +931,7 @@ class ManagementPanelDumper( ManagementPanel ):
if self._dumping:
time_left = self._next_dump_time - int( time.time() )
time_left = self._next_dump_time - HC.GetNow()
if time_left < 1:
@ -957,7 +957,7 @@ class ManagementPanelDumper( ManagementPanel ):
( challenge, bitmap, captcha_runs_out, entry, ready ) = value
if int( time.time() ) > captcha_runs_out or not ready:
if HC.GetNow() > captcha_runs_out or not ready:
wait = True
@ -1018,12 +1018,12 @@ class ManagementPanelDumper( ManagementPanel ):
threading.Thread( target = self._THREADDoDump, args = ( media_to_dump, post_field_info, headers, body ) ).start()
else: self._progress_info.SetLabel( 'dumping next file in ' + str( time_left ) + ' seconds' )
else: self._progress_info.SetLabel( 'dumping next file in ' + HC.u( time_left ) + ' seconds' )
else:
if self._num_dumped == 0: self._progress_info.SetLabel( 'will dump to ' + self._imageboard.GetName() )
else: self._progress_info.SetLabel( 'paused after ' + str( self._num_dumped ) + ' files dumped' )
else: self._progress_info.SetLabel( 'paused after ' + HC.u( self._num_dumped ) + ' files dumped' )
@ -1135,7 +1135,7 @@ class ManagementPanelImport( ManagementPanel ):
def _GetPreimportStatus( self ):
status = 'importing ' + str( self._import_queue_position + 1 ) + '/' + str( len( self._import_queue ) )
status = 'importing ' + HC.u( self._import_queue_position + 1 ) + '/' + HC.u( len( self._import_queue ) )
return status
@ -1146,10 +1146,10 @@ class ManagementPanelImport( ManagementPanel ):
strs = []
if self._successful > 0: strs.append( str( self._successful ) + ' successful' )
if self._failed > 0: strs.append( str( self._failed ) + ' failed' )
if self._deleted > 0: strs.append( str( self._deleted ) + ' already deleted' )
if self._redundant > 0: strs.append( str( self._redundant ) + ' already in db' )
if self._successful > 0: strs.append( HC.u( self._successful ) + ' successful' )
if self._failed > 0: strs.append( HC.u( self._failed ) + ' failed' )
if self._deleted > 0: strs.append( HC.u( self._deleted ) + ' already deleted' )
if self._redundant > 0: strs.append( HC.u( self._redundant ) + ' already in db' )
return strs
@ -1189,7 +1189,7 @@ class ManagementPanelImport( ManagementPanel ):
else:
self._currently_importing = False
self._import_current_info.SetLabel( unicode( exception ) )
self._import_current_info.SetLabel( HC.u( exception ) )
self._import_gauge.SetValue( self._import_queue_position + 1 )
self._import_queue_position += 1
@ -1292,9 +1292,13 @@ class ManagementPanelImport( ManagementPanel ):
if exception is None: self._timer_process_import_queue.Start( 10, wx.TIMER_ONE_SHOT )
else:
print( os.linesep + 'Had trouble importing ' + str( self._import_queue[ self._import_queue_position - 1 ] ) + ':' + os.linesep + unicode( exception ) )
message = os.linesep + 'Had trouble importing ' + HC.u( self._import_queue[ self._import_queue_position - 1 ] ) + ':' + os.linesep + HC.u( exception )
self._import_current_info.SetLabel( unicode( exception ) )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, Exception( message ) ) )
print( message )
self._import_current_info.SetLabel( HC.u( exception ) )
self._timer_process_import_queue.Start( 2000, wx.TIMER_ONE_SHOT )
@ -1357,7 +1361,7 @@ class ManagementPanelImportHDD( ManagementPanelImport ):
path = path_info
with open( path, 'rb' ) as f: file = f.read()
with HC.o( path, 'rb' ) as f: file = f.read()
elif path_type == 'zip':
@ -1374,13 +1378,14 @@ class ManagementPanelImportHDD( ManagementPanelImport ):
wx.CallAfter( self.CALLBACKImportArgs, file, self._advanced_import_options, service_identifiers_to_tags )
except Exception as e:
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
print( traceback.format_exc() )
wx.CallAfter( self.CALLBACKImportArgs, '', {}, {}, exception = e )
def _GetPreprocessStatus( self ):
status = 'reading ' + str( self._import_queue_position + 1 ) + '/' + str( len( self._import_queue ) )
status = 'reading ' + HC.u( self._import_queue_position + 1 ) + '/' + HC.u( len( self._import_queue ) )
return status
@ -1448,7 +1453,7 @@ class ManagementPanelImportWithQueue( ManagementPanelImport ):
def _GetPreprocessStatus( self ):
status = 'checking url status ' + str( self._import_queue_position + 1 ) + '/' + str( len( self._import_queue ) )
status = 'checking url status ' + HC.u( self._import_queue_position + 1 ) + '/' + HC.u( len( self._import_queue ) )
return status
@ -1709,7 +1714,7 @@ class ManagementPanelImportWithQueueAdvanced( ManagementPanelImportWithQueue ):
else:
HC.pubsub.pub( 'set_import_info', self._page_key, 'downloading ' + str( self._import_queue_position + 1 ) + '/' + str( len( self._import_queue ) ) )
HC.pubsub.pub( 'set_import_info', self._page_key, 'downloading ' + HC.u( self._import_queue_position + 1 ) + '/' + HC.u( len( self._import_queue ) ) )
if do_tags: ( file, tags ) = downloader.GetFileAndTags( *url_args )
else:
@ -1727,6 +1732,7 @@ class ManagementPanelImportWithQueueAdvanced( ManagementPanelImportWithQueue ):
except Exception as e:
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
print( traceback.format_exc() )
wx.CallAfter( self.CALLBACKImportArgs, self._page_key, '', {}, {}, exception = e )
@ -1752,7 +1758,7 @@ class ManagementPanelImportWithQueueAdvanced( ManagementPanelImportWithQueue ):
for downloader in downloaders:
HC.pubsub.pub( 'set_outer_queue_info', self._page_key, 'found ' + str( total_urls_found ) + ' urls' )
HC.pubsub.pub( 'set_outer_queue_info', self._page_key, 'found ' + HC.u( total_urls_found ) + ' urls' )
while self._pause_outer_queue: time.sleep( 1 )
@ -1779,8 +1785,9 @@ class ManagementPanelImportWithQueueAdvanced( ManagementPanelImportWithQueue ):
except HydrusExceptions.NotFoundException: pass
except Exception as e:
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
print( traceback.format_exc() )
HC.pubsub.pub( 'set_outer_queue_info', self._page_key, unicode( e ) )
HC.pubsub.pub( 'set_outer_queue_info', self._page_key, HC.u( e ) )
HC.pubsub.pub( 'done_adding_to_import_queue', self._page_key )
@ -2036,13 +2043,13 @@ class ManagementPanelImportWithQueueURL( ManagementPanelImportWithQueue ):
else:
HC.pubsub.pub( 'set_import_info', self._page_key, 'downloading ' + str( self._import_queue_position + 1 ) + '/' + str( len( self._import_queue ) ) )
HC.pubsub.pub( 'set_import_info', self._page_key, 'downloading ' + HC.u( self._import_queue_position + 1 ) + '/' + HC.u( len( self._import_queue ) ) )
parse_result = urlparse.urlparse( url )
( scheme, host, port ) = ( parse_result.scheme, parse_result.hostname, parse_result.port )
if ( scheme, host, port ) not in self._connections: self._connections[ ( scheme, host, port ) ] = HC.AdvancedHTTPConnection( scheme = scheme, host = host, port = port )
if ( scheme, host, port ) not in self._connections: self._connections[ ( scheme, host, port ) ] = HC.get_connection( scheme = scheme, host = host, port = port )
connection = self._connections[ ( scheme, host, port ) ]
@ -2056,6 +2063,7 @@ class ManagementPanelImportWithQueueURL( ManagementPanelImportWithQueue ):
except Exception as e:
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
print( traceback.format_exc() )
wx.CallAfter( self.CALLBACKImportArgs, '', {}, {}, exception = e )
@ -2076,7 +2084,7 @@ class ManagementPanelImportWithQueueURL( ManagementPanelImportWithQueue ):
HC.pubsub.pub( 'set_outer_queue_info', self._page_key, 'Connecting to address' )
try: connection = HC.AdvancedHTTPConnection( scheme = scheme, host = host, port = port )
try: connection = HC.get_connection( scheme = scheme, host = host, port = port )
except: raise Exception( 'Could not connect to server' )
try: html = connection.geturl( url )
@ -2089,7 +2097,7 @@ class ManagementPanelImportWithQueueURL( ManagementPanelImportWithQueue ):
wx.CallAfter( self.CALLBACKAddToImportQueue, urls )
except Exception as e: HC.pubsub.pub( 'set_outer_queue_info', self._page_key, unicode( e ) )
except Exception as e: HC.pubsub.pub( 'set_outer_queue_info', self._page_key, HC.u( e ) )
HC.pubsub.pub( 'done_adding_to_import_queue', self._page_key )
@ -2174,7 +2182,7 @@ class ManagementPanelImportThreadWatcher( ManagementPanelImport ):
try:
connection = HC.AdvancedHTTPConnection( url = url )
connection = HC.get_connection( url = url )
raw_json = connection.geturl( url )
@ -2182,7 +2190,7 @@ class ManagementPanelImportThreadWatcher( ManagementPanelImport ):
posts_list = json_dict[ 'posts' ]
image_infos = [ ( post[ 'md5' ].decode( 'base64' ), str( post[ 'tim' ] ), post[ 'ext' ], post[ 'filename' ] ) for post in posts_list if 'md5' in post ]
image_infos = [ ( post[ 'md5' ].decode( 'base64' ), HC.u( post[ 'tim' ] ), post[ 'ext' ], post[ 'filename' ] ) for post in posts_list if 'md5' in post ]
image_infos_i_can_add = [ image_info for image_info in image_infos if image_info not in self._image_infos_already_added ]
@ -2200,14 +2208,14 @@ class ManagementPanelImportThreadWatcher( ManagementPanelImport ):
except Exception as e:
HC.pubsub.pub( 'set_thread_info', self._page_key, unicode( e ) )
HC.pubsub.pub( 'set_thread_info', self._page_key, HC.u( e ) )
wx.CallAfter( self._thread_pause_button.Disable )
return
self._last_thread_check = int( time.time() )
self._last_thread_check = HC.GetNow()
self._currently_checking_thread = False
@ -2248,13 +2256,13 @@ class ManagementPanelImportThreadWatcher( ManagementPanelImport ):
else:
HC.pubsub.pub( 'set_import_info', self._page_key, 'downloading ' + str( self._import_queue_position + 1 ) + '/' + str( len( self._import_queue ) ) )
HC.pubsub.pub( 'set_import_info', self._page_key, 'downloading ' + HC.u( self._import_queue_position + 1 ) + '/' + HC.u( len( self._import_queue ) ) )
parse_result = urlparse.urlparse( url )
( scheme, host, port ) = ( parse_result.scheme, parse_result.hostname, parse_result.port )
if ( scheme, host, port ) not in self._connections: self._connections[ ( scheme, host, port ) ] = HC.AdvancedHTTPConnection( scheme = scheme, host = host, port = port )
if ( scheme, host, port ) not in self._connections: self._connections[ ( scheme, host, port ) ] = HC.get_connection( scheme = scheme, host = host, port = port )
connection = self._connections[ ( scheme, host, port ) ]
@ -2273,13 +2281,14 @@ class ManagementPanelImportThreadWatcher( ManagementPanelImport ):
except Exception as e:
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, e ) )
print( traceback.format_exc() )
wx.CallAfter( self.CALLBACKImportArgs, '', {}, {}, exception = e )
def _GetPreprocessStatus( self ):
status = 'checking url/hash status ' + str( self._import_queue_position + 1 ) + '/' + str( len( self._import_queue ) )
status = 'checking url/hash status ' + HC.u( self._import_queue_position + 1 ) + '/' + HC.u( len( self._import_queue ) )
return status
@ -2313,7 +2322,7 @@ class ManagementPanelImportThreadWatcher( ManagementPanelImport ):
except Exception as e:
self._thread_info.SetLabel( unicode( e ) )
self._thread_info.SetLabel( HC.u( e ) )
return
@ -2341,7 +2350,7 @@ class ManagementPanelImportThreadWatcher( ManagementPanelImport ):
next_thread_check = self._last_thread_check + thread_time
if next_thread_check < int( time.time() ):
if next_thread_check < HC.GetNow():
self._currently_checking_thread = True
@ -2572,7 +2581,7 @@ class ManagementPanelPetitions( ManagementPanel ):
if self._num_petitions > 0: self.EventGetPetition( event )
except Exception as e: self._num_petitions_text.SetLabel( unicode( e ) )
except Exception as e: self._num_petitions_text.SetLabel( HC.u( e ) )
def RefreshQuery( self, page_key ):

View File

@ -543,7 +543,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
if hashes is not None and len( hashes ) > 0:
try: HC.app.Write( 'content_updates', { file_service_identifier : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_RESCIND_PETITION, hashes ) ] } )
except Exception as e: wx.MessageBox( unicode( e ) )
except Exception as e: wx.MessageBox( HC.u( e ) )
@ -554,7 +554,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
if hashes is not None and len( hashes ) > 0:
try: HC.app.Write( 'content_updates', { file_service_identifier : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_RESCIND_PENDING, hashes ) ] } )
except Exception as e: wx.MessageBox( unicode( e ) )
except Exception as e: wx.MessageBox( HC.u( e ) )
@ -620,7 +620,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
if hashes is not None and len( hashes ) > 0:
try: HC.app.Write( 'content_updates', { file_service_identifier : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_PENDING, hashes ) ] } )
except Exception as e: wx.MessageBox( unicode( e ) )
except Exception as e: wx.MessageBox( HC.u( e ) )
@ -1192,7 +1192,7 @@ class MediaPanelThumbnails( MediaPanel ):
except Exception as e:
wx.MessageBox( unicode( e ) )
wx.MessageBox( HC.u( e ) )
@ -1864,7 +1864,14 @@ class Thumbnail( Selectable ):
local = self.GetFileServiceIdentifiersCDPP().HasLocal()
( creators, series, titles, volumes, chapters, pages ) = self.GetTagsManager().GetCSTVCP()
namespaces = self.GetTagsManager().GetCombinedNamespaces( ( 'creator', 'series', 'title', 'volume', 'chapter', 'page' ) )
creators = namespaces[ 'creator' ]
series = namespaces[ 'series' ]
titles = namespaces[ 'title' ]
volumes = namespaces[ 'volume' ]
chapters = namespaces[ 'chapter' ]
pages = namespaces[ 'page' ]
if self._hydrus_bmp is None: self._LoadFromDB()
@ -1907,9 +1914,9 @@ class Thumbnail( Selectable ):
( volume, ) = volumes
collections_string = 'v' + str( volume )
collections_string = 'v' + HC.u( volume )
else: collections_string = 'v' + str( min( volumes ) ) + '-' + str( max( volumes ) )
else: collections_string = 'v' + HC.u( min( volumes ) ) + '-' + HC.u( max( volumes ) )
if len( chapters ) > 0:
@ -1918,9 +1925,9 @@ class Thumbnail( Selectable ):
( chapter, ) = chapters
collections_string_append = 'c' + str( chapter )
collections_string_append = 'c' + HC.u( chapter )
else: collections_string_append = 'c' + str( min( chapters ) ) + '-' + str( max( chapters ) )
else: collections_string_append = 'c' + HC.u( min( chapters ) ) + '-' + HC.u( max( chapters ) )
if len( collections_string ) > 0: collections_string += '-' + collections_string_append
else: collections_string = collections_string_append
@ -1932,9 +1939,9 @@ class Thumbnail( Selectable ):
( page, ) = pages
collections_string_append = 'p' + str( page )
collections_string_append = 'p' + HC.u( page )
else: collections_string_append = 'p' + str( min( pages ) ) + '-' + str( max( pages ) )
else: collections_string_append = 'p' + HC.u( min( pages ) ) + '-' + HC.u( max( pages ) )
if len( collections_string ) > 0: collections_string += '-' + collections_string_append
else: collections_string = collections_string_append
@ -2032,7 +2039,7 @@ class Thumbnail( Selectable ):
dc.DrawBitmap( CC.GlobalBMPs.collection_bmp, 1, height - 17 )
num_files_str = str( len( self._hashes ) )
num_files_str = HC.u( len( self._hashes ) )
dc.SetFont( wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT ) )

View File

@ -114,7 +114,7 @@ class ConversationsListCtrl( wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMi
def _GetPrettyStatus( self ):
if len( self._conversations ) == 1: return '1 conversation'
else: return str( len( self._conversations ) ) + ' conversations'
else: return HC.u( len( self._conversations ) ) + ' conversations'
def _SetConversations( self, conversations ):
@ -147,7 +147,7 @@ class ConversationsListCtrl( wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMi
updated_string = HC.ConvertTimestampToHumanPrettyTime( updated )
self.Append( ( '', subject, name_from, ', '.join( [ contact.GetName() for contact in participants if contact.GetName() != name_from ] ), str( message_count ), str( unread_count ), created_string, updated_string ) )
self.Append( ( '', subject, name_from, ', '.join( [ contact.GetName() for contact in participants if contact.GetName() != name_from ] ), HC.u( message_count ), HC.u( unread_count ), created_string, updated_string ) )
data_index = i
@ -186,8 +186,8 @@ class ConversationsListCtrl( wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMi
if inbox: self.SetItemImage( selection, 1 )
else: self.SetItemImage( selection, 0 )
self.SetStringItem( selection, 4, str( message_count ) )
self.SetStringItem( selection, 5, str( unread_count ) )
self.SetStringItem( selection, 4, HC.u( message_count ) )
self.SetStringItem( selection, 5, HC.u( unread_count ) )
if created is None:
@ -265,7 +265,7 @@ class ConversationsListCtrl( wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMi
except Exception as e:
wx.MessageBox( unicode( e ) )
wx.MessageBox( HC.u( e ) )
wx.MessageBox( traceback.format_exc() )
@ -662,7 +662,7 @@ class DestinationPanel( wx.Panel ):
wx.MessageBox( 'Could not contact your message depot, so could not update status!' )
wx.MessageBox( unicode( e ) )
wx.MessageBox( HC.u( e ) )
wx.MessageBox( traceback.format_exc() )
@ -1300,7 +1300,10 @@ class DraftPanel( wx.Panel ):
except:
wx.MessageBox( 'The hydrus client could not connect to your message depot, so the message could not be sent!' )
message = 'The hydrus client could not connect to your message depot, so the message could not be sent!'
wx.MessageBox( message )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, Exception( message ) ) )
print( traceback.format_exc() )
return

View File

@ -87,9 +87,9 @@ class PageLog( PageBase, wx.Panel ):
log = HC.app.GetLog()
self._log_list_ctrl = ClientGUICommon.SaneListCtrl( self, 480, [ ( 'type', 60 ), ( 'source', 180 ), ( 'message', -1 ), ( 'time', 120 ) ] )
self._log_list_ctrl = ClientGUICommon.SaneListCtrl( self, 480, [ ( 'type', 60 ), ( 'message', -1 ), ( 'time', 120 ) ] )
for ( type, source, message, time ) in log: self._AddEntry( type, source, message, time )
for ( message, timestamp ) in log: self.AddMessage( message, timestamp )
vbox = wx.BoxSizer( wx.VERTICAL )
@ -97,24 +97,40 @@ class PageLog( PageBase, wx.Panel ):
self.SetSizer( vbox )
HC.pubsub.sub( self, 'AddError', 'log_error' )
HC.pubsub.sub( self, 'AddMessage', 'log_message' )
HC.pubsub.sub( self, 'AddMessage', 'message' )
def _AddEntry( self, type, source, message, time ): self._log_list_ctrl.Append( ( CC.log_string_lookup[ type ], source, message, HC.ConvertTimestampToPrettyTime( time ) ), ( CC.log_string_lookup[ type ], source, message, time ) )
def _AddEntry( self, message_type_string, message_string, timestamp ): self._log_list_ctrl.Append( ( message_type_string, message_string, HC.ConvertTimestampToPrettyTime( timestamp ) ), ( message_type_string, message_string, timestamp ) )
def AddError( self, source, message ):
def AddMessage( self, message, timestamp = None ):
# assuming we want to show errors right now
if timestamp is None: timestamp = HC.GetNow()
self._AddEntry( CC.LOG_ERROR, source, message, time.time() )
message_type = message.GetType()
info = message.GetInfo()
def AddMessage( self, source, message ):
if message_type == HC.MESSAGE_TYPE_TEXT:
message_type_string = 'message'
message_string = info
elif message_type == HC.MESSAGE_TYPE_ERROR:
message_type_string = 'error'
exception = info
message_string = HC.u( exception )
elif message_type == HC.MESSAGE_TYPE_FILES:
message_type_string = 'files'
( message_string, hashes ) = info
# assuming we want to show messages right now
self._AddEntry( CC.LOG_MESSAGE, source, message, time.time() )
self._AddEntry( message_type_string, message_string, timestamp )
class PageMessages( PageBase, wx.SplitterWindow ):

View File

@ -14,7 +14,11 @@ def Parse4chanPostScreen( html ):
print( soup )
return ( 'big error', 'you are banned from this board! html written to log' )
message = 'You are banned from this board! html written to log.'
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, Exception( error ) ) )
return ( 'big error', message )
else:
@ -27,10 +31,14 @@ def Parse4chanPostScreen( html ):
try: print( soup )
except: pass
return ( 'error', 'unknown problem, writing 4chan html to log' )
message = 'Unknown problem; writing 4chan html to log.'
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, Exception( message ) ) )
return ( 'error', message )
problem = str( problem_tag )
problem = HC.u( problem_tag )
if 'CAPTCHA' in problem: return ( 'captcha', None )
elif 'seconds' in problem: return ( 'too quick', None )

View File

@ -16,7 +16,7 @@ def GetFLACDuration( file ):
path = HC.TEMP_DIR + os.path.sep + 'flac_parse.flac'
with open( path, 'wb' ) as f: f.write( file )
with HC.o( path, 'wb' ) as f: f.write( file )
try: flac_object = mutagen.flac.FLAC( path )
except: raise Exception( 'Could not parse the ogg!' )
@ -35,7 +35,7 @@ def GetMP3Duration( file ):
path = HC.TEMP_DIR + os.path.sep + 'mp3_parse.mp3'
with open( path, 'wb' ) as f: f.write( file )
with HC.o( path, 'wb' ) as f: f.write( file )
try: mp3_object = mutagen.mp3.MP3( path )
except: raise Exception( 'Could not parse the mp3!' )
@ -54,7 +54,7 @@ def GetOGGVorbisDuration( file ):
path = HC.TEMP_DIR + os.path.sep + 'oggvorbis_parse.ogg'
with open( path, 'wb' ) as f: f.write( file )
with HC.o( path, 'wb' ) as f: f.write( file )
try: ogg_object = mutagen.oggvorbis.OggVorbis( path )
except: raise Exception( 'Could not parse the ogg!' )

View File

@ -17,6 +17,12 @@ import urlparse
import wx
import yaml
# open
o = open
# dirs
BASE_DIR = sys.path[0]
DB_DIR = BASE_DIR + os.path.sep + 'db'
@ -33,7 +39,7 @@ TEMP_DIR = BASE_DIR + os.path.sep + 'temp'
# Misc
NETWORK_VERSION = 10
SOFTWARE_VERSION = 78
SOFTWARE_VERSION = 79
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
@ -548,7 +554,7 @@ def CleanTag( tag ):
tag = tag.lower()
tag = unicode( tag )
tag = u( tag )
tag = re.sub( '[\s]+', ' ', tag, flags = re.UNICODE ) # turns multiple spaces into single spaces
@ -589,37 +595,28 @@ def ConvertIntToBytes( size ):
return '%.0f' % size + suffixes[ suffix_index ] + 'B'
def ConvertIntToPrettyString( num ):
processed_num = locale.format( "%d", num, grouping = True )
try: return unicode( processed_num )
except:
try: return processed_num.decode( locale.getpreferredencoding() )
except: return str( num )
def ConvertIntToPrettyString( num ): return u( locale.format( "%d", num, grouping = True ) )
def ConvertMillisecondsToPrettyTime( ms ):
hours = ms / 3600000
if hours == 1: hours_result = '1 hour'
else: hours_result = str( hours ) + ' hours'
else: hours_result = u( hours ) + ' hours'
ms = ms % 3600000
minutes = ms / 60000
if minutes == 1: minutes_result = '1 minute'
else: minutes_result = str( minutes ) + ' minutes'
else: minutes_result = u( minutes ) + ' minutes'
ms = ms % 60000
seconds = ms / 1000
if seconds == 1: seconds_result = '1 second'
else: seconds_result = str( seconds ) + ' seconds'
else: seconds_result = u( seconds ) + ' seconds'
detailed_seconds = float( ms ) / 1000.0
@ -629,7 +626,7 @@ def ConvertMillisecondsToPrettyTime( ms ):
ms = ms % 1000
if ms == 1: milliseconds_result = '1 millisecond'
else: milliseconds_result = str( ms ) + ' milliseconds'
else: milliseconds_result = u( ms ) + ' milliseconds'
if hours > 0: return hours_result + ' ' + minutes_result
@ -643,12 +640,12 @@ def ConvertNumericalRatingToPrettyString( lower, upper, rating, rounded_result =
rating_converted = ( rating * ( upper - lower ) ) + lower
if rounded_result: s = str( '%.2f' % round( rating_converted ) )
else: s = str( '%.2f' % rating_converted )
if rounded_result: s = u( '%.2f' % round( rating_converted ) )
else: s = u( '%.2f' % rating_converted )
if out_of:
if lower in ( 0, 1 ): s += '/' + str( '%.2f' % upper )
if lower in ( 0, 1 ): s += '/' + u( '%.2f' % upper )
return s
@ -688,35 +685,35 @@ def ConvertTimestampToPrettyAge( timestamp ):
if timestamp == 0 or timestamp is None: return 'unknown age'
age = int( time.time() ) - timestamp
age = GetNow() - timestamp
seconds = age % 60
if seconds == 1: s = '1 second'
else: s = str( seconds ) + ' seconds'
else: s = u( seconds ) + ' seconds'
age = age / 60
minutes = age % 60
if minutes == 1: m = '1 minute'
else: m = str( minutes ) + ' minutes'
else: m = u( minutes ) + ' minutes'
age = age / 60
hours = age % 24
if hours == 1: h = '1 hour'
else: h = str( hours ) + ' hours'
else: h = u( hours ) + ' hours'
age = age / 24
days = age % 30
if days == 1: d = '1 day'
else: d = str( days ) + ' days'
else: d = u( days ) + ' days'
age = age / 30
months = age % 12
if months == 1: mo = '1 month'
else: mo = str( months ) + ' months'
else: mo = u( months ) + ' months'
years = age / 12
if years == 1: y = '1 year'
else: y = str( years ) + ' years'
else: y = u( years ) + ' years'
if years > 0: return ' '.join( ( y, mo ) ) + ' old'
elif months > 0: return ' '.join( ( mo, d ) ) + ' old'
@ -728,35 +725,35 @@ def ConvertTimestampToPrettyAgo( timestamp ):
if timestamp == 0: return 'unknown time'
age = int( time.time() ) - timestamp
age = GetNow() - timestamp
seconds = age % 60
if seconds == 1: s = '1 second'
else: s = str( seconds ) + ' seconds'
else: s = u( seconds ) + ' seconds'
age = age / 60
minutes = age % 60
if minutes == 1: m = '1 minute'
else: m = str( minutes ) + ' minutes'
else: m = u( minutes ) + ' minutes'
age = age / 60
hours = age % 24
if hours == 1: h = '1 hour'
else: h = str( hours ) + ' hours'
else: h = u( hours ) + ' hours'
age = age / 24
days = age % 30
if days == 1: d = '1 day'
else: d = str( days ) + ' days'
else: d = u( days ) + ' days'
age = age / 30
months = age % 12
if months == 1: mo = '1 month'
else: mo = str( months ) + ' months'
else: mo = u( months ) + ' months'
years = age / 12
if years == 1: y = '1 year'
else: y = str( years ) + ' years'
else: y = u( years ) + ' years'
if years > 0: return ' '.join( ( y, mo ) ) + ' ago'
elif months > 0: return ' '.join( ( mo, d ) ) + ' ago'
@ -769,7 +766,7 @@ def ConvertTimestampToPrettyExpires( timestamp ):
if timestamp is None: return 'does not expire'
if timestamp == 0: return 'unknown expiry'
expires = int( time.time() ) - timestamp
expires = GetNow() - timestamp
if expires >= 0: already_happend = True
else:
@ -781,31 +778,31 @@ def ConvertTimestampToPrettyExpires( timestamp ):
seconds = expires % 60
if seconds == 1: s = '1 second'
else: s = str( seconds ) + ' seconds'
else: s = u( seconds ) + ' seconds'
expires = expires / 60
minutes = expires % 60
if minutes == 1: m = '1 minute'
else: m = str( minutes ) + ' minutes'
else: m = u( minutes ) + ' minutes'
expires = expires / 60
hours = expires % 24
if hours == 1: h = '1 hour'
else: h = str( hours ) + ' hours'
else: h = u( hours ) + ' hours'
expires = expires / 24
days = expires % 30
if days == 1: d = '1 day'
else: d = str( days ) + ' days'
else: d = u( days ) + ' days'
expires = expires / 30
months = expires % 12
if months == 1: mo = '1 month'
else: mo = str( months ) + ' months'
else: mo = u( months ) + ' months'
years = expires / 12
if years == 1: y = '1 year'
else: y = str( years ) + ' years'
else: y = u( years ) + ' years'
if already_happend:
@ -829,38 +826,38 @@ def ConvertTimestampToPrettyPending( timestamp ):
if timestamp is None: return ''
if timestamp == 0: return 'imminent'
pending = int( time.time() ) - timestamp
pending = GetNow() - timestamp
if pending >= 0: return 'imminent'
else: pending *= -1
seconds = pending % 60
if seconds == 1: s = '1 second'
else: s = str( seconds ) + ' seconds'
else: s = u( seconds ) + ' seconds'
pending = pending / 60
minutes = pending % 60
if minutes == 1: m = '1 minute'
else: m = str( minutes ) + ' minutes'
else: m = u( minutes ) + ' minutes'
pending = pending / 60
hours = pending % 24
if hours == 1: h = '1 hour'
else: h = str( hours ) + ' hours'
else: h = u( hours ) + ' hours'
pending = pending / 24
days = pending % 30
if days == 1: d = '1 day'
else: d = str( days ) + ' days'
else: d = u( days ) + ' days'
pending = pending / 30
months = pending % 12
if months == 1: mo = '1 month'
else: mo = str( months ) + ' months'
else: mo = u( months ) + ' months'
years = pending / 12
if years == 1: y = '1 year'
else: y = str( years ) + ' years'
else: y = u( years ) + ' years'
if years > 0: return 'in ' + ' '.join( ( y, mo ) )
elif months > 0: return 'in ' + ' '.join( ( mo, d ) )
@ -872,35 +869,35 @@ def ConvertTimestampToPrettySync( timestamp ):
if timestamp == 0: return 'not updated'
age = int( time.time() ) - timestamp
age = GetNow() - timestamp
seconds = age % 60
if seconds == 1: s = '1 second'
else: s = str( seconds ) + ' seconds'
else: s = u( seconds ) + ' seconds'
age = age / 60
minutes = age % 60
if minutes == 1: m = '1 minute'
else: m = str( minutes ) + ' minutes'
else: m = u( minutes ) + ' minutes'
age = age / 60
hours = age % 24
if hours == 1: h = '1 hour'
else: h = str( hours ) + ' hours'
else: h = u( hours ) + ' hours'
age = age / 24
days = age % 30
if days == 1: d = '1 day'
else: d = str( days ) + ' days'
else: d = u( days ) + ' days'
age = age / 30
months = age % 12
if months == 1: mo = '1 month'
else: mo = str( months ) + ' months'
else: mo = u( months ) + ' months'
years = age / 12
if years == 1: y = '1 year'
else: y = str( years ) + ' years'
else: y = u( years ) + ' years'
if years > 0: return 'updated to ' + ' '.join( ( y, mo ) ) + ' ago'
elif months > 0: return 'updated to ' + ' '.join( ( mo, d ) ) + ' ago'
@ -912,7 +909,7 @@ def ConvertTimestampToPrettyTime( timestamp ): return time.strftime( '%Y/%m/%d %
def ConvertTimestampToHumanPrettyTime( timestamp ):
now = int( time.time() )
now = GetNow()
difference = now - timestamp
@ -952,6 +949,8 @@ def GetEmptyDataDict():
return data
def GetNow(): return int( time.time() )
def GetShortcutFromEvent( event ):
modifier = wx.ACCEL_NORMAL
@ -1012,18 +1011,18 @@ def MergeKeyToListDicts( key_to_list_dicts ):
return result
class Message():
def u( text_producing_object ):
def __init__( self, message_type, info ):
if type( text_producing_object ) in ( str, unicode ): text = text_producing_object
else: text = str( text_producing_object ) # dealing with exceptions, etc...
try: return unicode( text )
except:
self._message_type = message_type
self._info = info
try: return text.decode( locale.getpreferredencoding() )
except: return str( text )
def GetInfo( self ): return self._info
def GetType( self ): return self._message_type
def SearchEntryMatchesPredicate( search_entry, predicate ):
( predicate_type, info ) = predicate.GetInfo()
@ -1063,9 +1062,9 @@ def SearchEntryMatchesTag( search_entry, tag, search_siblings = True ):
return False
def SplayListForDB( xs ): return '(' + ','.join( [ '"' + str( x ) + '"' for x in xs ] ) + ')'
def SplayListForDB( xs ): return '(' + ','.join( [ '"' + u( x ) + '"' for x in xs ] ) + ')'
def SplayTupleListForDB( first_column_name, second_column_name, xys ): return ' OR '.join( [ '( ' + first_column_name + '=' + str( x ) + ' AND ' + second_column_name + ' IN ' + SplayListForDB( ys ) + ' )' for ( x, ys ) in xys ] )
def SplayTupleListForDB( first_column_name, second_column_name, xys ): return ' OR '.join( [ '( ' + first_column_name + '=' + u( x ) + ' AND ' + second_column_name + ' IN ' + SplayListForDB( ys ) + ' )' for ( x, ys ) in xys ] )
def ThumbnailResolution( original_resolution, target_resolution ):
@ -1133,7 +1132,7 @@ class AdvancedHTTPConnection():
def request( self, request_type, request, headers = {}, body = None, is_redirect = False, follow_redirects = True ):
if 'User-Agent' not in headers: headers[ 'User-Agent' ] = 'hydrus/' + str( NETWORK_VERSION )
if 'User-Agent' not in headers: headers[ 'User-Agent' ] = 'hydrus/' + u( NETWORK_VERSION )
if len( self._cookies ) > 0: headers[ 'Cookie' ] = '; '.join( [ k + '=' + v for ( k, v ) in self._cookies.items() ] )
@ -1148,9 +1147,8 @@ class AdvancedHTTPConnection():
except ( httplib.CannotSendRequest, httplib.BadStatusLine ):
# for some reason, we can't send a request on the current connection, so let's make a new one!
try:
if self._scheme == 'http': self._connection = httplib.HTTPConnection( self._host, self._port )
else: self._connection = httplib.HTTPSConnection( self._host, self._port )
@ -1220,7 +1218,7 @@ class AdvancedHTTPConnection():
if mime_string in mime_enum_lookup and mime_enum_lookup[ mime_string ] == APPLICATION_YAML:
try: parsed_response = yaml.safe_load( raw_response )
except Exception as e: raise HydrusExceptions.NetworkVersionException( 'Failed to parse a response object!' + os.linesep + unicode( e ) )
except Exception as e: raise HydrusExceptions.NetworkVersionException( 'Failed to parse a response object!' + os.linesep + u( e ) )
else: parsed_response = raw_response
@ -1330,6 +1328,8 @@ class AdvancedHTTPConnection():
def SetCookie( self, key, value ): self._cookies[ key ] = value
get_connection = AdvancedHTTPConnection
class HydrusYAMLBase( yaml.YAMLObject ):
yaml_loader = yaml.SafeLoader
@ -1350,7 +1350,7 @@ class Account( HydrusYAMLBase ):
self._used_data = used_data
self._banned_info = banned_info
self._object_instantiation_timestamp = int( time.time() )
self._object_instantiation_timestamp = GetNow()
def __repr__( self ): return self.ConvertToString()
@ -1365,14 +1365,14 @@ class Account( HydrusYAMLBase ):
( reason, created, expires ) = self._banned_info
if expires is None: return True
else: return int( time.time() ) > expires
else: return GetNow() > expires
def _IsExpired( self ):
if self._expires is None: return False
else: return int( time.time() ) > self._expires
else: return GetNow() > self._expires
def CheckPermissions( self, permissions ):
@ -1457,9 +1457,9 @@ class Account( HydrusYAMLBase ):
def IsBanned( self ): return self._IsBanned()
def IsStale( self ): return self._object_instantiation_timestamp + UPDATE_DURATION * 5 < int( time.time() )
def IsStale( self ): return self._object_instantiation_timestamp + UPDATE_DURATION * 5 < GetNow()
def MakeFresh( self ): self._object_instantiation_timestamp = int( time.time() )
def MakeFresh( self ): self._object_instantiation_timestamp = GetNow()
def MakeStale( self ): self._object_instantiation_timestamp = 0
@ -1493,7 +1493,7 @@ class AccountIdentifier( HydrusYAMLBase ):
def __ne__( self, other ): return self.__hash__() != other.__hash__()
def __repr__( self ): return 'Account Identifier: ' + str( ( self._access_key.encode( 'hex' ), self._hash.encode( 'hex' ), self._tag, self._account_id ) )
def __repr__( self ): return 'Account Identifier: ' + u( ( self._access_key.encode( 'hex' ), self._hash.encode( 'hex' ), self._tag, self._account_id ) )
def GetAccessKey( self ): return self._access_key
@ -1580,7 +1580,7 @@ class ClientServiceIdentifier( HydrusYAMLBase ):
def __ne__( self, other ): return self.__hash__() != other.__hash__()
def __repr__( self ): return 'Client Service Identifier: ' + str( ( name, self._type, self._service_key ) )
def __repr__( self ): return 'Client Service Identifier: ' + u( ( self._name, self._type, self._service_key ) )
def GetInfo( self ): return ( self._service_key, self._type, self._name )
@ -1715,7 +1715,7 @@ class ContentUpdate():
def __ne__( self, other ): return not self.__eq__( other )
def __repr__( self ): return 'Content Update: ' + str( ( self._data_type, self._action, self._row ) )
def __repr__( self ): return 'Content Update: ' + u( ( self._data_type, self._action, self._row ) )
def GetHashes( self ):
@ -1755,6 +1755,7 @@ class DAEMON( threading.Thread ):
threading.Thread.__init__( self, name = name )
self._name = name
self._callable = callable
self._period = period
@ -1801,7 +1802,14 @@ class DAEMONQueue( DAEMON ):
while self._queue.qsize() > 0: items.append( self._queue.get() )
try: self._callable( items )
except: print( traceback.format_exc() )
except Exception as e:
message = self._name + os.linesep + type( e ).__name__ + os.linesep + traceback.format_exc()
pubsub.pub( 'message', Message( MESSAGE_TYPE_ERROR, Exception( message ) ) )
print( message )
@ -1828,7 +1836,14 @@ class DAEMONWorker( DAEMON ):
if shutdown: return
try: self._callable()
except: print( traceback.format_exc() )
except Exception as e:
message = self._name + os.linesep + type( e ).__name__ + os.linesep + traceback.format_exc()
pubsub.pub( 'message', Message( MESSAGE_TYPE_ERROR, Exception( message ) ) )
print( message )
if shutdown: return
@ -1840,6 +1855,18 @@ class DAEMONWorker( DAEMON ):
def set( self, *args, **kwargs ): self._event.set()
class Message():
def __init__( self, message_type, info ):
self._message_type = message_type
self._info = info
def GetInfo( self ): return self._info
def GetType( self ): return self._message_type
class JobInternal():
yaml_tag = u'!JobInternal'
@ -1930,7 +1957,7 @@ class Predicate():
def __ne__( self, other ): return self.__hash__() != other.__hash__()
def __repr__( self ): return 'Predicate: ' + str( ( self._predicate_type, self._value, self._count ) )
def __repr__( self ): return 'Predicate: ' + u( ( self._predicate_type, self._value, self._count ) )
def AddToCount( self, count ): self._count += count
@ -1969,7 +1996,7 @@ class Predicate():
( operator, value ) = info
base += u' ' + operator + u' ' + unicode( value )
base += u' ' + operator + u' ' + u( value )
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_SIZE:
@ -1980,7 +2007,7 @@ class Predicate():
( operator, size, unit ) = info
base += u' ' + operator + u' ' + unicode( size ) + ConvertUnitToString( unit )
base += u' ' + operator + u' ' + u( size ) + ConvertUnitToString( unit )
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_LIMIT:
@ -1991,7 +2018,7 @@ class Predicate():
value = info
base += u' is ' + unicode( value )
base += u' is ' + u( value )
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_AGE:
@ -2002,7 +2029,7 @@ class Predicate():
( operator, years, months, days, hours ) = info
base += u' ' + operator + u' ' + unicode( years ) + u'y' + unicode( months ) + u'm' + unicode( days ) + u'd' + unicode( hours ) + u'h'
base += u' ' + operator + u' ' + u( years ) + u'y' + u( months ) + u'm' + u( days ) + u'd' + u( hours ) + u'h'
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_HASH:
@ -2035,7 +2062,7 @@ class Predicate():
( service_identifier, operator, value ) = info
base += u' for ' + service_identifier.GetName() + u' ' + operator + u' ' + unicode( value )
base += u' for ' + service_identifier.GetName() + u' ' + operator + u' ' + u( value )
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_SIMILAR_TO:
@ -2046,7 +2073,7 @@ class Predicate():
( hash, max_hamming ) = info
base += u' ' + hash.encode( 'hex' ) + u' using max hamming of ' + unicode( max_hamming )
base += u' ' + hash.encode( 'hex' ) + u' using max hamming of ' + u( max_hamming )
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_FILE_SERVICE:
@ -2182,7 +2209,7 @@ class ServerServiceIdentifier( HydrusYAMLBase ):
def __ne__( self, other ): return self.__hash__() != other.__hash__()
def __repr__( self ): return 'Server Service Identifier: ' + str( ( self._type, self._port ) )
def __repr__( self ): return 'Server Service Identifier: ' + u( ( self._type, self._port ) )
def GetPort( self ): return self._port

View File

@ -94,7 +94,7 @@ class Downloader():
if ( scheme, host, port ) not in self._connections:
connection = HC.AdvancedHTTPConnection( scheme = scheme, host = host, port = port )
connection = HC.get_connection( scheme = scheme, host = host, port = port )
self._EstablishSession( connection )
@ -178,7 +178,7 @@ class DownloaderBooru( Downloader ):
else: index = self._num_pages_done * self._gallery_advance_num
return self._search_url.replace( '%tags%', self._search_separator.join( self._tags ) ).replace( '%index%', str( index ) )
return self._search_url.replace( '%tags%', self._search_separator.join( self._tags ) ).replace( '%index%', HC.u( index ) )
def _ParseGalleryPage( self, html, url_base ):
@ -324,7 +324,7 @@ class DownloaderDeviantArt( Downloader ):
Downloader.__init__( self )
def _GetNextGalleryPageURL( self ): return self._gallery_url + str( self._num_pages_done * 24 )
def _GetNextGalleryPageURL( self ): return self._gallery_url + HC.u( self._num_pages_done * 24 )
def _ParseGalleryPage( self, html, url_base ):
@ -427,7 +427,7 @@ class DownloaderGiphy( Downloader ):
Downloader.__init__( self )
def _GetNextGalleryPageURL( self ): return self._gallery_url + str( self._num_pages_done + 1 )
def _GetNextGalleryPageURL( self ): return self._gallery_url + HC.u( self._num_pages_done + 1 )
def _ParseGalleryPage( self, data, url_base ):
@ -444,7 +444,7 @@ class DownloaderGiphy( Downloader ):
def GetTags( self, url, id ):
url = 'http://giphy.com/api/gifs/' + str( id )
url = 'http://giphy.com/api/gifs/' + HC.u( id )
connection = self._GetConnection( url )
@ -503,7 +503,7 @@ class DownloaderHentaiFoundry( Downloader ):
gallery_url = 'http://www.hentai-foundry.com/pictures/user/' + artist
return gallery_url + '/page/' + str( self._num_pages_done + 1 )
return gallery_url + '/page/' + HC.u( self._num_pages_done + 1 )
elif self._query_type == 'artist scraps':
@ -511,13 +511,13 @@ class DownloaderHentaiFoundry( Downloader ):
gallery_url = 'http://www.hentai-foundry.com/pictures/user/' + artist + '/scraps'
return gallery_url + '/page/' + str( self._num_pages_done + 1 )
return gallery_url + '/page/' + HC.u( self._num_pages_done + 1 )
elif self._query_type == 'tags':
tags = self._query
return 'http://www.hentai-foundry.com/search/pictures?query=' + '+'.join( tags ) + '&search_in=all&scraps=-1&page=' + str( self._num_pages_done + 1 )
return 'http://www.hentai-foundry.com/search/pictures?query=' + '+'.join( tags ) + '&search_in=all&scraps=-1&page=' + HC.u( self._num_pages_done + 1 )
# scraps = 0 hide
# -1 means show both
# 1 means scraps only. wetf
@ -592,7 +592,7 @@ class DownloaderHentaiFoundry( Downloader ):
title = soup.find( 'title' )
( data, nothing ) = unicode( title.string ).split( ' - Hentai Foundry' )
( data, nothing ) = HC.u( title.string ).split( ' - Hentai Foundry' )
data_reversed = data[::-1] # want to do it right-side first, because title might have ' by ' in it
@ -733,7 +733,7 @@ class DownloaderNewgrounds( Downloader ):
soup = bs4.BeautifulSoup( html )
tags = []
tags = set()
author_links = soup.find( 'ul', class_ = 'authorlinks' )
@ -751,7 +751,7 @@ class DownloaderNewgrounds( Downloader ):
creator = href.replace( 'http://', '' ).replace( '.newgrounds.com', '' )
tags.append( 'creator:' + creator )
tags.add( u'creator:' + creator )
except: pass
@ -761,7 +761,7 @@ class DownloaderNewgrounds( Downloader ):
title = soup.find( 'title' )
tags.append( 'title:' + title.string )
tags.add( u'title:' + title.string )
except: pass
@ -773,7 +773,7 @@ class DownloaderNewgrounds( Downloader ):
href = link[ 'href' ]
if '/browse/tag/' in href: tags.append( link.string )
if '/browse/tag/' in href: tags.add( link.string )
except: pass
@ -782,7 +782,7 @@ class DownloaderNewgrounds( Downloader ):
try:
components = html.split( '"src"' )
components = html.split( '"http://uploads.ungrounded.net/' )
# there is sometimes another bit of api flash earlier on that we don't want
# it is called http://uploads.ungrounded.net/apiassets/sandbox.swf
@ -790,20 +790,13 @@ class DownloaderNewgrounds( Downloader ):
if len( components ) == 2: flash_url = components[1]
else: flash_url = components[2]
#"src": "http:\/\/flash.ngfiles.com\/video_player\/videoplayer.swf",
#"width": "100%",
flash_url = flash_url.split( '"', 1 )[0]
#"src": "http:\/\/uploads.ungrounded.net\/593000\/593806_Kitty.swf",
#"width": "100%",
flash_url = 'http://uploads.ungrounded.net/' + flash_url
flash_url = flash_url.split( '"width"', 1 )[0]
flash_url = flash_url.split( '"' )[1]
flash_url = flash_url.replace( '\\/', '/' )
except: raise Exception( 'Could not find the swf file!' )
if flash_url == 'http://flash.ngfiles.com/video_player/videoplayer.swf': raise Exception( 'It was an mp4 movie, not a swf!' )
except:
print( traceback.format_exc())
raise Exception( 'Could not find the swf file! It was probably an mp4!' )
return ( flash_url, tags )
@ -858,7 +851,7 @@ class DownloaderPixiv( Downloader ):
artist_id = self._query
gallery_url = 'http://www.pixiv.net/member_illust.php?id=' + str( artist_id )
gallery_url = 'http://www.pixiv.net/member_illust.php?id=' + HC.u( artist_id )
elif self._query_type == 'tag':
@ -869,7 +862,7 @@ class DownloaderPixiv( Downloader ):
gallery_url = 'http://www.pixiv.net/search.php?word=' + tag + '&s_mode=s_tag_full&order=date_d'
return gallery_url + '&p=' + str( self._num_pages_done + 1 )
return gallery_url + '&p=' + HC.u( self._num_pages_done + 1 )
def _ParseGalleryPage( self, html, url_base ):
@ -981,7 +974,7 @@ class DownloaderTumblr( Downloader ):
Downloader.__init__( self )
def _GetNextGalleryPageURL( self ): return self._gallery_url.replace( '%start%', str( self._num_pages_done * 50 ) )
def _GetNextGalleryPageURL( self ): return self._gallery_url.replace( '%start%', HC.u( self._num_pages_done * 50 ) )
def _ParseGalleryPage( self, data, url_base ):

View File

@ -42,9 +42,9 @@ def DecryptAESFile( aes_key, iv, path ):
if '.encrypted' in path: path_to = path.replace( '.encrypted', '' )
else: path_to = path + '.decrypted'
with open( path, 'rb' ) as encrypted_f:
with HC.o( path, 'rb' ) as encrypted_f:
with open( path_to, 'wb' ) as decrypted_f:
with HC.o( path_to, 'wb' ) as decrypted_f:
next_block = encrypted_f.read( 65536 )
@ -96,9 +96,9 @@ def EncryptAESFile( path, preface = '' ):
aes_cipher = Crypto.Cipher.AES.new( aes_key, Crypto.Cipher.AES.MODE_CFB, iv )
with open( path, 'rb' ) as decrypted_f:
with HC.o( path, 'rb' ) as decrypted_f:
with open( path + '.encrypted', 'wb' ) as encrypted_f:
with HC.o( path + '.encrypted', 'wb' ) as encrypted_f:
encrypted_f.write( preface )
@ -128,7 +128,7 @@ def EncryptAESFile( path, preface = '' ):
aes_key_text = AESKeyToText( aes_key, iv )
with open( path + '.key', 'wb' ) as f: f.write( aes_key_text )
with HC.o( path + '.key', 'wb' ) as f: f.write( aes_key_text )
def EncryptPKCS( public_key, message ):

View File

@ -68,7 +68,7 @@ def GetFileInfo( file, hash ):
def GetMimeFromPath( filename ):
with open( filename, 'rb' ) as f: return GetMimeFromFilePointer( f )
with HC.o( filename, 'rb' ) as f: return GetMimeFromFilePointer( f )
header_and_mime = [
( 0, '\xff\xd8', HC.IMAGE_JPEG ),
@ -109,7 +109,7 @@ def GetMimeFromFilePointer( f ):
path = HC.TEMP_DIR + os.path.sep + 'mime_parsing'
with open( path, 'wb' ) as temp_f:
with HC.o( path, 'wb' ) as temp_f:
block = f.read( 65536 )
@ -121,29 +121,23 @@ def GetMimeFromFilePointer( f ):
try:
mutagen_object = mutagen.File( path )
if type( mutagen_object ) == mutagen.oggvorbis.OggVorbis: return HC.AUDIO_OGG
elif type( mutagen_object ) == mutagen.flac.FLAC: return HC.AUDIO_FLAC
elif type( mutagen_object ) == mutagen.mp3.MP3: return HC.AUDIO_MP3
elif type( mutagen_object ) == mutagen.mp4.MP4 or mutagen_object is None:
mutagen_object = mutagen.File( path )
# mutagen sometimes does not auto-detect mp3s properly, so try it explicitly
mutagen_object = mutagen.mp3.MP3( path )
if type( mutagen_object ) == mutagen.oggvorbis.OggVorbis: return HC.AUDIO_OGG
elif type( mutagen_object ) == mutagen.flac.FLAC: return HC.AUDIO_FLAC
elif type( mutagen_object ) == mutagen.mp3.MP3: return HC.AUDIO_MP3
elif type( mutagen_object ) == mutagen.mp4.MP4 or mutagen_object is None:
# mutagen sometimes does not auto-detect mp3s properly, so try it explicitly
mutagen_object = mutagen.mp3.MP3( path )
if type( mutagen_object ) == mutagen.mp3.MP3: return HC.AUDIO_MP3
if type( mutagen_object ) == mutagen.mp3.MP3: return HC.AUDIO_MP3
except: print( traceback.format_exc() )
return HC.mime_enum_lookup[ 'unknown mime' ]
except:
wx.MessageBox( traceback.format_exc() )
raise Exception( 'I could not identify the mime of the file' )
except: return HC.APPLICATION_UNKNOWN
def GetMimeFromString( file ):

View File

@ -123,7 +123,7 @@ class Message( HC.HydrusYAMLBase ):
if type( self._body ) == unicode: body_text = self._body.encode( 'utf-8' )
else: body_text = self._body
message += ''.join( [ yaml.safe_dump( public_key ) for public_key in contact_to_public_keys ] ) + subject_text + body_text + ''.join( self._files ) + str( self._conversation_key ) + str( self._timestamp )
message += ''.join( [ yaml.safe_dump( public_key ) for public_key in contact_to_public_keys ] ) + subject_text + body_text + ''.join( self._files ) + HC.u( self._conversation_key ) + HC.u( self._timestamp )
hash_object = Crypto.Hash.SHA256.new( message )

View File

@ -47,7 +47,7 @@ class HydrusPubSub():
wx.PostEvent( HC.app, PubSubEvent() )
except wx.PyDeadObjectError: pass
except: print( topic + ' for ' + str( object ) + ' bound to ' + method_name + os.linesep + traceback.format_exc() )
except: print( topic + ' for ' + HC.u( object ) + ' bound to ' + method_name + os.linesep + traceback.format_exc() )
@ -77,7 +77,7 @@ class HydrusPubSub():
try: getattr( object, method_name )( *args, **kwargs )
except wx.PyDeadObjectError: pass
except: print( topic + ' for ' + str( object ) + ' bound to ' + method_name + os.linesep + traceback.format_exc() )
except: print( topic + ' for ' + HC.u( object ) + ' bound to ' + method_name + os.linesep + traceback.format_exc() )

View File

@ -113,7 +113,7 @@ eris = '''<html><head><title>hydrus</title></head><body><pre>
<font color="gray">MM</font>:::::<font color="gray">M</font>:::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>::::<font color="gray">M</font>::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>:::<font color="gray">M</font>::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>::<font color="gray">M</font>:::::::::::::::::::<font color="gray">MMM</font> THIS IS THE HYDRUS SERVER ADMIN SERVICE, VERSION ''' + str( HC.SOFTWARE_VERSION ) + '''
<font color="gray">MM</font>::<font color="gray">M</font>:::::::::::::::::::<font color="gray">MMM</font> THIS IS THE HYDRUS SERVER ADMIN SERVICE, VERSION ''' + HC.u( HC.SOFTWARE_VERSION ) + '''
<font color="gray">MM</font>:<font color="gray">M</font>:::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MMM</font>::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>::::::::::::::::::<font color="gray">MMM</font>
@ -205,7 +205,7 @@ CLIENT_ROOT_MESSAGE = '''<html>
<title>hydrus client</title>
</head>
<body>
<p>This hydrus client uses software version ''' + str( HC.SOFTWARE_VERSION ) + ''' and network version ''' + str( HC.NETWORK_VERSION ) + '''.</p>
<p>This hydrus client uses software version ''' + HC.u( HC.SOFTWARE_VERSION ) + ''' and network version ''' + HC.u( HC.NETWORK_VERSION ) + '''.</p>
<p>It only serves requests from 127.0.0.1.</p>
</body>
</html>'''
@ -215,7 +215,7 @@ ROOT_MESSAGE_BEGIN = '''<html>
<title>hydrus service</title>
</head>
<body>
<p>This hydrus service uses software version ''' + str( HC.SOFTWARE_VERSION ) + ''' and network version ''' + str( HC.NETWORK_VERSION ) + '''.</p>
<p>This hydrus service uses software version ''' + HC.u( HC.SOFTWARE_VERSION ) + ''' and network version ''' + HC.u( HC.NETWORK_VERSION ) + '''.</p>
<p>'''
ROOT_MESSAGE_END = '''</p>
@ -246,7 +246,7 @@ def ParseFileArguments( file ):
try: ( size, mime, width, height, duration, num_frames, num_words ) = HydrusFileHandling.GetFileInfo( file, hash )
except HydrusExceptions.SizeException: raise HydrusExceptions.ForbiddenException( 'File is of zero length!' )
except HydrusExceptions.MimeException: raise HydrusExceptions.ForbiddenException( 'Filetype is not permitted!' )
except Exception as e: raise HydrusExceptions.ForbiddenException( unicode( e ) )
except Exception as e: raise HydrusExceptions.ForbiddenException( HC.u( e ) )
args = {}
@ -370,10 +370,10 @@ class HydrusHTTPServer( SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer )
class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ):
server_version = 'hydrus/' + str( HC.NETWORK_VERSION )
server_version = 'hydrus/' + HC.u( HC.NETWORK_VERSION )
protocol_version = 'HTTP/1.1'
with open( HC.STATIC_DIR + os.path.sep + 'hydrus.ico', 'rb' ) as f: _favicon = f.read()
with HC.o( HC.STATIC_DIR + os.path.sep + 'hydrus.ico', 'rb' ) as f: _favicon = f.read()
def __init__( self, request, client_address, server ):
@ -390,7 +390,7 @@ class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ):
try:
default_mime = HC.TEXT_HTML
default_encoding = lambda x: unicode( x )
default_encoding = lambda x: HC.u( x )
user_agent_text = self.headers.getheader( 'User-Agent' )
@ -407,7 +407,7 @@ class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ):
if client == 'hydrus':
default_mime = HC.APPLICATION_YAML
default_encoding = lambda x: yaml.safe_dump( unicode( x ) )
default_encoding = lambda x: yaml.safe_dump( HC.u( x ) )
network_version = int( network_version )
@ -416,7 +416,7 @@ class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ):
if network_version < HC.NETWORK_VERSION: message = 'Please download the latest release.'
else: message = 'Please ask this server\'s admin to update to the latest release.'
raise HydrusExceptions.NetworkVersionException( 'Network version mismatch! This server\'s network version is ' + str( HC.NETWORK_VERSION ) + ', whereas your client\'s is ' + str( network_version ) + '! ' + message )
raise HydrusExceptions.NetworkVersionException( 'Network version mismatch! This server\'s network version is ' + HC.u( HC.NETWORK_VERSION ) + ', whereas your client\'s is ' + HC.u( network_version ) + '! ' + message )
@ -555,7 +555,7 @@ class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ):
def log_message( self, format, *args ): print( "[%s] %s%s" % ( self.log_date_time_string(), format%args, os.linesep ) )
def log_request( self, *args ): pass # to start logging a little about every request, just delete this def. the default pushes to log_message
def log_request( self, *args ): pass
def log_string( self, message ): print( message )
@ -564,7 +564,7 @@ class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ):
service_type = self._service_identifier.GetType()
server_version = HC.service_string_lookup[ service_type ] + '/' + str( HC.NETWORK_VERSION )
server_version = HC.service_string_lookup[ service_type ] + '/' + HC.u( HC.NETWORK_VERSION )
return server_version + ' ' + self.sys_version

View File

@ -36,7 +36,7 @@ class HydrusSessionManagerClient():
def GetSessionKey( self, service_identifier ):
now = int( time.time() )
now = HC.GetNow()
with self._lock:
@ -91,7 +91,7 @@ class HydrusSessionManagerServer():
def GetAccountIdentifier( self, session_key, service_identifier ):
now = int( time.time() )
now = HC.GetNow()
with self._lock:

View File

@ -55,52 +55,43 @@ class TagsManagerSimple():
self._service_identifiers_to_statuses_to_tags = service_identifiers_to_statuses_to_tags
self._cstvcp_initialised = False
self._combined_namespaces_cache = None
def _RecalcCSTVCP( self ):
def GetCombinedNamespaces( self, namespaces ):
self._creators = set()
self._series = set()
self._titles = set()
self._volumes = set()
self._chapters = set()
self._pages = set()
combined_statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ HC.COMBINED_TAG_SERVICE_IDENTIFIER ]
combined_current = combined_statuses_to_tags[ HC.CURRENT ]
combined_pending = combined_statuses_to_tags[ HC.PENDING ]
for tag in combined_current.union( combined_pending ):
if self._combined_namespaces_cache is None:
combined_statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ HC.COMBINED_TAG_SERVICE_IDENTIFIER ]
if ':' in tag:
combined_current = combined_statuses_to_tags[ HC.CURRENT ]
combined_pending = combined_statuses_to_tags[ HC.PENDING ]
self._combined_namespaces_cache = HC.BuildKeyToSetDict( tag.split( ':', 1 ) for tag in combined_current.union( combined_pending ) if ':' in tag )
only_int_allowed = ( 'volume', 'chapter', 'page' )
for namespace in only_int_allowed:
( namespace, tag ) = tag.split( ':', 1 )
tags = self._combined_namespaces_cache[ namespace ]
if namespace == 'creator': self._creators.add( tag )
elif namespace == 'series': self._series.add( tag )
elif namespace == 'title': self._titles.add( tag )
elif namespace in ( 'volume', 'chapter', 'page' ):
int_tags = set()
for tag in tags:
try: tag = int( tag )
except: continue
if namespace == 'volume': self._volumes.add( tag )
elif namespace == 'chapter': self._chapters.add( tag )
elif namespace == 'page': self._pages.add( tag )
int_tags.add( tag )
self._combined_namespaces_cache[ namespace ] = int_tags
self._cstvcp_initialised = True
result = { namespace : self._combined_namespaces_cache[ namespace ] for namespace in namespaces }
def GetCSTVCP( self ):
if not self._cstvcp_initialised: self._RecalcCSTVCP()
return ( self._creators, self._series, self._titles, self._volumes, self._chapters, self._pages )
return result
def GetNamespaceSlice( self, namespaces, collapse = True ):
@ -110,7 +101,7 @@ class TagsManagerSimple():
combined_current = combined_statuses_to_tags[ HC.CURRENT ]
combined_pending = combined_statuses_to_tags[ HC.PENDING ]
slice = { tag for tag in list( combined_current ) + list( combined_pending ) if True in ( tag.startswith( namespace + ':' ) for namespace in namespaces ) }
slice = { tag for tag in combined_current.union( combined_pending ) if True in ( tag.startswith( namespace + ':' ) for namespace in namespaces ) }
if collapse:
@ -159,7 +150,7 @@ class TagsManager( TagsManagerSimple ):
self._service_identifiers_to_statuses_to_tags[ HC.COMBINED_TAG_SERVICE_IDENTIFIER ] = combined_statuses_to_tags
if self._cstvcp_initialised: self._RecalcCSTVCP()
self._combined_namespaces_cache = None
def DeletePending( self, service_identifier ):

View File

@ -50,7 +50,7 @@ def GetMP4Duration( file ):
filename = HC.TEMP_DIR + os.path.sep + 'mp4_parse.mp4'
with open( filename, 'wb' ) as f: f.write( file )
with HC.o( filename, 'wb' ) as f: f.write( file )
try: mp4_object = mutagen.mp4.MP4( filename )
except: raise Exception( 'Could not parse the mp4!' )

View File

@ -14,7 +14,7 @@ class Controller( wx.App ):
def _AlreadyRunning( self, port ):
connection = httplib.HTTPConnection( 'localhost:' + str( port ) )
connection = httplib.HTTPConnection( 'localhost:' + HC.u( port ) )
try:
@ -36,7 +36,7 @@ class Controller( wx.App ):
server_daemon.setDaemon( True )
server_daemon.start()
connection = httplib.HTTPConnection( 'localhost:' + str( port ) )
connection = httplib.HTTPConnection( 'localhost:' + HC.u( port ) )
connection.connect()

View File

@ -60,7 +60,7 @@ class FileDB():
hash_id = self._GetHashId( c, hash )
now = int( time.time() )
now = HC.GetNow()
if c.execute( 'SELECT 1 FROM file_map WHERE service_id = ? AND hash_id = ?;', ( service_id, hash_id ) ).fetchone() is None or c.execute( 'SELECT 1 FROM file_petitions WHERE service_id = ? AND hash_id = ? AND status = ?;', ( service_id, hash_id, HC.DELETED ) ).fetchone() is None:
@ -100,7 +100,7 @@ class FileDB():
file = file_dict[ 'file' ]
with open( dest_path, 'wb' ) as f: f.write( file )
with HC.o( dest_path, 'wb' ) as f: f.write( file )
if 'thumbnail' in file_dict:
@ -111,7 +111,7 @@ class FileDB():
thumbnail = file_dict[ 'thumbnail' ]
with open( thumbnail_dest_path, 'wb' ) as f: f.write( thumbnail )
with HC.o( thumbnail_dest_path, 'wb' ) as f: f.write( thumbnail )
@ -142,7 +142,7 @@ class FileDB():
# this clears out any old reasons, if the user wants to overwrite them
c.execute( 'DELETE FROM file_petitions WHERE service_id = ? AND account_id = ? AND hash_id IN ' + HC.SplayListForDB( valid_hash_ids ) + ' AND status = ?;', ( service_id, account_id, HC.PETITIONED ) )
now = int( time.time() )
now = HC.GetNow()
c.executemany( 'INSERT OR IGNORE INTO file_petitions ( service_id, account_id, hash_id, reason_id, timestamp, status ) VALUES ( ?, ?, ?, ?, ?, ? );', [ ( service_id, account_id, hash_id, reason_id, now, HC.PETITIONED ) for hash_id in valid_hash_ids ] )
@ -174,7 +174,7 @@ class FileDB():
c.execute( 'DELETE FROM file_map WHERE service_id = ? AND hash_id IN ' + splayed_hash_ids + ';', ( service_id, ) )
c.execute( 'DELETE FROM file_petitions WHERE service_id = ? AND hash_id IN ' + splayed_hash_ids + ' AND status = ?;', ( service_id, HC.PETITIONED ) )
now = int( time.time() )
now = HC.GetNow()
c.executemany( 'INSERT OR IGNORE INTO file_petitions ( service_id, account_id, hash_id, reason_id, timestamp, status ) VALUES ( ?, ?, ?, ?, ?, ? );', ( ( service_id, account_id, hash_id, reason_id, now, HC.DELETED ) for hash_id in hash_ids ) )
@ -247,7 +247,7 @@ class FileDB():
path = GetPath( 'file', hash )
with open( path, 'rb' ) as f: file = f.read()
with HC.o( path, 'rb' ) as f: file = f.read()
except: raise HydrusExceptions.NotFoundException( 'Could not find that file!' )
@ -355,7 +355,7 @@ class FileDB():
path = GetPath( 'thumbnail', hash )
with open( path, 'rb' ) as f: thumbnail = f.read()
with HC.o( path, 'rb' ) as f: thumbnail = f.read()
return thumbnail
@ -378,11 +378,11 @@ class MessageDB():
message_key = os.urandom( 32 )
c.execute( 'INSERT OR IGNORE INTO messages ( message_key, service_id, account_id, timestamp ) VALUES ( ?, ?, ?, ? );', ( sqlite3.Binary( message_key ), service_id, account_id, int( time.time() ) ) )
c.execute( 'INSERT OR IGNORE INTO messages ( message_key, service_id, account_id, timestamp ) VALUES ( ?, ?, ?, ? );', ( sqlite3.Binary( message_key ), service_id, account_id, HC.GetNow() ) )
dest_path = GetPath( 'message', message_key )
with open( dest_path, 'wb' ) as f: f.write( message )
with HC.o( dest_path, 'wb' ) as f: f.write( message )
def _AddStatuses( self, c, contact_key, statuses ):
@ -390,7 +390,7 @@ class MessageDB():
try: ( service_id, account_id ) = c.execute( 'SELECT service_id, account_id FROM contacts WHERE contact_key = ?;', ( sqlite3.Binary( contact_key ), ) ).fetchone()
except: raise HydrusExceptions.ForbiddenException( 'Did not find that contact key for the message depot!' )
now = int( time.time() )
now = HC.GetNow()
c.executemany( 'INSERT OR REPLACE INTO message_statuses ( status_key, service_id, account_id, status, timestamp ) VALUES ( ?, ?, ?, ?, ? );', [ ( sqlite3.Binary( status_key ), service_id, account_id, sqlite3.Binary( status ), now ) for ( status_key, status ) in statuses ] )
@ -422,7 +422,7 @@ class MessageDB():
path = GetPath( 'message', message_key )
with open( path, 'rb' ) as f: message = f.read()
with HC.o( path, 'rb' ) as f: message = f.read()
except: raise HydrusExceptions.NotFoundException( 'Could not find that message!' )
@ -466,7 +466,7 @@ class TagDB():
hash_ids = set( hash_ids ).difference( already_deleted )
now = int( time.time() )
now = HC.GetNow()
c.executemany( 'INSERT OR IGNORE INTO mappings ( service_id, tag_id, hash_id, account_id, timestamp ) VALUES ( ?, ?, ?, ?, ? );', [ ( service_id, tag_id, hash_id, account_id, now ) for hash_id in hash_ids ] )
@ -479,7 +479,7 @@ class TagDB():
c.execute( 'DELETE FROM mapping_petitions WHERE service_id = ? AND account_id = ? AND tag_id = ? AND hash_id IN ' + HC.SplayListForDB( valid_hash_ids ) + ' AND STATUS = ?;', ( service_id, account_id, tag_id, HC.PETITIONED ) )
now = int( time.time() )
now = HC.GetNow()
c.executemany( 'INSERT OR IGNORE INTO mapping_petitions ( service_id, account_id, tag_id, hash_id, reason_id, timestamp, status ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', [ ( service_id, account_id, tag_id, hash_id, reason_id, now, HC.PETITIONED ) for hash_id in valid_hash_ids ] )
@ -501,7 +501,7 @@ class TagDB():
c.execute( 'DELETE FROM tag_parents WHERE service_id = ? AND account_id = ? AND old_tag_id = ? AND new_tag_id = ? AND status = ?;', ( service_id, account_id, old_tag_id, new_tag_id, status ) )
now = int( time.time() )
now = HC.GetNow()
c.execute( 'INSERT OR IGNORE INTO tag_parents ( service_id, account_id, old_tag_id, new_tag_id, reason_id, status, timestamp ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', ( service_id, account_id, old_tag_id, new_tag_id, reason_id, status, now ) )
@ -523,7 +523,7 @@ class TagDB():
c.execute( 'DELETE FROM tag_siblings WHERE service_id = ? AND account_id = ? AND old_tag_id = ? AND new_tag_id = ? AND status = ?;', ( service_id, account_id, old_tag_id, new_tag_id, status ) )
now = int( time.time() )
now = HC.GetNow()
c.execute( 'INSERT OR IGNORE INTO tag_siblings ( service_id, account_id, old_tag_id, new_tag_id, reason_id, status, timestamp ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', ( service_id, account_id, old_tag_id, new_tag_id, reason_id, status, now ) )
@ -572,7 +572,7 @@ class TagDB():
if status == HC.PENDING: new_status = HC.CURRENT
elif status == HC.PETITIONED: new_status = HC.DELETED
now = int( time.time() )
now = HC.GetNow()
c.execute( 'INSERT OR IGNORE INTO tag_parents ( service_id, account_id, old_tag_id, new_tag_id, reason_id, status, timestamp ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', ( service_id, account_id, old_tag_id, new_tag_id, reason_id, new_status, now ) )
@ -605,7 +605,7 @@ class TagDB():
if status == HC.PENDING: new_status = HC.CURRENT
elif status == HC.PETITIONED: new_status = HC.DELETED
now = int( time.time() )
now = HC.GetNow()
c.execute( 'INSERT OR IGNORE INTO tag_siblings ( service_id, account_id, old_tag_id, new_tag_id, reason_id, status, timestamp ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', ( service_id, account_id, old_tag_id, new_tag_id, reason_id, new_status, now ) )
@ -621,7 +621,7 @@ class TagDB():
c.execute( 'DELETE FROM mappings WHERE service_id = ? AND tag_id = ? AND hash_id IN ' + splayed_hash_ids + ';', ( service_id, tag_id ) )
c.execute( 'DELETE FROM mapping_petitions WHERE service_id = ? AND tag_id = ? AND hash_id IN ' + splayed_hash_ids + ' AND status = ?;', ( service_id, tag_id, HC.PETITIONED ) )
c.executemany( 'INSERT OR IGNORE INTO mapping_petitions ( service_id, tag_id, hash_id, account_id, reason_id, timestamp, status ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', ( ( service_id, tag_id, hash_id, account_id, reason_id, int( time.time() ), HC.DELETED ) for hash_id in hash_ids ) )
c.executemany( 'INSERT OR IGNORE INTO mapping_petitions ( service_id, tag_id, hash_id, account_id, reason_id, timestamp, status ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', ( ( service_id, tag_id, hash_id, account_id, reason_id, HC.GetNow(), HC.DELETED ) for hash_id in hash_ids ) )
self._RefreshUpdateCache( c, service_id, affected_timestamps )
@ -923,7 +923,7 @@ class RatingDB():
hash_ids_to_new_timestamps = { hash_id : new_timestamp for ( hash_id, new_timestamp ) in c.execute( 'SELECT hash_id, new_timestamp FROM aggregate_ratings WHERE service_id = ? AND hash_id IN ' + HC.SplayListForDB( hash_ids ) + ';', ( service_id, ) ) }
now = int( time.time() )
now = HC.GetNow()
for ( hash_id, total_score, count ) in aggregates:
@ -947,7 +947,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
def _AccountTypeExists( self, c, service_id, title ): return c.execute( 'SELECT 1 FROM account_types, account_type_map USING ( account_type_id ) WHERE service_id = ? AND title = ?;', ( service_id, title ) ).fetchone() is not None
def _AddNews( self, c, service_id, news ): c.execute( 'INSERT INTO news ( service_id, news, timestamp ) VALUES ( ?, ?, ? );', ( service_id, news, int( time.time() ) ) )
def _AddNews( self, c, service_id, news ): c.execute( 'INSERT INTO news ( service_id, news, timestamp ) VALUES ( ?, ?, ? );', ( service_id, news, HC.GetNow() ) )
def _AddSession( self, c, session_key, service_identifier, account_identifier, expiry ):
@ -964,7 +964,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
splayed_subject_account_ids = HC.SplayListForDB( subject_account_ids )
now = int( time.time() )
now = HC.GetNow()
if expiration is not None: expires = expiration + now
else: expires = None
@ -1077,14 +1077,14 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
path = GetPath( 'update', update_key_bytes )
with open( path, 'wb' ) as f: f.write( yaml.safe_dump( clean_update ) )
with HC.o( path, 'wb' ) as f: f.write( yaml.safe_dump( clean_update ) )
c.execute( 'UPDATE update_cache SET dirty = ? WHERE service_id = ? AND begin = ?;', ( False, service_id, begin ) )
def _ClearBans( self, c ):
now = int( time.time() )
now = HC.GetNow()
c.execute( 'DELETE FROM bans WHERE expires < ?;', ( now, ) )
@ -1102,7 +1102,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
path = GetPath( 'update', update_key_bytes )
with open( path, 'wb' ) as f: f.write( yaml.safe_dump( update ) )
with HC.o( path, 'wb' ) as f: f.write( yaml.safe_dump( update ) )
c.execute( 'INSERT OR REPLACE INTO update_cache ( service_id, begin, end, update_key, dirty ) VALUES ( ?, ?, ?, ?, ? );', ( service_id, begin, end, update_key, False ) )
@ -1159,9 +1159,9 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
account_ids = self._GetAccountIds( c, access_keys )
now = int( time.time() )
now = HC.GetNow()
if expiration is not None: expires = expiration + int( time.time() )
if expiration is not None: expires = expiration + HC.GetNow()
else: expires = None
c.executemany( 'INSERT INTO account_map ( service_id, account_id, account_type_id, created, expires, used_bytes, used_requests ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', [ ( service_id, account_id, account_type_id, now, expires, 0, 0 ) for account_id in account_ids ] )
@ -1171,9 +1171,9 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
def _GenerateRegistrationKeys( self, c, service_id, num, account_type_id, expiration ):
now = int( time.time() )
now = HC.GetNow()
if expiration is not None: expiry = expiration + int( time.time() )
if expiration is not None: expiry = expiration + HC.GetNow()
else: expiry = None
keys = [ ( os.urandom( HC.HYDRUS_KEY_LENGTH ), os.urandom( HC.HYDRUS_KEY_LENGTH ) ) for i in range( num ) ]
@ -1331,7 +1331,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
result = c.execute( 'SELECT account_type_id FROM account_types, account_type_map USING ( account_type_id ) WHERE service_id = ? AND title = ?;', ( service_id, title ) ).fetchone()
if result is None: raise HydrusExceptions.NotFoundException( 'Could not find account title ' + str( title ) + ' in db for this service.' )
if result is None: raise HydrusExceptions.NotFoundException( 'Could not find account title ' + HC.u( title ) + ' in db for this service.' )
( account_type_id, ) = result
@ -1357,7 +1357,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
path = GetPath( 'update', update_key_bytes )
with open( path, 'rb' ) as f: update = f.read()
with HC.o( path, 'rb' ) as f: update = f.read()
return update
@ -1451,7 +1451,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
def _GetSessions( self, c ):
now = int( time.time() )
now = HC.GetNow()
c.execute( 'DELETE FROM sessions WHERE ? > expiry;', ( now, ) )
@ -1494,7 +1494,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
title = account_type.GetTitle()
if self._AccountTypeExists( c, service_id, title ): raise HydrusExceptions.ForbiddenException( 'Already found account type ' + str( title ) + ' in the db for this service, so could not add!' )
if self._AccountTypeExists( c, service_id, title ): raise HydrusExceptions.ForbiddenException( 'Already found account type ' + HC.u( title ) + ' in the db for this service, so could not add!' )
c.execute( 'INSERT OR IGNORE INTO account_types ( title, account_type ) VALUES ( ?, ? );', ( title, account_type ) )
@ -1523,7 +1523,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
title = account_type.GetTitle()
if old_title != title and self._AccountTypeExists( c, service_id, title ): raise HydrusExceptions.ForbiddenException( 'Already found account type ' + str( title ) + ' in the database, so could not rename ' + str( old_title ) + '!' )
if old_title != title and self._AccountTypeExists( c, service_id, title ): raise HydrusExceptions.ForbiddenException( 'Already found account type ' + HC.u( title ) + ' in the database, so could not rename ' + HC.u( old_title ) + '!' )
account_type_id = self._GetAccountTypeId( c, service_id, old_title )
@ -1534,7 +1534,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
def _ModifyServices( self, c, account_id, edit_log ):
now = int( time.time() )
now = HC.GetNow()
for ( action, data ) in edit_log:
@ -1545,7 +1545,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
service_type = service_identifier.GetType()
port = service_identifier.GetPort()
if c.execute( 'SELECT 1 FROM services WHERE port = ?;', ( port, ) ).fetchone() is not None: raise Exception( 'There is already a service hosted at port ' + str( port ) )
if c.execute( 'SELECT 1 FROM services WHERE port = ?;', ( port, ) ).fetchone() is not None: raise Exception( 'There is already a service hosted at port ' + HC.u( port ) )
c.execute( 'INSERT INTO services ( type, port, options ) VALUES ( ?, ?, ? );', ( service_type, port, yaml.safe_dump( HC.DEFAULT_OPTIONS[ service_type ] ) ) )
@ -1564,7 +1564,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
if service_type in HC.REPOSITORIES:
begin = 0
end = int( time.time() )
end = HC.GetNow()
self._CreateUpdate( c, service_id, begin, end )
@ -1575,7 +1575,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
service_id = self._GetServiceId( c, service_identifier )
if c.execute( 'SELECT 1 FROM services WHERE port = ?;', ( new_port, ) ).fetchone() is not None: raise Exception( 'There is already a service hosted at port ' + str( port ) )
if c.execute( 'SELECT 1 FROM services WHERE port = ?;', ( new_port, ) ).fetchone() is not None: raise Exception( 'There is already a service hosted at port ' + HC.u( port ) )
c.execute( 'UPDATE services SET port = ? WHERE service_id = ?;', ( new_port, service_id ) )
@ -1661,7 +1661,7 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
account_id = c.lastrowid
now = int( time.time() )
now = HC.GetNow()
c.execute( 'INSERT INTO account_map ( service_id, account_id, account_type_id, created, expires, used_bytes, used_requests ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', ( service_id, account_id, account_type_id, now, expiry, 0, 0 ) )
@ -1719,7 +1719,7 @@ class DB( ServiceDB ):
already_running = False
if already_running: raise Exception( 'The server appears to be running already!' + os.linesep + 'Either that, or something else is using port ' + str( port ) + '.' )
if already_running: raise Exception( 'The server appears to be running already!' + os.linesep + 'Either that, or something else is using port ' + HC.u( port ) + '.' )
service_id = self._GetServiceId( c, service_identifier )
@ -1785,7 +1785,7 @@ class DB( ServiceDB ):
c.execute( 'PRAGMA auto_vacuum = 0;' ) # none
c.execute( 'PRAGMA journal_mode=WAL;' )
now = int( time.time() )
now = HC.GetNow()
c.execute( 'CREATE TABLE services ( service_id INTEGER PRIMARY KEY, type INTEGER, port INTEGER, options TEXT_YAML );' )
@ -2005,7 +2005,7 @@ class DB( ServiceDB ):
#
now = int( time.time() )
now = HC.GetNow()
#
@ -2125,7 +2125,7 @@ class DB( ServiceDB ):
path_to = HC.SERVER_FILES_DIR + os.path.sep + hash.encode( 'hex' )
with open( path_to, 'wb' ) as f: f.write( file )
with HC.o( path_to, 'wb' ) as f: f.write( file )
c.execute( 'DELETE FROM files WHERE hash_id IN ' + HC.SplayListForDB( local_files_subset ) + ';' )
@ -2170,7 +2170,7 @@ class DB( ServiceDB ):
path_to = HC.SERVER_THUMBNAILS_DIR + os.path.sep + hash.encode( 'hex' )
with open( path_to, 'wb' ) as f: f.write( thumbnail )
with HC.o( path_to, 'wb' ) as f: f.write( thumbnail )
@ -2256,7 +2256,7 @@ class DB( ServiceDB ):
update_key = update_key_bytes.encode( 'hex' )
with open( HC.SERVER_UPDATES_DIR + os.path.sep + update_key, 'wb' ) as f: f.write( update )
with HC.o( HC.SERVER_UPDATES_DIR + os.path.sep + update_key, 'wb' ) as f: f.write( update )
c.execute( 'INSERT INTO update_cache ( service_id, begin, end, update_key, dirty ) VALUES ( ?, ?, ?, ?, ? );', ( service_id, begin, end, update_key, dirty ) )
@ -2388,7 +2388,7 @@ class DB( ServiceDB ):
for ( service_id, biggest_end ) in update_ends:
now = int( time.time() )
now = HC.GetNow()
next_begin = biggest_end + 1
next_end = biggest_end + HC.UPDATE_DURATION
@ -2399,7 +2399,7 @@ class DB( ServiceDB ):
biggest_end = next_end
now = int( time.time() )
now = HC.GetNow()
next_begin = biggest_end + 1
next_end = biggest_end + HC.UPDATE_DURATION
@ -2500,11 +2500,11 @@ class DB( ServiceDB ):
max_age = 30 * 86400
expiry = int( time.time() ) + max_age
expiry = HC.GetNow() + max_age
HC.app.AddSession( session_key, service_identifier, account_identifier, expiry )
cookies = [ 'session_key=' + session_key.encode( 'hex' ) + '; Max-Age=' + str( max_age ) + '; Path=/' ]
cookies = [ 'session_key=' + session_key.encode( 'hex' ) + '; Max-Age=' + HC.u( max_age ) + '; Path=/' ]
response_context = HC.ResponseContext( 200, mime = HC.APPLICATION_YAML, body = '', cookies = cookies )
@ -2810,6 +2810,8 @@ class DB( ServiceDB ):
options = request_args[ 'options' ]
service_identifier = self._GetServiceIdentifier( c, service_id )
self._SetOptions( c, service_id, service_identifier, options )
elif request == 'services_modification':

View File

@ -0,0 +1,105 @@
import ClientDB
import collections
import HydrusConstants as HC
import os
import TestConstants
import unittest
class TestDaemons( unittest.TestCase ):
def test_import_folders_daemon( self ):
test_dir = HC.TEMP_DIR + os.path.sep + 'test'
if not os.path.exists( test_dir ): os.mkdir( test_dir )
with HC.o( test_dir + os.path.sep + '1', 'wb' ) as f: f.write( TestConstants.tinest_gif )
with HC.o( test_dir + os.path.sep + '2', 'wb' ) as f: f.write( TestConstants.tinest_gif )
with HC.o( test_dir + os.path.sep + '3', 'wb' ) as f: f.write( TestConstants.tinest_gif )
with HC.o( test_dir + os.path.sep + '4', 'wb' ) as f: f.write( 'blarg' ) # broken
with HC.o( test_dir + os.path.sep + '5', 'wb' ) as f: f.write( TestConstants.tinest_gif ) # previously failed for whatever reason
#
path = test_dir
details = {}
details[ 'type' ] = HC.IMPORT_FOLDER_TYPE_SYNCHRONISE
details[ 'cached_imported_paths' ] = { test_dir + os.path.sep + '2' }
details[ 'failed_imported_paths' ] = { test_dir + os.path.sep + '5' }
details[ 'local_tag' ] = 'local tag'
details[ 'last_checked' ] = HC.GetNow() - 1500
details[ 'check_period' ] = 1000
old_details = dict( details )
HC.app.SetRead( 'import_folders', [ ( path, details ) ] )
ClientDB.DAEMONCheckImportFolders()
expected_import_file = [(('GIF89a\x01\x00\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x00;',), {'service_identifiers_to_tags': {HC.LOCAL_TAG_SERVICE_IDENTIFIER: set(['local tag'])}}), (('GIF89a\x01\x00\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x00;',), {'service_identifiers_to_tags': {HC.LOCAL_TAG_SERVICE_IDENTIFIER: set(['local tag'])}}), (('blarg',), {'service_identifiers_to_tags': {HC.LOCAL_TAG_SERVICE_IDENTIFIER: set(['local tag'])}})]
import_file = HC.app.GetWrite( 'import_file' )
self.assertEqual( import_file, expected_import_file )
[ ( ( updated_path, updated_details ), kwargs ) ] = HC.app.GetWrite( 'import_folder' )
self.assertEqual( path, updated_path )
self.assertEqual( updated_details[ 'type' ], old_details[ 'type' ] )
self.assertEqual( updated_details[ 'cached_imported_paths' ], { test_dir + os.path.sep + '1', test_dir + os.path.sep + '2', test_dir + os.path.sep + '3' } )
self.assertEqual( updated_details[ 'failed_imported_paths' ], { test_dir + os.path.sep + '4', test_dir + os.path.sep + '5' } )
self.assertEqual( updated_details[ 'local_tag' ], old_details[ 'local_tag' ] )
self.assertGreater( updated_details[ 'last_checked' ], old_details[ 'last_checked' ] )
self.assertEqual( updated_details[ 'check_period' ], old_details[ 'check_period' ] )
#
path = test_dir
details = {}
details[ 'type' ] = HC.IMPORT_FOLDER_TYPE_DELETE
details[ 'cached_imported_paths' ] = set()
details[ 'failed_imported_paths' ] = { test_dir + os.path.sep + '5' }
details[ 'local_tag' ] = 'local tag'
details[ 'last_checked' ] = HC.GetNow() - 1500
details[ 'check_period' ] = 1000
old_details = dict( details )
HC.app.SetRead( 'import_folders', [ ( path, details ) ] )
ClientDB.DAEMONCheckImportFolders()
expected_import_file = [(('GIF89a\x01\x00\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x00;',), {'service_identifiers_to_tags': {HC.LOCAL_TAG_SERVICE_IDENTIFIER: set(['local tag'])}}), (('GIF89a\x01\x00\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x00;',), {'service_identifiers_to_tags': {HC.LOCAL_TAG_SERVICE_IDENTIFIER: set(['local tag'])}}), (('GIF89a\x01\x00\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x00;',), {'service_identifiers_to_tags': {HC.LOCAL_TAG_SERVICE_IDENTIFIER: set(['local tag'])}}), (('blarg',), {'service_identifiers_to_tags': {HC.LOCAL_TAG_SERVICE_IDENTIFIER: set(['local tag'])}})]
import_file = HC.app.GetWrite( 'import_file' )
self.assertEqual( import_file, expected_import_file )
[ ( ( updated_path, updated_details ), kwargs ) ] = HC.app.GetWrite( 'import_folder' )
self.assertEqual( path, updated_path )
self.assertEqual( updated_details[ 'type' ], old_details[ 'type' ] )
self.assertEqual( updated_details[ 'cached_imported_paths' ], set() )
self.assertEqual( updated_details[ 'failed_imported_paths' ], { test_dir + os.path.sep + '4', test_dir + os.path.sep + '5' } )
self.assertEqual( updated_details[ 'local_tag' ], old_details[ 'local_tag' ] )
self.assertGreater( updated_details[ 'last_checked' ], old_details[ 'last_checked' ] )
self.assertEqual( updated_details[ 'check_period' ], old_details[ 'check_period' ] )
self.assertTrue( not os.path.exists( test_dir + os.path.sep + '1' ) )
self.assertTrue( not os.path.exists( test_dir + os.path.sep + '2' ) )
self.assertTrue( not os.path.exists( test_dir + os.path.sep + '3' ) )
self.assertTrue( os.path.exists( test_dir + os.path.sep + '4' ) )
self.assertTrue( os.path.exists( test_dir + os.path.sep + '5' ) )
os.remove( test_dir + os.path.sep + '4' )
os.remove( test_dir + os.path.sep + '5' )
os.rmdir( test_dir )

View File

@ -3,7 +3,9 @@ import HydrusConstants as HC
import HydrusTags
import os
import random
import TestConstants
import urlparse
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'
def GenerateClientServiceIdentifier( service_type ):
@ -16,4 +18,100 @@ def GenerateClientServiceIdentifier( service_type ):
return HC.ClientServiceIdentifier( service_key, service_type, service_name )
class FakeFile():
def __init__( self, data ):
self._data = data
def __enter__( self ): return self
def __exit__( self, exc_type, exc_value, traceback ): return True
def read( self ): return self._data
def write( self, data ): self._data = data
class FakeFileManager():
def __init__( self ):
self._fake_files = {}
def GetFile( self, path, access_type ): return self._fake_files[ path ]
def SetFile( self, path, fake_file ): self._fake_files[ path ] = fake_file
fake_file_manager = FakeFileManager()
class FakeHTTPConnection():
def __init__( self, url = '', scheme = 'http', host = '', port = None, service_identifier = None, accept_cookies = False ):
self._url = url
self._scheme = scheme
self._host = host
self._port = port
self._service_identifier = service_identifier
self._accept_cookies = accept_cookies
self._responses = {}
self._cookies = {}
def close( self ): pass
def connect( self ): pass
def GetCookies( self ): return self._cookies
def geturl( self, url, headers = {}, is_redirect = False, follow_redirects = True ):
parse_result = urlparse.urlparse( url )
request = parse_result.path
query = parse_result.query
if query != '': request += '?' + query
return self.request( 'GET', request, headers = headers, is_redirect = is_redirect, follow_redirects = follow_redirects )
def request( self, request_type, request, headers = {}, body = None, is_redirect = False, follow_redirects = True ):
response = self._responses[ ( request_type, request ) ]
if issubclass( type( response ), Exception ): raise response
else: return response
def SetCookie( self, key, value ): self._cookies[ key ] = value
def SetResponse( self, request_type, request, response ): self._responses[ ( request_type, request ) ] = response
class FakeHTTPConnectionManager():
def __init__( self ):
self._fake_connections = {}
def GetConnection( self, url = '', scheme = 'http', host = '', port = None, service_identifier = None, accept_cookies = False ):
args = ( url, scheme, host, port, service_identifier, accept_cookies )
return self._fake_connections[ args ]
def SetConnection( self, connection, url = '', scheme = 'http', host = '', port = None, service_identifier = None, accept_cookies = False ):
args = ( url, scheme, host, port, service_identifier, accept_cookies )
self._fake_connections[ args ] = connection
fake_http_connection_manager = FakeHTTPConnectionManager()

View File

@ -1,13 +1,4 @@
import TestConstants
import unittest
class TestDB( unittest.TestCase ): pass
if __name__ == '__main__':
app = TestConstants.TestController()
unittest.main( verbosity = 2, exit = False )
raw_input()
class TestDB( unittest.TestCase ): pass

View File

@ -1,4 +1,4 @@
import ClientConstants
import ClientConstants as CC
import ClientGUIDialogs
import collections
import HydrusConstants as HC
@ -9,7 +9,33 @@ import wx
def HitButton( button ): wx.PostEvent( button, wx.CommandEvent( wx.EVT_BUTTON.typeId, button.GetId() ) )
class TestNonValidatorDialogs( unittest.TestCase ):
def PressKey( window, key ):
event = wx.KeyEvent( wx.EVT_KEY_DOWN.typeId )
event.m_keyCode = key
event.SetEventObject( window )
event.SetId( window.GetId() )
wx.PostEvent( window, event )
class TestDBDialogs( unittest.TestCase ):
def test_dialog_select_booru( self ):
HC.app.SetRead( 'boorus', CC.DEFAULT_BOORUS )
with ClientGUIDialogs.DialogSelectBooru( None ) as dlg:
HitButton( dlg._dialog_cancel_button )
result = dlg.ShowModal()
self.assertEqual( result, wx.ID_CANCEL )
class TestNonDBDialogs( unittest.TestCase ):
def test_dialog_choose_new_service_method( self ):
@ -41,7 +67,7 @@ class TestNonValidatorDialogs( unittest.TestCase ):
with ClientGUIDialogs.DialogChooseNewServiceMethod( None ) as dlg:
HitButton( dlg._cancel )
HitButton( dlg._dialog_cancel_button )
result = dlg.ShowModal()
@ -113,7 +139,7 @@ class TestNonValidatorDialogs( unittest.TestCase ):
with ClientGUIDialogs.DialogFirstStart( None ) as dlg:
HitButton( dlg._cancel )
HitButton( dlg._dialog_cancel_button )
result = dlg.ShowModal()
@ -141,4 +167,66 @@ class TestNonValidatorDialogs( unittest.TestCase ):
self.assertEqual( result, wx.ID_CANCEL )
def test_select_from_list_of_strings( self ):
with ClientGUIDialogs.DialogSelectFromListOfStrings( None, 'select from a list of strings', [ 'a', 'b', 'c' ] ) as dlg:
wx.CallAfter( dlg._strings.Select, 0 )
PressKey( dlg._strings, wx.WXK_SPACE )
result = dlg.ShowModal()
self.assertEqual( result, wx.ID_OK )
value = dlg.GetString()
self.assertEqual( value, 'a' )
with ClientGUIDialogs.DialogSelectFromListOfStrings( None, 'select from a list of strings', [ 'a', 'b', 'c' ] ) as dlg:
HitButton( dlg._dialog_cancel_button )
result = dlg.ShowModal()
self.assertEqual( result, wx.ID_CANCEL )
with ClientGUIDialogs.DialogSelectFromListOfStrings( None, 'select from a list of strings', [ 'a', 'b', 'c' ] ) as dlg:
wx.CallAfter( dlg._strings.Select, 1 )
HitButton( dlg._ok )
result = dlg.ShowModal()
self.assertEqual( result, wx.ID_OK )
value = dlg.GetString()
self.assertEqual( value, 'b' )
def test_dialog_yes_no( self ):
with ClientGUIDialogs.DialogYesNo( None, 'hello' ) as dlg:
HitButton( dlg._yes )
result = dlg.ShowModal()
self.assertEqual( result, wx.ID_YES )
with ClientGUIDialogs.DialogYesNo( None, 'hello' ) as dlg:
HitButton( dlg._no )
result = dlg.ShowModal()
self.assertEqual( result, wx.ID_NO )

View File

@ -0,0 +1,64 @@
import collections
import HydrusConstants as HC
import HydrusDownloading
import os
import TestConstants
import unittest
class TestDownloaders( unittest.TestCase ):
def test_newgrounds( self ):
with HC.o( HC.STATIC_DIR + os.path.sep + 'testing' + os.path.sep + 'newgrounds_gallery_games.html' ) as f: newgrounds_gallery_games = f.read()
with HC.o( HC.STATIC_DIR + os.path.sep + 'testing' + os.path.sep + 'newgrounds_gallery_movies.html' ) as f: newgrounds_gallery_movies = f.read()
fake_connection = TestConstants.FakeHTTPConnection( host = 'warlord-of-noodles.newgrounds.com' )
fake_connection.SetResponse( 'GET', '/games/', newgrounds_gallery_games )
fake_connection.SetResponse( 'GET', '/movies/', newgrounds_gallery_movies )
TestConstants.fake_http_connection_manager.SetConnection( fake_connection, host = 'warlord-of-noodles.newgrounds.com' )
HC.get_connection = TestConstants.fake_http_connection_manager.GetConnection
#
downloader = HydrusDownloading.DownloaderNewgrounds( 'warlord-of-noodles' )
#
gallery_urls = downloader.GetAnotherPage()
expected_gallery_urls = [('http://www.newgrounds.com/portal/view/621259',), ('http://www.newgrounds.com/portal/view/617915',), ('http://www.newgrounds.com/portal/view/612665',), ('http://www.newgrounds.com/portal/view/610813',), ('http://www.newgrounds.com/portal/view/609683',), ('http://www.newgrounds.com/portal/view/593806',), ('http://www.newgrounds.com/portal/view/606387',), ('http://www.newgrounds.com/portal/view/606111',), ('http://www.newgrounds.com/portal/view/604603',), ('http://www.newgrounds.com/portal/view/604152',), ('http://www.newgrounds.com/portal/view/603027',), ('http://www.newgrounds.com/portal/view/601680',), ('http://www.newgrounds.com/portal/view/600626',), ('http://www.newgrounds.com/portal/view/591049',), ('http://www.newgrounds.com/portal/view/583715',), ('http://www.newgrounds.com/portal/view/584272',), ('http://www.newgrounds.com/portal/view/577497',), ('http://www.newgrounds.com/portal/view/563780',), ('http://www.newgrounds.com/portal/view/562785',), ('http://www.newgrounds.com/portal/view/553298',), ('http://www.newgrounds.com/portal/view/550882',), ('http://www.newgrounds.com/portal/view/488200',), ('http://www.newgrounds.com/portal/view/509249',), ('http://www.newgrounds.com/portal/view/509175',), ('http://www.newgrounds.com/portal/view/488180',)]
self.assertEqual( gallery_urls, expected_gallery_urls )
#
with HC.o( HC.STATIC_DIR + os.path.sep + 'testing' + os.path.sep + 'newgrounds_page.html' ) as f: newgrounds_page = f.read()
fake_connection = TestConstants.FakeHTTPConnection( host = 'www.newgrounds.com' )
fake_connection.SetResponse( 'GET', '/portal/view/583715', newgrounds_page )
TestConstants.fake_http_connection_manager.SetConnection( fake_connection, host = 'www.newgrounds.com' )
fake_connection = TestConstants.FakeHTTPConnection( host = 'uploads.ungrounded.net' )
fake_connection.SetResponse( 'GET', '/583000/583715_catdust.swf', 'swf file' )
TestConstants.fake_http_connection_manager.SetConnection( fake_connection, host = 'uploads.ungrounded.net' )
info = downloader.GetFileAndTags( 'http://www.newgrounds.com/portal/view/583715' )
expected_info = ('swf file', set([u'chores', u'laser', u'silent', u'title:Cat Dust', u'creator:warlord-of-noodles', u'pointer']))
self.assertEqual( info, expected_info )
# check the swf url and tags are correct
#
HC.get_connection = HC.AdvancedHTTPConnection

View File

@ -68,7 +68,9 @@ class TestMergeTagsManagers( unittest.TestCase ):
#
self.assertEqual( tags_manager.GetCSTVCP(), ( { 'tsutomu nihei' }, { 'blame!' }, { 'double page spread' }, { 3 }, { 1, 2 }, { 4, 5 } ) )
result = { 'creator' : { 'tsutomu nihei' }, 'series' : { 'blame!' }, 'title' : { 'double page spread' }, 'volume' : { 3 }, 'chapter' : { 1, 2 }, 'page' : { 4, 5 } }
self.assertEqual( tags_manager.GetCombinedNamespaces( ( 'creator', 'series', 'title', 'volume', 'chapter', 'page' ) ), result )
self.assertEqual( tags_manager.GetNamespaceSlice( ( 'character', ) ), frozenset( { 'character:cibo' } ) )
@ -130,8 +132,9 @@ class TestTagsManager( unittest.TestCase ):
def test_get_cstvcp( self ):
# volume, chapter and page can only return numbers, so broken_volume etc. are discarded
self.assertEqual( self._tags_manager.GetCSTVCP(), ( { 'tsutomu nihei' }, { 'blame!' }, { 'test title' }, { 3 }, { 2 }, { 1 } ) )
result = { 'creator' : { 'tsutomu nihei' }, 'series' : { 'blame!' }, 'title' : { 'test title' }, 'volume' : { 3 }, 'chapter' : { 2 }, 'page' : { 1 } }
self.assertEqual( self._tags_manager.GetCombinedNamespaces( ( 'creator', 'series', 'title', 'volume', 'chapter', 'page' ) ), result )
def test_delete_pending( self ):

View File

@ -66,7 +66,7 @@ def __is_number_start(text):
# End of Assume
def base10 (text,base):
number = str(text).lower()
number = HC.u(text).lower()
result=0L
for digit in number:
result*=base

View File

@ -14,22 +14,33 @@ import locale
locale.setlocale( locale.LC_ALL, '' )
import os
import sys
from include import HydrusConstants as HC
from include import ServerController
try:
app = ServerController.Controller( True, HC.LOGS_DIR + os.path.sep + 'server.log' )
app.MainLoop()
except:
import traceback
print( traceback.format_exc() )
initial_sys_stdout = sys.stdout
initial_sys_stderr = sys.stderr
try: HC.shutdown = True
except: pass
with HC.o( HC.LOGS_DIR + os.path.sep + 'server.log', 'a' ) as f:
sys.stdout = f
sys.stderr = f
try:
app = ServerController.Controller()
app.MainLoop()
except:
import traceback
print( traceback.format_exc() )
sys.stdout = initial_sys_stdout
sys.stderr = initial_sys_stderr
HC.shutdown = True
HC.pubsub.pubimmediate( 'shutdown' )

View File

@ -0,0 +1,536 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Warlord-of-Noodles's Games</title>
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge" /><![endif]-->
<link rel="stylesheet" href="http://css.ngfiles.com/ng_publish.css?1374679673" type="text/css" media="all" /> <link rel="stylesheet" href="http://css.ngfiles.com/iphone.css?1328564601" type="text/css" media="only screen and (max-device-width: 480px)" /> <link rel="stylesheet" href="http://css.ngfiles.com/print.css?1328564601" type="text/css" media="print" />
<!--[if lte IE 8]>
<script type="text/javascript">
// <![CDATA[
PHP.set('is_ie', true);
// ]]>
</script>
<![endif]-->
<!--[if lte IE 9]>
<link rel="stylesheet" href="http://css.ngfiles.com/ie9.css?1328656560" type="text/css" media="screen" />
<![endif]-->
<!--[if lte IE 8]>
<link rel="stylesheet" href="http://css.ngfiles.com/ie8.css?1337819134" type="text/css" media="screen" />
<![endif]-->
<!--[if lte IE 7]>
<link rel="stylesheet" href="http://css.ngfiles.com/ie7.css?1328564601" type="text/css" media="screen" />
<![endif]-->
<!--[if lte IE 6]>
<link rel="stylesheet" href="http://css.ngfiles.com/ie6.css?1328564286" type="text/css" media="screen" />
<![endif]-->
<style type="text/css">
/* this way the menus work with or without the javascript working */
#header dl dd {
display: none;
}
#header dl:hover dd {
/*display: block; */
}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
// <![CDATA[
if (!window.jQuery) {
document.write('<script src="http://js.ngfiles.com/jquery/jquery.js" type="text/javascript"><\/script>');
}
// ]]>
</script>
<script type="text/javascript" src="http://js.ngfiles.com/ng_publish.js?1374772896"></script>
<script type="text/javascript" src="http://js.ngfiles.com/css_browser_selector.js"></script>
<script type="text/javascript">
// <![CDATA[
var $ng_adcode_ctime = 1375211106;
var $ng_adcode_country = 2;
var $ng_adcode_revsharing_id = null;
var $ng_adcode_page = "userpages";
var $ng_adcode_suitability = "T";
//]]>
</script>
<link rel="icon" type="image/png" href="http://www.newgrounds.com/img/icons/favicon.png" />
<link rel="shortcut icon" href="http://www.newgrounds.com/favicon.ico" type="image/vnd.microsoft.icon" />
<link rel="apple-touch-icon" href="http://img.ngfiles.com/misc/newgrounds_webclip.png" />
<meta http-equiv="content-type" content="text/html; charset=windows-1252" />
<meta name="viewport" content="width=976" />
<script type="text/javascript">
var $ng_adcode_user_is_supporter = 0;
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-850825-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div id="blackout" style="display: none">
<div id="blackout_bg"></div>
<div class="pagecentered" id="blackout_center">
</div>
</div>
<a href="#main" class="skipto">Skip to content.</a>
<div id="outer" >
<div id="header" class="header">
<div class="siteinfo">
<h1><a href="http://www.newgrounds.com">Newgrounds.com &mdash; Everything, By Everyone.</a></h1>
<div class="navigation">
<div class="navbar" id="header_nav">
<dl id="games">
<dt><a href="http://www.newgrounds.com/games">Games</a></dt>
<dd><a href="http://www.newgrounds.com/games/browse">Latest</a></dd>
<dd><a href="http://www.newgrounds.com/games/browse/sort/score/interval/month">Greatest</a></dd>
<dd><a href="http://www.newgrounds.com/games/browse/sort/views/interval/week">Popular</a></dd>
<dd><a href="http://www.newgrounds.com/games/under_judgment">Under Judgment</a></dd>
<dd><a href="http://www.newgrounds.com/portal">Classic Portal</a></dd>
<dd><a href="http://www.newgrounds.com/projects/games"><em>Submit Yours!</em></a></dd>
<dd><a href="http://www.newgrounds.com/collab/browse/programmer"><em>Team Up!</em></a></dd>
</dl>
<dl id="movies">
<dt><a href="http://www.newgrounds.com/movies">Movies</a></dt>
<dd><a href="http://www.newgrounds.com/movies/browse">Latest</a></dd>
<dd><a href="http://www.newgrounds.com/movies/browse/sort/score/interval/month">Greatest</a></dd>
<dd><a href="http://www.newgrounds.com/movies/browse/sort/views/interval/week">Popular</a></dd>
<dd><a href="http://www.newgrounds.com/movies/under_judgment">Under Judgment</a></dd>
<dd><a href="http://www.newgrounds.com/portal">Classic Portal</a></dd>
<dd><a href="http://www.newgrounds.com/projects/movies"><em>Submit Yours!</em></a></dd>
<dd><a href="http://www.newgrounds.com/collab/browse/artist"><em>Team Up!</em></a></dd>
</dl>
<dl id="audio">
<dt><a href="http://www.newgrounds.com/audio">Audio</a></dt>
<dd><a href="http://www.newgrounds.com/audio/browse/sort/date">Latest</a></dd>
<dd><a href="http://www.newgrounds.com/audio/browse/sort/score/interval/month">Greatest</a></dd>
<dd><a href="http://www.newgrounds.com/audio/browse/sort/views/interval/week">Popular</a></dd>
<dd><a href="http://www.newgrounds.com/bbs/forum/13">Audio Forum</a></dd>
<dd><a href="http://www.newgrounds.com/projects/audio"><em>Submit Yours!</em></a></dd>
<dd><a href="http://www.newgrounds.com/collab/browse/musician"><em>Team Up!</em></a></dd>
</dl>
<dl id="art">
<dt><a href="http://www.newgrounds.com/art">Art</a></dt>
<dd><a href="http://www.newgrounds.com/art/browse">Latest</a></dd>
<dd><a href="http://www.newgrounds.com/art/browse/sort/score/interval/month">Greatest</a></dd>
<dd><a href="http://www.newgrounds.com/art/browse/sort/views/interval/week">Popular</a></dd>
<dd><a href="http://www.newgrounds.com/bbs/forum/14">Art Forum</a></dd>
<dd><a href="http://www.newgrounds.com/art/submit/create"><em>Submit Yours!</em></a></dd>
<dd><a href="http://www.newgrounds.com/collab/browse/artist"><em>Team Up!</em></a></dd>
</dl>
<dl id="channels">
<dt><a href="http://www.newgrounds.com/collection">Channels</a></dt>
<dd><a href="http://www.newgrounds.com/collection/series">Series</a></dd>
<dd><a href="http://www.newgrounds.com/collection">Collections</a></dd>
<dd><a href="http://www.newgrounds.com/movies/under_judgment">Judgment</a></dd>
<dd><a href="http://www.newgrounds.com/playlists">Playlists</a></dd>
</dl>
<dl id="community">
<dt><a href="http://www.newgrounds.com/bbs">Community</a></dt>
<dd><a href="http://www.newgrounds.com/bbs">Forums</a></dd>
<dd><a href="http://chat.newgrounds.com">Chat</a></dd>
<dd><a href="http://www.newgrounds.com/calendar">Calendar</a></dd>
<dd><a href="http://www.newgrounds.com/news/artists">Artist News</a></dd>
<dd><a href="http://www.newgrounds.com/rankings">Rankings</a></dd>
<dd><a href="http://www.newgrounds.com/downloads">Downloads</a></dd>
<dd><a href="http://www.newgrounds.com/wiki">Wiki</a></dd>
</dl>
<dl id="shop">
<dt><a href="http://www.newgrounds.com/store">Shop</a></dt>
<dd><a href="http://www.newgrounds.com/store/category/apparel">T-Shirts</a></dd>
<dd><a href="http://www.newgrounds.com/store/category/collectible">Collectibles</a></dd>
<dd><a href="http://www.newgrounds.com/store/category/print">Print</a></dd>
<dd><a href="http://www.newgrounds.com/store/category/disc">Discs</a></dd>
</dl>
</div>
</div>
<h6>
<a href="http://qikalain.newgrounds.com">Wall Artist</a> </h6>
</div>
<div class="sitelinks">
<form id="loginboxform" action="https://www.newgrounds.com/login" method="post" class="loginbox">
<label id="header_label_username" for="username" style="display:none">Username</label>
<input type="text" maxlength="20" id="username" name="username" value="" />
<label id="header_label_password" for="password" style="display:none">Password</label>
<input type="password" maxlength="32" id="password" name="password" />
<input type="hidden" name="referrer" value="http://warlord-of-noodles.newgrounds.com/games" />
<div class="checkboxes">
<input type="checkbox" value="on" id="remember" name="remember" />
<span><label for="remember">Save Info?</label></span>
</div>
<button type="submit">Log In</button>
<ul class="loginlinks">
<li><a href="http://www.newgrounds.com/join">Not a member? Sign Up!</a></li>
<li><a href="http://www.newgrounds.com/join/forgot">Forgot login?</a></li>
</ul>
</form>
<form class="search" id="topsearch" action="http://www.newgrounds.com/search" method="get">
<input type="text" name="topsearch_text" id="topsearch_text" />
<div class="select">
<div></div>
<span>Movies</span>
<select class="formtext" name="topsearch_type" id="topsearch_type">
<option value="16">Games</option>
<option value="15" selected="selected">Movies</option>
<option value="17">Audio</option>
<option value="14">Art</option>
<option value="4">Forums</option> </select>
</div>
<button type="submit">Search</button>
</form>
<script type="text/javascript">
// <![CDATA[
PHP.set('search_urls', {"16":"http:\/\/www.newgrounds.com\/portal\/search\/games","15":"http:\/\/www.newgrounds.com\/portal\/search\/movies","17":"http:\/\/www.newgrounds.com\/audio\/search\/title","14":"http:\/\/www.newgrounds.com\/art\/search","4":"http:\/\/www.newgrounds.com\/bbs\/search\/topic","9":"http:\/\/www.newgrounds.com\/users\/search"});
// ]]>
</script>
</div>
</div>
<div class="headerads">
<!-- include ads here -->
<div style='display:none' class='adcode_container'>top-superbanner:728x90</div> <div style="display:none" class="storead_container">212:90:0</div> </div>
<div id="main">
<div class="three3">
<div class="podtop userheader">
<h2 class="empty" id="page_username"><img src="http://uimg.ngfiles.com/icons/2785/2785798_small.jpg" alt="Warlord-of-Noodles" width="25" height="25" title="" />Warlord-of-Noodles</h2>
<div>
<a href="/"><span>Main</span></a>
<a href="/news/"><span>News</span></a>
<a href="/movies/"><span>Movies</span></a>
<a ><span>Games</span></a>
<a href="/art/"><span>Art</span></a>
<a href="/favorites/"><span>Favorites</span></a>
<a href="/reviews/"><span>Reviews</span></a>
<a href="/stats/"><span>Stats</span></a>
<a href="/fans/"><span>2,357 Fans</span></a>
<a title="Manage Favorites" href="http://&lt;deleted&gt;.newgrounds.com/favorites/following"
id="manage_favorites" class="fave" style="display: none">
<span></span>
<span class="hovertext"><span>Manage Favorites</span></span>
</a>
<script type="text/javascript" src="http://js.ngfiles.com/portal/favorites.js"></script>
<form method="post" action="/follow" id="follow_user" class="fave">
<input type="hidden" name="userkey" id="userkey" value="e7ae1%O825db0362509%14b6O9b47c7ac6c%Pc225cr75%%d2c9a4%7%1%105%e25fs948c5c0dO9e52r7732rs%3fe6e7%%sc%6%1d9db5d70d3r7Pa18e%6frPfb2b1ecr06e06eab28e914d426938429b15f15665%s%4d7P%%O%rr5791-3443319" /> <input type="hidden" value="30" name="fav_type" />
<input type="hidden" name="id" value="2785798" />
<button type="submit" name="submit_favorite"><span></span></button>
<span class="hovertext">
<span>Follow Warlord-of-Noodles</span>
</span>
</form>
<script type="text/javascript">
listen_follow('#follow_user', '#manage_favorites');
</script>
</div>
</div>
</div>
<div class="thincol">
<div style='display:none' class='adcode_container'>left-rectangle:300x250</div>
<div class="one3">
<div class="podtop">
<h2 class="info">Contact Info / Websites</h2>
<div>
</div>
</div>
<div class="podcontent">
<ul class="blocklist">
<li class="mail"><a href="http://www.newgrounds.com/pm/send/warlord-of-noodles">Send a Private Message (PM)</a></li>
</ul>
</div>
<div class="podcontent">
<ol class="website-links">
<li><a href="http://www.betsydraws.com/" target="_blank" rel="nofollow"><img alt="www.betsydraws.com" src="http://s2.googleusercontent.com/s2/favicons?domain=www.betsydraws.com&amp;feature=newgrounds" /> www.betsydraws.com</a></li>
<li><a href="http://warlordofnoodles.comicgenesis.com/" target="_blank" rel="nofollow"><img alt="warlordofnoodles.comicgenesis.com" src="http://s2.googleusercontent.com/s2/favicons?domain=warlordofnoodles.comicgenesis.com&amp;feature=newgrounds" /> Brother Swan</a></li>
<li><a href="http://www.youtube.com/user/LadyCelest" target="_blank" rel="nofollow"><img alt="www.youtube.com" src="http://s2.googleusercontent.com/s2/favicons?domain=www.youtube.com&amp;feature=newgrounds" /> My Youtube</a></li>
<li><a href="http://warlord-of-noodles.deviantart.com/" target="_blank" rel="nofollow"><img alt="warlord-of-noodles.deviantart.com" src="http://s2.googleusercontent.com/s2/favicons?domain=warlord-of-noodles.deviantart.com&amp;feature=newgrounds" /> My Deviant Art</a></li>
<li><a href="https://twitter.com/#!/Warlordofnoodle" target="_blank" rel="nofollow"><img alt="twitter.com" src="http://s2.googleusercontent.com/s2/favicons?domain=twitter.com&amp;feature=newgrounds" /> My Twitter</a></li>
<li><a href="http://brotherswan.proboards.com/" target="_blank" rel="nofollow"><img alt="brotherswan.proboards.com" src="http://s2.googleusercontent.com/s2/favicons?domain=brotherswan.proboards.com&amp;feature=newgrounds" /> My Stories' forum</a></li>
</ol>
</div>
<div class="podbot"></div>
</div>
</div>
<div class="fatcol">
<div class="two3">
<div class="podcontent">
<p><span style="text-transform:capitalize">Warlord-of-Noodles</span> does not have any games.</p>
</div>
<div class="podbot"></div>
</div>
</div>
<br style="clear: both" />
</div>
<div id="footer" >
<div class="featuredcontent">
<div class="featurebar">
<dl>
<dt>Featured Content</dt>
<dd id="featgames" >
<a href="/ajax/footer_feature.php?footer_feature=games" rel="nofollow">Games</a>
</dd>
<dd id="featmovies" >
<a href="/ajax/footer_feature.php?footer_feature=movies" rel="nofollow">Movies</a>
</dd>
<dd id="feataudio" >
<a href="/ajax/footer_feature.php?footer_feature=audio" rel="nofollow">Audio</a>
</dd>
<dd id="featart" >
<a href="/ajax/footer_feature.php?footer_feature=art" rel="nofollow">Art</a>
</dd>
<dd id="featchannels" >
<a href="/ajax/footer_feature.php?footer_feature=channels" rel="nofollow">Channels</a>
</dd>
<dd id="featusers" class="currentfeat">
<a href="/ajax/footer_feature.php?footer_feature=users" rel="nofollow">Users</a>
</dd>
</dl>
</div>
<div class="footerfeatures">
<a href="/ajax/footer_feature.php?footer_feature=channels" class="fprev" rel="nofollow">
<span>Previous Section</span>
</a>
<div id="content">
<div class="user">
<a href="http://freyaloi.newgrounds.com/news/post/858254">
Freyaloi <strong>livestream: online</strong>
</a>
</div>
<div class="user">
<a href="http://mirocka.newgrounds.com/news/post/858251">
Mirocka <strong>Commissions</strong>
</a>
</div>
<div class="user">
<a href="http://ramenrider.newgrounds.com/news/post/858249">
RamenRider <strong>Update Entry (July 30th)</strong>
</a>
</div>
<div class="user">
<a href="http://gujit.newgrounds.com/news/post/858246">
Gujit <strong>Way to the Mountain</strong>
</a>
</div>
<div class="user">
<a href="http://evil-dog.newgrounds.com/news/post/858244">
Evil-Dog <strong>Road of the Dead 2: Live streaming all day!</strong>
</a>
</div>
<div class="user">
<a href="http://sonik1.newgrounds.com/news/post/858239">
sonik1 <strong>Suprise project comming up!</strong>
</a>
</div>
</div>
<a href="/ajax/footer_feature.php?footer_feature=games" class="fnext" rel="nofollow">
<span>Next Section</span>
</a>
</div>
<script type="text/javascript">
// <![CDATA[
PHP.set('feature_url', '/ajax/footer_feature.php');
(function () {
var featuredcontent = jQuery('#footer div.featuredcontent');
featuredcontent.delegate('div.featurebar a, a.fprev, a.fnext', 'click', function (e) {
featuredcontent.load(
PHP.get('feature_url'),
this.href.split('?')[1]
);
e.preventDefault();
});
})();
// ]]>
</script>
</div>
<div class="footerads">
<div style="display:none" class="storead_container">212:90:0</div> <div style='display:none' class='adcode_container'>bottom-superbanner:728x90</div> </div>
<div class="siteinfo">
<div class="copyright">
<p><strong>&copy; Copyright 1995-2013 Newgrounds, Inc. All rights reserved. <a href="http://www.newgrounds.com/wiki/help-information/privacy-policy">Privacy Policy</a> | <a href="http://www.newgrounds.com/wiki/help-information/terms-of-use">Terms of Use</a></strong></p>
<p>newgrounds.com &mdash; Your #1 online entertainment &amp; artist community! All your base are belong to us.</p>
</div>
<div class="navigation">
<dl>
<dt>Main Sections</dt>
<dd><a href="http://www.newgrounds.com/games"><span>Games</span></a></dd>
<dd><a href="http://www.newgrounds.com/movies"><span>Movies</span></a></dd>
<dd><a href="http://www.newgrounds.com/art"><span>Art</span></a></dd>
<dd><a href="http://www.newgrounds.com/audio"><span>Audio</span></a></dd>
<dd><a href="http://www.newgrounds.com/store"><span>Store</span></a></dd>
</dl>
<dl>
<dt>Extra, Extra!</dt>
<dd><a href="http://www.newgrounds.com/collection/series"><span>Series</span></a></dd>
<dd><a href="http://www.newgrounds.com/collection"><span>Collections</span></a></dd>
<dd><a href="http://www.newgrounds.com/games/under_judgment"><span>Game Judging</span></a></dd>
<dd><a href="http://www.newgrounds.com/movies/under_judgment"><span>Movie Judging</span></a></dd>
<dd><a href="http://www.newgrounds.com/portal"><span>Classic Portal</span></a></dd>
<dd><a href="http://www.newgrounds.com/downloads"><span>Downloads</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki/creator-resources"><span>Creator Resources</span></a></dd>
</dl>
<dl>
<dt>Community</dt>
<dd><a href="http://www.newgrounds.com/bbs"><span>Forums</span></a></dd>
<dd><a href="http://www.newgrounds.com/calendar"><span>Calendar</span></a></dd>
<dd><a href="http://www.newgrounds.com/news/artists"><span>Artist News</span></a></dd>
<dd><a href="http://www.newgrounds.com/rankings"><span>Rankings</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki"><span>NG Wiki</span></a></dd>
</dl>
<dl>
<dt>NG Related</dt>
<dd><a href="http://www.newgrounds.com/wiki/about-newgrounds"><span>About NG</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki/help-information"><span>Site Help</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki/about-newgrounds/staff"><span>The Staff</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki/about-newgrounds/history"><span>NG History</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki/help-information/rss"><span>RSS</span></a></dd>
</dl>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="//www.newgrounds.com/ads/cache/ad_controller.js?rand=1363205747"></script>
<script type="text/javascript">
// <![CDATA[
(function ($) {
if ($ng_adcode_user_is_supporter) {
//$('#footer').css('height','575px');
//$('#frontpagemessage').css('bottom','-556px');
} else {
$('.adcode_container').each(function() {
$(this).show();
var params = $(this).html().split(":");
var adcode = $ng_adcode_config.getUnit(params[0],params[1]);
$(this).html(''+adcode);
});
$('.storead_container').each(function() {
$(this).show();
var params = $(this).html().split(":");
var adcode = $ng_adcode_config.getStoreAd(params[0],params[1],params[2]);
$(this).html(''+adcode);
});
}
})(jQuery);
$ng_adcode_config = null; // free memory
// ]]>
</script>
<script type="text/javascript"> (function(){ var sNew = document.createElement("script"); sNew.defer = true; sNew.src = "http://tag.crsspxl.com/s1.js?d=1370"; var s0 = document.getElementsByTagName('script')[0]; s0.parentNode.insertBefore(sNew, s0); })(); </script>
</body>
</html>

View File

@ -0,0 +1,989 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Warlord-of-Noodles's Movies</title>
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge" /><![endif]-->
<link rel="stylesheet" href="http://css.ngfiles.com/ng_publish.css?1374679673" type="text/css" media="all" /> <link rel="stylesheet" href="http://css.ngfiles.com/iphone.css?1328564601" type="text/css" media="only screen and (max-device-width: 480px)" /> <link rel="stylesheet" href="http://css.ngfiles.com/print.css?1328564601" type="text/css" media="print" />
<!--[if lte IE 8]>
<script type="text/javascript">
// <![CDATA[
PHP.set('is_ie', true);
// ]]>
</script>
<![endif]-->
<!--[if lte IE 9]>
<link rel="stylesheet" href="http://css.ngfiles.com/ie9.css?1328656560" type="text/css" media="screen" />
<![endif]-->
<!--[if lte IE 8]>
<link rel="stylesheet" href="http://css.ngfiles.com/ie8.css?1337819134" type="text/css" media="screen" />
<![endif]-->
<!--[if lte IE 7]>
<link rel="stylesheet" href="http://css.ngfiles.com/ie7.css?1328564601" type="text/css" media="screen" />
<![endif]-->
<!--[if lte IE 6]>
<link rel="stylesheet" href="http://css.ngfiles.com/ie6.css?1328564286" type="text/css" media="screen" />
<![endif]-->
<style type="text/css">
/* this way the menus work with or without the javascript working */
#header dl dd {
display: none;
}
#header dl:hover dd {
/*display: block; */
}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
// <![CDATA[
if (!window.jQuery) {
document.write('<script src="http://js.ngfiles.com/jquery/jquery.js" type="text/javascript"><\/script>');
}
// ]]>
</script>
<script type="text/javascript" src="http://js.ngfiles.com/ng_publish.js?1374772896"></script>
<script type="text/javascript" src="http://js.ngfiles.com/css_browser_selector.js"></script>
<script type="text/javascript">
// <![CDATA[
var $ng_adcode_ctime = 1375207749;
var $ng_adcode_country = 2;
var $ng_adcode_revsharing_id = null;
var $ng_adcode_page = "userpages";
var $ng_adcode_suitability = "T";
//]]>
</script>
<link rel="icon" type="image/png" href="http://www.newgrounds.com/img/icons/favicon.png" />
<link rel="shortcut icon" href="http://www.newgrounds.com/favicon.ico" type="image/vnd.microsoft.icon" />
<link rel="apple-touch-icon" href="http://img.ngfiles.com/misc/newgrounds_webclip.png" />
<meta http-equiv="content-type" content="text/html; charset=windows-1252" />
<meta name="viewport" content="width=976" />
<script type="text/javascript">
var $ng_adcode_user_is_supporter = 0;
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-850825-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div id="blackout" style="display: none">
<div id="blackout_bg"></div>
<div class="pagecentered" id="blackout_center">
</div>
</div>
<a href="#main" class="skipto">Skip to content.</a>
<div id="outer" >
<div id="header" class="header">
<div class="siteinfo">
<h1><a href="http://www.newgrounds.com">Newgrounds.com &mdash; Everything, By Everyone.</a></h1>
<div class="navigation">
<div class="navbar" id="header_nav">
<dl id="games">
<dt><a href="http://www.newgrounds.com/games">Games</a></dt>
<dd><a href="http://www.newgrounds.com/games/browse">Latest</a></dd>
<dd><a href="http://www.newgrounds.com/games/browse/sort/score/interval/month">Greatest</a></dd>
<dd><a href="http://www.newgrounds.com/games/browse/sort/views/interval/week">Popular</a></dd>
<dd><a href="http://www.newgrounds.com/games/under_judgment">Under Judgment</a></dd>
<dd><a href="http://www.newgrounds.com/portal">Classic Portal</a></dd>
<dd><a href="http://www.newgrounds.com/projects/games"><em>Submit Yours!</em></a></dd>
<dd><a href="http://www.newgrounds.com/collab/browse/programmer"><em>Team Up!</em></a></dd>
</dl>
<dl id="movies">
<dt><a href="http://www.newgrounds.com/movies">Movies</a></dt>
<dd><a href="http://www.newgrounds.com/movies/browse">Latest</a></dd>
<dd><a href="http://www.newgrounds.com/movies/browse/sort/score/interval/month">Greatest</a></dd>
<dd><a href="http://www.newgrounds.com/movies/browse/sort/views/interval/week">Popular</a></dd>
<dd><a href="http://www.newgrounds.com/movies/under_judgment">Under Judgment</a></dd>
<dd><a href="http://www.newgrounds.com/portal">Classic Portal</a></dd>
<dd><a href="http://www.newgrounds.com/projects/movies"><em>Submit Yours!</em></a></dd>
<dd><a href="http://www.newgrounds.com/collab/browse/artist"><em>Team Up!</em></a></dd>
</dl>
<dl id="audio">
<dt><a href="http://www.newgrounds.com/audio">Audio</a></dt>
<dd><a href="http://www.newgrounds.com/audio/browse/sort/date">Latest</a></dd>
<dd><a href="http://www.newgrounds.com/audio/browse/sort/score/interval/month">Greatest</a></dd>
<dd><a href="http://www.newgrounds.com/audio/browse/sort/views/interval/week">Popular</a></dd>
<dd><a href="http://www.newgrounds.com/bbs/forum/13">Audio Forum</a></dd>
<dd><a href="http://www.newgrounds.com/projects/audio"><em>Submit Yours!</em></a></dd>
<dd><a href="http://www.newgrounds.com/collab/browse/musician"><em>Team Up!</em></a></dd>
</dl>
<dl id="art">
<dt><a href="http://www.newgrounds.com/art">Art</a></dt>
<dd><a href="http://www.newgrounds.com/art/browse">Latest</a></dd>
<dd><a href="http://www.newgrounds.com/art/browse/sort/score/interval/month">Greatest</a></dd>
<dd><a href="http://www.newgrounds.com/art/browse/sort/views/interval/week">Popular</a></dd>
<dd><a href="http://www.newgrounds.com/bbs/forum/14">Art Forum</a></dd>
<dd><a href="http://www.newgrounds.com/art/submit/create"><em>Submit Yours!</em></a></dd>
<dd><a href="http://www.newgrounds.com/collab/browse/artist"><em>Team Up!</em></a></dd>
</dl>
<dl id="channels">
<dt><a href="http://www.newgrounds.com/collection">Channels</a></dt>
<dd><a href="http://www.newgrounds.com/collection/series">Series</a></dd>
<dd><a href="http://www.newgrounds.com/collection">Collections</a></dd>
<dd><a href="http://www.newgrounds.com/movies/under_judgment">Judgment</a></dd>
<dd><a href="http://www.newgrounds.com/playlists">Playlists</a></dd>
</dl>
<dl id="community">
<dt><a href="http://www.newgrounds.com/bbs">Community</a></dt>
<dd><a href="http://www.newgrounds.com/bbs">Forums</a></dd>
<dd><a href="http://chat.newgrounds.com">Chat</a></dd>
<dd><a href="http://www.newgrounds.com/calendar">Calendar</a></dd>
<dd><a href="http://www.newgrounds.com/news/artists">Artist News</a></dd>
<dd><a href="http://www.newgrounds.com/rankings">Rankings</a></dd>
<dd><a href="http://www.newgrounds.com/downloads">Downloads</a></dd>
<dd><a href="http://www.newgrounds.com/wiki">Wiki</a></dd>
</dl>
<dl id="shop">
<dt><a href="http://www.newgrounds.com/store">Shop</a></dt>
<dd><a href="http://www.newgrounds.com/store/category/apparel">T-Shirts</a></dd>
<dd><a href="http://www.newgrounds.com/store/category/collectible">Collectibles</a></dd>
<dd><a href="http://www.newgrounds.com/store/category/print">Print</a></dd>
<dd><a href="http://www.newgrounds.com/store/category/disc">Discs</a></dd>
</dl>
</div>
</div>
<h6>
<a href="http://qikalain.newgrounds.com">Wall Artist</a> </h6>
</div>
<div class="sitelinks">
<form id="loginboxform" action="https://www.newgrounds.com/login" method="post" class="loginbox">
<label id="header_label_username" for="username" style="display:none">Username</label>
<input type="text" maxlength="20" id="username" name="username" value="" />
<label id="header_label_password" for="password" style="display:none">Password</label>
<input type="password" maxlength="32" id="password" name="password" />
<input type="hidden" name="referrer" value="http://warlord-of-noodles.newgrounds.com/movies/" />
<div class="checkboxes">
<input type="checkbox" value="on" id="remember" name="remember" />
<span><label for="remember">Save Info?</label></span>
</div>
<button type="submit">Log In</button>
<ul class="loginlinks">
<li><a href="http://www.newgrounds.com/join">Not a member? Sign Up!</a></li>
<li><a href="http://www.newgrounds.com/join/forgot">Forgot login?</a></li>
</ul>
</form>
<form class="search" id="topsearch" action="http://www.newgrounds.com/search" method="get">
<input type="text" name="topsearch_text" id="topsearch_text" />
<div class="select">
<div></div>
<span>Movies</span>
<select class="formtext" name="topsearch_type" id="topsearch_type">
<option value="16">Games</option>
<option value="15" selected="selected">Movies</option>
<option value="17">Audio</option>
<option value="14">Art</option>
<option value="4">Forums</option> </select>
</div>
<button type="submit">Search</button>
</form>
<script type="text/javascript">
// <![CDATA[
PHP.set('search_urls', {"16":"http:\/\/www.newgrounds.com\/portal\/search\/games","15":"http:\/\/www.newgrounds.com\/portal\/search\/movies","17":"http:\/\/www.newgrounds.com\/audio\/search\/title","14":"http:\/\/www.newgrounds.com\/art\/search","4":"http:\/\/www.newgrounds.com\/bbs\/search\/topic","9":"http:\/\/www.newgrounds.com\/users\/search"});
// ]]>
</script>
</div>
</div>
<div class="headerads">
<!-- include ads here -->
<div style='display:none' class='adcode_container'>top-superbanner:728x90</div> <div style="display:none" class="storead_container">212:90:0</div> </div>
<div id="main">
<div class="three3">
<div class="podtop userheader">
<h2 class="empty" id="page_username"><img src="http://uimg.ngfiles.com/icons/2785/2785798_small.jpg" alt="Warlord-of-Noodles" width="25" height="25" title="" />Warlord-of-Noodles</h2>
<div>
<a href="/"><span>Main</span></a>
<a href="/news/"><span>News</span></a>
<a ><span>Movies</span></a>
<a href="/art/"><span>Art</span></a>
<a href="/favorites/"><span>Favorites</span></a>
<a href="/reviews/"><span>Reviews</span></a>
<a href="/stats/"><span>Stats</span></a>
<a href="/fans/"><span>2,357 Fans</span></a>
<a title="Manage Favorites" href="http://&lt;deleted&gt;.newgrounds.com/favorites/following"
id="manage_favorites" class="fave" style="display: none">
<span></span>
<span class="hovertext"><span>Manage Favorites</span></span>
</a>
<script type="text/javascript" src="http://js.ngfiles.com/portal/favorites.js"></script>
<form method="post" action="/follow" id="follow_user" class="fave">
<input type="hidden" name="userkey" id="userkey" value="f0fe1%O425db43666fd%74b6O9b4cc7a1bc%Pc221br72%%d2c9a4%7%7%105%ea5fs448a5cf7O9e8br773frs%dde6e6%%s8%9%1c9db5d74dbr3Pa800%60rPfb290dcr06e06eab28e914d426938429b15f15665%s%4d7P%%O%rr2116-3425970" /> <input type="hidden" value="30" name="fav_type" />
<input type="hidden" name="id" value="2785798" />
<button type="submit" name="submit_favorite"><span></span></button>
<span class="hovertext">
<span>Follow Warlord-of-Noodles</span>
</span>
</form>
<script type="text/javascript">
listen_follow('#follow_user', '#manage_favorites');
</script>
</div>
</div>
</div>
<div class="thincol">
<div style='display:none' class='adcode_container'>left-rectangle:300x250</div>
<div class="one3">
<div class="podtop">
<h2 class="info">Contact Info / Websites</h2>
<div>
</div>
</div>
<div class="podcontent">
<ul class="blocklist">
<li class="mail"><a href="http://www.newgrounds.com/pm/send/warlord-of-noodles">Send a Private Message (PM)</a></li>
</ul>
</div>
<div class="podcontent">
<ol class="website-links">
<li><a href="http://www.betsydraws.com/" target="_blank" rel="nofollow"><img alt="www.betsydraws.com" src="http://s2.googleusercontent.com/s2/favicons?domain=www.betsydraws.com&amp;feature=newgrounds" /> www.betsydraws.com</a></li>
<li><a href="http://warlordofnoodles.comicgenesis.com/" target="_blank" rel="nofollow"><img alt="warlordofnoodles.comicgenesis.com" src="http://s2.googleusercontent.com/s2/favicons?domain=warlordofnoodles.comicgenesis.com&amp;feature=newgrounds" /> Brother Swan</a></li>
<li><a href="http://www.youtube.com/user/LadyCelest" target="_blank" rel="nofollow"><img alt="www.youtube.com" src="http://s2.googleusercontent.com/s2/favicons?domain=www.youtube.com&amp;feature=newgrounds" /> My Youtube</a></li>
<li><a href="http://warlord-of-noodles.deviantart.com/" target="_blank" rel="nofollow"><img alt="warlord-of-noodles.deviantart.com" src="http://s2.googleusercontent.com/s2/favicons?domain=warlord-of-noodles.deviantart.com&amp;feature=newgrounds" /> My Deviant Art</a></li>
<li><a href="https://twitter.com/#!/Warlordofnoodle" target="_blank" rel="nofollow"><img alt="twitter.com" src="http://s2.googleusercontent.com/s2/favicons?domain=twitter.com&amp;feature=newgrounds" /> My Twitter</a></li>
<li><a href="http://brotherswan.proboards.com/" target="_blank" rel="nofollow"><img alt="brotherswan.proboards.com" src="http://s2.googleusercontent.com/s2/favicons?domain=brotherswan.proboards.com&amp;feature=newgrounds" /> My Stories' forum</a></li>
</ol>
</div>
<div class="podbot"></div>
</div>
<div>
<div class="podtop">
<h2 class="trophies">Movie Trophies</h2>
<div><a href="/trophies">View All &raquo;</a></div>
</div>
<div class="podcontent">
<ul class="trophies">
<li>
<a href="http://www.newgrounds.com/portal/view/621259" class="daily1">
<strong>Little Bunny Foo Foo</strong>
Daily Feature </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/621259" class="weekly2">
<strong>Little Bunny Foo Foo</strong>
Weekly 2nd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/617915" class="daily1">
<strong>Swingers 006</strong>
Daily Feature </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/612665" class="daily1">
<strong>Tlaloc's Test</strong>
Daily Feature </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/612665" class="weekly3">
<strong>Tlaloc's Test</strong>
Weekly 3rd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/610813" class="daily3">
<strong>Dandy</strong>
Daily 3rd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/609683" class="daily1">
<strong>Swingers Episode 5</strong>
Daily Feature </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/609683" class="weekly4">
<strong>Swingers Episode 5</strong>
Weekly 4th Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/606387" class="daily2">
<strong>Out takes 01</strong>
Daily 2nd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/606111" class="daily2">
<strong>A Simple Melody</strong>
Daily 2nd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/606111" class="weekly3">
<strong>A Simple Melody</strong>
Weekly 3rd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/604603" class="daily2">
<strong>Coyote and Rattlesnake</strong>
Daily 2nd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/603027" class="daily2">
<strong>Swingers Episode 4</strong>
Daily 2nd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/601680" class="daily1">
<strong>And TheRaven Brought Fire</strong>
Daily Feature </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/601680" class="weekly5">
<strong>And TheRaven Brought Fire</strong>
Weekly 5th Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/600626" class="daily3">
<strong>The Fox and the Grapes</strong>
Daily 3rd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/593806" class="daily4">
<strong>Miss Kitty Sees You</strong>
Daily 4th Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/591049" class="daily3">
<strong>Swingers Episode 3</strong>
Daily 3rd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/584272" class="daily4">
<strong>Swingers Episode 2</strong>
Daily 4th Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/583715" class="daily2">
<strong>Cat Dust</strong>
Daily 2nd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/583715" class="weekly4">
<strong>Cat Dust</strong>
Weekly 4th Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/577497" class="daily2">
<strong>Swingers Episode 1</strong>
Daily 2nd Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/563780" class="daily4">
<strong>Do I Smell Chocolate?</strong>
Daily 4th Place </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/562785" class="daily1">
<strong>Step Sleeper</strong>
Daily Feature </a>
</li>
<li>
<a href="http://www.newgrounds.com/portal/view/488200" class="daily5">
<strong>Mordred's Lullaby</strong>
Daily 5th Place </a>
</li>
</ul>
</div>
<div class="podbot"></div>
</div>
</div>
<div class="fatcol">
<div>
<div class="podtop">
<h2 class="movie">2013 Submissions</h2>
<div>
<a href="http://www.newgrounds.com/portal/view/621259"><strong>Best of 2013: </strong>Little Bunny Foo Foo </a>
</div>
</div>
<div class="podcontent iconarray movies">
<a href="http://www.newgrounds.com/portal/view/621259" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/621000/flash_621259.jpg" alt="Little Bunny Foo Foo" width="140" height="90" title="" /> <span>
<strong>Little Bunny Foo Foo</strong>
<em><span style="width:89%">Rated Stars</span></em>
</span>
<span>
<span>someimes the field mice deserve it.</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/617915" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/617000/flash_617915.png" alt="Swingers 006" width="140" height="90" title="" /> <span>
<strong>Swingers 006</strong>
<em><span style="width:83%">Rated Stars</span></em>
</span>
<span>
<span>Not even golden geese are easy money</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/612665" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/612000/flash_612665.jpg" alt="Tlaloc's Test" width="140" height="90" title="" /> <span>
<strong>Tlaloc's Test</strong>
<em><span style="width:90%">Rated Stars</span></em>
</span>
<span>
<span>Do you trust the Water Pump?</span>
<span>Other</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/610813" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/610000/flash_610813.png" alt="Dandy" width="140" height="90" title="" /> <span>
<strong>Dandy</strong>
<em><span style="width:87%">Rated Stars</span></em>
</span>
<span>
<span>Be careful of whom you ask favors</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/609683" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/609000/flash_609683.jpg" alt="Swingers Episode 5" width="140" height="90" title="" /> <span>
<strong>Swingers Episode 5</strong>
<em><span style="width:84%">Rated Stars</span></em>
</span>
<span>
<span>Curiosity Kills</span>
<span>Comedy - Original</span>
</span>
</a>
</div>
<div class="podbot"></div>
</div>
<div>
<div class="podtop">
<h2 class="movie">2012 Submissions</h2>
<div>
<a href="http://www.newgrounds.com/portal/view/593806"><strong>Best of 2012: </strong>Miss Kitty Sees You </a>
</div>
</div>
<div class="podcontent iconarray movies">
<a href="http://www.newgrounds.com/portal/view/606387" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/606000/flash_606387.jpg" alt="Out takes 01" width="140" height="90" title="" /> <span>
<strong>Out takes 01</strong>
<em><span style="width:80%">Rated Stars</span></em>
</span>
<span>
<span>Out takes from swingers and no evil</span>
<span>Other</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/606111" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/606000/flash_606111.jpg" alt="A Simple Melody" width="140" height="90" title="" /> <span>
<strong>A Simple Melody</strong>
<em><span style="width:89%">Rated Stars</span></em>
</span>
<span>
<span>Sing a simple melody</span>
<span>Other</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/604603" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/604000/flash_604603.jpg" alt="Coyote and Rattlesnake" width="140" height="90" title="" /> <span>
<strong>Coyote and Rattlesnake</strong>
<em><span style="width:86%">Rated Stars</span></em>
</span>
<span>
<span>A Sia Folktale</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/604152" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/604000/flash_604152.jpg" alt="Falling Angel" width="140" height="90" title="" /> <span>
<strong>Falling Angel</strong>
<em><span style="width:77%">Rated Stars</span></em>
</span>
<span>
<span>A message from above</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/603027" class="rated-t"><span></span>
<img src="http://picon.ngfiles.com/603000/flash_603027.jpg" alt="Swingers Episode 4" width="140" height="90" title="" /> <span>
<strong>Swingers Episode 4</strong>
<em><span style="width:84%">Rated Stars</span></em>
</span>
<span>
<span>I do beleive in spooks</span>
<span>Action</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/601680" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/601000/flash_601680.jpg" alt="And TheRaven Brought Fire" width="140" height="90" title="" /> <span>
<strong>And TheRaven Brought Fire</strong>
<em><span style="width:89%">Rated Stars</span></em>
</span>
<span>
<span>At one time there was nothing but darkness, and then the Raven brought fire</span>
<span>Action</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/600626" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/600000/flash_600626.jpg" alt="The Fox and the Grapes" width="140" height="90" title="" /> <span>
<strong>The Fox and the Grapes</strong>
<em><span style="width:81%">Rated Stars</span></em>
</span>
<span>
<span>An Aesop Fabel</span>
<span>Other</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/593806" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/593000/flash_593806.jpg" alt="Miss Kitty Sees You" width="140" height="90" title="" /> <span>
<strong>Miss Kitty Sees You</strong>
<em><span style="width:83%">Rated Stars</span></em>
</span>
<span>
<span>Miss Kitty sings all ladylike</span>
<span>Other</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/591049" class="rated-t"><span></span>
<img src="http://picon.ngfiles.com/591000/flash_591049.jpg" alt="Swingers Episode 3" width="140" height="90" title="" /> <span>
<strong>Swingers Episode 3</strong>
<em><span style="width:82%">Rated Stars</span></em>
</span>
<span>
<span>Blues is hazed</span>
<span>Comedy - Original</span>
</span>
</a>
</div>
<div class="podbot"></div>
</div>
<div>
<div class="podtop">
<h2 class="movie">2011 Submissions</h2>
<div>
<a href="http://www.newgrounds.com/portal/view/583715"><strong>Best of 2011: </strong>Cat Dust </a>
</div>
</div>
<div class="podcontent iconarray movies">
<a href="http://www.newgrounds.com/portal/view/584272" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/584000/flash_584272.jpg" alt="Swingers Episode 2" width="140" height="90" title="" /> <span>
<strong>Swingers Episode 2</strong>
<em><span style="width:82%">Rated Stars</span></em>
</span>
<span>
<span>An exstortionist comes to make an offer.</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/583715" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/583000/flash_583715.jpg" alt="Cat Dust" width="140" height="90" title="" /> <span>
<strong>Cat Dust</strong>
<em><span style="width:88%">Rated Stars</span></em>
</span>
<span>
<span>How far will lazyness go?</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/577497" class="rated-t"><span></span>
<img src="http://picon.ngfiles.com/577000/flash_577497.jpg" alt="Swingers Episode 1" width="140" height="90" title="" /> <span>
<strong>Swingers Episode 1</strong>
<em><span style="width:82%">Rated Stars</span></em>
</span>
<span>
<span>Tonight normal activity is broken by a thunderclap.... or several</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/563780" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/563000/flash_563780.jpg" alt="Do I Smell Chocolate?" width="140" height="90" title="" /> <span>
<strong>Do I Smell Chocolate?</strong>
<em><span style="width:75%">Rated Stars</span></em>
</span>
<span>
<span>Papllion is a Special snowflake</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/562785" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/562000/flash_562785.jpg" alt="Step Sleeper" width="140" height="90" title="" /> <span>
<strong>Step Sleeper</strong>
<em><span style="width:82%">Rated Stars</span></em>
</span>
<span>
<span>Happy cat is a stubborn cat</span>
<span>Comedy - Original</span>
</span>
</a>
</div>
<div class="podbot"></div>
</div>
<div>
<div class="podtop">
<h2 class="movie">2010 Submissions</h2>
<div>
<a href="http://www.newgrounds.com/portal/view/553298"><strong>Best of 2010: </strong>She's in my Class </a>
</div>
</div>
<div class="podcontent iconarray movies">
<a href="http://www.newgrounds.com/portal/view/553298" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/553000/flash_553298.jpg" alt="She's in my Class" width="140" height="90" title="" /> <span>
<strong>She's in my Class</strong>
<em><span style="width:74%">Rated Stars</span></em>
</span>
<span>
<span>Sorrel is afraid of Spider</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/550882" class="rated-t"><span></span>
<img src="http://picon.ngfiles.com/550000/flash_550882.jpeg" alt="The Tree Knows" width="140" height="90" title="" /> <span>
<strong>The Tree Knows</strong>
<em><span style="width:72%">Rated Stars</span></em>
</span>
<span>
<span>The tree sees you doing wrong</span>
<span>Comedy - Original</span>
</span>
</a>
</div>
<div class="podbot"></div>
</div>
<div>
<div class="podtop">
<h2 class="movie">2009 Submissions</h2>
<div>
<a href="http://www.newgrounds.com/portal/view/488200"><strong>Best of 2009: </strong>Mordred's Lullaby </a>
</div>
</div>
<div class="podcontent iconarray movies">
<a href="http://www.newgrounds.com/portal/view/509249" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/509000/flash_509249.png" alt="Doushite?" width="140" height="90" title="" /> <span>
<strong>Doushite?</strong>
<em><span style="width:73%">Rated Stars</span></em>
</span>
<span>
<span>Spider has a nervous break down</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/509175" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/509000/flash_509175.png" alt="Oscar" width="140" height="90" title="" /> <span>
<strong>Oscar</strong>
<em><span style="width:78%">Rated Stars</span></em>
</span>
<span>
<span>Havre Highschool is pleagued by the ghost of a janator</span>
<span>Comedy - Original</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/488200" class="rated-t"><span></span>
<img src="http://picon.ngfiles.com/488000/flash_488200.png" alt="Mordred's Lullaby" width="140" height="90" title="" /> <span>
<strong>Mordred's Lullaby</strong>
<em><span style="width:86%">Rated Stars</span></em>
</span>
<span>
<span>Morgan Lafe Sings of her son's Destiny</span>
<span>Music Video</span>
</span>
</a>
<a href="http://www.newgrounds.com/portal/view/488180" class="rated-e"><span></span>
<img src="http://picon.ngfiles.com/488000/flash_488180.png" alt="Stop Eating Mud" width="140" height="90" title="" /> <span>
<strong>Stop Eating Mud</strong>
<em><span style="width:82%">Rated Stars</span></em>
</span>
<span>
<span>A little girl attempts to sell mud as candy.</span>
<span>Comedy - Original</span>
</span>
</a>
</div>
<div class="podbot"></div>
</div>
</div>
<br style="clear: both" />
</div>
<div id="footer" >
<div class="featuredcontent">
<div class="featurebar">
<dl>
<dt>Featured Content</dt>
<dd id="featgames" >
<a href="/ajax/footer_feature.php?footer_feature=games" rel="nofollow">Games</a>
</dd>
<dd id="featmovies" >
<a href="/ajax/footer_feature.php?footer_feature=movies" rel="nofollow">Movies</a>
</dd>
<dd id="feataudio" >
<a href="/ajax/footer_feature.php?footer_feature=audio" rel="nofollow">Audio</a>
</dd>
<dd id="featart" >
<a href="/ajax/footer_feature.php?footer_feature=art" rel="nofollow">Art</a>
</dd>
<dd id="featchannels" >
<a href="/ajax/footer_feature.php?footer_feature=channels" rel="nofollow">Channels</a>
</dd>
<dd id="featusers" class="currentfeat">
<a href="/ajax/footer_feature.php?footer_feature=users" rel="nofollow">Users</a>
</dd>
</dl>
</div>
<div class="footerfeatures">
<a href="/ajax/footer_feature.php?footer_feature=channels" class="fprev" rel="nofollow">
<span>Previous Section</span>
</a>
<div id="content">
<div class="user">
<a href="http://mirocka.newgrounds.com/news/post/858251">
Mirocka <strong>Commissions</strong>
</a>
</div>
<div class="user">
<a href="http://ramenrider.newgrounds.com/news/post/858249">
RamenRider <strong>Update Entry (July 30th)</strong>
</a>
</div>
<div class="user">
<a href="http://gujit.newgrounds.com/news/post/858246">
Gujit <strong>Way to the Mountain</strong>
</a>
</div>
<div class="user">
<a href="http://evil-dog.newgrounds.com/news/post/858244">
Evil-Dog <strong>Road of the Dead 2: Live streaming all day!</strong>
</a>
</div>
<div class="user">
<a href="http://sonik1.newgrounds.com/news/post/858239">
sonik1 <strong>Suprise project comming up!</strong>
</a>
</div>
<div class="user">
<a href="http://justsomerandomdude.newgrounds.com/news/post/858238">
justsomerandomdude <strong>Sneakpeek</strong>
</a>
</div>
</div>
<a href="/ajax/footer_feature.php?footer_feature=games" class="fnext" rel="nofollow">
<span>Next Section</span>
</a>
</div>
<script type="text/javascript">
// <![CDATA[
PHP.set('feature_url', '/ajax/footer_feature.php');
(function () {
var featuredcontent = jQuery('#footer div.featuredcontent');
featuredcontent.delegate('div.featurebar a, a.fprev, a.fnext', 'click', function (e) {
featuredcontent.load(
PHP.get('feature_url'),
this.href.split('?')[1]
);
e.preventDefault();
});
})();
// ]]>
</script>
</div>
<div class="footerads">
<div style="display:none" class="storead_container">212:90:0</div> <div style='display:none' class='adcode_container'>bottom-superbanner:728x90</div> </div>
<div class="siteinfo">
<div class="copyright">
<p><strong>&copy; Copyright 1995-2013 Newgrounds, Inc. All rights reserved. <a href="http://www.newgrounds.com/wiki/help-information/privacy-policy">Privacy Policy</a> | <a href="http://www.newgrounds.com/wiki/help-information/terms-of-use">Terms of Use</a></strong></p>
<p>newgrounds.com &mdash; Your #1 online entertainment &amp; artist community! All your base are belong to us.</p>
</div>
<div class="navigation">
<dl>
<dt>Main Sections</dt>
<dd><a href="http://www.newgrounds.com/games"><span>Games</span></a></dd>
<dd><a href="http://www.newgrounds.com/movies"><span>Movies</span></a></dd>
<dd><a href="http://www.newgrounds.com/art"><span>Art</span></a></dd>
<dd><a href="http://www.newgrounds.com/audio"><span>Audio</span></a></dd>
<dd><a href="http://www.newgrounds.com/store"><span>Store</span></a></dd>
</dl>
<dl>
<dt>Extra, Extra!</dt>
<dd><a href="http://www.newgrounds.com/collection/series"><span>Series</span></a></dd>
<dd><a href="http://www.newgrounds.com/collection"><span>Collections</span></a></dd>
<dd><a href="http://www.newgrounds.com/games/under_judgment"><span>Game Judging</span></a></dd>
<dd><a href="http://www.newgrounds.com/movies/under_judgment"><span>Movie Judging</span></a></dd>
<dd><a href="http://www.newgrounds.com/portal"><span>Classic Portal</span></a></dd>
<dd><a href="http://www.newgrounds.com/downloads"><span>Downloads</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki/creator-resources"><span>Creator Resources</span></a></dd>
</dl>
<dl>
<dt>Community</dt>
<dd><a href="http://www.newgrounds.com/bbs"><span>Forums</span></a></dd>
<dd><a href="http://www.newgrounds.com/calendar"><span>Calendar</span></a></dd>
<dd><a href="http://www.newgrounds.com/news/artists"><span>Artist News</span></a></dd>
<dd><a href="http://www.newgrounds.com/rankings"><span>Rankings</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki"><span>NG Wiki</span></a></dd>
</dl>
<dl>
<dt>NG Related</dt>
<dd><a href="http://www.newgrounds.com/wiki/about-newgrounds"><span>About NG</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki/help-information"><span>Site Help</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki/about-newgrounds/staff"><span>The Staff</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki/about-newgrounds/history"><span>NG History</span></a></dd>
<dd><a href="http://www.newgrounds.com/wiki/help-information/rss"><span>RSS</span></a></dd>
</dl>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="//www.newgrounds.com/ads/cache/ad_controller.js?rand=1363205747"></script>
<script type="text/javascript">
// <![CDATA[
(function ($) {
if ($ng_adcode_user_is_supporter) {
//$('#footer').css('height','575px');
//$('#frontpagemessage').css('bottom','-556px');
} else {
$('.adcode_container').each(function() {
$(this).show();
var params = $(this).html().split(":");
var adcode = $ng_adcode_config.getUnit(params[0],params[1]);
$(this).html(''+adcode);
});
$('.storead_container').each(function() {
$(this).show();
var params = $(this).html().split(":");
var adcode = $ng_adcode_config.getStoreAd(params[0],params[1],params[2]);
$(this).html(''+adcode);
});
}
})(jQuery);
$ng_adcode_config = null; // free memory
// ]]>
</script>
<script type="text/javascript"> (function(){ var sNew = document.createElement("script"); sNew.defer = true; sNew.src = "http://tag.crsspxl.com/s1.js?d=1370"; var s0 = document.getElementsByTagName('script')[0]; s0.parentNode.insertBefore(sNew, s0); })(); </script>
</body>
</html>

File diff suppressed because it is too large Load Diff

32
test.py
View File

@ -1,10 +1,13 @@
from include import HydrusConstants as HC
from include import HydrusTags
from include import TestClientDaemons
from include import TestConstants
from include import TestDialogs
from include import TestDB
from include import TestFunctions
from include import TestHydrusDownloading
from include import TestHydrusTags
import collections
import os
import unittest
import wx
@ -22,14 +25,18 @@ class App( wx.App ):
self._reads[ 'tag_service_precedence' ] = []
self._reads[ 'tag_siblings' ] = {}
self._writes = collections.defaultdict( list )
self._tag_parents_manager = HydrusTags.TagParentsManager()
self._tag_siblings_manager = HydrusTags.TagSiblingsManager()
suites = []
suites.append( unittest.TestLoader().loadTestsFromModule( TestClientDaemons ) )
suites.append( unittest.TestLoader().loadTestsFromModule( TestDialogs ) )
suites.append( unittest.TestLoader().loadTestsFromModule( TestDB ) )
suites.append( unittest.TestLoader().loadTestsFromModule( TestFunctions ) )
suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusDownloading ) )
suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusTags ) )
suite = unittest.TestSuite( suites )
@ -44,10 +51,35 @@ class App( wx.App ):
def GetTagParentsManager( self ): return self._tag_parents_manager
def GetTagSiblingsManager( self ): return self._tag_siblings_manager
def GetWrite( self, name ):
write = self._writes[ name ]
del self._writes[ name ]
return write
def Read( self, name ): return self._reads[ name ]
def ReadDaemon( self, name ): return self.Read( name )
def SetRead( self, name, value ): self._reads[ name ] = value
def Write( self, name, *args, **kwargs ):
self._writes[ name ].append( ( args, kwargs ) )
def WriteDaemon( self, name, *args, **kwargs ):
self._writes[ name ].append( ( args, kwargs ) )
if name == 'import_file':
if args == ( 'blarg', ): raise Exception( 'File failed to import for some reason!' )
else: return ( 'successful', 'hash' )
if __name__ == '__main__':
app = App()