def SetServices( self, services ):
     
     # doesn't need the dirty_object_lock because the caller takes it
     
     # first test available ports
     
     my_ports = { s.GetPort() for s in self._services }
     
     for service in services:
         
         port = service.GetPort()
         
         if port not in my_ports and HydrusNetworking.LocalPortInUse( port ):
             
             raise HydrusExceptions.ServerException( 'Something was already bound to port ' + str( port ) )
             
         
     
     #
     
     self._services = services
     
     self.CallToThread( self.services_upnp_manager.SetServices, self._services )
     
     [ self._admin_service ] = [ service for service in self._services if service.GetServiceType() == HC.SERVER_ADMIN ]
     
     self.SetRunningTwistedServices( self._services )
 def GetTagId( self, tag ) -> int:
     
     clean_tag = HydrusTags.CleanTag( tag )
     
     try:
         
         HydrusTags.CheckTagNotEmpty( clean_tag )
         
     except HydrusExceptions.TagSizeException:
         
         raise HydrusExceptions.TagSizeException( '"{}" tag seems not valid--when cleaned, it ends up with zero size!'.format( tag ) )
         
     
     result = self._c.execute( 'SELECT tag_id FROM local_tags_cache WHERE tag = ?;', ( tag, ) ).fetchone()
     
     if result is None:
         
         return self.modules_tags.GetTagId( tag )
         
     else:
         
         ( tag_id, ) = result
         
     
     return tag_id
예제 #3
0
    def GetValue(self):

        service_key = self._service_keys.GetValue()

        if service_key is None:

            raise HydrusExceptions.VetoException(
                'Please select a rating service!')

        action = self._flip_or_set_action.GetValue()

        if self._ratings_numerical_remove.isChecked():

            rating = None

        else:

            value = self._ratings_numerical_slider.GetValue()

            rating = self._current_ratings_numerical_service.ConvertStarsToRating(
                value)

        return CAC.ApplicationCommand(
            CAC.APPLICATION_COMMAND_TYPE_CONTENT,
            (service_key, HC.CONTENT_TYPE_RATINGS, action, rating))
예제 #4
0
def ParseFFMPEGVideoLine(lines, png_ok=False):

    if png_ok:

        bad_video_formats = ['jpg']

    else:

        bad_video_formats = ['png', 'jpg']

    # get the output line that speaks about video
    # the ^\sStream is to exclude the 'title' line, when it exists, includes the string 'Video: ', ha ha
    lines_video = [
        l for l in lines
        if re.search(r'^\s*Stream', l) is not None and 'Video: ' in l
        and True not in ('Video: {}'.format(bad_video_format) in l
                         for bad_video_format in bad_video_formats)
    ]  # mp3 says it has a 'png' video stream

    if len(lines_video) == 0:

        raise HydrusExceptions.DamagedOrUnusualFileException(
            'Could not find video information!')

    line = lines_video[0]

    return line
예제 #5
0
def GetFFMPEGAPNGProperties(path):

    with open(path, 'rb') as f:

        file_header_bytes = f.read(256)

    apng_actl_bytes = GetAPNGACTLChunk(file_header_bytes)

    if apng_actl_bytes is None:

        raise HydrusExceptions.DamagedOrUnusualFileException(
            'This APNG had an unusual file header!')

    num_frames = GetAPNGNumFrames(apng_actl_bytes)

    lines = GetFFMPEGInfoLines(path)

    resolution = ParseFFMPEGVideoResolution(lines, png_ok=True)

    (fps, confident_fps) = ParseFFMPEGFPS(lines, png_ok=True)

    if not confident_fps:

        fps = 24

    duration = num_frames / fps

    duration_in_ms = int(duration * 1000)

    has_audio = False

    return (resolution, duration_in_ms, num_frames, has_audio)
