2014-04-23 20:56:12 +00:00
import os
import sys
# dirs
BASE_DIR = sys . path [ 0 ]
BIN_DIR = BASE_DIR + os . path . sep + ' bin '
DB_DIR = BASE_DIR + os . path . sep + ' db '
2014-11-12 23:33:13 +00:00
CLIENT_ARCHIVES_DIR = DB_DIR + os . path . sep + ' client_archives '
2014-04-23 20:56:12 +00:00
CLIENT_FILES_DIR = DB_DIR + os . path . sep + ' client_files '
SERVER_FILES_DIR = DB_DIR + os . path . sep + ' server_files '
CLIENT_THUMBNAILS_DIR = DB_DIR + os . path . sep + ' client_thumbnails '
SERVER_THUMBNAILS_DIR = DB_DIR + os . path . sep + ' server_thumbnails '
SERVER_MESSAGES_DIR = DB_DIR + os . path . sep + ' server_messages '
CLIENT_UPDATES_DIR = DB_DIR + os . path . sep + ' client_updates '
SERVER_UPDATES_DIR = DB_DIR + os . path . sep + ' server_updates '
LOGS_DIR = BASE_DIR + os . path . sep + ' logs '
STATIC_DIR = BASE_DIR + os . path . sep + ' static '
TEMP_DIR = BASE_DIR + os . path . sep + ' temp '
#
PLATFORM_WINDOWS = False
PLATFORM_OSX = False
PLATFORM_LINUX = False
if sys . platform == ' win32 ' : PLATFORM_WINDOWS = True
elif sys . platform == ' darwin ' : PLATFORM_OSX = True
elif sys . platform == ' linux2 ' : PLATFORM_LINUX = True
2014-10-22 22:31:58 +00:00
#if PLATFORM_LINUX:
#
# if not hasattr( sys, 'frozen' ):
#
# import wxversion
#
# if not wxversion.checkInstalled( '2.9' ): raise Exception( 'Need wxPython 2.9 on Linux!' )
#
# wxversion.select( '2.9' )
#
2014-04-23 20:56:12 +00:00
import wx
2013-08-28 21:31:52 +00:00
import bisect
2013-09-04 16:48:44 +00:00
import bs4
2013-02-19 00:11:43 +00:00
import collections
2013-10-30 22:28:06 +00:00
import cStringIO
2013-04-10 18:10:37 +00:00
import httplib
2013-07-24 20:26:00 +00:00
import HydrusExceptions
2014-01-29 21:59:42 +00:00
import HydrusNetworking
2013-02-19 00:11:43 +00:00
import HydrusPubSub
2013-06-12 22:53:31 +00:00
import itertools
2013-02-19 00:11:43 +00:00
import locale
import Queue
import re
import sqlite3
2015-01-07 23:09:00 +00:00
import subprocess
2013-02-19 00:11:43 +00:00
import threading
import time
import traceback
import yaml
2013-08-07 22:25:18 +00:00
options = { }
2013-02-19 00:11:43 +00:00
# Misc
2014-10-01 22:58:32 +00:00
NETWORK_VERSION = 15
2015-01-14 22:27:55 +00:00
SOFTWARE_VERSION = 144
2013-02-19 00:11:43 +00:00
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200 , 200 )
HYDRUS_KEY_LENGTH = 32
UPDATE_DURATION = 100000
2013-12-04 22:44:16 +00:00
lifetimes = [ ( ' one month ' , 31 * 86400 ) , ( ' three months ' , 3 * 31 * 86400 ) , ( ' six months ' , 6 * 31 * 86400 ) , ( ' one year ' , 12 * 31 * 86400 ) , ( ' two years ' , 24 * 31 * 86400 ) , ( ' five years ' , 60 * 31 * 86400 ) , ( ' does not expire ' , None ) ]
2013-02-19 00:11:43 +00:00
2013-07-10 20:25:57 +00:00
app = None
2013-02-19 00:11:43 +00:00
shutdown = False
2014-01-29 21:59:42 +00:00
2013-04-03 20:56:07 +00:00
is_first_start = False
2013-08-14 20:21:49 +00:00
is_db_updated = False
2014-02-19 22:37:23 +00:00
repos_changed = False
subs_changed = False
2013-02-19 00:11:43 +00:00
2014-01-29 21:59:42 +00:00
http = None
2014-06-18 21:53:48 +00:00
currently_doing_pubsub = False
2013-08-28 21:31:52 +00:00
2013-02-19 00:11:43 +00:00
# Enums
2013-06-12 22:53:31 +00:00
CONTENT_DATA_TYPE_MAPPINGS = 0
CONTENT_DATA_TYPE_TAG_SIBLINGS = 1
CONTENT_DATA_TYPE_TAG_PARENTS = 2
CONTENT_DATA_TYPE_FILES = 3
CONTENT_DATA_TYPE_RATINGS = 4
2013-04-10 18:10:37 +00:00
CONTENT_UPDATE_ADD = 0
CONTENT_UPDATE_DELETE = 1
CONTENT_UPDATE_PENDING = 2
CONTENT_UPDATE_RESCIND_PENDING = 3
CONTENT_UPDATE_PETITION = 4
CONTENT_UPDATE_RESCIND_PETITION = 5
CONTENT_UPDATE_EDIT_LOG = 6
CONTENT_UPDATE_ARCHIVE = 7
CONTENT_UPDATE_INBOX = 8
CONTENT_UPDATE_RATING = 9
CONTENT_UPDATE_RATINGS_FILTER = 10
2013-06-12 22:53:31 +00:00
CONTENT_UPDATE_DENY_PEND = 11
CONTENT_UPDATE_DENY_PETITION = 12
2013-11-20 21:12:21 +00:00
CONTENT_UPDATE_ADVANCED = 13
2013-04-10 18:10:37 +00:00
2013-11-06 18:22:07 +00:00
content_update_string_lookup = { }
content_update_string_lookup [ CONTENT_UPDATE_ADD ] = ' add '
content_update_string_lookup [ CONTENT_UPDATE_DELETE ] = ' delete '
content_update_string_lookup [ CONTENT_UPDATE_PENDING ] = ' pending '
content_update_string_lookup [ CONTENT_UPDATE_RESCIND_PENDING ] = ' rescind pending '
content_update_string_lookup [ CONTENT_UPDATE_PETITION ] = ' petition '
content_update_string_lookup [ CONTENT_UPDATE_RESCIND_PETITION ] = ' rescind petition '
content_update_string_lookup [ CONTENT_UPDATE_EDIT_LOG ] = ' edit log '
content_update_string_lookup [ CONTENT_UPDATE_ARCHIVE ] = ' archive '
content_update_string_lookup [ CONTENT_UPDATE_INBOX ] = ' inbox '
content_update_string_lookup [ CONTENT_UPDATE_RATING ] = ' rating '
content_update_string_lookup [ CONTENT_UPDATE_RATINGS_FILTER ] = ' incomplete ratings '
content_update_string_lookup [ CONTENT_UPDATE_DENY_PEND ] = ' deny pend '
content_update_string_lookup [ CONTENT_UPDATE_DENY_PETITION ] = ' deny petition '
2013-07-17 20:56:13 +00:00
IMPORT_FOLDER_TYPE_DELETE = 0
IMPORT_FOLDER_TYPE_SYNCHRONISE = 1
2013-02-19 00:11:43 +00:00
GET_DATA = 0
POST_DATA = 1
POST_PETITIONS = 2
RESOLVE_PETITIONS = 3
MANAGE_USERS = 4
GENERAL_ADMIN = 5
EDIT_SERVICES = 6
2014-10-01 22:58:32 +00:00
UNKNOWN_PERMISSION = 7
2013-02-19 00:11:43 +00:00
CREATABLE_PERMISSIONS = [ GET_DATA , POST_DATA , POST_PETITIONS , RESOLVE_PETITIONS , MANAGE_USERS , GENERAL_ADMIN ]
ADMIN_PERMISSIONS = [ RESOLVE_PETITIONS , MANAGE_USERS , GENERAL_ADMIN , EDIT_SERVICES ]
permissions_string_lookup = { }
permissions_string_lookup [ GET_DATA ] = ' get data '
permissions_string_lookup [ POST_DATA ] = ' post data '
permissions_string_lookup [ POST_PETITIONS ] = ' post petitions '
permissions_string_lookup [ RESOLVE_PETITIONS ] = ' resolve petitions '
permissions_string_lookup [ MANAGE_USERS ] = ' manage users '
permissions_string_lookup [ GENERAL_ADMIN ] = ' general administration '
permissions_string_lookup [ EDIT_SERVICES ] = ' edit services '
2014-10-01 22:58:32 +00:00
permissions_string_lookup [ UNKNOWN_PERMISSION ] = ' unknown '
2013-02-19 00:11:43 +00:00
TAG_REPOSITORY = 0
FILE_REPOSITORY = 1
LOCAL_FILE = 2
MESSAGE_DEPOT = 3
LOCAL_TAG = 5
LOCAL_RATING_NUMERICAL = 6
LOCAL_RATING_LIKE = 7
RATING_NUMERICAL_REPOSITORY = 8
RATING_LIKE_REPOSITORY = 9
2013-05-29 20:19:54 +00:00
COMBINED_TAG = 10
COMBINED_FILE = 11
2014-05-14 20:46:38 +00:00
LOCAL_BOORU = 12
2013-02-19 00:11:43 +00:00
SERVER_ADMIN = 99
NULL_SERVICE = 100
service_string_lookup = { }
service_string_lookup [ TAG_REPOSITORY ] = ' hydrus tag repository '
service_string_lookup [ FILE_REPOSITORY ] = ' hydrus file repository '
service_string_lookup [ LOCAL_FILE ] = ' hydrus local file service '
service_string_lookup [ MESSAGE_DEPOT ] = ' hydrus message depot '
2013-10-02 22:06:06 +00:00
service_string_lookup [ LOCAL_TAG ] = ' local tag service '
service_string_lookup [ LOCAL_RATING_NUMERICAL ] = ' local numerical rating service '
service_string_lookup [ LOCAL_RATING_LIKE ] = ' local like/dislike rating service '
service_string_lookup [ RATING_NUMERICAL_REPOSITORY ] = ' hydrus numerical rating repository '
service_string_lookup [ RATING_LIKE_REPOSITORY ] = ' hydrus like/dislike rating repository '
service_string_lookup [ COMBINED_TAG ] = ' virtual combined tag service '
service_string_lookup [ COMBINED_FILE ] = ' virtual combined file service '
2014-05-14 20:46:38 +00:00
service_string_lookup [ LOCAL_BOORU ] = ' hydrus local booru '
2013-02-19 00:11:43 +00:00
service_string_lookup [ SERVER_ADMIN ] = ' hydrus server administration '
2013-10-02 22:06:06 +00:00
service_string_lookup [ NULL_SERVICE ] = ' null service '
2013-02-19 00:11:43 +00:00
RATINGS_SERVICES = [ LOCAL_RATING_LIKE , LOCAL_RATING_NUMERICAL , RATING_LIKE_REPOSITORY , RATING_NUMERICAL_REPOSITORY ]
REPOSITORIES = [ TAG_REPOSITORY , FILE_REPOSITORY , RATING_LIKE_REPOSITORY , RATING_NUMERICAL_REPOSITORY ]
2013-06-12 22:53:31 +00:00
RESTRICTED_SERVICES = ( REPOSITORIES ) + [ SERVER_ADMIN , MESSAGE_DEPOT ]
2013-02-19 00:11:43 +00:00
REMOTE_SERVICES = list ( RESTRICTED_SERVICES )
2014-11-12 23:33:13 +00:00
TAG_SERVICES = [ LOCAL_TAG , TAG_REPOSITORY ]
2014-08-27 22:15:22 +00:00
LOCAL_SERVICES = [ LOCAL_FILE , LOCAL_TAG , LOCAL_RATING_LIKE , LOCAL_RATING_NUMERICAL , LOCAL_BOORU , COMBINED_FILE , COMBINED_TAG ]
2014-11-12 23:33:13 +00:00
NONEDITABLE_SERVICES = [ LOCAL_BOORU , LOCAL_FILE , LOCAL_TAG ]
2014-05-14 20:46:38 +00:00
ALL_SERVICES = list ( REMOTE_SERVICES ) + list ( LOCAL_SERVICES )
2013-02-19 00:11:43 +00:00
SERVICES_WITH_THUMBNAILS = [ FILE_REPOSITORY , LOCAL_FILE ]
DELETE_FILES_PETITION = 0
DELETE_TAG_PETITION = 1
BAN = 0
SUPERBAN = 1
CHANGE_ACCOUNT_TYPE = 2
2014-10-01 22:58:32 +00:00
ADD_TO_EXPIRES = 3
SET_EXPIRES = 4
2013-02-19 00:11:43 +00:00
CURRENT = 0
PENDING = 1
DELETED = 2
PETITIONED = 3
2013-05-29 20:19:54 +00:00
DELETED_PENDING = 4
2013-02-19 00:11:43 +00:00
HIGH_PRIORITY = 0
LOW_PRIORITY = 2
SCORE_PETITION = 0
SERVICE_INFO_NUM_FILES = 0
SERVICE_INFO_NUM_INBOX = 1
SERVICE_INFO_NUM_LOCAL = 2
SERVICE_INFO_NUM_MAPPINGS = 3
SERVICE_INFO_NUM_DELETED_MAPPINGS = 4
SERVICE_INFO_NUM_DELETED_FILES = 5
SERVICE_INFO_NUM_THUMBNAILS = 6
SERVICE_INFO_NUM_THUMBNAILS_LOCAL = 7
SERVICE_INFO_TOTAL_SIZE = 8
SERVICE_INFO_NUM_NAMESPACES = 9
SERVICE_INFO_NUM_TAGS = 10
SERVICE_INFO_NUM_PENDING = 11
SERVICE_INFO_NUM_CONVERSATIONS = 12
SERVICE_INFO_NUM_UNREAD = 13
SERVICE_INFO_NUM_DRAFTS = 14
2013-05-29 20:19:54 +00:00
SERVICE_INFO_NUM_PENDING_MAPPINGS = 15
SERVICE_INFO_NUM_PETITIONED_MAPPINGS = 16
SERVICE_INFO_NUM_PENDING_FILES = 15
SERVICE_INFO_NUM_PETITIONED_FILES = 16
2013-06-12 22:53:31 +00:00
SERVICE_INFO_NUM_PENDING_TAG_SIBLINGS = 17
SERVICE_INFO_NUM_PETITIONED_TAG_SIBLINGS = 18
SERVICE_INFO_NUM_PENDING_TAG_PARENTS = 19
SERVICE_INFO_NUM_PETITIONED_TAG_PARENTS = 20
2014-05-14 20:46:38 +00:00
SERVICE_INFO_NUM_SHARES = 21
2013-02-19 00:11:43 +00:00
2013-04-10 18:10:37 +00:00
SERVICE_UPDATE_ACCOUNT = 0
SERVICE_UPDATE_DELETE_PENDING = 1
SERVICE_UPDATE_ERROR = 2
2014-03-05 22:44:02 +00:00
SERVICE_UPDATE_BEGIN_END = 3
2013-04-10 18:10:37 +00:00
SERVICE_UPDATE_RESET = 4
SERVICE_UPDATE_REQUEST_MADE = 5
SERVICE_UPDATE_LAST_CHECK = 6
2013-06-12 22:53:31 +00:00
SERVICE_UPDATE_NEWS = 7
2014-03-05 22:44:02 +00:00
SERVICE_UPDATE_NEXT_DOWNLOAD_TIMESTAMP = 8
SERVICE_UPDATE_NEXT_PROCESSING_TIMESTAMP = 9
2013-04-10 18:10:37 +00:00
2013-02-19 00:11:43 +00:00
ADD = 0
DELETE = 1
EDIT = 2
2014-02-12 23:09:38 +00:00
SET = 3
2013-02-19 00:11:43 +00:00
APPROVE = 0
DENY = 1
GET = 0
POST = 1
OPTIONS = 2
APPLICATION_HYDRUS_CLIENT_COLLECTION = 0
IMAGE_JPEG = 1
IMAGE_PNG = 2
IMAGE_GIF = 3
IMAGE_BMP = 4
APPLICATION_FLASH = 5
APPLICATION_YAML = 6
IMAGE_ICON = 7
TEXT_HTML = 8
VIDEO_FLV = 9
2013-03-15 02:38:12 +00:00
APPLICATION_PDF = 10
2013-05-01 17:21:53 +00:00
APPLICATION_ZIP = 11
APPLICATION_HYDRUS_ENCRYPTED_ZIP = 12
2013-07-10 20:25:57 +00:00
AUDIO_MP3 = 13
VIDEO_MP4 = 14
2013-07-17 20:56:13 +00:00
AUDIO_OGG = 15
AUDIO_FLAC = 16
2013-08-14 20:21:49 +00:00
AUDIO_WMA = 17
VIDEO_WMV = 18
UNDETERMINED_WM = 19
2014-04-30 21:31:40 +00:00
VIDEO_MKV = 20
VIDEO_WEBM = 21
2013-02-19 00:11:43 +00:00
APPLICATION_OCTET_STREAM = 100
APPLICATION_UNKNOWN = 101
2014-04-30 21:31:40 +00:00
ALLOWED_MIMES = ( IMAGE_JPEG , IMAGE_PNG , IMAGE_GIF , IMAGE_BMP , APPLICATION_FLASH , VIDEO_FLV , VIDEO_MP4 , VIDEO_MKV , VIDEO_WEBM , APPLICATION_PDF , AUDIO_MP3 , AUDIO_OGG , AUDIO_FLAC , AUDIO_WMA , VIDEO_WMV )
2013-02-19 00:11:43 +00:00
IMAGES = ( IMAGE_JPEG , IMAGE_PNG , IMAGE_GIF , IMAGE_BMP )
2013-08-14 20:21:49 +00:00
AUDIO = ( AUDIO_MP3 , AUDIO_OGG , AUDIO_FLAC , AUDIO_WMA )
2013-07-10 20:25:57 +00:00
2014-04-30 21:31:40 +00:00
VIDEO = ( VIDEO_FLV , VIDEO_MP4 , VIDEO_WMV , VIDEO_MKV , VIDEO_WEBM )
2013-07-10 20:25:57 +00:00
2013-05-01 17:21:53 +00:00
APPLICATIONS = ( APPLICATION_FLASH , APPLICATION_PDF , APPLICATION_ZIP )
2013-03-15 02:38:12 +00:00
2013-08-14 20:21:49 +00:00
NOISY_MIMES = tuple ( [ APPLICATION_FLASH ] + list ( AUDIO ) + list ( VIDEO ) )
2013-02-19 00:11:43 +00:00
2013-05-01 17:21:53 +00:00
ARCHIVES = ( APPLICATION_ZIP , APPLICATION_HYDRUS_ENCRYPTED_ZIP )
2014-06-25 20:37:06 +00:00
MIMES_WITH_THUMBNAILS = ( IMAGE_JPEG , IMAGE_PNG , IMAGE_GIF , IMAGE_BMP , VIDEO_WEBM , VIDEO_FLV , VIDEO_MP4 , VIDEO_WMV , VIDEO_MKV , VIDEO_WEBM )
2013-02-19 00:11:43 +00:00
2013-07-10 20:25:57 +00:00
# mp3 header is complicated
2013-02-19 00:11:43 +00:00
mime_enum_lookup = { }
mime_enum_lookup [ ' collection ' ] = APPLICATION_HYDRUS_CLIENT_COLLECTION
mime_enum_lookup [ ' image/jpe ' ] = IMAGE_JPEG
mime_enum_lookup [ ' image/jpeg ' ] = IMAGE_JPEG
mime_enum_lookup [ ' image/jpg ' ] = IMAGE_JPEG
2013-07-17 20:56:13 +00:00
mime_enum_lookup [ ' image/x-png ' ] = IMAGE_PNG
2013-02-19 00:11:43 +00:00
mime_enum_lookup [ ' image/png ' ] = IMAGE_PNG
mime_enum_lookup [ ' image/gif ' ] = IMAGE_GIF
mime_enum_lookup [ ' image/bmp ' ] = IMAGE_BMP
mime_enum_lookup [ ' image ' ] = IMAGES
mime_enum_lookup [ ' image/vnd.microsoft.icon ' ] = IMAGE_ICON
mime_enum_lookup [ ' application/x-shockwave-flash ' ] = APPLICATION_FLASH
mime_enum_lookup [ ' application/octet-stream ' ] = APPLICATION_OCTET_STREAM
mime_enum_lookup [ ' application/x-yaml ' ] = APPLICATION_YAML
2013-07-17 20:56:13 +00:00
mime_enum_lookup [ ' PDF document ' ] = APPLICATION_PDF
2013-03-15 02:38:12 +00:00
mime_enum_lookup [ ' application/pdf ' ] = APPLICATION_PDF
2013-05-01 17:21:53 +00:00
mime_enum_lookup [ ' application/zip ' ] = APPLICATION_ZIP
mime_enum_lookup [ ' application/hydrus-encrypted-zip ' ] = APPLICATION_HYDRUS_ENCRYPTED_ZIP
2013-03-15 02:38:12 +00:00
mime_enum_lookup [ ' application ' ] = APPLICATIONS
2013-07-10 20:25:57 +00:00
mime_enum_lookup [ ' audio/mp3 ' ] = AUDIO_MP3
2013-07-17 20:56:13 +00:00
mime_enum_lookup [ ' audio/ogg ' ] = AUDIO_OGG
mime_enum_lookup [ ' audio/flac ' ] = AUDIO_FLAC
2013-08-14 20:21:49 +00:00
mime_enum_lookup [ ' audio/x-ms-wma ' ] = AUDIO_WMA
2013-02-19 00:11:43 +00:00
mime_enum_lookup [ ' text/html ' ] = TEXT_HTML
mime_enum_lookup [ ' video/x-flv ' ] = VIDEO_FLV
2013-08-14 20:21:49 +00:00
mime_enum_lookup [ ' video/mp4 ' ] = VIDEO_MP4
mime_enum_lookup [ ' video/x-ms-wmv ' ] = VIDEO_WMV
2014-04-30 21:31:40 +00:00
mime_enum_lookup [ ' video/x-matroska ' ] = VIDEO_MKV
mime_enum_lookup [ ' video/webm ' ] = VIDEO_WEBM
2013-08-14 20:21:49 +00:00
mime_enum_lookup [ ' video ' ] = VIDEO
2013-02-19 00:11:43 +00:00
mime_enum_lookup [ ' unknown mime ' ] = APPLICATION_UNKNOWN
mime_string_lookup = { }
mime_string_lookup [ APPLICATION_HYDRUS_CLIENT_COLLECTION ] = ' collection '
mime_string_lookup [ IMAGE_JPEG ] = ' image/jpg '
mime_string_lookup [ IMAGE_PNG ] = ' image/png '
mime_string_lookup [ IMAGE_GIF ] = ' image/gif '
mime_string_lookup [ IMAGE_BMP ] = ' image/bmp '
mime_string_lookup [ IMAGES ] = ' image '
mime_string_lookup [ IMAGE_ICON ] = ' image/vnd.microsoft.icon '
mime_string_lookup [ APPLICATION_FLASH ] = ' application/x-shockwave-flash '
mime_string_lookup [ APPLICATION_OCTET_STREAM ] = ' application/octet-stream '
mime_string_lookup [ APPLICATION_YAML ] = ' application/x-yaml '
2013-03-15 02:38:12 +00:00
mime_string_lookup [ APPLICATION_PDF ] = ' application/pdf '
2013-05-01 17:21:53 +00:00
mime_string_lookup [ APPLICATION_ZIP ] = ' application/zip '
mime_string_lookup [ APPLICATION_HYDRUS_ENCRYPTED_ZIP ] = ' application/hydrus-encrypted-zip '
2013-03-15 02:38:12 +00:00
mime_string_lookup [ APPLICATIONS ] = ' application '
2013-07-10 20:25:57 +00:00
mime_string_lookup [ AUDIO_MP3 ] = ' audio/mp3 '
2013-07-17 20:56:13 +00:00
mime_string_lookup [ AUDIO_OGG ] = ' audio/ogg '
mime_string_lookup [ AUDIO_FLAC ] = ' audio/flac '
2013-08-14 20:21:49 +00:00
mime_string_lookup [ AUDIO_WMA ] = ' audio/x-ms-wma '
2013-07-24 20:26:00 +00:00
mime_string_lookup [ AUDIO ] = ' audio '
2013-02-19 00:11:43 +00:00
mime_string_lookup [ TEXT_HTML ] = ' text/html '
mime_string_lookup [ VIDEO_FLV ] = ' video/x-flv '
2013-08-14 20:21:49 +00:00
mime_string_lookup [ VIDEO_MP4 ] = ' video/mp4 '
mime_string_lookup [ VIDEO_WMV ] = ' video/x-ms-wmv '
2014-04-30 21:31:40 +00:00
mime_string_lookup [ VIDEO_MKV ] = ' video/x-matroska '
mime_string_lookup [ VIDEO_WEBM ] = ' video/webm '
2013-08-14 20:21:49 +00:00
mime_string_lookup [ VIDEO ] = ' video '
mime_string_lookup [ UNDETERMINED_WM ] = ' audio/x-ms-wma or video/x-ms-wmv '
2013-02-19 00:11:43 +00:00
mime_string_lookup [ APPLICATION_UNKNOWN ] = ' unknown mime '
mime_ext_lookup = { }
mime_ext_lookup [ APPLICATION_HYDRUS_CLIENT_COLLECTION ] = ' .collection '
mime_ext_lookup [ IMAGE_JPEG ] = ' .jpg '
mime_ext_lookup [ IMAGE_PNG ] = ' .png '
mime_ext_lookup [ IMAGE_GIF ] = ' .gif '
mime_ext_lookup [ IMAGE_BMP ] = ' .bmp '
mime_ext_lookup [ IMAGE_ICON ] = ' .ico '
mime_ext_lookup [ APPLICATION_FLASH ] = ' .swf '
mime_ext_lookup [ APPLICATION_OCTET_STREAM ] = ' .bin '
mime_ext_lookup [ APPLICATION_YAML ] = ' .yaml '
2013-03-15 02:38:12 +00:00
mime_ext_lookup [ APPLICATION_PDF ] = ' .pdf '
2013-05-01 17:21:53 +00:00
mime_ext_lookup [ APPLICATION_ZIP ] = ' .zip '
mime_ext_lookup [ APPLICATION_HYDRUS_ENCRYPTED_ZIP ] = ' .zip.encrypted '
2013-07-10 20:25:57 +00:00
mime_ext_lookup [ AUDIO_MP3 ] = ' .mp3 '
2013-07-17 20:56:13 +00:00
mime_ext_lookup [ AUDIO_OGG ] = ' .ogg '
mime_ext_lookup [ AUDIO_FLAC ] = ' .flac '
2013-08-14 20:21:49 +00:00
mime_ext_lookup [ AUDIO_WMA ] = ' .wma '
2013-02-19 00:11:43 +00:00
mime_ext_lookup [ TEXT_HTML ] = ' .html '
mime_ext_lookup [ VIDEO_FLV ] = ' .flv '
2013-08-14 20:21:49 +00:00
mime_ext_lookup [ VIDEO_MP4 ] = ' .mp4 '
mime_ext_lookup [ VIDEO_WMV ] = ' .wmv '
2014-04-30 21:31:40 +00:00
mime_ext_lookup [ VIDEO_MKV ] = ' .mkv '
mime_ext_lookup [ VIDEO_WEBM ] = ' .webm '
2013-02-19 00:11:43 +00:00
mime_ext_lookup [ APPLICATION_UNKNOWN ] = ' '
#mime_ext_lookup[ 'application/x-rar-compressed' ] = '.rar'
ALLOWED_MIME_EXTENSIONS = [ mime_ext_lookup [ mime ] for mime in ALLOWED_MIMES ]
2013-03-27 20:02:51 +00:00
PREDICATE_TYPE_SYSTEM = 0
PREDICATE_TYPE_TAG = 1
PREDICATE_TYPE_NAMESPACE = 2
2013-05-15 18:58:14 +00:00
PREDICATE_TYPE_PARENT = 3
2014-12-31 22:56:38 +00:00
PREDICATE_TYPE_WILDCARD = 4
2013-03-27 20:02:51 +00:00
2014-02-12 23:09:38 +00:00
SITE_TYPE_DEVIANT_ART = 0
SITE_TYPE_GIPHY = 1
SITE_TYPE_PIXIV = 2
SITE_TYPE_BOORU = 3
SITE_TYPE_TUMBLR = 4
SITE_TYPE_HENTAI_FOUNDRY = 5
SITE_TYPE_NEWGROUNDS = 6
2013-04-10 18:10:37 +00:00
2014-09-03 20:26:49 +00:00
site_type_string_lookup = { }
site_type_string_lookup [ SITE_TYPE_BOORU ] = ' booru '
site_type_string_lookup [ SITE_TYPE_DEVIANT_ART ] = ' deviant art '
site_type_string_lookup [ SITE_TYPE_GIPHY ] = ' giphy '
site_type_string_lookup [ SITE_TYPE_HENTAI_FOUNDRY ] = ' hentai foundry '
site_type_string_lookup [ SITE_TYPE_NEWGROUNDS ] = ' newgrounds '
site_type_string_lookup [ SITE_TYPE_PIXIV ] = ' pixiv '
site_type_string_lookup [ SITE_TYPE_TUMBLR ] = ' tumblr '
2013-03-27 20:02:51 +00:00
SYSTEM_PREDICATE_TYPE_EVERYTHING = 0
SYSTEM_PREDICATE_TYPE_INBOX = 1
SYSTEM_PREDICATE_TYPE_ARCHIVE = 2
SYSTEM_PREDICATE_TYPE_UNTAGGED = 3
SYSTEM_PREDICATE_TYPE_NUM_TAGS = 4
SYSTEM_PREDICATE_TYPE_LIMIT = 5
SYSTEM_PREDICATE_TYPE_SIZE = 6
SYSTEM_PREDICATE_TYPE_AGE = 7
SYSTEM_PREDICATE_TYPE_HASH = 8
SYSTEM_PREDICATE_TYPE_WIDTH = 9
SYSTEM_PREDICATE_TYPE_HEIGHT = 10
SYSTEM_PREDICATE_TYPE_RATIO = 11
SYSTEM_PREDICATE_TYPE_DURATION = 12
SYSTEM_PREDICATE_TYPE_MIME = 13
SYSTEM_PREDICATE_TYPE_RATING = 14
SYSTEM_PREDICATE_TYPE_SIMILAR_TO = 15
SYSTEM_PREDICATE_TYPE_LOCAL = 17
SYSTEM_PREDICATE_TYPE_NOT_LOCAL = 18
SYSTEM_PREDICATE_TYPE_NUM_WORDS = 19
2013-04-03 20:56:07 +00:00
SYSTEM_PREDICATE_TYPE_FILE_SERVICE = 20
2013-03-27 20:02:51 +00:00
2013-02-19 00:11:43 +00:00
wxk_code_string_lookup = {
wx . WXK_SPACE : ' space ' ,
wx . WXK_BACK : ' backspace ' ,
wx . WXK_TAB : ' tab ' ,
wx . WXK_RETURN : ' return ' ,
wx . WXK_NUMPAD_ENTER : ' enter ' ,
wx . WXK_PAUSE : ' pause ' ,
wx . WXK_ESCAPE : ' escape ' ,
wx . WXK_INSERT : ' insert ' ,
wx . WXK_DELETE : ' delete ' ,
wx . WXK_UP : ' up ' ,
wx . WXK_DOWN : ' down ' ,
wx . WXK_LEFT : ' left ' ,
wx . WXK_RIGHT : ' right ' ,
wx . WXK_HOME : ' home ' ,
wx . WXK_END : ' end ' ,
wx . WXK_PAGEDOWN : ' page up ' ,
wx . WXK_PAGEUP : ' page down ' ,
wx . WXK_F1 : ' f1 ' ,
wx . WXK_F2 : ' f2 ' ,
wx . WXK_F3 : ' f3 ' ,
wx . WXK_F4 : ' f4 ' ,
wx . WXK_F5 : ' f5 ' ,
wx . WXK_F6 : ' f6 ' ,
wx . WXK_F7 : ' f7 ' ,
wx . WXK_F8 : ' f8 ' ,
wx . WXK_F9 : ' f9 ' ,
wx . WXK_F10 : ' f10 ' ,
wx . WXK_F11 : ' f11 ' ,
wx . WXK_F12 : ' f12 ' ,
wx . WXK_ADD : ' + ' ,
wx . WXK_DIVIDE : ' / ' ,
wx . WXK_SUBTRACT : ' - ' ,
wx . WXK_MULTIPLY : ' * ' ,
wx . WXK_NUMPAD1 : ' numpad 1 ' ,
wx . WXK_NUMPAD2 : ' numpad 2 ' ,
wx . WXK_NUMPAD3 : ' numpad 3 ' ,
wx . WXK_NUMPAD4 : ' numpad 4 ' ,
wx . WXK_NUMPAD5 : ' numpad 5 ' ,
wx . WXK_NUMPAD6 : ' numpad 6 ' ,
wx . WXK_NUMPAD7 : ' numpad 7 ' ,
wx . WXK_NUMPAD8 : ' numpad 8 ' ,
wx . WXK_NUMPAD9 : ' numpad 9 ' ,
wx . WXK_NUMPAD0 : ' numpad 0 ' ,
wx . WXK_NUMPAD_UP : ' numpad up ' ,
wx . WXK_NUMPAD_DOWN : ' numpad down ' ,
wx . WXK_NUMPAD_LEFT : ' numpad left ' ,
wx . WXK_NUMPAD_RIGHT : ' numpad right ' ,
wx . WXK_NUMPAD_HOME : ' numpad home ' ,
wx . WXK_NUMPAD_END : ' numpad end ' ,
wx . WXK_NUMPAD_PAGEDOWN : ' numpad page up ' ,
wx . WXK_NUMPAD_PAGEUP : ' numpad page down ' ,
wx . WXK_NUMPAD_ADD : ' numpad + ' ,
wx . WXK_NUMPAD_DIVIDE : ' numpad / ' ,
wx . WXK_NUMPAD_SUBTRACT : ' numpad - ' ,
2013-03-27 20:02:51 +00:00
wx . WXK_NUMPAD_MULTIPLY : ' numpad * ' ,
wx . WXK_NUMPAD_DELETE : ' numpad delete ' ,
wx . WXK_NUMPAD_DECIMAL : ' numpad decimal '
2013-02-19 00:11:43 +00:00
}
# request checking
BANDWIDTH_CONSUMING_REQUESTS = set ( )
BANDWIDTH_CONSUMING_REQUESTS . add ( ( TAG_REPOSITORY , GET , ' update ' ) )
BANDWIDTH_CONSUMING_REQUESTS . add ( ( TAG_REPOSITORY , POST , ' mappings ' ) )
BANDWIDTH_CONSUMING_REQUESTS . add ( ( TAG_REPOSITORY , POST , ' petitions ' ) )
BANDWIDTH_CONSUMING_REQUESTS . add ( ( FILE_REPOSITORY , GET , ' update ' ) )
BANDWIDTH_CONSUMING_REQUESTS . add ( ( FILE_REPOSITORY , GET , ' file ' ) )
BANDWIDTH_CONSUMING_REQUESTS . add ( ( FILE_REPOSITORY , GET , ' thumbnail ' ) )
BANDWIDTH_CONSUMING_REQUESTS . add ( ( FILE_REPOSITORY , POST , ' file ' ) )
BANDWIDTH_CONSUMING_REQUESTS . add ( ( FILE_REPOSITORY , POST , ' petitions ' ) )
service_requests = [ ]
service_requests . append ( ( GET , ' ' , None ) )
service_requests . append ( ( GET , ' favicon.ico ' , None ) )
local_file_requests = list ( service_requests )
local_file_requests . append ( ( GET , ' file ' , None ) )
local_file_requests . append ( ( GET , ' thumbnail ' , None ) )
restricted_requests = list ( service_requests )
2013-03-15 02:38:12 +00:00
restricted_requests . append ( ( GET , ' access_key ' , None ) )
2014-01-01 20:01:00 +00:00
restricted_requests . append ( ( GET , ' access_key_verification ' , None ) )
2013-02-19 00:11:43 +00:00
restricted_requests . append ( ( GET , ' account ' , None ) )
2013-03-15 02:38:12 +00:00
restricted_requests . append ( ( GET , ' account_info ' , MANAGE_USERS ) )
restricted_requests . append ( ( GET , ' account_types ' , MANAGE_USERS ) )
2013-02-19 00:11:43 +00:00
restricted_requests . append ( ( GET , ' options ' , GENERAL_ADMIN ) )
2013-03-15 02:38:12 +00:00
restricted_requests . append ( ( GET , ' registration_keys ' , GENERAL_ADMIN ) )
restricted_requests . append ( ( GET , ' session_key ' , None ) )
2013-02-19 00:11:43 +00:00
restricted_requests . append ( ( GET , ' stats ' , GENERAL_ADMIN ) )
2013-10-02 22:06:06 +00:00
restricted_requests . append ( ( POST , ' account ' , ( MANAGE_USERS , GENERAL_ADMIN ) ) )
restricted_requests . append ( ( POST , ' account_types ' , GENERAL_ADMIN ) )
2013-02-19 00:11:43 +00:00
admin_requests = list ( restricted_requests )
admin_requests . append ( ( GET , ' init ' , None ) )
2014-09-17 21:28:26 +00:00
admin_requests . append ( ( GET , ' services_info ' , EDIT_SERVICES ) )
2013-02-19 00:11:43 +00:00
admin_requests . append ( ( POST , ' backup ' , EDIT_SERVICES ) )
2013-10-02 22:06:06 +00:00
admin_requests . append ( ( POST , ' services ' , EDIT_SERVICES ) )
2013-02-19 00:11:43 +00:00
repository_requests = list ( restricted_requests )
2013-03-15 02:38:12 +00:00
repository_requests . append ( ( GET , ' num_petitions ' , RESOLVE_PETITIONS ) )
2013-02-19 00:11:43 +00:00
repository_requests . append ( ( GET , ' petition ' , RESOLVE_PETITIONS ) )
repository_requests . append ( ( GET , ' update ' , GET_DATA ) )
repository_requests . append ( ( POST , ' news ' , GENERAL_ADMIN ) )
2013-06-12 22:53:31 +00:00
repository_requests . append ( ( POST , ' update ' , POST_DATA ) )
2013-02-19 00:11:43 +00:00
file_repository_requests = list ( repository_requests )
file_repository_requests . append ( ( GET , ' file ' , GET_DATA ) )
file_repository_requests . append ( ( GET , ' ip ' , GENERAL_ADMIN ) )
file_repository_requests . append ( ( GET , ' thumbnail ' , GET_DATA ) )
file_repository_requests . append ( ( POST , ' file ' , POST_DATA ) )
tag_repository_requests = list ( repository_requests )
message_depot_requests = list ( restricted_requests )
message_depot_requests . append ( ( GET , ' message ' , GET_DATA ) )
2013-03-15 02:38:12 +00:00
message_depot_requests . append ( ( GET , ' message_info_since ' , GET_DATA ) )
message_depot_requests . append ( ( GET , ' public_key ' , None ) )
2013-02-19 00:11:43 +00:00
message_depot_requests . append ( ( POST , ' contact ' , POST_DATA ) )
message_depot_requests . append ( ( POST , ' message ' , None ) )
message_depot_requests . append ( ( POST , ' message_statuses ' , None ) )
all_requests = [ ]
all_requests . extend ( [ ( LOCAL_FILE , request_type , request , permissions ) for ( request_type , request , permissions ) in local_file_requests ] )
all_requests . extend ( [ ( SERVER_ADMIN , request_type , request , permissions ) for ( request_type , request , permissions ) in admin_requests ] )
all_requests . extend ( [ ( FILE_REPOSITORY , request_type , request , permissions ) for ( request_type , request , permissions ) in file_repository_requests ] )
all_requests . extend ( [ ( TAG_REPOSITORY , request_type , request , permissions ) for ( request_type , request , permissions ) in tag_repository_requests ] )
all_requests . extend ( [ ( MESSAGE_DEPOT , request_type , request , permissions ) for ( request_type , request , permissions ) in message_depot_requests ] )
ALLOWED_REQUESTS = { ( service_type , request_type , request ) for ( service_type , request_type , request , permissions ) in all_requests }
REQUESTS_TO_PERMISSIONS = { ( service_type , request_type , request ) : permissions for ( service_type , request_type , request , permissions ) in all_requests }
# default options
DEFAULT_LOCAL_FILE_PORT = 45865
2014-07-16 20:50:18 +00:00
DEFAULT_LOCAL_BOORU_PORT = 45866
2013-02-19 00:11:43 +00:00
DEFAULT_SERVER_ADMIN_PORT = 45870
DEFAULT_SERVICE_PORT = 45871
DEFAULT_OPTIONS = { }
DEFAULT_OPTIONS [ SERVER_ADMIN ] = { }
DEFAULT_OPTIONS [ SERVER_ADMIN ] [ ' max_monthly_data ' ] = None
DEFAULT_OPTIONS [ SERVER_ADMIN ] [ ' max_storage ' ] = None
DEFAULT_OPTIONS [ SERVER_ADMIN ] [ ' message ' ] = ' hydrus server administration service '
2013-11-06 18:22:07 +00:00
DEFAULT_OPTIONS [ SERVER_ADMIN ] [ ' upnp ' ] = None
2013-02-19 00:11:43 +00:00
DEFAULT_OPTIONS [ FILE_REPOSITORY ] = { }
DEFAULT_OPTIONS [ FILE_REPOSITORY ] [ ' max_monthly_data ' ] = None
DEFAULT_OPTIONS [ FILE_REPOSITORY ] [ ' max_storage ' ] = None
DEFAULT_OPTIONS [ FILE_REPOSITORY ] [ ' log_uploader_ips ' ] = False
DEFAULT_OPTIONS [ FILE_REPOSITORY ] [ ' message ' ] = ' hydrus file repository '
2013-11-06 18:22:07 +00:00
DEFAULT_OPTIONS [ FILE_REPOSITORY ] [ ' upnp ' ] = None
2013-02-19 00:11:43 +00:00
DEFAULT_OPTIONS [ TAG_REPOSITORY ] = { }
DEFAULT_OPTIONS [ TAG_REPOSITORY ] [ ' max_monthly_data ' ] = None
DEFAULT_OPTIONS [ TAG_REPOSITORY ] [ ' message ' ] = ' hydrus tag repository '
2013-11-06 18:22:07 +00:00
DEFAULT_OPTIONS [ TAG_REPOSITORY ] [ ' upnp ' ] = None
2013-02-19 00:11:43 +00:00
DEFAULT_OPTIONS [ MESSAGE_DEPOT ] = { }
DEFAULT_OPTIONS [ MESSAGE_DEPOT ] [ ' max_monthly_data ' ] = None
DEFAULT_OPTIONS [ MESSAGE_DEPOT ] [ ' max_storage ' ] = None
DEFAULT_OPTIONS [ MESSAGE_DEPOT ] [ ' message ' ] = ' hydrus message depot '
2013-11-06 18:22:07 +00:00
DEFAULT_OPTIONS [ MESSAGE_DEPOT ] [ ' upnp ' ] = None
2013-02-19 00:11:43 +00:00
# Hydrus pubsub
EVT_PUBSUB = HydrusPubSub . EVT_PUBSUB
pubsub = HydrusPubSub . HydrusPubSub ( )
2013-06-12 22:53:31 +00:00
def default_dict_list ( ) : return collections . defaultdict ( list )
def default_dict_set ( ) : return collections . defaultdict ( set )
2013-08-07 22:25:18 +00:00
def b ( text_producing_object ) :
if type ( text_producing_object ) == unicode : return text_producing_object . encode ( ' utf-8 ' )
else : return str ( text_producing_object )
2013-09-18 17:23:30 +00:00
def ChunkifyList ( the_list , chunk_size ) :
for i in xrange ( 0 , len ( the_list ) , chunk_size ) : yield the_list [ i : i + chunk_size ]
2013-02-19 00:11:43 +00:00
def BuildKeyToListDict ( pairs ) :
d = collections . defaultdict ( list )
for ( key , value ) in pairs : d [ key ] . append ( value )
return d
2013-05-29 20:19:54 +00:00
def BuildKeyToSetDict ( pairs ) :
d = collections . defaultdict ( set )
for ( key , value ) in pairs : d [ key ] . add ( value )
return d
2013-02-19 00:11:43 +00:00
def CalculateScoreFromRating ( count , rating ) :
# http://www.evanmiller.org/how-not-to-sort-by-average-rating.html
count = float ( count )
positive = count * rating
negative = count * ( 1.0 - rating )
# positive + negative = count
# I think I've parsed this correctly from the website! Not sure though!
score = ( ( positive + 1.9208 ) / count - 1.96 * ( ( ( positive * negative ) / count + 0.9604 ) * * 0.5 ) / count ) / ( 1 + 3.8416 / count )
return score
2014-11-20 01:48:04 +00:00
def CheckTagNotEmpty ( tag ) :
empty_tag = False
if tag == ' ' : empty_tag = True
if ' : ' in tag :
( namespace , subtag ) = tag . split ( ' : ' , 1 )
if subtag == ' ' : empty_tag = True
if empty_tag : raise Exception ( ' Received a zero-length tag! ' )
2013-02-19 00:11:43 +00:00
def CleanTag ( tag ) :
2013-09-11 21:28:19 +00:00
tag = tag [ : 1024 ]
2014-11-20 01:48:04 +00:00
empty_tag = False
2013-02-19 00:11:43 +00:00
tag = tag . lower ( )
2013-07-31 21:26:38 +00:00
tag = u ( tag )
2013-02-19 00:11:43 +00:00
tag = re . sub ( ' [ \ s]+ ' , ' ' , tag , flags = re . UNICODE ) # turns multiple spaces into single spaces
tag = re . sub ( ' \ s \ Z ' , ' ' , tag , flags = re . UNICODE ) # removes space at the end
while re . match ( ' \ s|-|system: ' , tag , flags = re . UNICODE ) is not None :
tag = re . sub ( ' \ A( \ s|-|system:) ' , ' ' , tag , flags = re . UNICODE ) # removes space at the beginning
return tag
2014-11-20 01:48:04 +00:00
def CleanTags ( tags ) :
clean_tags = set ( )
for tag in tags :
try :
tag = CleanTag ( tag )
CheckTagNotEmpty ( tag )
clean_tags . add ( tag )
except : continue
return clean_tags
2013-02-19 00:11:43 +00:00
def ConvertAbsPathToPortablePath ( abs_path ) :
if abs_path == ' ' : return None
try : return os . path . relpath ( abs_path , BASE_DIR )
except : return abs_path
def ConvertIntToBytes ( size ) :
if size is None : return ' unknown size '
suffixes = ( ' ' , ' K ' , ' M ' , ' G ' , ' T ' , ' P ' )
suffix_index = 0
size = float ( size )
while size > 1024.0 :
size = size / 1024.0
suffix_index + = 1
if size < 10.0 : return ' %.1f ' % size + suffixes [ suffix_index ] + ' B '
return ' %.0f ' % size + suffixes [ suffix_index ] + ' B '
2013-07-31 21:26:38 +00:00
def ConvertIntToPrettyString ( num ) : return u ( locale . format ( " %d " , num , grouping = True ) )
2014-12-10 22:02:39 +00:00
def ConvertJobKeyToString ( job_key ) :
stuff_to_print = [ ]
if job_key . HasVariable ( ' popup_message_title ' ) : stuff_to_print . append ( job_key . GetVariable ( ' popup_message_title ' ) )
if job_key . HasVariable ( ' popup_message_text_1 ' ) : stuff_to_print . append ( job_key . GetVariable ( ' popup_message_text_1 ' ) )
if job_key . HasVariable ( ' popup_message_text_2 ' ) : stuff_to_print . append ( job_key . GetVariable ( ' popup_message_text_2 ' ) )
if job_key . HasVariable ( ' popup_message_traceback ' ) : stuff_to_print . append ( job_key . GetVariable ( ' popup_message_traceback ' ) )
if job_key . HasVariable ( ' popup_message_caller_traceback ' ) : stuff_to_print . append ( job_key . GetVariable ( ' popup_message_caller_traceback ' ) )
if job_key . HasVariable ( ' popup_message_db_traceback ' ) : stuff_to_print . append ( job_key . GetVariable ( ' popup_message_db_traceback ' ) )
sep = os . linesep
return sep . join ( stuff_to_print )
2013-02-19 00:11:43 +00:00
def ConvertMillisecondsToPrettyTime ( ms ) :
hours = ms / 3600000
if hours == 1 : hours_result = ' 1 hour '
2013-07-31 21:26:38 +00:00
else : hours_result = u ( hours ) + ' hours '
2013-02-19 00:11:43 +00:00
ms = ms % 3600000
minutes = ms / 60000
if minutes == 1 : minutes_result = ' 1 minute '
2013-07-31 21:26:38 +00:00
else : minutes_result = u ( minutes ) + ' minutes '
2013-02-19 00:11:43 +00:00
ms = ms % 60000
seconds = ms / 1000
if seconds == 1 : seconds_result = ' 1 second '
2013-07-31 21:26:38 +00:00
else : seconds_result = u ( seconds ) + ' seconds '
2013-02-19 00:11:43 +00:00
detailed_seconds = float ( ms ) / 1000.0
if detailed_seconds == 1.0 : detailed_seconds_result = ' 1.0 seconds '
else : detailed_seconds_result = ' %.1f ' % detailed_seconds + ' seconds '
ms = ms % 1000
if ms == 1 : milliseconds_result = ' 1 millisecond '
2013-07-31 21:26:38 +00:00
else : milliseconds_result = u ( ms ) + ' milliseconds '
2013-02-19 00:11:43 +00:00
if hours > 0 : return hours_result + ' ' + minutes_result
if minutes > 0 : return minutes_result + ' ' + seconds_result
if seconds > 0 : return detailed_seconds_result
return milliseconds_result
def ConvertNumericalRatingToPrettyString ( lower , upper , rating , rounded_result = False , out_of = True ) :
rating_converted = ( rating * ( upper - lower ) ) + lower
2013-07-31 21:26:38 +00:00
if rounded_result : s = u ( ' %.2f ' % round ( rating_converted ) )
else : s = u ( ' %.2f ' % rating_converted )
2013-02-19 00:11:43 +00:00
if out_of :
2013-07-31 21:26:38 +00:00
if lower in ( 0 , 1 ) : s + = ' / ' + u ( ' %.2f ' % upper )
2013-02-19 00:11:43 +00:00
return s
def ConvertPortablePathToAbsPath ( portable_path ) :
if portable_path is None : return None
if os . path . isabs ( portable_path ) : abs_path = portable_path
else : abs_path = os . path . normpath ( BASE_DIR + os . path . sep + portable_path )
if os . path . exists ( abs_path ) : return abs_path
else : return None
2014-11-12 23:33:13 +00:00
def ConvertPrettyStringsToUglyNamespaces ( pretty_strings ) :
result = { s for s in pretty_strings if s != ' no namespace ' }
if ' no namespace ' in pretty_strings : result . add ( ' ' )
return result
2014-08-27 22:15:22 +00:00
def ConvertServiceKeysToContentUpdatesToPrettyString ( service_keys_to_content_updates ) :
2013-11-06 18:22:07 +00:00
num_files = 0
actions = set ( )
locations = set ( )
2013-11-20 21:12:21 +00:00
extra_words = ' '
2014-08-27 22:15:22 +00:00
for ( service_key , content_updates ) in service_keys_to_content_updates . items ( ) :
2013-11-06 18:22:07 +00:00
2014-08-27 22:15:22 +00:00
if len ( content_updates ) > 0 :
name = app . GetManager ( ' services ' ) . GetService ( service_key ) . GetName ( )
locations . add ( name )
2013-11-06 18:22:07 +00:00
for content_update in content_updates :
( data_type , action , row ) = content_update . ToTuple ( )
2013-11-20 21:12:21 +00:00
if data_type == CONTENT_DATA_TYPE_MAPPINGS : extra_words = ' tags for '
2013-11-06 18:22:07 +00:00
actions . add ( content_update_string_lookup [ action ] )
num_files + = len ( content_update . GetHashes ( ) )
2013-11-20 21:12:21 +00:00
s = ' , ' . join ( locations ) + ' -> ' + ' , ' . join ( actions ) + extra_words + ' ' + ConvertIntToPrettyString ( num_files ) + ' files '
2013-11-06 18:22:07 +00:00
return s
2013-02-19 00:11:43 +00:00
def ConvertShortcutToPrettyShortcut ( modifier , key , action ) :
if modifier == wx . ACCEL_NORMAL : modifier = ' '
elif modifier == wx . ACCEL_ALT : modifier = ' alt '
elif modifier == wx . ACCEL_CTRL : modifier = ' ctrl '
elif modifier == wx . ACCEL_SHIFT : modifier = ' shift '
if key in range ( 65 , 91 ) : key = chr ( key + 32 ) # + 32 for converting ascii A -> a
elif key in range ( 97 , 123 ) : key = chr ( key )
else : key = wxk_code_string_lookup [ key ]
return ( modifier , key , action )
2013-06-12 22:53:31 +00:00
def ConvertStatusToPrefix ( status ) :
if status == CURRENT : return ' '
2013-06-19 20:25:06 +00:00
elif status == PENDING : return ' (+) '
elif status == PETITIONED : return ' (-) '
elif status == DELETED : return ' (X) '
elif status == DELETED_PENDING : return ' (X+) '
2013-06-12 22:53:31 +00:00
2013-02-19 00:11:43 +00:00
def ConvertTimestampToPrettyAge ( timestamp ) :
if timestamp == 0 or timestamp is None : return ' unknown age '
2013-07-31 21:26:38 +00:00
age = GetNow ( ) - timestamp
2013-02-19 00:11:43 +00:00
seconds = age % 60
if seconds == 1 : s = ' 1 second '
2013-07-31 21:26:38 +00:00
else : s = u ( seconds ) + ' seconds '
2013-02-19 00:11:43 +00:00
age = age / 60
minutes = age % 60
if minutes == 1 : m = ' 1 minute '
2013-07-31 21:26:38 +00:00
else : m = u ( minutes ) + ' minutes '
2013-02-19 00:11:43 +00:00
age = age / 60
hours = age % 24
if hours == 1 : h = ' 1 hour '
2013-07-31 21:26:38 +00:00
else : h = u ( hours ) + ' hours '
2013-02-19 00:11:43 +00:00
age = age / 24
days = age % 30
if days == 1 : d = ' 1 day '
2013-07-31 21:26:38 +00:00
else : d = u ( days ) + ' days '
2013-02-19 00:11:43 +00:00
age = age / 30
months = age % 12
if months == 1 : mo = ' 1 month '
2013-07-31 21:26:38 +00:00
else : mo = u ( months ) + ' months '
2013-02-19 00:11:43 +00:00
years = age / 12
if years == 1 : y = ' 1 year '
2013-07-31 21:26:38 +00:00
else : y = u ( years ) + ' years '
2013-02-19 00:11:43 +00:00
if years > 0 : return ' ' . join ( ( y , mo ) ) + ' old '
elif months > 0 : return ' ' . join ( ( mo , d ) ) + ' old '
elif days > 0 : return ' ' . join ( ( d , h ) ) + ' old '
elif hours > 0 : return ' ' . join ( ( h , m ) ) + ' old '
else : return ' ' . join ( ( m , s ) ) + ' old '
def ConvertTimestampToPrettyAgo ( timestamp ) :
2013-08-28 21:31:52 +00:00
if timestamp is None or timestamp == 0 : return ' unknown time '
2013-02-19 00:11:43 +00:00
2013-07-31 21:26:38 +00:00
age = GetNow ( ) - timestamp
2013-02-19 00:11:43 +00:00
seconds = age % 60
if seconds == 1 : s = ' 1 second '
2013-07-31 21:26:38 +00:00
else : s = u ( seconds ) + ' seconds '
2013-02-19 00:11:43 +00:00
age = age / 60
minutes = age % 60
if minutes == 1 : m = ' 1 minute '
2013-07-31 21:26:38 +00:00
else : m = u ( minutes ) + ' minutes '
2013-02-19 00:11:43 +00:00
age = age / 60
hours = age % 24
if hours == 1 : h = ' 1 hour '
2013-07-31 21:26:38 +00:00
else : h = u ( hours ) + ' hours '
2013-02-19 00:11:43 +00:00
age = age / 24
days = age % 30
if days == 1 : d = ' 1 day '
2013-07-31 21:26:38 +00:00
else : d = u ( days ) + ' days '
2013-02-19 00:11:43 +00:00
age = age / 30
months = age % 12
if months == 1 : mo = ' 1 month '
2013-07-31 21:26:38 +00:00
else : mo = u ( months ) + ' months '
2013-02-19 00:11:43 +00:00
years = age / 12
if years == 1 : y = ' 1 year '
2013-07-31 21:26:38 +00:00
else : y = u ( years ) + ' years '
2013-02-19 00:11:43 +00:00
if years > 0 : return ' ' . join ( ( y , mo ) ) + ' ago '
elif months > 0 : return ' ' . join ( ( mo , d ) ) + ' ago '
elif days > 0 : return ' ' . join ( ( d , h ) ) + ' ago '
elif hours > 0 : return ' ' . join ( ( h , m ) ) + ' ago '
else : return ' ' . join ( ( m , s ) ) + ' ago '
2014-10-01 22:58:32 +00:00
def ConvertTimestampToPrettyExpires ( timestamp ) :
2013-02-19 00:11:43 +00:00
if timestamp is None : return ' does not expire '
2013-12-04 22:44:16 +00:00
if timestamp == 0 : return ' unknown expiration '
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
expires = GetNow ( ) - timestamp
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
if expires > = 0 : already_happend = True
2013-02-19 00:11:43 +00:00
else :
2014-10-01 22:58:32 +00:00
expires * = - 1
2013-02-19 00:11:43 +00:00
already_happend = False
2014-10-01 22:58:32 +00:00
seconds = expires % 60
2013-02-19 00:11:43 +00:00
if seconds == 1 : s = ' 1 second '
2013-07-31 21:26:38 +00:00
else : s = u ( seconds ) + ' seconds '
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
expires = expires / 60
minutes = expires % 60
2013-02-19 00:11:43 +00:00
if minutes == 1 : m = ' 1 minute '
2013-07-31 21:26:38 +00:00
else : m = u ( minutes ) + ' minutes '
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
expires = expires / 60
hours = expires % 24
2013-02-19 00:11:43 +00:00
if hours == 1 : h = ' 1 hour '
2013-07-31 21:26:38 +00:00
else : h = u ( hours ) + ' hours '
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
expires = expires / 24
days = expires % 30
2013-02-19 00:11:43 +00:00
if days == 1 : d = ' 1 day '
2013-07-31 21:26:38 +00:00
else : d = u ( days ) + ' days '
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
expires = expires / 30
months = expires % 12
2013-02-19 00:11:43 +00:00
if months == 1 : mo = ' 1 month '
2013-07-31 21:26:38 +00:00
else : mo = u ( months ) + ' months '
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
years = expires / 12
2013-02-19 00:11:43 +00:00
if years == 1 : y = ' 1 year '
2013-07-31 21:26:38 +00:00
else : y = u ( years ) + ' years '
2013-02-19 00:11:43 +00:00
if already_happend :
if years > 0 : return ' expired ' + ' ' . join ( ( y , mo ) ) + ' ago '
elif months > 0 : return ' expired ' + ' ' . join ( ( mo , d ) ) + ' ago '
elif days > 0 : return ' expired ' + ' ' . join ( ( d , h ) ) + ' ago '
elif hours > 0 : return ' expired ' + ' ' . join ( ( h , m ) ) + ' ago '
else : return ' expired ' + ' ' . join ( ( m , s ) ) + ' ago '
else :
if years > 0 : return ' expires in ' + ' ' . join ( ( y , mo ) )
elif months > 0 : return ' expires in ' + ' ' . join ( ( mo , d ) )
elif days > 0 : return ' expires in ' + ' ' . join ( ( d , h ) )
elif hours > 0 : return ' expires in ' + ' ' . join ( ( h , m ) )
else : return ' expires in ' + ' ' . join ( ( m , s ) )
def ConvertTimestampToPrettyPending ( timestamp ) :
if timestamp is None : return ' '
if timestamp == 0 : return ' imminent '
2013-07-31 21:26:38 +00:00
pending = GetNow ( ) - timestamp
2013-02-19 00:11:43 +00:00
if pending > = 0 : return ' imminent '
else : pending * = - 1
seconds = pending % 60
if seconds == 1 : s = ' 1 second '
2013-07-31 21:26:38 +00:00
else : s = u ( seconds ) + ' seconds '
2013-02-19 00:11:43 +00:00
pending = pending / 60
minutes = pending % 60
if minutes == 1 : m = ' 1 minute '
2013-07-31 21:26:38 +00:00
else : m = u ( minutes ) + ' minutes '
2013-02-19 00:11:43 +00:00
pending = pending / 60
hours = pending % 24
if hours == 1 : h = ' 1 hour '
2013-07-31 21:26:38 +00:00
else : h = u ( hours ) + ' hours '
2013-02-19 00:11:43 +00:00
pending = pending / 24
days = pending % 30
if days == 1 : d = ' 1 day '
2013-07-31 21:26:38 +00:00
else : d = u ( days ) + ' days '
2013-02-19 00:11:43 +00:00
pending = pending / 30
months = pending % 12
if months == 1 : mo = ' 1 month '
2013-07-31 21:26:38 +00:00
else : mo = u ( months ) + ' months '
2013-02-19 00:11:43 +00:00
years = pending / 12
if years == 1 : y = ' 1 year '
2013-07-31 21:26:38 +00:00
else : y = u ( years ) + ' years '
2013-02-19 00:11:43 +00:00
if years > 0 : return ' in ' + ' ' . join ( ( y , mo ) )
elif months > 0 : return ' in ' + ' ' . join ( ( mo , d ) )
elif days > 0 : return ' in ' + ' ' . join ( ( d , h ) )
elif hours > 0 : return ' in ' + ' ' . join ( ( h , m ) )
else : return ' in ' + ' ' . join ( ( m , s ) )
def ConvertTimestampToPrettySync ( timestamp ) :
2013-08-28 21:31:52 +00:00
if timestamp is None or timestamp == 0 : return ' not updated '
2013-02-19 00:11:43 +00:00
2013-07-31 21:26:38 +00:00
age = GetNow ( ) - timestamp
2013-02-19 00:11:43 +00:00
seconds = age % 60
if seconds == 1 : s = ' 1 second '
2013-07-31 21:26:38 +00:00
else : s = u ( seconds ) + ' seconds '
2013-02-19 00:11:43 +00:00
age = age / 60
minutes = age % 60
if minutes == 1 : m = ' 1 minute '
2013-07-31 21:26:38 +00:00
else : m = u ( minutes ) + ' minutes '
2013-02-19 00:11:43 +00:00
age = age / 60
hours = age % 24
if hours == 1 : h = ' 1 hour '
2013-07-31 21:26:38 +00:00
else : h = u ( hours ) + ' hours '
2013-02-19 00:11:43 +00:00
age = age / 24
days = age % 30
if days == 1 : d = ' 1 day '
2013-07-31 21:26:38 +00:00
else : d = u ( days ) + ' days '
2013-02-19 00:11:43 +00:00
age = age / 30
months = age % 12
if months == 1 : mo = ' 1 month '
2013-07-31 21:26:38 +00:00
else : mo = u ( months ) + ' months '
2013-02-19 00:11:43 +00:00
years = age / 12
if years == 1 : y = ' 1 year '
2013-07-31 21:26:38 +00:00
else : y = u ( years ) + ' years '
2013-02-19 00:11:43 +00:00
2014-03-12 22:08:23 +00:00
if years > 0 : return ' ' . join ( ( y , mo ) ) + ' ago '
elif months > 0 : return ' ' . join ( ( mo , d ) ) + ' ago '
elif days > 0 : return ' ' . join ( ( d , h ) ) + ' ago '
elif hours > 0 : return ' ' . join ( ( h , m ) ) + ' ago '
else : return ' ' . join ( ( m , s ) ) + ' ago '
2013-02-19 00:11:43 +00:00
def ConvertTimestampToPrettyTime ( timestamp ) : return time . strftime ( ' % Y/ % m/ %d % H: % M: % S ' , time . localtime ( timestamp ) )
def ConvertTimestampToHumanPrettyTime ( timestamp ) :
2013-07-31 21:26:38 +00:00
now = GetNow ( )
2013-02-19 00:11:43 +00:00
difference = now - timestamp
if difference < 60 : return ' just now '
elif difference < 86400 * 7 : return ConvertTimestampToPrettyAgo ( timestamp )
else : return ConvertTimestampToPrettyTime ( timestamp )
def ConvertTimeToPrettyTime ( secs ) :
return time . strftime ( ' % H: % M: % S ' , time . gmtime ( secs ) )
2014-11-12 23:33:13 +00:00
def ConvertUglyNamespacesToPrettyStrings ( namespaces ) :
result = [ namespace for namespace in namespaces if namespace != ' ' and namespace is not None ]
result . sort ( )
if ' ' in namespaces or None in namespaces : result . insert ( 0 , ' no namespace ' )
return result
2013-03-27 20:02:51 +00:00
def ConvertUnitToInteger ( unit ) :
2013-10-23 21:36:47 +00:00
if unit == ' B ' : return 1
2013-03-27 20:02:51 +00:00
elif unit == ' KB ' : return 1024
elif unit == ' MB ' : return 1048576
elif unit == ' GB ' : return 1073741824
def ConvertUnitToString ( unit ) :
if unit == 8 : return ' B '
elif unit == 1024 : return ' KB '
elif unit == 1048576 : return ' MB '
elif unit == 1073741824 : return ' GB '
2013-02-19 00:11:43 +00:00
def ConvertZoomToPercentage ( zoom ) :
zoom = zoom * 100.0
pretty_zoom = ' %.0f ' % zoom + ' % '
return pretty_zoom
2014-09-03 20:26:49 +00:00
def GetDefaultAdvancedTagOptions ( lookup ) :
backup_lookup = None
if type ( lookup ) == tuple :
( site_type , site_name ) = lookup
if site_type == SITE_TYPE_BOORU : backup_lookup = SITE_TYPE_BOORU
ato_options = options [ ' default_advanced_tag_options ' ]
if lookup in ato_options : ato = ato_options [ lookup ]
elif backup_lookup is not None and backup_lookup in ato_options : ato = ato_options [ backup_lookup ]
elif ' default ' in ato_options : ato = ato_options [ ' default ' ]
else : ato = { }
return ato
2013-06-12 22:53:31 +00:00
def GetEmptyDataDict ( ) :
data = collections . defaultdict ( default_dict_list )
return data
2013-07-31 21:26:38 +00:00
def GetNow ( ) : return int ( time . time ( ) )
2014-07-23 21:21:37 +00:00
def GetNowPrecise ( ) :
if PLATFORM_WINDOWS : return time . clock ( )
else : return time . time ( )
2013-02-19 00:11:43 +00:00
def GetShortcutFromEvent ( event ) :
modifier = wx . ACCEL_NORMAL
if event . AltDown ( ) : modifier = wx . ACCEL_ALT
2014-01-29 21:59:42 +00:00
elif event . CmdDown ( ) : modifier = wx . ACCEL_CTRL
2013-02-19 00:11:43 +00:00
elif event . ShiftDown ( ) : modifier = wx . ACCEL_SHIFT
key = event . KeyCode
return ( modifier , key )
2013-08-07 22:25:18 +00:00
def GetTempPath ( ) : return TEMP_DIR + os . path . sep + os . urandom ( 32 ) . encode ( ' hex ' )
2013-02-19 00:11:43 +00:00
def IntelligentMassIntersect ( sets_to_reduce ) :
answer = None
sets_to_reduce = list ( sets_to_reduce )
sets_to_reduce . sort ( cmp = lambda x , y : cmp ( len ( x ) , len ( y ) ) )
for set_to_reduce in sets_to_reduce :
if len ( set_to_reduce ) == 0 : return set ( )
if answer is None : answer = set ( set_to_reduce )
else :
# same thing as union; I could go &= here, but I want to be quick, so use the function call
if len ( answer ) == 0 : return set ( )
else : answer . intersection_update ( set_to_reduce )
if answer is None : return set ( )
else : return answer
def IsCollection ( mime ) : return mime in ( APPLICATION_HYDRUS_CLIENT_COLLECTION , ) # this is a little convoluted, but I want to keep it similar to IsImage, IsText, IsAudio, IsX
def IsImage ( mime ) : return mime in ( IMAGE_JPEG , IMAGE_GIF , IMAGE_PNG , IMAGE_BMP )
2015-01-07 23:09:00 +00:00
def LaunchFile ( path ) :
# Don't even think about omitting the double quotes on start
if PLATFORM_WINDOWS : launch_phrase = ' start " " '
elif PLATFORM_OSX : launch_phrase = ' open '
elif PLATFORM_LINUX : launch_phrase = ' xdg-open '
subprocess . Popen ( launch_phrase + ' " ' + path + ' " ' , shell = True )
def LaunchDirectory ( path ) :
if PLATFORM_WINDOWS : launch_phrase = ' explorer '
elif PLATFORM_OSX : launch_phrase = ' open '
elif PLATFORM_LINUX : launch_phrase = ' xdg-open '
subprocess . Popen ( launch_phrase + ' " ' + path + ' " ' , shell = True )
2013-06-12 22:53:31 +00:00
def MergeKeyToListDicts ( key_to_list_dicts ) :
result = collections . defaultdict ( list )
for key_to_list_dict in key_to_list_dicts :
for ( key , value ) in key_to_list_dict . items ( ) : result [ key ] . extend ( value )
return result
2013-07-24 20:26:00 +00:00
2014-11-12 23:33:13 +00:00
def ReadFileLikeAsBlocks ( f , block_size ) :
next_block = f . read ( block_size )
while next_block != ' ' :
yield next_block
next_block = f . read ( block_size )
2013-03-27 20:02:51 +00:00
def SearchEntryMatchesPredicate ( search_entry , predicate ) :
2015-01-07 23:09:00 +00:00
( predicate_type , value , inclusive ) = predicate . GetInfo ( )
2013-03-27 20:02:51 +00:00
2015-01-07 23:09:00 +00:00
if predicate_type == PREDICATE_TYPE_TAG : return SearchEntryMatchesTag ( search_entry , value )
2013-03-27 20:02:51 +00:00
else : return False
2013-07-10 20:25:57 +00:00
def SearchEntryMatchesTag ( search_entry , tag , search_siblings = True ) :
2013-02-19 00:11:43 +00:00
2014-12-31 22:56:38 +00:00
def compile_re ( s ) :
regular_parts_of_s = s . split ( ' * ' )
escaped_parts_of_s = [ re . escape ( part ) for part in regular_parts_of_s ]
s = ' .* ' . join ( escaped_parts_of_s )
return re . compile ( ' ( \\ A| \\ s) ' + s + ' ( \\ s| \\ Z) ' , flags = re . UNICODE )
if ' : ' in search_entry :
search_namespace = True
( namespace_entry , search_entry ) = search_entry . split ( ' : ' , 1 )
namespace_re_predicate = compile_re ( namespace_entry )
else : search_namespace = False
if ' * ' not in search_entry : search_entry + = ' * '
re_predicate = compile_re ( search_entry )
2013-02-19 00:11:43 +00:00
2013-07-10 20:25:57 +00:00
if search_siblings :
2013-11-27 18:27:11 +00:00
sibling_manager = app . GetManager ( ' tag_siblings ' )
2013-07-10 20:25:57 +00:00
tags = sibling_manager . GetAllSiblings ( tag )
else : tags = [ tag ]
2013-05-08 20:31:00 +00:00
for tag in tags :
2013-02-19 00:11:43 +00:00
2013-05-08 20:31:00 +00:00
if ' : ' in tag :
( n , t ) = tag . split ( ' : ' , 1 )
2014-12-31 22:56:38 +00:00
if search_namespace and re . search ( namespace_re_predicate , n ) is None : continue
2013-05-08 20:31:00 +00:00
comparee = t
2014-12-31 22:56:38 +00:00
else :
if search_namespace : continue
comparee = tag
2013-02-19 00:11:43 +00:00
2014-12-31 22:56:38 +00:00
if re . search ( re_predicate , comparee ) is not None : return True
2013-02-19 00:11:43 +00:00
2013-05-08 20:31:00 +00:00
return False
2013-02-19 00:11:43 +00:00
2014-01-22 21:11:22 +00:00
def ShowExceptionDefault ( e ) :
etype = type ( e )
value = u ( e )
trace_list = traceback . format_stack ( )
trace = ' ' . join ( trace_list )
message = u ( etype . __name__ ) + ' : ' + u ( value ) + os . linesep + u ( trace )
try : print ( message )
except : print ( repr ( message ) )
ShowException = ShowExceptionDefault
def ShowTextDefault ( text ) :
print ( text )
ShowText = ShowTextDefault
2014-12-17 22:35:12 +00:00
def SplayListForDB ( xs ) : return ' ( ' + ' , ' . join ( ( ' " ' + u ( x ) + ' " ' for x in xs ) ) + ' ) '
2013-02-19 00:11:43 +00:00
2013-07-31 21:26:38 +00:00
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 ] )
2013-02-19 00:11:43 +00:00
def ThumbnailResolution ( original_resolution , target_resolution ) :
( original_width , original_height ) = original_resolution
( target_width , target_height ) = target_resolution
if original_width > target_width :
original_height = max ( original_height * target_width / float ( original_width ) , 1 )
original_width = target_width
if round ( original_height ) > target_height :
original_width = max ( original_width * target_height / float ( original_height ) , 1 )
original_height = target_height
return ( int ( round ( original_width ) ) , int ( round ( original_height ) ) )
2014-01-22 21:11:22 +00:00
def u ( text_producing_object ) :
if type ( text_producing_object ) in ( str , unicode , bs4 . element . NavigableString ) : text = text_producing_object
else :
try : text = str ( text_producing_object ) # dealing with exceptions, etc...
except : text = repr ( text_producing_object )
try : return unicode ( text )
except :
try : return text . decode ( locale . getpreferredencoding ( ) )
except : return str ( text )
2013-02-19 00:11:43 +00:00
class HydrusYAMLBase ( yaml . YAMLObject ) :
yaml_loader = yaml . SafeLoader
yaml_dumper = yaml . SafeDumper
class Account ( HydrusYAMLBase ) :
yaml_tag = u ' !Account '
2014-10-01 22:58:32 +00:00
def __init__ ( self , account_key , account_type , created , expires , used_bytes , used_requests , banned_info = None ) :
2013-02-19 00:11:43 +00:00
HydrusYAMLBase . __init__ ( self )
2014-10-01 22:58:32 +00:00
self . _info = { }
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
self . _info [ ' account_key ' ] = account_key
self . _info [ ' account_type ' ] = account_type
self . _info [ ' created ' ] = created
self . _info [ ' expires ' ] = expires
self . _info [ ' used_bytes ' ] = used_bytes
self . _info [ ' used_requests ' ] = used_requests
if banned_info is not None : self . _info [ ' banned_info ' ] = banned_info
self . _info [ ' fresh_timestamp ' ] = GetNow ( )
2013-02-19 00:11:43 +00:00
def __repr__ ( self ) : return self . ConvertToString ( )
def __str__ ( self ) : return self . ConvertToString ( )
def _IsBanned ( self ) :
2014-10-01 22:58:32 +00:00
if ' banned_info ' not in self . _info : return False
2013-02-19 00:11:43 +00:00
else :
2014-10-01 22:58:32 +00:00
( reason , created , expires ) = self . _info [ ' banned_info ' ]
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
if expires is None : return True
else : return GetNow ( ) > expires
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def _IsBytesExceeded ( self ) :
account_type = self . _info [ ' account_type ' ]
max_num_bytes = account_type . GetMaxBytes ( )
used_bytes = self . _info [ ' used_bytes ' ]
return max_num_bytes is not None and used_bytes > max_num_bytes
2013-02-19 00:11:43 +00:00
def _IsExpired ( self ) :
2014-10-01 22:58:32 +00:00
if self . _info [ ' expires ' ] is None : return False
else : return GetNow ( ) > self . _info [ ' expires ' ]
def _IsRequestsExceeded ( self ) :
account_type = self . _info [ ' account_type ' ]
max_num_requests = account_type . GetMaxRequests ( )
used_requests = self . _info [ ' used_requests ' ]
return max_num_requests is not None and used_requests > max_num_requests
2013-02-19 00:11:43 +00:00
2013-10-02 22:06:06 +00:00
def CheckPermission ( self , permission ) :
2013-02-19 00:11:43 +00:00
2013-07-24 20:26:00 +00:00
if self . _IsBanned ( ) : raise HydrusExceptions . PermissionException ( ' This account is banned! ' )
2013-02-19 00:11:43 +00:00
2013-07-24 20:26:00 +00:00
if self . _IsExpired ( ) : raise HydrusExceptions . PermissionException ( ' This account is expired. ' )
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
if self . _IsBytesExceeded ( ) : raise HydrusExceptions . PermissionException ( ' You have hit your data transfer limit, and cannot make any more requests for the month. ' )
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
if self . _IsRequestsExceeded ( ) : raise HydrusExceptions . PermissionException ( ' You have hit your requests limit, and cannot make any more requests for the month. ' )
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
if not self . _info [ ' account_type ' ] . HasPermission ( permission ) : raise HydrusExceptions . PermissionException ( ' You do not have permission to do that. ' )
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def ConvertToString ( self ) : return ConvertTimestampToPrettyAge ( self . _info [ ' created ' ] ) + os . linesep + self . _info [ ' account_type ' ] . ConvertToString ( ) + os . linesep + ' which ' + ConvertTimestampToPrettyExpires ( self . _info [ ' expires ' ] )
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def GetAccountKey ( self ) : return self . _info [ ' account_key ' ]
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def GetAccountType ( self ) : return self . _info [ ' account_type ' ]
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def GetCreated ( self ) : return self . _info [ ' created ' ]
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def GetExpires ( self ) : return self . _info [ ' expires ' ]
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def GetExpiresString ( self ) :
2013-02-19 00:11:43 +00:00
if self . _IsBanned ( ) :
2014-10-01 22:58:32 +00:00
( reason , created , expires ) = self . _info [ ' banned_info ' ]
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
return ' banned ' + ConvertTimestampToPrettyAge ( created ) + ' , ' + ConvertTimestampToPrettyExpires ( expires ) + ' because: ' + reason
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
else : return ConvertTimestampToPrettyAge ( self . _info [ ' created ' ] ) + ' and ' + ConvertTimestampToPrettyExpires ( self . _info [ ' expires ' ] )
2013-02-19 00:11:43 +00:00
def GetUsedBytesString ( self ) :
2014-10-01 22:58:32 +00:00
max_num_bytes = self . _info [ ' account_type ' ] . GetMaxBytes ( )
used_bytes = self . _info [ ' used_bytes ' ]
2013-02-19 00:11:43 +00:00
if max_num_bytes is None : return ConvertIntToBytes ( used_bytes ) + ' used this month '
else : return ConvertIntToBytes ( used_bytes ) + ' / ' + ConvertIntToBytes ( max_num_bytes ) + ' used this month '
def GetUsedRequestsString ( self ) :
2014-10-01 22:58:32 +00:00
max_num_requests = self . _info [ ' account_type ' ] . GetMaxRequests ( )
used_requests = self . _info [ ' used_requests ' ]
2013-02-19 00:11:43 +00:00
if max_num_requests is None : return ConvertIntToPrettyString ( used_requests ) + ' requests used this month '
else : return ConvertIntToPrettyString ( used_requests ) + ' / ' + ConvertIntToPrettyString ( max_num_requests ) + ' requests used this month '
2014-10-01 22:58:32 +00:00
def GetUsedBytes ( self ) : return self . _info [ ' used_bytes ' ]
def GetUsedRequests ( self ) : return self . _info [ ' used_bytes ' ]
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def HasAccountKey ( self ) :
if ' account_key ' in self . _info and self . _info [ ' account_key ' ] is not None : return True
return False
2014-09-03 20:26:49 +00:00
2013-02-19 00:11:43 +00:00
def HasPermission ( self , permission ) :
2013-10-02 22:06:06 +00:00
if self . _IsBanned ( ) : return False
2013-02-19 00:11:43 +00:00
if self . _IsExpired ( ) : return False
2014-10-01 22:58:32 +00:00
if self . _IsBytesExceeded ( ) : return False
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
if self . _IsRequestsExceeded ( ) : return False
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
return self . _info [ ' account_type ' ] . HasPermission ( permission )
2013-02-19 00:11:43 +00:00
def IsAdmin ( self ) : return True in [ self . HasPermissions ( permission ) for permission in ADMIN_PERMISSIONS ]
def IsBanned ( self ) : return self . _IsBanned ( )
2014-10-01 22:58:32 +00:00
def IsStale ( self ) : return self . _info [ ' fresh_timestamp ' ] + UPDATE_DURATION * 5 < GetNow ( )
def IsUnknownAccount ( self ) : return self . _info [ ' account_type ' ] . IsUnknownAccountType ( )
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def MakeFresh ( self ) : self . _info [ ' fresh_timestamp ' ] = GetNow ( )
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def MakeStale ( self ) : self . _info [ ' fresh_timestamp ' ] = 0
2013-02-19 00:11:43 +00:00
def RequestMade ( self , num_bytes ) :
2014-10-01 22:58:32 +00:00
self . _info [ ' used_bytes ' ] + = num_bytes
self . _info [ ' used_requests ' ] + = 1
2013-02-19 00:11:43 +00:00
class AccountIdentifier ( HydrusYAMLBase ) :
2014-10-01 22:58:32 +00:00
TYPE_ACCOUNT_KEY = 1
2014-01-01 20:01:00 +00:00
TYPE_HASH = 2
TYPE_MAPPING = 3
TYPE_SIBLING = 4
TYPE_PARENT = 5
2013-02-19 00:11:43 +00:00
yaml_tag = u ' !AccountIdentifier '
2014-10-01 22:58:32 +00:00
def __init__ ( self , account_key = None , hash = None , tag = None ) :
2013-02-19 00:11:43 +00:00
HydrusYAMLBase . __init__ ( self )
2014-10-01 22:58:32 +00:00
if account_key is not None :
2014-01-01 20:01:00 +00:00
2014-10-01 22:58:32 +00:00
self . _type = self . TYPE_ACCOUNT_KEY
self . _data = account_key
2014-01-01 20:01:00 +00:00
elif hash is not None :
if tag is not None :
self . _type = self . TYPE_MAPPING
self . _data = ( hash , tag )
else :
self . _type = self . TYPE_HASH
self . _data = hash
2013-02-19 00:11:43 +00:00
def __eq__ ( self , other ) : return self . __hash__ ( ) == other . __hash__ ( )
2014-01-01 20:01:00 +00:00
def __hash__ ( self ) : return ( self . _type , self . _data ) . __hash__ ( )
2013-02-19 00:11:43 +00:00
def __ne__ ( self , other ) : return self . __hash__ ( ) != other . __hash__ ( )
2014-01-01 20:01:00 +00:00
def __repr__ ( self ) : return ' Account Identifier: ' + u ( ( self . _type , self . _data ) )
2013-02-19 00:11:43 +00:00
2014-01-01 20:01:00 +00:00
def GetData ( self ) : return self . _data
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def HasAccountKey ( self ) : return self . _type == self . TYPE_ACCOUNT_KEY
2013-02-19 00:11:43 +00:00
2014-01-01 20:01:00 +00:00
def HasHash ( self ) : return self . _type == self . TYPE_HASH
2013-02-19 00:11:43 +00:00
2014-01-01 20:01:00 +00:00
def HasMapping ( self ) : return self . _type == self . TYPE_MAPPING
2013-02-19 00:11:43 +00:00
class AccountType ( HydrusYAMLBase ) :
yaml_tag = u ' !AccountType '
def __init__ ( self , title , permissions , max_monthly_data ) :
HydrusYAMLBase . __init__ ( self )
self . _title = title
self . _permissions = permissions
self . _max_monthly_data = max_monthly_data
def __repr__ ( self ) : return self . ConvertToString ( )
def GetPermissions ( self ) : return self . _permissions
def GetTitle ( self ) : return self . _title
2014-10-01 22:58:32 +00:00
def GetMaxBytes ( self ) :
( max_num_bytes , max_num_requests ) = self . _max_monthly_data
return max_num_bytes
def GetMaxRequests ( self ) :
( max_num_bytes , max_num_requests ) = self . _max_monthly_data
return max_num_requests
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def GetMaxBytesString ( self ) :
2013-02-19 00:11:43 +00:00
( max_num_bytes , max_num_requests ) = self . _max_monthly_data
if max_num_bytes is None : max_num_bytes_string = ' No limit '
else : max_num_bytes_string = ConvertIntToBytes ( max_num_bytes )
2014-10-01 22:58:32 +00:00
return max_num_bytes_string
def GetMaxRequestsString ( self ) :
( max_num_bytes , max_num_requests ) = self . _max_monthly_data
2013-02-19 00:11:43 +00:00
if max_num_requests is None : max_num_requests_string = ' No limit '
else : max_num_requests_string = ConvertIntToPrettyString ( max_num_requests )
2014-10-01 22:58:32 +00:00
return max_num_requests_string
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def ConvertToString ( self ) :
2013-02-19 00:11:43 +00:00
result_string = self . _title + ' with '
2014-10-01 22:58:32 +00:00
if self . _permissions == [ UNKNOWN_PERMISSION ] : result_string + = ' no permissions '
2013-02-19 00:11:43 +00:00
else : result_string + = ' , ' . join ( [ permissions_string_lookup [ permission ] for permission in self . _permissions ] ) + ' permissions '
return result_string
2014-10-01 22:58:32 +00:00
def IsUnknownAccountType ( self ) : return self . _permissions == [ UNKNOWN_PERMISSION ]
2014-09-03 20:26:49 +00:00
2013-02-19 00:11:43 +00:00
def HasPermission ( self , permission ) : return permission in self . _permissions
2014-10-01 22:58:32 +00:00
UNKNOWN_ACCOUNT_TYPE = AccountType ( ' unknown account ' , [ UNKNOWN_PERMISSION ] , ( None , None ) )
2013-06-12 22:53:31 +00:00
2014-10-01 22:58:32 +00:00
def GetUnknownAccount ( account_key = None ) : return Account ( account_key , UNKNOWN_ACCOUNT_TYPE , 0 , None , 0 , 0 )
2013-06-12 22:53:31 +00:00
class ClientServiceIdentifier ( HydrusYAMLBase ) :
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
yaml_tag = u ' !ClientServiceIdentifier '
2013-02-19 00:11:43 +00:00
2014-09-10 22:37:38 +00:00
def __init__ ( self , service_key , service_type , name ) :
2013-02-19 00:11:43 +00:00
HydrusYAMLBase . __init__ ( self )
2013-06-12 22:53:31 +00:00
self . _service_key = service_key
2014-09-10 22:37:38 +00:00
self . _type = service_type
2013-06-12 22:53:31 +00:00
self . _name = name
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def __eq__ ( self , other ) : return self . __hash__ ( ) == other . __hash__ ( )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def __hash__ ( self ) : return self . _service_key . __hash__ ( )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def __ne__ ( self , other ) : return self . __hash__ ( ) != other . __hash__ ( )
2013-02-19 00:11:43 +00:00
2013-10-02 22:06:06 +00:00
def __repr__ ( self ) : return ' Client Service Identifier: ' + u ( ( self . _name , service_string_lookup [ self . _type ] ) )
2013-07-17 20:56:13 +00:00
2013-06-12 22:53:31 +00:00
def GetInfo ( self ) : return ( self . _service_key , self . _type , self . _name )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def GetName ( self ) : return self . _name
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def GetServiceKey ( self ) : return self . _service_key
2013-02-19 00:11:43 +00:00
2014-09-17 21:28:26 +00:00
def GetServiceType ( self ) : return self . _type
2013-02-19 00:11:43 +00:00
2014-08-13 22:18:12 +00:00
LOCAL_FILE_SERVICE_KEY = ' local files '
LOCAL_TAG_SERVICE_KEY = ' local tags '
LOCAL_BOORU_SERVICE_KEY = ' local booru '
COMBINED_FILE_SERVICE_KEY = ' all known files '
COMBINED_TAG_SERVICE_KEY = ' all known tags '
2013-06-12 22:53:31 +00:00
class ClientToServerUpdate ( HydrusYAMLBase ) :
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
yaml_tag = u ' !ClientToServerUpdate '
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def __init__ ( self , content_data , hash_ids_to_hashes ) :
2013-02-19 00:11:43 +00:00
HydrusYAMLBase . __init__ ( self )
2013-06-12 22:53:31 +00:00
# we need to flatten it from a collections.defaultdict to just a normal dict so it can be YAMLised
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
self . _content_data = { }
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
for data_type in content_data :
self . _content_data [ data_type ] = { }
for action in content_data [ data_type ] : self . _content_data [ data_type ] [ action ] = content_data [ data_type ] [ action ]
2013-02-19 00:11:43 +00:00
self . _hash_ids_to_hashes = hash_ids_to_hashes
2013-06-12 22:53:31 +00:00
def GetContentUpdates ( self , for_client = False ) :
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
data_types = [ CONTENT_DATA_TYPE_FILES , CONTENT_DATA_TYPE_MAPPINGS , CONTENT_DATA_TYPE_TAG_SIBLINGS , CONTENT_DATA_TYPE_TAG_PARENTS ]
actions = [ CONTENT_UPDATE_PENDING , CONTENT_UPDATE_PETITION , CONTENT_UPDATE_DENY_PEND , CONTENT_UPDATE_DENY_PETITION ]
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
content_updates = [ ]
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
for ( data_type , action ) in itertools . product ( data_types , actions ) :
munge_row = lambda row : row
if for_client :
if action == CONTENT_UPDATE_PENDING : new_action = CONTENT_UPDATE_ADD
elif action == CONTENT_UPDATE_PETITION : new_action = CONTENT_UPDATE_DELETE
else : continue
if data_type in ( CONTENT_DATA_TYPE_TAG_SIBLINGS , CONTENT_DATA_TYPE_TAG_PARENTS ) and action in ( CONTENT_UPDATE_PENDING , CONTENT_UPDATE_PETITION ) :
munge_row = lambda ( pair , reason ) : pair
elif data_type == CONTENT_DATA_TYPE_FILES and action == CONTENT_UPDATE_PETITION :
munge_row = lambda ( hashes , reason ) : hashes
elif data_type == CONTENT_DATA_TYPE_MAPPINGS and action == CONTENT_UPDATE_PETITION :
munge_row = lambda ( tag , hashes , reason ) : ( tag , hashes )
else : new_action = action
content_updates . extend ( [ ContentUpdate ( data_type , new_action , munge_row ( row ) ) for row in self . GetContentDataIterator ( data_type , action ) ] )
return content_updates
2013-02-19 00:11:43 +00:00
def GetHashes ( self ) : return self . _hash_ids_to_hashes . values ( )
2013-06-12 22:53:31 +00:00
def GetContentDataIterator ( self , data_type , action ) :
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
if data_type not in self . _content_data or action not in self . _content_data [ data_type ] : return ( )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
data = self . _content_data [ data_type ] [ action ]
if data_type == CONTENT_DATA_TYPE_FILES :
if action == CONTENT_UPDATE_PETITION : return ( ( { self . _hash_ids_to_hashes [ hash_id ] for hash_id in hash_ids } , reason ) for ( hash_ids , reason ) in data )
else : return ( { self . _hash_ids_to_hashes [ hash_id ] for hash_id in hash_ids } for hash_ids in ( data , ) )
if data_type == CONTENT_DATA_TYPE_MAPPINGS :
if action == CONTENT_UPDATE_PETITION : return ( ( tag , [ self . _hash_ids_to_hashes [ hash_id ] for hash_id in hash_ids ] , reason ) for ( tag , hash_ids , reason ) in data )
else : return ( ( tag , [ self . _hash_ids_to_hashes [ hash_id ] for hash_id in hash_ids ] ) for ( tag , hash_ids ) in data )
else : return data . __iter__ ( )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def GetTags ( self ) :
tags = set ( )
try : tags . update ( ( tag for ( tag , hash_ids ) in self . _content_data [ CONTENT_DATA_TYPE_MAPPINGS ] [ CONTENT_UPDATE_PENDING ] ) )
except : pass
try : tags . update ( ( tag for ( tag , hash_ids , reason ) in self . _content_data [ CONTENT_DATA_TYPE_MAPPINGS ] [ CONTENT_UPDATE_PETITION ] ) )
except : pass
return tags
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def IsEmpty ( self ) :
num_total = 0
for data_type in self . _content_data :
for action in self . _content_data [ data_type ] : num_total + = len ( self . _content_data [ data_type ] [ action ] )
return num_total == 0
2013-02-19 00:11:43 +00:00
2014-07-23 21:21:37 +00:00
class ContentUpdate ( object ) :
2013-03-23 17:57:29 +00:00
2013-06-12 22:53:31 +00:00
def __init__ ( self , data_type , action , row ) :
2013-03-23 17:57:29 +00:00
2013-06-12 22:53:31 +00:00
self . _data_type = data_type
2013-03-23 17:57:29 +00:00
self . _action = action
2013-06-12 22:53:31 +00:00
self . _row = row
2013-03-23 17:57:29 +00:00
2013-07-10 20:25:57 +00:00
def __eq__ ( self , other ) : return self . _data_type == other . _data_type and self . _action == other . _action and self . _row == other . _row
def __ne__ ( self , other ) : return not self . __eq__ ( other )
2013-07-31 21:26:38 +00:00
def __repr__ ( self ) : return ' Content Update: ' + u ( ( self . _data_type , self . _action , self . _row ) )
2013-07-17 20:56:13 +00:00
2013-06-12 22:53:31 +00:00
def GetHashes ( self ) :
if self . _data_type == CONTENT_DATA_TYPE_FILES :
if self . _action == CONTENT_UPDATE_ADD :
hash = self . _row [ 0 ]
hashes = set ( ( hash , ) )
elif self . _action in ( CONTENT_UPDATE_ARCHIVE , CONTENT_UPDATE_DELETE , CONTENT_UPDATE_INBOX , CONTENT_UPDATE_PENDING , CONTENT_UPDATE_RESCIND_PENDING , CONTENT_UPDATE_RESCIND_PETITION ) : hashes = self . _row
elif self . _action == CONTENT_UPDATE_PETITION : ( hashes , reason ) = self . _row
elif self . _data_type == CONTENT_DATA_TYPE_MAPPINGS :
if self . _action == CONTENT_UPDATE_PETITION : ( tag , hashes , reason ) = self . _row
else : ( tag , hashes ) = self . _row
elif self . _data_type in ( CONTENT_DATA_TYPE_TAG_PARENTS , CONTENT_DATA_TYPE_TAG_SIBLINGS ) : hashes = set ( )
2013-06-19 20:25:06 +00:00
elif self . _data_type == CONTENT_DATA_TYPE_RATINGS :
if self . _action == CONTENT_UPDATE_ADD : ( rating , hashes ) = self . _row
elif self . _action == CONTENT_UPDATE_RATINGS_FILTER : ( min , max , hashes ) = self . _row
2013-06-12 22:53:31 +00:00
if type ( hashes ) != set : hashes = set ( hashes )
return hashes
2013-03-23 17:57:29 +00:00
2013-06-12 22:53:31 +00:00
def ToTuple ( self ) : return ( self . _data_type , self . _action , self . _row )
2013-03-23 17:57:29 +00:00
2014-10-29 21:39:01 +00:00
class EditLogAction ( object ) :
yaml_tag = u ' !EditLogAction '
def __init__ ( self , action ) : self . _action = action
def GetAction ( self ) : return self . _action
class EditLogActionAdd ( EditLogAction ) :
yaml_tag = u ' !EditLogActionAdd '
def __init__ ( self , data ) :
EditLogAction . __init__ ( self , ADD )
self . _data = data
def GetData ( self ) : return self . _data
class EditLogActionDelete ( EditLogAction ) :
yaml_tag = u ' !EditLogActionDelete '
def __init__ ( self , identifier ) :
EditLogAction . __init__ ( self , DELETE )
self . _identifier = identifier
def GetIdentifier ( self ) : return self . _identifier
class EditLogActionEdit ( EditLogAction ) :
yaml_tag = u ' !EditLogActionEdit '
def __init__ ( self , identifier , data ) :
EditLogAction . __init__ ( self , EDIT )
self . _identifier = identifier
self . _data = data
def GetData ( self ) : return self . _data
def GetIdentifier ( self ) : return self . _identifier
2014-07-23 21:21:37 +00:00
class JobDatabase ( object ) :
2013-02-19 00:11:43 +00:00
2014-01-22 21:11:22 +00:00
yaml_tag = u ' !JobDatabase '
2013-02-19 00:11:43 +00:00
2014-09-10 22:37:38 +00:00
def __init__ ( self , action , job_type , synchronous , * args , * * kwargs ) :
2014-01-22 21:11:22 +00:00
self . _action = action
2014-09-10 22:37:38 +00:00
self . _type = job_type
2014-01-22 21:11:22 +00:00
self . _synchronous = synchronous
self . _args = args
self . _kwargs = kwargs
2013-02-19 00:11:43 +00:00
self . _result = None
self . _result_ready = threading . Event ( )
2014-01-22 21:11:22 +00:00
def GetAction ( self ) : return self . _action
def GetArgs ( self ) : return self . _args
def GetKWArgs ( self ) : return self . _kwargs
2013-02-19 00:11:43 +00:00
def GetResult ( self ) :
while True :
if self . _result_ready . wait ( 5 ) == True : break
elif shutdown : raise Exception ( ' Application quit before db could serve result! ' )
2014-02-26 22:09:54 +00:00
if isinstance ( self . _result , Exception ) :
2013-08-28 21:31:52 +00:00
2014-02-26 22:09:54 +00:00
if isinstance ( self . _result , HydrusExceptions . DBException ) :
2014-04-09 20:18:58 +00:00
( text , gumpf , db_traceback ) = self . _result . args
2014-02-26 22:09:54 +00:00
trace_list = traceback . format_stack ( )
2014-09-24 21:50:07 +00:00
caller_traceback = ' Stack Trace (most recent call last): ' + os . linesep * 2 + os . linesep . join ( trace_list )
2014-02-26 22:09:54 +00:00
2014-04-09 20:18:58 +00:00
raise HydrusExceptions . DBException ( text , caller_traceback , db_traceback )
2014-02-26 22:09:54 +00:00
else : raise self . _result
2013-08-28 21:31:52 +00:00
2013-02-19 00:11:43 +00:00
else : return self . _result
2014-01-22 21:11:22 +00:00
def GetType ( self ) : return self . _type
def IsSynchronous ( self ) : return self . _synchronous
2013-02-19 00:11:43 +00:00
def PutResult ( self , result ) :
self . _result = result
self . _result_ready . set ( )
2014-07-23 21:21:37 +00:00
class JobKey ( object ) :
2013-09-11 21:28:19 +00:00
2014-12-10 22:02:39 +00:00
def __init__ ( self , pausable = False , cancellable = False ) :
2013-09-11 21:28:19 +00:00
self . _key = os . urandom ( 32 )
2014-08-13 22:18:12 +00:00
self . _pausable = pausable
self . _cancellable = cancellable
2014-12-17 22:35:12 +00:00
self . _deleted = threading . Event ( )
2014-01-08 18:40:02 +00:00
self . _begun = threading . Event ( )
self . _done = threading . Event ( )
2013-09-11 21:28:19 +00:00
self . _cancelled = threading . Event ( )
2014-01-08 18:40:02 +00:00
self . _paused = threading . Event ( )
2013-09-11 21:28:19 +00:00
2014-01-22 21:11:22 +00:00
self . _variable_lock = threading . Lock ( )
self . _variables = dict ( )
2013-09-11 21:28:19 +00:00
def __eq__ ( self , other ) : return self . __hash__ ( ) == other . __hash__ ( )
def __hash__ ( self ) : return self . _key . __hash__ ( )
def __ne__ ( self , other ) : return self . __hash__ ( ) != other . __hash__ ( )
2014-01-08 18:40:02 +00:00
def Begin ( self ) : self . _begun . set ( )
def Cancel ( self ) :
self . _cancelled . set ( )
self . Finish ( )
2014-12-17 22:35:12 +00:00
def Delete ( self ) :
self . Finish ( )
self . _deleted . set ( )
2014-08-13 22:18:12 +00:00
def DeleteVariable ( self , name ) :
2014-12-03 22:56:40 +00:00
with self . _variable_lock :
if name in self . _variables : del self . _variables [ name ]
2014-08-13 22:18:12 +00:00
2014-12-25 00:07:20 +00:00
time . sleep ( 0.00001 )
2014-08-13 22:18:12 +00:00
2014-01-08 18:40:02 +00:00
def Finish ( self ) : self . _done . set ( )
2013-09-11 21:28:19 +00:00
def GetKey ( self ) : return self . _key
2014-01-22 21:11:22 +00:00
def GetVariable ( self , name ) :
with self . _variable_lock : return self . _variables [ name ]
def HasVariable ( self , name ) :
with self . _variable_lock : return name in self . _variables
2014-01-08 18:40:02 +00:00
def IsBegun ( self ) : return self . _begun . is_set ( )
2014-12-10 22:02:39 +00:00
def IsCancellable ( self ) : return self . _cancellable and not self . IsDone ( )
2014-08-13 22:18:12 +00:00
2014-01-22 21:11:22 +00:00
def IsCancelled ( self ) : return shutdown or self . _cancelled . is_set ( )
2013-09-11 21:28:19 +00:00
2014-12-17 22:35:12 +00:00
def IsDeleted ( self ) : return shutdown or self . _deleted . is_set ( )
2014-01-22 21:11:22 +00:00
def IsDone ( self ) : return shutdown or self . _done . is_set ( )
2013-02-19 00:11:43 +00:00
2014-12-10 22:02:39 +00:00
def IsPausable ( self ) : return self . _pausable and not self . IsDone ( )
2014-08-13 22:18:12 +00:00
2014-12-25 00:07:20 +00:00
def IsPaused ( self ) : return self . _paused . is_set ( ) and not self . IsDone ( )
2013-02-19 00:11:43 +00:00
2014-01-08 18:40:02 +00:00
def IsWorking ( self ) : return self . IsBegun ( ) and not self . IsDone ( )
def Pause ( self ) : self . _paused . set ( )
def PauseResume ( self ) :
2013-02-19 00:11:43 +00:00
2014-01-08 18:40:02 +00:00
if self . _paused . is_set ( ) : self . _paused . clear ( )
else : self . _paused . set ( )
2013-02-19 00:11:43 +00:00
2014-01-08 18:40:02 +00:00
def Resume ( self ) : self . _paused . clear ( )
2013-02-19 00:11:43 +00:00
2014-08-13 22:18:12 +00:00
def SetCancellable ( self , value ) : self . _cancellable = value
def SetPausable ( self , value ) : self . _pausable = value
2014-01-22 21:11:22 +00:00
def SetVariable ( self , name , value ) :
with self . _variable_lock : self . _variables [ name ] = value
2014-12-25 00:07:20 +00:00
time . sleep ( 0.00001 )
2014-01-22 21:11:22 +00:00
2014-01-08 18:40:02 +00:00
def WaitOnPause ( self ) :
2013-02-19 00:11:43 +00:00
2014-01-08 18:40:02 +00:00
while self . _paused . is_set ( ) :
2013-02-19 00:11:43 +00:00
2014-01-08 18:40:02 +00:00
time . sleep ( 0.1 )
2014-01-22 21:11:22 +00:00
if shutdown or self . IsDone ( ) : return
2014-07-23 21:21:37 +00:00
class JobNetwork ( object ) :
2014-01-22 21:11:22 +00:00
yaml_tag = u ' !JobNetwork '
2014-08-27 22:15:22 +00:00
def __init__ ( self , request_type , request , headers = { } , body = None , response_to_path = False , redirects_permitted = 4 , service_key = None ) :
2014-01-22 21:11:22 +00:00
self . _request_type = request_type
self . _request = request
self . _headers = headers
self . _body = body
self . _response_to_path = response_to_path
self . _redirects_permitted = redirects_permitted
2014-08-27 22:15:22 +00:00
self . _service_key = service_key
2014-01-22 21:11:22 +00:00
self . _result = None
self . _result_ready = threading . Event ( )
2014-08-27 22:15:22 +00:00
def ToTuple ( self ) : return ( self . _request_type , self . _request , self . _headers , self . _body , self . _response_to_path , self . _redirects_permitted , self . _service_key )
2014-01-22 21:11:22 +00:00
def GetResult ( self ) :
while True :
if self . _result_ready . wait ( 5 ) == True : break
elif shutdown : raise Exception ( ' Application quit before network could serve result! ' )
if issubclass ( type ( self . _result ) , Exception ) :
etype = type ( self . _result )
network_traceback = unicode ( self . _result )
trace_list = traceback . format_stack ( )
2014-09-24 21:50:07 +00:00
my_trace = ' Stack Trace (most recent call last): ' + os . linesep * 2 + os . linesep . join ( trace_list )
2014-01-22 21:11:22 +00:00
full_message = os . linesep . join ( ( ' Calling Thread: ' , my_trace , ' Network Thread: ' , network_traceback ) )
2013-02-19 00:11:43 +00:00
2014-01-22 21:11:22 +00:00
raise etype ( full_message )
else : return self . _result
def PutResult ( self , result ) :
self . _result = result
self . _result_ready . set ( )
2013-02-19 00:11:43 +00:00
2013-11-27 18:27:11 +00:00
class Predicate ( HydrusYAMLBase ) :
yaml_tag = u ' !Predicate '
2013-03-27 20:02:51 +00:00
2015-01-07 23:09:00 +00:00
def __init__ ( self , predicate_type , value , inclusive = True , counts = { } ) :
2013-03-27 20:02:51 +00:00
self . _predicate_type = predicate_type
self . _value = value
2014-04-16 20:31:59 +00:00
2015-01-07 23:09:00 +00:00
self . _inclusive = inclusive
2014-04-16 20:31:59 +00:00
self . _counts = { }
self . _counts [ CURRENT ] = 0
self . _counts [ PENDING ] = 0
2014-09-10 22:37:38 +00:00
for ( current_or_pending , count ) in counts . items ( ) : self . AddToCount ( current_or_pending , count )
2013-03-27 20:02:51 +00:00
def __eq__ ( self , other ) : return self . __hash__ ( ) == other . __hash__ ( )
def __hash__ ( self ) : return ( self . _predicate_type , self . _value ) . __hash__ ( )
def __ne__ ( self , other ) : return self . __hash__ ( ) != other . __hash__ ( )
2014-04-09 20:18:58 +00:00
def __repr__ ( self ) : return ' Predicate: ' + u ( ( self . _predicate_type , self . _value , self . _counts ) )
2013-07-17 20:56:13 +00:00
2014-09-10 22:37:38 +00:00
def AddToCount ( self , current_or_pending , count ) : self . _counts [ current_or_pending ] + = count
2013-05-08 20:31:00 +00:00
2015-01-07 23:09:00 +00:00
def GetCopy ( self ) : return Predicate ( self . _predicate_type , self . _value , self . _inclusive , self . _counts )
2013-05-08 20:31:00 +00:00
2015-01-07 23:09:00 +00:00
def GetCountlessCopy ( self ) : return Predicate ( self . _predicate_type , self . _value , self . _inclusive )
2013-03-27 20:02:51 +00:00
2014-09-10 22:37:38 +00:00
def GetCount ( self , current_or_pending = None ) :
2014-04-09 20:18:58 +00:00
2014-09-10 22:37:38 +00:00
if current_or_pending is None : return sum ( self . _counts . values ( ) )
else : return self . _counts [ current_or_pending ]
2014-04-09 20:18:58 +00:00
2013-03-27 20:02:51 +00:00
2015-01-07 23:09:00 +00:00
def GetInclusive ( self ) : return self . _inclusive
def GetInfo ( self ) : return ( self . _predicate_type , self . _value , self . _inclusive )
2013-03-27 20:02:51 +00:00
def GetPredicateType ( self ) : return self . _predicate_type
2013-11-06 18:22:07 +00:00
def GetUnicode ( self , with_count = True ) :
2013-03-27 20:02:51 +00:00
2014-04-09 20:18:58 +00:00
count_text = u ' '
if with_count :
count_text
if self . _counts [ CURRENT ] > 0 : count_text + = u ' ( ' + ConvertIntToPrettyString ( self . _counts [ CURRENT ] ) + u ' ) '
if self . _counts [ PENDING ] > 0 : count_text + = u ' (+ ' + ConvertIntToPrettyString ( self . _counts [ PENDING ] ) + u ' ) '
2013-03-27 20:02:51 +00:00
if self . _predicate_type == PREDICATE_TYPE_SYSTEM :
( system_predicate_type , info ) = self . _value
if system_predicate_type == SYSTEM_PREDICATE_TYPE_EVERYTHING : base = u ' system:everything '
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_INBOX : base = u ' system:inbox '
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_ARCHIVE : base = u ' system:archive '
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_UNTAGGED : base = u ' system:untagged '
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_LOCAL : base = u ' system:local '
2013-04-03 20:56:07 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_NOT_LOCAL : base = u ' system:not local '
2013-08-28 21:31:52 +00:00
elif system_predicate_type in ( SYSTEM_PREDICATE_TYPE_NUM_TAGS , SYSTEM_PREDICATE_TYPE_WIDTH , SYSTEM_PREDICATE_TYPE_HEIGHT , SYSTEM_PREDICATE_TYPE_DURATION , SYSTEM_PREDICATE_TYPE_NUM_WORDS ) :
2013-03-27 20:02:51 +00:00
2013-04-03 20:56:07 +00:00
if system_predicate_type == SYSTEM_PREDICATE_TYPE_NUM_TAGS : base = u ' system:number of tags '
2013-03-27 20:02:51 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_WIDTH : base = u ' system:width '
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_HEIGHT : base = u ' system:height '
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_DURATION : base = u ' system:duration '
2013-04-03 20:56:07 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_NUM_WORDS : base = u ' system:number of words '
2013-03-27 20:02:51 +00:00
if info is not None :
( operator , value ) = info
2015-01-14 22:27:55 +00:00
base + = u ' ' + operator + u ' ' + ConvertIntToPrettyString ( value )
2013-03-27 20:02:51 +00:00
2013-08-28 21:31:52 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_RATIO :
base = u ' system:ratio '
if info is not None :
( operator , ratio_width , ratio_height ) = info
base + = u ' ' + operator + u ' ' + u ( ratio_width ) + u ' : ' + u ( ratio_height )
2013-03-27 20:02:51 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_SIZE :
base = u ' system:size '
if info is not None :
( operator , size , unit ) = info
2013-07-31 21:26:38 +00:00
base + = u ' ' + operator + u ' ' + u ( size ) + ConvertUnitToString ( unit )
2013-03-27 20:02:51 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_LIMIT :
base = u ' system:limit '
if info is not None :
value = info
2015-01-14 22:27:55 +00:00
base + = u ' is ' + ConvertIntToPrettyString ( value )
2013-03-27 20:02:51 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_AGE :
base = u ' system:age '
if info is not None :
2013-06-19 20:25:06 +00:00
( operator , years , months , days , hours ) = info
2013-03-27 20:02:51 +00:00
2013-07-31 21:26:38 +00:00
base + = u ' ' + operator + u ' ' + u ( years ) + u ' y ' + u ( months ) + u ' m ' + u ( days ) + u ' d ' + u ( hours ) + u ' h '
2013-03-27 20:02:51 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_HASH :
base = u ' system:hash '
if info is not None :
hash = info
2013-04-03 20:56:07 +00:00
base + = u ' is ' + hash . encode ( ' hex ' )
2013-03-27 20:02:51 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_MIME :
base = u ' system:mime '
if info is not None :
mime = info
2013-04-03 20:56:07 +00:00
base + = u ' is ' + mime_string_lookup [ mime ]
2013-03-27 20:02:51 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_RATING :
base = u ' system:rating '
if info is not None :
2014-08-27 22:15:22 +00:00
( service_key , operator , value ) = info
service = app . GetManager ( ' services ' ) . GetService ( service_key )
2013-03-27 20:02:51 +00:00
2014-08-27 22:15:22 +00:00
base + = u ' for ' + service . GetName ( ) + u ' ' + operator + u ' ' + u ( value )
2013-03-27 20:02:51 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_SIMILAR_TO :
2015-01-14 22:27:55 +00:00
base = u ' system:similar to '
2013-03-27 20:02:51 +00:00
if info is not None :
( hash , max_hamming ) = info
2013-07-31 21:26:38 +00:00
base + = u ' ' + hash . encode ( ' hex ' ) + u ' using max hamming of ' + u ( max_hamming )
2013-03-27 20:02:51 +00:00
2013-04-03 20:56:07 +00:00
elif system_predicate_type == SYSTEM_PREDICATE_TYPE_FILE_SERVICE :
2013-03-27 20:02:51 +00:00
2015-01-14 22:27:55 +00:00
base = u ' system: '
2013-03-27 20:02:51 +00:00
if info is not None :
2014-09-10 22:37:38 +00:00
( operator , current_or_pending , service_key ) = info
2013-03-27 20:02:51 +00:00
2015-01-14 22:27:55 +00:00
if operator == True : base + = u ' is '
else : base + = u ' is not '
2013-04-03 20:56:07 +00:00
2014-09-10 22:37:38 +00:00
if current_or_pending == PENDING : base + = u ' pending to '
2013-04-03 20:56:07 +00:00
else : base + = u ' currently in '
2014-08-27 22:15:22 +00:00
service = app . GetManager ( ' services ' ) . GetService ( service_key )
base + = service . GetName ( )
2013-03-27 20:02:51 +00:00
2014-04-09 20:18:58 +00:00
base + = count_text
2013-05-08 20:31:00 +00:00
2013-03-27 20:02:51 +00:00
elif self . _predicate_type == PREDICATE_TYPE_TAG :
2015-01-07 23:09:00 +00:00
tag = self . _value
2013-03-27 20:02:51 +00:00
2015-01-07 23:09:00 +00:00
if not self . _inclusive : base = u ' - '
else : base = u ' '
2013-03-27 20:02:51 +00:00
2013-04-03 20:56:07 +00:00
base + = tag
2013-03-27 20:02:51 +00:00
2014-04-09 20:18:58 +00:00
base + = count_text
2013-05-08 20:31:00 +00:00
2013-11-27 18:27:11 +00:00
siblings_manager = app . GetManager ( ' tag_siblings ' )
2013-05-08 20:31:00 +00:00
sibling = siblings_manager . GetSibling ( tag )
if sibling is not None : base + = u ' ( ' + sibling + u ' ) '
2013-05-15 18:58:14 +00:00
elif self . _predicate_type == PREDICATE_TYPE_PARENT :
base = ' '
tag = self . _value
base + = tag
2014-04-09 20:18:58 +00:00
base + = count_text
2013-05-15 18:58:14 +00:00
2013-03-27 20:02:51 +00:00
elif self . _predicate_type == PREDICATE_TYPE_NAMESPACE :
2015-01-07 23:09:00 +00:00
namespace = self . _value
2013-03-27 20:02:51 +00:00
2015-01-14 22:27:55 +00:00
if not self . _inclusive : base = u ' - '
2015-01-07 23:09:00 +00:00
else : base = u ' '
2013-03-27 20:02:51 +00:00
2013-04-03 20:56:07 +00:00
base + = namespace + u ' :* '
2013-03-27 20:02:51 +00:00
2014-12-31 22:56:38 +00:00
elif self . _predicate_type == PREDICATE_TYPE_WILDCARD :
2015-01-14 22:27:55 +00:00
wildcard = self . _value
2014-12-31 22:56:38 +00:00
2015-01-07 23:09:00 +00:00
if not self . _inclusive : base = u ' - '
else : base = u ' '
2014-12-31 22:56:38 +00:00
base + = wildcard
2013-03-27 20:02:51 +00:00
2013-05-08 20:31:00 +00:00
return base
2013-03-27 20:02:51 +00:00
def GetValue ( self ) : return self . _value
2015-01-07 23:09:00 +00:00
def SetInclusive ( self , inclusive ) : self . _inclusive = inclusive
2013-03-27 20:02:51 +00:00
2014-04-16 20:31:59 +00:00
SYSTEM_PREDICATE_INBOX = Predicate ( PREDICATE_TYPE_SYSTEM , ( SYSTEM_PREDICATE_TYPE_INBOX , None ) )
SYSTEM_PREDICATE_ARCHIVE = Predicate ( PREDICATE_TYPE_SYSTEM , ( SYSTEM_PREDICATE_TYPE_ARCHIVE , None ) )
SYSTEM_PREDICATE_LOCAL = Predicate ( PREDICATE_TYPE_SYSTEM , ( SYSTEM_PREDICATE_TYPE_LOCAL , None ) )
SYSTEM_PREDICATE_NOT_LOCAL = Predicate ( PREDICATE_TYPE_SYSTEM , ( SYSTEM_PREDICATE_TYPE_NOT_LOCAL , None ) )
2013-04-03 20:56:07 +00:00
2014-07-23 21:21:37 +00:00
class ResponseContext ( object ) :
2013-02-19 00:11:43 +00:00
2013-10-02 22:06:06 +00:00
def __init__ ( self , status_code , mime = APPLICATION_YAML , body = None , path = None , is_yaml = False , cookies = [ ] ) :
2013-02-19 00:11:43 +00:00
self . _status_code = status_code
self . _mime = mime
self . _body = body
2013-10-02 22:06:06 +00:00
self . _path = path
self . _is_yaml = is_yaml
2013-03-15 02:38:12 +00:00
self . _cookies = cookies
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def GetCookies ( self ) : return self . _cookies
2013-02-19 00:11:43 +00:00
def GetLength ( self ) : return len ( self . _body )
def GetMimeBody ( self ) : return ( self . _mime , self . _body )
2013-10-02 22:06:06 +00:00
def GetPath ( self ) : return self . _path
2013-02-19 00:11:43 +00:00
def GetStatusCode ( self ) : return self . _status_code
2013-10-02 22:06:06 +00:00
def HasBody ( self ) : return self . _body is not None
def HasPath ( self ) : return self . _path is not None
def IsYAML ( self ) : return self . _is_yaml
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
class ServerServiceIdentifier ( HydrusYAMLBase ) :
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
yaml_tag = u ' !ServerServiceIdentifier '
2013-02-19 00:11:43 +00:00
2014-09-10 22:37:38 +00:00
def __init__ ( self , service_key , service_type ) :
2013-02-19 00:11:43 +00:00
HydrusYAMLBase . __init__ ( self )
2013-10-02 22:06:06 +00:00
self . _service_key = service_key
2014-09-10 22:37:38 +00:00
self . _type = service_type
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def __eq__ ( self , other ) : return self . __hash__ ( ) == other . __hash__ ( )
2013-02-19 00:11:43 +00:00
2013-10-02 22:06:06 +00:00
def __hash__ ( self ) : return self . _service_key . __hash__ ( )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def __ne__ ( self , other ) : return self . __hash__ ( ) != other . __hash__ ( )
2013-02-19 00:11:43 +00:00
2013-10-02 22:06:06 +00:00
def __repr__ ( self ) : return ' Server Service Identifier: ' + service_string_lookup [ self . _type ]
2013-07-17 20:56:13 +00:00
2013-10-02 22:06:06 +00:00
def GetServiceKey ( self ) : return self . _service_key
2013-02-19 00:11:43 +00:00
2014-09-17 21:28:26 +00:00
def GetServiceType ( self ) : return self . _type
2013-02-19 00:11:43 +00:00
2014-08-13 22:18:12 +00:00
SERVER_ADMIN_KEY = ' server admin '
2013-10-02 22:06:06 +00:00
2014-07-23 21:21:37 +00:00
class ServiceUpdate ( object ) :
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def __init__ ( self , action , row = None ) :
self . _action = action
self . _row = row
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def ToTuple ( self ) : return ( self . _action , self . _row )
2014-07-23 21:21:37 +00:00
2013-06-12 22:53:31 +00:00
class ServerToClientPetition ( HydrusYAMLBase ) :
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
yaml_tag = u ' !ServerToClientPetition '
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def __init__ ( self , petition_type , action , petitioner_account_identifier , petition_data , reason ) :
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
HydrusYAMLBase . __init__ ( self )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
self . _petition_type = petition_type
self . _action = action
self . _petitioner_account_identifier = petitioner_account_identifier
self . _petition_data = petition_data
2013-02-19 00:11:43 +00:00
self . _reason = reason
2013-06-12 22:53:31 +00:00
def GetApproval ( self , reason = None ) :
if reason is None : reason = self . _reason
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
if self . _petition_type == CONTENT_DATA_TYPE_FILES : hashes = self . _petition_data
elif self . _petition_type == CONTENT_DATA_TYPE_MAPPINGS : ( tag , hashes ) = self . _petition_data
else : hashes = set ( )
hash_ids_to_hashes = dict ( enumerate ( hashes ) )
2013-02-19 00:11:43 +00:00
hash_ids = hash_ids_to_hashes . keys ( )
2013-06-12 22:53:31 +00:00
content_data = GetEmptyDataDict ( )
if self . _petition_type == CONTENT_DATA_TYPE_FILES : row = ( hash_ids , reason )
elif self . _petition_type == CONTENT_DATA_TYPE_MAPPINGS : row = ( tag , hash_ids , reason )
else :
( old , new ) = self . _petition_data
row = ( ( old , new ) , reason )
content_data [ self . _petition_type ] [ self . _action ] . append ( row )
return ClientToServerUpdate ( content_data , hash_ids_to_hashes )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def GetDenial ( self ) :
if self . _petition_type == CONTENT_DATA_TYPE_FILES : hashes = self . _petition_data
elif self . _petition_type == CONTENT_DATA_TYPE_MAPPINGS : ( tag , hashes ) = self . _petition_data
else : hashes = set ( )
hash_ids_to_hashes = dict ( enumerate ( hashes ) )
hash_ids = hash_ids_to_hashes . keys ( )
if self . _petition_type == CONTENT_DATA_TYPE_FILES : row_list = hash_ids
elif self . _petition_type == CONTENT_DATA_TYPE_MAPPINGS : row_list = [ ( tag , hash_ids ) ]
else : row_list = [ self . _petition_data ]
content_data = GetEmptyDataDict ( )
if self . _action == CONTENT_UPDATE_PENDING : denial_action = CONTENT_UPDATE_DENY_PEND
elif self . _action == CONTENT_UPDATE_PETITION : denial_action = CONTENT_UPDATE_DENY_PETITION
content_data [ self . _petition_type ] [ denial_action ] = row_list
return ClientToServerUpdate ( content_data , hash_ids_to_hashes )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def GetHashes ( self ) :
if self . _petition_type == CONTENT_DATA_TYPE_FILES : hashes = self . _petition_data
elif self . _petition_type == CONTENT_DATA_TYPE_MAPPINGS : ( tag , hashes ) = self . _petition_data
else : hashes = set ( )
return hashes
2013-02-19 00:11:43 +00:00
2014-01-01 20:01:00 +00:00
def GetPetitionerIdentifier ( self ) : return self . _petitioner_account_identifier
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def GetPetitionString ( self ) :
if self . _action == CONTENT_UPDATE_PENDING : action_word = ' Add '
elif self . _action == CONTENT_UPDATE_PETITION : action_word = ' Remove '
if self . _petition_type == CONTENT_DATA_TYPE_FILES :
hashes = self . _petition_data
content_phrase = ConvertIntToPrettyString ( len ( hashes ) ) + ' files '
elif self . _petition_type == CONTENT_DATA_TYPE_MAPPINGS :
( tag , hashes ) = self . _petition_data
content_phrase = tag + ' for ' + ConvertIntToPrettyString ( len ( hashes ) ) + ' files '
elif self . _petition_type == CONTENT_DATA_TYPE_TAG_SIBLINGS :
( old_tag , new_tag ) = self . _petition_data
2014-12-17 22:35:12 +00:00
content_phrase = ' sibling ' + old_tag + ' -> ' + new_tag
2013-06-12 22:53:31 +00:00
elif self . _petition_type == CONTENT_DATA_TYPE_TAG_PARENTS :
( old_tag , new_tag ) = self . _petition_data
2014-12-17 22:35:12 +00:00
content_phrase = ' parent ' + old_tag + ' -> ' + new_tag
2013-06-12 22:53:31 +00:00
2014-09-24 21:50:07 +00:00
return action_word + content_phrase + os . linesep * 2 + self . _reason
2013-06-12 22:53:31 +00:00
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
class ServerToClientUpdate ( HydrusYAMLBase ) :
yaml_tag = u ' !ServerToClientUpdate '
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def __init__ ( self , service_data , content_data , hash_ids_to_hashes ) :
2013-02-19 00:11:43 +00:00
HydrusYAMLBase . __init__ ( self )
2013-06-12 22:53:31 +00:00
self . _service_data = service_data
self . _content_data = { }
for data_type in content_data :
self . _content_data [ data_type ] = { }
for action in content_data [ data_type ] : self . _content_data [ data_type ] [ action ] = content_data [ data_type ] [ action ]
self . _hash_ids_to_hashes = hash_ids_to_hashes
2013-02-19 00:11:43 +00:00
2014-03-05 22:44:02 +00:00
def GetBeginEnd ( self ) :
2013-06-12 22:53:31 +00:00
2014-03-05 22:44:02 +00:00
( begin , end ) = self . _service_data [ SERVICE_UPDATE_BEGIN_END ]
return ( begin , end )
2013-06-12 22:53:31 +00:00
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def GetContentDataIterator ( self , data_type , action ) :
if data_type not in self . _content_data or action not in self . _content_data [ data_type ] : return ( )
data = self . _content_data [ data_type ] [ action ]
if data_type == CONTENT_DATA_TYPE_FILES :
if action == CONTENT_UPDATE_ADD : return ( ( self . _hash_ids_to_hashes [ hash_id ] , size , mime , timestamp , width , height , duration , num_frames , num_words ) for ( hash_id , size , mime , timestamp , width , height , duration , num_frames , num_words ) in data )
else : return ( { self . _hash_ids_to_hashes [ hash_id ] for hash_id in hash_ids } for hash_ids in ( data , ) )
elif data_type == CONTENT_DATA_TYPE_MAPPINGS : return ( ( tag , [ self . _hash_ids_to_hashes [ hash_id ] for hash_id in hash_ids ] ) for ( tag , hash_ids ) in data )
else : return data . __iter__ ( )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def GetNumContentUpdates ( self ) :
num = 0
data_types = [ CONTENT_DATA_TYPE_FILES , CONTENT_DATA_TYPE_MAPPINGS , CONTENT_DATA_TYPE_TAG_SIBLINGS , CONTENT_DATA_TYPE_TAG_PARENTS ]
actions = [ CONTENT_UPDATE_ADD , CONTENT_UPDATE_DELETE ]
for ( data_type , action ) in itertools . product ( data_types , actions ) :
for row in self . GetContentDataIterator ( data_type , action ) : num + = 1
return num
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
# this needs work!
# we need a universal content_update for both client and server
2014-07-23 21:21:37 +00:00
def IterateContentUpdates ( self , as_if_pending = False ) :
2013-06-12 22:53:31 +00:00
data_types = [ CONTENT_DATA_TYPE_FILES , CONTENT_DATA_TYPE_MAPPINGS , CONTENT_DATA_TYPE_TAG_SIBLINGS , CONTENT_DATA_TYPE_TAG_PARENTS ]
actions = [ CONTENT_UPDATE_ADD , CONTENT_UPDATE_DELETE ]
for ( data_type , action ) in itertools . product ( data_types , actions ) :
2014-07-23 21:21:37 +00:00
for row in self . GetContentDataIterator ( data_type , action ) :
yieldee_action = action
if as_if_pending :
if action == CONTENT_UPDATE_ADD : yieldee_action = CONTENT_UPDATE_PENDING
elif action == CONTENT_UPDATE_DELETE : continue
yield ContentUpdate ( data_type , yieldee_action , row )
2013-06-12 22:53:31 +00:00
2013-04-10 18:10:37 +00:00
2013-06-12 22:53:31 +00:00
def IterateServiceUpdates ( self ) :
2013-04-10 18:10:37 +00:00
2014-03-05 22:44:02 +00:00
service_types = [ SERVICE_UPDATE_NEWS ]
2013-06-12 22:53:31 +00:00
for service_type in service_types :
if service_type in self . _service_data :
data = self . _service_data [ service_type ]
yield ServiceUpdate ( service_type , data )
2013-04-10 18:10:37 +00:00
2013-06-12 22:53:31 +00:00
def GetHashes ( self ) : return set ( hash_ids_to_hashes . values ( ) )
2013-04-10 18:10:37 +00:00
2013-06-12 22:53:31 +00:00
def GetTags ( self ) :
tags = set ( )
tags . update ( ( tag for ( tag , hash_ids ) in self . GetContentDataIterator ( CONTENT_DATA_TYPE_MAPPINGS , CURRENT ) ) )
tags . update ( ( tag for ( tag , hash_ids ) in self . GetContentDataIterator ( CONTENT_DATA_TYPE_MAPPINGS , DELETED ) ) )
tags . update ( ( old_tag for ( old_tag , new_tag ) in self . GetContentDataIterator ( CONTENT_DATA_TYPE_TAG_SIBLINGS , CURRENT ) ) )
tags . update ( ( new_tag for ( old_tag , new_tag ) in self . GetContentDataIterator ( CONTENT_DATA_TYPE_TAG_SIBLINGS , CURRENT ) ) )
tags . update ( ( old_tag for ( old_tag , new_tag ) in self . GetContentDataIterator ( CONTENT_DATA_TYPE_TAG_SIBLINGS , DELETED ) ) )
tags . update ( ( new_tag for ( old_tag , new_tag ) in self . GetContentDataIterator ( CONTENT_DATA_TYPE_TAG_SIBLINGS , DELETED ) ) )
return tags
2013-04-10 18:10:37 +00:00
2013-06-12 22:53:31 +00:00
def GetServiceData ( self , service_type ) : return self . _service_data [ service_type ]
2013-04-10 18:10:37 +00:00
2014-07-23 21:21:37 +00:00
class SortedList ( object ) :
2013-08-28 21:31:52 +00:00
def __init__ ( self , initial_items = [ ] , sort_function = None ) :
do_sort = sort_function is not None
if sort_function is None : sort_function = lambda x : x
self . _sorted_list = [ ( sort_function ( item ) , item ) for item in initial_items ]
self . _items_to_indices = None
self . _sort_function = sort_function
if do_sort : self . sort ( )
def __contains__ ( self , item ) : return self . _items_to_indices . __contains__ ( item )
def __getitem__ ( self , value ) :
if type ( value ) == int : return self . _sorted_list . __getitem__ ( value ) [ 1 ]
elif type ( value ) == slice : return [ item for ( sort_item , item ) in self . _sorted_list . __getitem__ ( value ) ]
def __iter__ ( self ) :
for ( sorting_value , item ) in self . _sorted_list : yield item
def __len__ ( self ) : return self . _sorted_list . __len__ ( )
def _DirtyIndices ( self ) : self . _items_to_indices = None
def _RecalcIndices ( self ) : self . _items_to_indices = { item : index for ( index , ( sort_item , item ) ) in enumerate ( self . _sorted_list ) }
def append_items ( self , items ) :
self . _sorted_list . extend ( [ ( self . _sort_function ( item ) , item ) for item in items ] )
self . _DirtyIndices ( )
def index ( self , item ) :
if self . _items_to_indices is None : self . _RecalcIndices ( )
return self . _items_to_indices [ item ]
def insert_items ( self , items ) :
for item in items : bisect . insort ( self . _sorted_list , ( self . _sort_function ( item ) , item ) )
self . _DirtyIndices ( )
def remove_items ( self , items ) :
2013-09-04 16:48:44 +00:00
deletee_indices = [ self . index ( item ) for item in items ]
2013-08-28 21:31:52 +00:00
deletee_indices . sort ( )
deletee_indices . reverse ( )
for index in deletee_indices : self . _sorted_list . pop ( index )
self . _DirtyIndices ( )
def sort ( self , f = None ) :
if f is not None : self . _sort_function = f
self . _sorted_list = [ ( self . _sort_function ( item ) , item ) for ( old_value , item ) in self . _sorted_list ]
self . _sorted_list . sort ( )
self . _DirtyIndices ( )
2013-11-27 18:27:11 +00:00
# adding tuple to yaml
def construct_python_tuple ( self , node ) : return tuple ( self . construct_sequence ( node ) )
def represent_python_tuple ( self , data ) : return self . represent_sequence ( u ' tag:yaml.org,2002:python/tuple ' , data )
yaml . SafeLoader . add_constructor ( u ' tag:yaml.org,2002:python/tuple ' , construct_python_tuple )
2014-02-12 23:09:38 +00:00
yaml . SafeDumper . add_representer ( tuple , represent_python_tuple )
# for some reason, sqlite doesn't parse to int before this, despite the column affinity
# it gives the register_converter function a bytestring :/
def integer_boolean_to_bool ( integer_boolean ) : return bool ( int ( integer_boolean ) )
2013-11-27 18:27:11 +00:00
2013-02-19 00:11:43 +00:00
# sqlite mod
sqlite3 . register_adapter ( dict , yaml . safe_dump )
2013-03-15 02:38:12 +00:00
sqlite3 . register_adapter ( list , yaml . safe_dump )
2014-02-12 23:09:38 +00:00
sqlite3 . register_adapter ( tuple , yaml . safe_dump )
sqlite3 . register_adapter ( bool , int )
# no longer needed since adding tuple? do yaml objects somehow cast to __tuple__?
2013-02-19 00:11:43 +00:00
sqlite3 . register_adapter ( Account , yaml . safe_dump )
sqlite3 . register_adapter ( AccountType , yaml . safe_dump )
2014-02-12 23:09:38 +00:00
sqlite3 . register_adapter ( ServerToClientUpdate , yaml . safe_dump )
2013-02-19 00:11:43 +00:00
sqlite3 . register_converter ( ' BLOB_BYTES ' , str )
sqlite3 . register_converter ( ' INTEGER_BOOLEAN ' , integer_boolean_to_bool )
2014-02-12 23:09:38 +00:00
sqlite3 . register_converter ( ' TEXT_YAML ' , yaml . safe_load )