202 lines
7.7 KiB
Python
202 lines
7.7 KiB
Python
import sqlite3
|
|
import typing
|
|
|
|
from hydrus.core import HydrusConstants as HC
|
|
from hydrus.core import HydrusGlobals as HG
|
|
|
|
from hydrus.client import ClientConstants as CC
|
|
from hydrus.client.db import ClientDBModule
|
|
|
|
class ClientDBFilesViewingStats( ClientDBModule.ClientDBModule ):
|
|
|
|
def __init__(
|
|
self,
|
|
cursor: sqlite3.Cursor
|
|
):
|
|
|
|
ClientDBModule.ClientDBModule.__init__( self, 'client files viewing stats', cursor )
|
|
|
|
|
|
def _GetInitialIndexGenerationDict( self ) -> dict:
|
|
|
|
index_generation_dict = {}
|
|
|
|
index_generation_dict[ 'main.file_viewing_stats' ] = [
|
|
( [ 'last_viewed_timestamp' ], False, 400 ),
|
|
( [ 'views' ], False, 400 ),
|
|
( [ 'viewtime' ], False, 400 )
|
|
]
|
|
|
|
return index_generation_dict
|
|
|
|
|
|
def _GetInitialTableGenerationDict( self ) -> dict:
|
|
|
|
return {
|
|
'main.file_viewing_stats' : ( 'CREATE TABLE IF NOT EXISTS {} ( hash_id INTEGER, canvas_type INTEGER, last_viewed_timestamp INTEGER, views INTEGER, viewtime INTEGER, PRIMARY KEY ( hash_id, canvas_type ) );', 400 )
|
|
}
|
|
|
|
|
|
def AddViews( self, hash_id, canvas_type, view_timestamp, views_delta, viewtime_delta ):
|
|
|
|
self._Execute( 'INSERT OR IGNORE INTO file_viewing_stats ( hash_id, canvas_type, last_viewed_timestamp, views, viewtime ) VALUES ( ?, ?, ?, ?, ? );', ( hash_id, canvas_type, 0, 0, 0 ) )
|
|
|
|
self._Execute( 'UPDATE file_viewing_stats SET last_viewed_timestamp = ?, views = views + ?, viewtime = viewtime + ? WHERE hash_id = ? AND canvas_type = ?;', ( view_timestamp, views_delta, viewtime_delta, hash_id, canvas_type ) )
|
|
|
|
|
|
def ClearAllStats( self ):
|
|
|
|
self._Execute( 'DELETE FROM file_viewing_stats;' )
|
|
|
|
|
|
def ClearViews( self, hash_ids ):
|
|
|
|
self._ExecuteMany( 'DELETE FROM file_viewing_stats WHERE hash_id = ?;', ( ( hash_id, ) for hash_id in hash_ids ) )
|
|
|
|
|
|
def CullFileViewingStatistics( self ):
|
|
|
|
media_min = HG.client_controller.new_options.GetNoneableInteger( 'file_viewing_statistics_media_min_time' )
|
|
media_max = HG.client_controller.new_options.GetNoneableInteger( 'file_viewing_statistics_media_max_time' )
|
|
preview_min = HG.client_controller.new_options.GetNoneableInteger( 'file_viewing_statistics_preview_min_time' )
|
|
preview_max = HG.client_controller.new_options.GetNoneableInteger( 'file_viewing_statistics_preview_max_time' )
|
|
|
|
if media_min is not None and media_max is not None and media_min > media_max:
|
|
|
|
raise Exception( 'Media min was greater than media max! Abandoning cull now!' )
|
|
|
|
|
|
if preview_min is not None and preview_max is not None and preview_min > preview_max:
|
|
|
|
raise Exception( 'Preview min was greater than preview max! Abandoning cull now!' )
|
|
|
|
|
|
if media_min is not None:
|
|
|
|
self._Execute( 'UPDATE file_viewing_stats SET views = CAST( viewtime / ? AS INTEGER ) WHERE views * ? > viewtime AND canvas_type = ?;', ( media_min, media_min, CC.CANVAS_MEDIA_VIEWER ) )
|
|
|
|
|
|
if media_max is not None:
|
|
|
|
self._Execute( 'UPDATE file_viewing_stats SET viewtime = views * ? WHERE viewtime > views * ? AND canvas_type = ?;', ( media_max, media_max, CC.CANVAS_MEDIA_VIEWER ) )
|
|
|
|
|
|
if preview_min is not None:
|
|
|
|
self._Execute( 'UPDATE file_viewing_stats SET views = CAST( viewtime / ? AS INTEGER ) WHERE views * ? > viewtime AND canvas_type = ?;', ( preview_min, preview_min, CC.CANVAS_PREVIEW ) )
|
|
|
|
|
|
if preview_max is not None:
|
|
|
|
self._Execute( 'UPDATE file_viewing_stats SET viewtime = views * ? WHERE viewtime > views * ? AND canvas_type = ?;', ( preview_max, preview_max, CC.CANVAS_PREVIEW ) )
|
|
|
|
|
|
|
|
def GetHashIdsFromFileViewingStatistics( self, view_type, viewing_locations, operator, viewing_value ) -> typing.Set[ int ]:
|
|
|
|
# only works for positive values like '> 5'. won't work for '= 0' or '< 1' since those are absent from the table
|
|
|
|
include_media = 'media' in viewing_locations
|
|
include_preview = 'preview' in viewing_locations
|
|
|
|
canvas_type_predicate = '1=1'
|
|
group_by_phrase = ''
|
|
having_phrase = ''
|
|
|
|
if view_type == 'views':
|
|
|
|
content_phrase = 'views'
|
|
|
|
elif view_type == 'viewtime':
|
|
|
|
content_phrase = 'viewtime'
|
|
|
|
else:
|
|
|
|
return set()
|
|
|
|
|
|
if include_media and include_preview:
|
|
|
|
group_by_phrase = ' GROUP BY hash_id'
|
|
|
|
if view_type == 'views':
|
|
|
|
content_phrase = 'SUM( views )'
|
|
|
|
elif view_type == 'viewtime':
|
|
|
|
content_phrase = 'SUM( viewtime )'
|
|
|
|
|
|
elif include_media:
|
|
|
|
canvas_type_predicate = 'canvas_type = {}'.format( CC.CANVAS_MEDIA_VIEWER )
|
|
|
|
elif include_preview:
|
|
|
|
canvas_type_predicate = 'canvas_type = {}'.format( CC.CANVAS_PREVIEW )
|
|
|
|
else:
|
|
|
|
return set()
|
|
|
|
|
|
if operator == CC.UNICODE_ALMOST_EQUAL_TO:
|
|
|
|
lower_bound = int( 0.8 * viewing_value )
|
|
upper_bound = int( 1.2 * viewing_value )
|
|
|
|
test_phrase = '{} BETWEEN {} AND {}'.format( content_phrase, str( lower_bound ), str( upper_bound ) )
|
|
|
|
else:
|
|
|
|
test_phrase = '{} {} {}'.format( content_phrase, operator, str( viewing_value ) )
|
|
|
|
|
|
if include_media and include_preview:
|
|
|
|
select_statement = 'SELECT hash_id FROM file_viewing_stats {} HAVING {};'.format( group_by_phrase, test_phrase )
|
|
|
|
else:
|
|
|
|
select_statement = 'SELECT hash_id FROM file_viewing_stats WHERE {} AND {}{};'.format( test_phrase, canvas_type_predicate, group_by_phrase )
|
|
|
|
|
|
hash_ids = self._STS( self._Execute( select_statement ) )
|
|
|
|
return hash_ids
|
|
|
|
|
|
def GetHashIdsFromLastViewed( self, min_last_viewed_timestamp = None, max_last_viewed_timestamp = None ) -> typing.Set[ int ]:
|
|
|
|
last_viewed_timestamp_predicates = []
|
|
|
|
if min_last_viewed_timestamp is not None: last_viewed_timestamp_predicates.append( 'last_viewed_timestamp >= ' + str( min_last_viewed_timestamp ) )
|
|
if max_last_viewed_timestamp is not None: last_viewed_timestamp_predicates.append( 'last_viewed_timestamp <= ' + str( max_last_viewed_timestamp ) )
|
|
|
|
if len( last_viewed_timestamp_predicates ) == 0:
|
|
|
|
return set()
|
|
|
|
|
|
pred_string = ' AND '.join( last_viewed_timestamp_predicates )
|
|
|
|
last_viewed_timestamp_hash_ids = self._STS( self._Execute( 'SELECT hash_id FROM file_viewing_stats WHERE canvas_type = ? AND {};'.format( pred_string ), ( CC.CANVAS_MEDIA_VIEWER, ) ) )
|
|
|
|
return last_viewed_timestamp_hash_ids
|
|
|
|
|
|
def GetTablesAndColumnsThatUseDefinitions( self, content_type: int ) -> typing.List[ typing.Tuple[ str, str ] ]:
|
|
|
|
tables_and_columns = []
|
|
|
|
if content_type == HC.CONTENT_TYPE_HASH:
|
|
|
|
tables_and_columns.append( ( 'file_viewing_stats', 'hash_id' ) )
|
|
|
|
|
|
return tables_and_columns
|
|
|
|
|