예제 #6
0
 def GetResult( self ):
     
     time.sleep( 0.00001 ) # this one neat trick can save hassle on superquick jobs as event.wait can be laggy
     
     while True:
         
         if self._result_ready.wait( 2 ) == True:
             
             break
             
         elif HG.model_shutdown:
             
             raise HydrusExceptions.ShutdownException( 'Application quit before db could serve result!' )
             
         
         self._DoDelayedResultRelief()
         
     
     if isinstance( self._result, Exception ):
         
         e = self._result
         
         raise e
         
     else:
         
         return self._result
    def _GetInfo(self, share_key):

        try:
            info = self._keys_to_infos[share_key]
        except:
            raise HydrusExceptions.NotFoundException(
                'Did not find that share on this booru.')

        if info is None:

            info = self._controller.Read('local_booru_share', share_key)

            hashes = info['hashes']

            info['hashes_set'] = set(hashes)

            media_results = self._controller.Read('media_results', hashes)

            info['media_results'] = media_results

            hashes_to_media_results = {
                media_result.GetHash(): media_result
                for media_result in media_results
            }

            info['hashes_to_media_results'] = hashes_to_media_results

            self._keys_to_infos[share_key] = info

        return info
 def _callbackParsePOSTArgs( self, request: HydrusServerRequest.HydrusRequest ):
     
     request.content.seek( 0 )
     
     if not request.requestHeaders.hasHeader( 'Content-Type' ):
         
         parsed_request_args = HydrusNetworkVariableHandling.ParsedRequestArguments()
         
     else:
         
         content_types = request.requestHeaders.getRawHeaders( 'Content-Type' )
         
         content_type = content_types[0]
         
         try:
             
             mime = HC.mime_enum_lookup[ content_type ]
             
         except:
             
             raise HydrusExceptions.BadRequestException( 'Did not recognise Content-Type header!' )
             
         
         total_bytes_read = 0
         
         if mime == HC.APPLICATION_JSON:
             
             json_string = request.content.read()
             
             total_bytes_read += len( json_string )
             
             parsed_request_args = HydrusNetworkVariableHandling.ParseNetworkBytesToParsedHydrusArgs( json_string )
             
         else:
             
             ( os_file_handle, temp_path ) = HydrusPaths.GetTempPath()
             
             request.temp_file_info = ( os_file_handle, temp_path )
             
             with open( temp_path, 'wb' ) as f:
                 
                 for block in HydrusPaths.ReadFileLikeAsBlocks( request.content ): 
                     
                     f.write( block )
                     
                     total_bytes_read += len( block )
                     
                 
             
             decompression_bombs_ok = self._DecompressionBombsOK( request )
             
             parsed_request_args = HydrusNetworkVariableHandling.ParseFileArguments( temp_path, decompression_bombs_ok )
             
         
         self._reportDataUsed( request, total_bytes_read )
         
     
     request.parsed_request_args = parsed_request_args
     
     return request
예제 #9
0
def CheckTagNotEmpty(tag):

    (namespace, subtag) = SplitTag(tag)

    if subtag == '':

        raise HydrusExceptions.TagSizeException('Received a zero-length tag!')
예제 #10
0
 def GetYAMLDump( self, dump_type, dump_name = None ):
     
     if dump_name is None:
         
         result = { dump_name : data for ( dump_name, data ) in self._c.execute( 'SELECT dump_name, dump FROM yaml_dumps WHERE dump_type = ?;', ( dump_type, ) ) }
         
         if dump_type == YAML_DUMP_ID_LOCAL_BOORU:
             
             result = { bytes.fromhex( dump_name ) : data for ( dump_name, data ) in list(result.items()) }
             
         
     else:
         
         if dump_type == YAML_DUMP_ID_LOCAL_BOORU: dump_name = dump_name.hex()
         
         result = self._c.execute( 'SELECT dump FROM yaml_dumps WHERE dump_type = ? AND dump_name = ?;', ( dump_type, dump_name ) ).fetchone()
         
         if result is None:
             
             if result is None:
                 
                 raise HydrusExceptions.DataMissing( dump_name + ' was not found!' )
                 
             
         else:
             
             ( result, ) = result
             
         
     
     return result
예제 #11
0
    def _threadDoPOSTJob(self, request: HydrusServerRequest.HydrusRequest):

        services = request.parsed_request_args['services']

        unique_ports = {service.GetPort() for service in services}

        if len(unique_ports) < len(services):

            raise HydrusExceptions.BadRequestException(
                'It looks like some of those services share ports! Please give them unique ports!'
            )

        with HG.dirty_object_lock:

            HG.server_controller.SetServices(services)

            service_keys_to_access_keys = HG.server_controller.WriteSynchronous(
                'services', request.hydrus_account, services)

        body = HydrusNetworkVariableHandling.DumpHydrusArgsToNetworkBytes(
            {'service_keys_to_access_keys': service_keys_to_access_keys})

        response_context = HydrusServerResources.ResponseContext(200,
                                                                 body=body)

        return response_context
예제 #12
0
    def InitialiseFromSerialisableInfo(self,
                                       version,
                                       serialisable_info,
                                       raise_error_on_future_version=False):

        if version > self.SERIALISABLE_VERSION:

            if raise_error_on_future_version:

                message = 'Unfortunately, an object of type {} could not be loaded because it was created in a client that uses an updated version of that object! This client supports versions up to {}, but the object was version {}.'.format(
                    self.SERIALISABLE_NAME, self.SERIALISABLE_VERSION, version)
                message += os.linesep * 2
                message += 'Please update your client to import this object.'

                raise HydrusExceptions.SerialisationException(message)

            else:

                message = 'An object of type {} was created in a client that uses an updated version of that object! This client supports versions up to {}, but the object was version {}. For now, the client will try to continue work, but things may break. If you know why this has occured, please correct it. If you do not, please let hydrus dev know.'.format(
                    self.SERIALISABLE_NAME, self.SERIALISABLE_VERSION, version)

                HydrusData.ShowText(message)

        while version < self.SERIALISABLE_VERSION:

            (version, serialisable_info) = self._UpdateSerialisableInfo(
                version, serialisable_info)

        self._InitialiseFromSerialisableInfo(serialisable_info)
예제 #13
0
def DealWithBrokenJSONDump( db_dir, dump, dump_descriptor ):
    
    timestamp_string = time.strftime( '%Y-%m-%d %H-%M-%S' )
    hex_chars = os.urandom( 4 ).hex()
    
    filename = '({}) at {} {}.json'.format( dump_descriptor, timestamp_string, hex_chars )
    
    path = os.path.join( db_dir, filename )
    
    with open( path, 'wb' ) as f:
        
        if isinstance( dump, str ):
            
            dump = bytes( dump, 'utf-8', errors = 'replace' )
            
        
        f.write( dump )
        
    
    message = 'A serialised object failed to load! Its description is "{}".'.format( dump_descriptor )
    message += os.linesep * 2
    message += 'This error could be due to several factors, but is most likely a hard drive fault (perhaps your computer recently had a bad power cut?).'
    message += os.linesep * 2
    message += 'The database has attempted to delete the broken object, errors have been written to the log, and the object\'s dump written to {}. Depending on the object, your client may no longer be able to boot, or it may have lost something like a session or a subscription.'.format( path )
    message += os.linesep * 2
    message += 'Please review the \'help my db is broke.txt\' file in your install_dir/db directory as background reading, and if the situation or fix here is not obvious, please contact hydrus dev.'
    
    HydrusData.ShowText( message )
    
    raise HydrusExceptions.SerialisationException( message )
예제 #14
0
    def Read(self, name, *args, **kwargs):

        self._read_call_args[name].append((args, kwargs))

        if self._test_db is not None:

            return self._test_db.Read(name, *args, **kwargs)

        try:

            if (name, args) in self._param_read_responses:

                return self._param_read_responses[(name, args)]

        except:

            pass

        result = self._name_read_responses[name]

        if isinstance(result, Exception):

            raise HydrusExceptions.DBException(result, str(result),
                                               'test trace')

        return result
def GetDeleteFilesJobs( win, media, default_reason, suggested_file_service_key = None ):
    
    title = 'Delete files?'
    
    with ClientGUITopLevelWindowsPanels.DialogEdit( win, title, frame_key = 'regular_center_dialog' ) as dlg:
        
        panel = ClientGUIScrolledPanelsEdit.EditDeleteFilesPanel( dlg, media, default_reason, suggested_file_service_key = suggested_file_service_key )
        
        dlg.SetPanel( panel )
        
        if panel.QuestionIsAlreadyResolved():
            
            ( involves_physical_delete, jobs ) = panel.GetValue()
            
            return ( involves_physical_delete, jobs )
            
        
        if dlg.exec() == QW.QDialog.Accepted:
            
            ( involves_physical_delete, jobs ) = panel.GetValue()
            
            return ( involves_physical_delete, jobs )
            
        else:
            
            raise HydrusExceptions.CancelledException( 'Dialog cancelled.' )
예제 #16
0
    def CheckReadyToImport(self) -> bool:

        if self._import_destination_location_context.IsEmpty():

            raise HydrusExceptions.FileImportBlockException(
                'There is no import destination set in the File Import Options!'
            )
예제 #17
0
        def qt_code(win: QW.QWidget, job_key: ClientThreading.JobKey):

            try:

                if win is not None and not QP.isValid(win):

                    raise HydrusExceptions.QtDeadWindowException(
                        'Parent Window was destroyed before Qt command was called!'
                    )

                result = func(*args, **kwargs)

                job_key.SetVariable('result', result)

            except (HydrusExceptions.QtDeadWindowException,
                    HydrusExceptions.DBCredentialsException,
                    HydrusExceptions.ShutdownException) as e:

                job_key.SetErrorException(e)

            except Exception as e:

                job_key.SetErrorException(e)

                HydrusData.Print('CallBlockingToQt just caught this error:')
                HydrusData.DebugPrint(traceback.format_exc())

            finally:

                job_key.Finish()
예제 #18
0
    def _GetListCtrlMenu( self ):
        
        selected_file_seeds = self._list_ctrl.GetData( only_selected = True )
        
        if len( selected_file_seeds ) == 0:
            
            raise HydrusExceptions.DataMissing()
            
        
        menu = QW.QMenu()
        
        can_show_files_in_new_page = True in ( file_seed.HasHash() for file_seed in selected_file_seeds )
        
        if can_show_files_in_new_page:
            
            ClientGUIMenus.AppendMenuItem( menu, 'open selected import files in a new page', 'Show all the known selected files in a new thumbnail page. This is complicated, so cannot always be guaranteed, even if the import says \'success\'.', self._ShowSelectionInNewPage )
            
            ClientGUIMenus.AppendSeparator( menu )

        ClientGUIMenus.AppendMenuItem( menu, 'copy sources', 'Copy all the selected sources to clipboard.', self._CopySelectedFileSeedData )
        ClientGUIMenus.AppendMenuItem( menu, 'copy notes', 'Copy all the selected notes to clipboard.', self._CopySelectedNotes )
        
        ClientGUIMenus.AppendSeparator( menu )

        ClientGUIMenus.AppendMenuItem( menu, 'open sources', 'Open all the selected sources in your file explorer or web browser.', self._OpenSelectedFileSeedData )
        
        ClientGUIMenus.AppendSeparator( menu )

        ClientGUIMenus.AppendMenuItem( menu, 'try again', 'Reset the progress of all the selected imports.', HydrusData.Call( self._SetSelected, CC.STATUS_UNKNOWN ) )
        ClientGUIMenus.AppendMenuItem( menu, 'skip', 'Skip all the selected imports.', HydrusData.Call( self._SetSelected, CC.STATUS_SKIPPED ) )
        ClientGUIMenus.AppendMenuItem( menu, 'delete from list', 'Remove all the selected imports.', self._DeleteSelected )
        
        return menu
    def _CheckDataUsage(self):

        if not self._local_booru_service.BandwidthOK():

            raise HydrusExceptions.InsufficientCredentialsException(
                'This booru has used all its monthly data. Please try again next month.'
            )
예제 #20
0
 def GetValue( self ):
     
     service_key = self._service_keys.GetValue()
     
     if service_key is None:
         
         raise HydrusExceptions.VetoException( 'Please select a rating service!' )
         
     
     action = self._flip_or_set_action.GetValue()
     
     if self._ratings_like_like.isChecked():
         
         value = 1.0
         
     elif self._ratings_like_dislike.isChecked():
         
         value = 0.0
         
     else:
         
         value = None
         
     
     return CAC.ApplicationCommand( CAC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, HC.CONTENT_TYPE_RATINGS, action, value ) )
예제 #21
0
 def GetTagId( self, tag ) -> int:
     
     clean_tag = HydrusTags.CleanTag( tag )
     
     try:
         
         HydrusTags.CheckTagNotEmpty( clean_tag )
         
     except HydrusExceptions.TagSizeException:
         
         # update this to instead go 'hey, does the dirty tag exist?' if it does, run the fix invalid tags routine
         
         raise HydrusExceptions.TagSizeException( '"{}" tag seems not valid--when cleaned, it ends up with zero size!'.format( tag ) )
         
     
     ( namespace, subtag ) = HydrusTags.SplitTag( clean_tag )
     
     namespace_id = self.GetNamespaceId( namespace )
     subtag_id = self.GetSubtagId( subtag )
     
     result = self._c.execute( 'SELECT tag_id FROM tags WHERE namespace_id = ? AND subtag_id = ?;', ( namespace_id, subtag_id ) ).fetchone()
     
     if result is None:
         
         self._c.execute( 'INSERT INTO tags ( namespace_id, subtag_id ) VALUES ( ?, ? );', ( namespace_id, subtag_id ) )
         
         tag_id = self._c.lastrowid
         
     else:
         
         ( tag_id, ) = result
         
     
     return tag_id
예제 #22
0
    def CheckPermission(self, permission):

        if not self.HasPermission(permission):

            raise HydrusExceptions.InsufficientCredentialsException(
                'You do not have permission to: {}'.format(
                    basic_permission_to_str_lookup[permission]))
예제 #23
0
 def CheckCanSeeAllFiles( self ):
     
     with self._lock:
         
         if not ( self._HasPermission( CLIENT_API_PERMISSION_SEARCH_FILES ) and self._search_tag_filter.AllowsEverything() ):
             
             raise HydrusExceptions.InsufficientCredentialsException( 'You do not have permission to see all files, so you cannot do this.' )
def file_service_pred_generator( o, v, u ):
    
    if o.startswith( 'is not' ):
        
        is_in = False
        
    else:
        
        is_in = True
        
    
    o_dict = {
        'currently in' : HC.CONTENT_STATUS_CURRENT,
        'deleted from' : HC.CONTENT_STATUS_DELETED,
        'pending to' : HC.CONTENT_STATUS_PENDING,
        'petitioned from' : HC.CONTENT_STATUS_PETITIONED
    }
    
    status = None
    
    for ( phrase, possible_status ) in o_dict.items():
        
        if phrase in o:
            
            status = possible_status
            
            break
            
        
    
    if status is None:
        
        raise HydrusExceptions.BadRequestException( 'Did not understand the file service status!' )
        
    
    try:
        
        service_name = v
        
        service_key = HG.client_controller.services_manager.GetServiceKeyFromName( HC.FILE_SERVICES, service_name )
        
    except:
        
        raise HydrusExceptions.BadRequestException( 'Could not find the service "{}"!'.format( service_name ) )
        
    
    return ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_SYSTEM_FILE_SERVICE, ( is_in, status, service_key ) )
예제 #25
0
def ParseFFMPEGDuration( lines ):
    
    # get duration (in seconds)
    #   Duration: 00:00:02.46, start: 0.033000, bitrate: 1069 kb/s
    try:
        
        # had a vid with 'Duration:' in title, ha ha, so now a regex
        line = [ l for l in lines if re.search( r'^\s*Duration:', l ) is not None ][0]
        
        if 'Duration: N/A' in line:
            
            return ( None, None )
            
        
        if 'start:' in line:
            
            m = re.search( '(start\\: )' + '-?[0-9]+\\.[0-9]*', line )
            
            start_offset = float( line[ m.start() + 7 : m.end() ] )
            
            if abs( start_offset ) > 1.0: # once had a file with start offset of 957499 seconds jej
                
                start_offset = 0
                
            
        else:
            
            start_offset = 0
            
        
        match = re.search("[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]", line)
        hms = list(map(float, line[match.start()+1:match.end()].split(':')))
        
        if len( hms ) == 1:
            
            duration = hms[0]
            
        elif len( hms ) == 2:
            
            duration = 60 * hms[0] + hms[1]
            
        elif len( hms ) ==3:
            
            duration = 3600 * hms[0] + 60 * hms[1] + hms[2]
            
        
        if duration == 0:
            
            return ( None, None )
            
        
        file_duration = duration + start_offset
        stream_duration = duration
        
        return ( file_duration, stream_duration )
        
    except:
        
        raise HydrusExceptions.DamagedOrUnusualFileException( 'Error reading duration!' )
예제 #26
0
 def GetServiceId( self, service_key: bytes ) -> int:
     
     if service_key in self._service_keys_to_service_ids:
         
         return self._service_keys_to_service_ids[ service_key ]
         
     
     raise HydrusExceptions.DataMissing( 'Service id error in database: key "{}" does not exist!'.format( service_key.hex() ) )
예제 #27
0
    def GetPageData(self, hash) -> "GUISessionPageData":

        if hash not in self._hashes_to_page_data:

            raise HydrusExceptions.DataMissing(
                'The page hash "{}" was not found!'.format(hash.hex()))

        return self._hashes_to_page_data[hash]
예제 #28
0
 def _checkService( self, request ):
     
     if self.BLOCKED_WHEN_BUSY and HG.server_busy.locked():
         
         raise HydrusExceptions.ServerBusyException( 'This server is busy, please try again later.' )
         
     
     return request
예제 #29
0
 def GetServiceType( self, service_id ) -> ClientServices.Service:
     
     if service_id in self._service_ids_to_services:
         
         return self._service_ids_to_services[ service_id ].GetServiceType()
         
     
     raise HydrusExceptions.DataMissing( 'Service id error in database: id "{}" does not exist!'.format( service_id ) )
예제 #30
0
 def _GetCurrentFrame( self ):
     
     if self._cv_mode:
         
         ( retval, numpy_image ) = self._cv_video.read()
         
         if not retval:
             
             self._next_render_index = ( self._next_render_index + 1 ) % self._num_frames
             
             raise HydrusExceptions.CantRenderWithCVException( 'CV could not render frame ' + str( self._next_render_index - 1 ) + '.' )
             
         
     else:
         
         current_frame = HydrusImageHandling.Dequantize( self._pil_image )
         
         if current_frame.mode == 'RGBA':
             
             if self._pil_canvas is None:
                 
                 self._pil_canvas = current_frame
                 
             else:
                 
                 self._pil_canvas.paste( current_frame, None, current_frame ) # use the rgba image as its own mask
                 
             
         elif current_frame.mode == 'RGB':
             
             self._pil_canvas = current_frame
             
         
         numpy_image = HydrusImageHandling.GenerateNumPyImageFromPILImage( self._pil_canvas )
         
     
     self._next_render_index = ( self._next_render_index + 1 ) % self._num_frames
     
     if self._next_render_index == 0:
         
         self._RewindGIF()
         
     else:
         
         if not self._cv_mode:
             
             self._pil_image.seek( self._next_render_index )
             
             if self._pil_global_palette is not None and self._pil_image.palette == self._pil_global_palette: # for some reason, when pil falls back from local palette to global palette, a bunch of important variables reset!
                 
                 self._pil_image.palette.dirty = self._pil_dirty
                 self._pil_image.palette.mode = self._pil_mode
                 self._pil_image.palette.rawmode = self._pil_rawmode
                 
             
         
     
     return numpy_image