checkpoint
This commit is contained in:
parent
0b85c309f8
commit
de60770d20
3 changed files with 182 additions and 107 deletions
|
@ -72,6 +72,32 @@ def _helper_comma_split(s):
|
||||||
s = [x for x in s if x]
|
s = [x for x in s if x]
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
def create_tag(easybake_string):
|
||||||
|
notes = P.easybake(easybake_string)
|
||||||
|
notes = [{'action': action, 'tagname': tagname} for (action, tagname) in notes]
|
||||||
|
return notes
|
||||||
|
|
||||||
|
def delete_tag(tag):
|
||||||
|
tag = tag.split('.')[-1].split('+')[0]
|
||||||
|
tag = P.get_tag(tag)
|
||||||
|
|
||||||
|
tag.delete()
|
||||||
|
return {'action': 'delete_tag', 'tagname': tag.name}
|
||||||
|
|
||||||
|
def delete_synonym(synonym):
|
||||||
|
synonym = synonym.split('+')[-1].split('.')[-1]
|
||||||
|
synonym = phototagger.normalize_tagname(synonym)
|
||||||
|
try:
|
||||||
|
master_tag = P.get_tag(synonym)
|
||||||
|
except phototagger.NoSuchTag:
|
||||||
|
flask.abort(404, 'That synonym doesnt exist')
|
||||||
|
|
||||||
|
if synonym not in master_tag.synonyms():
|
||||||
|
flask.abort(400, 'That name is not a synonym')
|
||||||
|
|
||||||
|
master_tag.remove_synonym(synonym)
|
||||||
|
return {'action':'delete_synonym', 'synonym': synonym}
|
||||||
|
|
||||||
def edit_params(original, modifications):
|
def edit_params(original, modifications):
|
||||||
new_params = original.to_dict()
|
new_params = original.to_dict()
|
||||||
new_params.update(modifications)
|
new_params.update(modifications)
|
||||||
|
@ -111,16 +137,6 @@ def P_tag(tagname):
|
||||||
except phototagger.NoSuchTag as e:
|
except phototagger.NoSuchTag as e:
|
||||||
flask.abort(404, 'That tag doesnt exist: %s' % e)
|
flask.abort(404, 'That tag doesnt exist: %s' % e)
|
||||||
|
|
||||||
def truthystring(s):
|
|
||||||
if isinstance(s, (bool, int)) or s is None:
|
|
||||||
return s
|
|
||||||
s = s.lower()
|
|
||||||
if s in {'1', 'true', 't', 'yes', 'y', 'on'}:
|
|
||||||
return True
|
|
||||||
if s in {'null', 'none'}:
|
|
||||||
return None
|
|
||||||
return False
|
|
||||||
|
|
||||||
def read_filebytes(filepath, range_min, range_max):
|
def read_filebytes(filepath, range_min, range_max):
|
||||||
range_span = range_max - range_min
|
range_span = range_max - range_min
|
||||||
|
|
||||||
|
@ -130,7 +146,7 @@ def read_filebytes(filepath, range_min, range_max):
|
||||||
sent_amount = 0
|
sent_amount = 0
|
||||||
with f:
|
with f:
|
||||||
while sent_amount < range_span:
|
while sent_amount < range_span:
|
||||||
print(sent_amount)
|
#print(sent_amount)
|
||||||
chunk = f.read(FILE_READ_CHUNK)
|
chunk = f.read(FILE_READ_CHUNK)
|
||||||
if len(chunk) == 0:
|
if len(chunk) == 0:
|
||||||
break
|
break
|
||||||
|
@ -138,6 +154,17 @@ def read_filebytes(filepath, range_min, range_max):
|
||||||
yield chunk
|
yield chunk
|
||||||
sent_amount += len(chunk)
|
sent_amount += len(chunk)
|
||||||
|
|
||||||
|
def seconds_to_hms(seconds):
|
||||||
|
seconds = math.ceil(seconds)
|
||||||
|
(minutes, seconds) = divmod(seconds, 60)
|
||||||
|
(hours, minutes) = divmod(minutes, 60)
|
||||||
|
parts = []
|
||||||
|
if hours: parts.append(hours)
|
||||||
|
if minutes: parts.append(minutes)
|
||||||
|
parts.append(seconds)
|
||||||
|
hms = ':'.join('%02d' % part for part in parts)
|
||||||
|
return hms
|
||||||
|
|
||||||
def send_file(filepath):
|
def send_file(filepath):
|
||||||
'''
|
'''
|
||||||
Range-enabled file sending.
|
Range-enabled file sending.
|
||||||
|
@ -202,31 +229,15 @@ def send_file(filepath):
|
||||||
)
|
)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def create_tag(easybake_string):
|
def truthystring(s):
|
||||||
notes = P.easybake(easybake_string)
|
if isinstance(s, (bool, int)) or s is None:
|
||||||
notes = [{'action': action, 'tagname': tagname} for (action, tagname) in notes]
|
return s
|
||||||
return notes
|
s = s.lower()
|
||||||
|
if s in {'1', 'true', 't', 'yes', 'y', 'on'}:
|
||||||
def delete_tag(tag):
|
return True
|
||||||
tag = tag.split('.')[-1].split('+')[0]
|
if s in {'null', 'none'}:
|
||||||
tag = P.get_tag(tag)
|
return None
|
||||||
|
return False
|
||||||
tag.delete()
|
|
||||||
return {'action': 'delete_tag', 'tagname': tag.name, 'tagid': tag.id}
|
|
||||||
|
|
||||||
def delete_synonym(synonym):
|
|
||||||
synonym = synonym.split('+')[-1].split('.')[-1]
|
|
||||||
synonym = phototagger.normalize_tagname(synonym)
|
|
||||||
try:
|
|
||||||
master_tag = P.get_tag(synonym)
|
|
||||||
except phototagger.NoSuchTag:
|
|
||||||
flask.abort(404, 'That synonym doesnt exist')
|
|
||||||
|
|
||||||
if synonym not in master_tag.synonyms():
|
|
||||||
flask.abort(400, 'That name is not a synonym')
|
|
||||||
|
|
||||||
master_tag.remove_synonym(synonym)
|
|
||||||
return {'action':'delete_synonym', 'synonym': synonym}
|
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
@ -246,17 +257,6 @@ def jsonify_album(album, minimal=False):
|
||||||
|
|
||||||
return j
|
return j
|
||||||
|
|
||||||
def seconds_to_hms(seconds):
|
|
||||||
seconds = math.ceil(seconds)
|
|
||||||
(minutes, seconds) = divmod(seconds, 60)
|
|
||||||
(hours, minutes) = divmod(minutes, 60)
|
|
||||||
parts = []
|
|
||||||
if hours: parts.append(hours)
|
|
||||||
if minutes: parts.append(minutes)
|
|
||||||
parts.append(seconds)
|
|
||||||
hms = ':'.join('%02d' % part for part in parts)
|
|
||||||
return hms
|
|
||||||
|
|
||||||
def jsonify_photo(photo):
|
def jsonify_photo(photo):
|
||||||
tags = photo.tags()
|
tags = photo.tags()
|
||||||
tags.sort(key=lambda x: x.name)
|
tags.sort(key=lambda x: x.name)
|
||||||
|
@ -268,7 +268,7 @@ def jsonify_photo(photo):
|
||||||
'ratio': photo.ratio,
|
'ratio': photo.ratio,
|
||||||
'area': photo.area,
|
'area': photo.area,
|
||||||
'bytes': photo.bytes,
|
'bytes': photo.bytes,
|
||||||
'duration': seconds_to_hms(photo.duration) if photo.duration else None,
|
'duration': seconds_to_hms(photo.duration) if photo.duration is not None else None,
|
||||||
'duration_int': photo.duration,
|
'duration_int': photo.duration,
|
||||||
'bytestring': photo.bytestring(),
|
'bytestring': photo.bytestring(),
|
||||||
'has_thumbnail': bool(photo.thumbnail),
|
'has_thumbnail': bool(photo.thumbnail),
|
||||||
|
@ -474,7 +474,7 @@ def get_search_core():
|
||||||
photos = list(P.search(**search_kwargs))
|
photos = list(P.search(**search_kwargs))
|
||||||
photos = [jsonify_photo(photo) for photo in photos]
|
photos = [jsonify_photo(photo) for photo in photos]
|
||||||
warns = [str(warning.message) for warning in catcher]
|
warns = [str(warning.message) for warning in catcher]
|
||||||
print(warns)
|
#print(warns)
|
||||||
|
|
||||||
# TAGS ON THIS PAGE
|
# TAGS ON THIS PAGE
|
||||||
total_tags = set()
|
total_tags = set()
|
||||||
|
@ -572,10 +572,20 @@ def get_thumbnail(photoid):
|
||||||
flask.abort(404, 'That file doesnt have a thumbnail')
|
flask.abort(404, 'That file doesnt have a thumbnail')
|
||||||
return send_file(path)
|
return send_file(path)
|
||||||
|
|
||||||
|
@site.route('/album/<albumid>', methods=['POST'])
|
||||||
|
@give_session_token
|
||||||
|
def post_edit_album(albumid):
|
||||||
|
'''
|
||||||
|
Edit the album's title and description.
|
||||||
|
Apply a tag to every photo in the album.
|
||||||
|
'''
|
||||||
|
|
||||||
@site.route('/photo/<photoid>', methods=['POST'])
|
@site.route('/photo/<photoid>', methods=['POST'])
|
||||||
@give_session_token
|
@give_session_token
|
||||||
def post_edit_photo(photoid):
|
def post_edit_photo(photoid):
|
||||||
print(request.form)
|
'''
|
||||||
|
Add and remove tags from photos.
|
||||||
|
'''
|
||||||
response = {}
|
response = {}
|
||||||
photo = P_photo(photoid)
|
photo = P_photo(photoid)
|
||||||
|
|
||||||
|
@ -595,17 +605,21 @@ def post_edit_photo(photoid):
|
||||||
try:
|
try:
|
||||||
tag = P.get_tag(tag)
|
tag = P.get_tag(tag)
|
||||||
except phototagger.NoSuchTag:
|
except phototagger.NoSuchTag:
|
||||||
return flask.Response('{"error": "That tag doesnt exist", "tagname":"%s"}'%tag, status=404)
|
response = {'error': 'That tag doesnt exist', 'tagname': tag}
|
||||||
|
return make_json_response(response, status=404)
|
||||||
|
|
||||||
method(tag)
|
method(tag)
|
||||||
response['action'] = action
|
response['action'] = action
|
||||||
response['tagid'] = tag.id
|
#response['tagid'] = tag.id
|
||||||
response['tagname'] = tag.name
|
response['tagname'] = tag.name
|
||||||
return json.dumps(response)
|
return make_json_response(response)
|
||||||
|
|
||||||
@site.route('/tags', methods=['POST'])
|
@site.route('/tags', methods=['POST'])
|
||||||
@give_session_token
|
@give_session_token
|
||||||
def post_edit_tags():
|
def post_edit_tags():
|
||||||
|
'''
|
||||||
|
Create and delete tags and synonyms.
|
||||||
|
'''
|
||||||
print(request.form)
|
print(request.form)
|
||||||
status = 200
|
status = 200
|
||||||
if 'create_tag' in request.form:
|
if 'create_tag' in request.form:
|
||||||
|
@ -618,13 +632,18 @@ def post_edit_tags():
|
||||||
action = 'delete_tag'
|
action = 'delete_tag'
|
||||||
method = delete_tag
|
method = delete_tag
|
||||||
else:
|
else:
|
||||||
|
status = 400
|
||||||
response = {'error': ERROR_INVALID_ACTION}
|
response = {'error': ERROR_INVALID_ACTION}
|
||||||
|
|
||||||
if status == 200:
|
if status == 200:
|
||||||
status = 400
|
|
||||||
tag = request.form[action].strip()
|
tag = request.form[action].strip()
|
||||||
if tag == '':
|
if tag == '':
|
||||||
response = {'error': ERROR_NO_TAG_GIVEN}
|
response = {'error': ERROR_NO_TAG_GIVEN}
|
||||||
|
status = 400
|
||||||
|
|
||||||
|
if status == 200:
|
||||||
|
# expect the worst
|
||||||
|
status = 400
|
||||||
try:
|
try:
|
||||||
response = method(tag)
|
response = method(tag)
|
||||||
except phototagger.TagTooShort:
|
except phototagger.TagTooShort:
|
||||||
|
|
|
@ -14,8 +14,8 @@ def easytagger():
|
||||||
P.export_tags(specific_tag=i)
|
P.export_tags(specific_tag=i)
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
continue
|
else:
|
||||||
P.easybake(i)
|
P.easybake(i)
|
||||||
|
|
||||||
def photag(photoid):
|
def photag(photoid):
|
||||||
photo = P.get_photo_by_id(photoid)
|
photo = P.get_photo_by_id(photoid)
|
||||||
|
|
|
@ -18,12 +18,12 @@ import warnings
|
||||||
sys.path.append('C:\\git\\else\\Bytestring'); import bytestring
|
sys.path.append('C:\\git\\else\\Bytestring'); import bytestring
|
||||||
sys.path.append('C:\\git\\else\\SpinalTap'); import spinal
|
sys.path.append('C:\\git\\else\\SpinalTap'); import spinal
|
||||||
|
|
||||||
ID_LENGTH = 12
|
|
||||||
VALID_TAG_CHARS = string.ascii_lowercase + string.digits + '_'
|
VALID_TAG_CHARS = string.ascii_lowercase + string.digits + '_'
|
||||||
MIN_TAG_NAME_LENGTH = 1
|
MIN_TAG_NAME_LENGTH = 1
|
||||||
MAX_TAG_NAME_LENGTH = 32
|
MAX_TAG_NAME_LENGTH = 32
|
||||||
|
DEFAULT_ID_LENGTH = 12
|
||||||
DEFAULT_DBNAME = 'phototagger.db'
|
DEFAULT_DBNAME = 'phototagger.db'
|
||||||
DEFAULT_THUMBDIR = '_site_thumbnails'
|
DEFAULT_THUMBDIR = '_etiquette\\site_thumbnails'
|
||||||
THUMBNAIL_WIDTH = 400
|
THUMBNAIL_WIDTH = 400
|
||||||
THUMBNAIL_HEIGHT = 400
|
THUMBNAIL_HEIGHT = 400
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ try:
|
||||||
ffprobe_path='C:\\software\\ffmpeg\\bin\\ffprobe.exe',
|
ffprobe_path='C:\\software\\ffmpeg\\bin\\ffprobe.exe',
|
||||||
)
|
)
|
||||||
except converter.ffmpeg.FFMpegError:
|
except converter.ffmpeg.FFMpegError:
|
||||||
|
traceback.print_exc()
|
||||||
ffmpeg = None
|
ffmpeg = None
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
@ -161,6 +162,7 @@ CREATE INDEX IF NOT EXISTS index_albumrel_photoid on album_photo_rel(photoid);
|
||||||
CREATE INDEX IF NOT EXISTS index_photo_id on photos(id);
|
CREATE INDEX IF NOT EXISTS index_photo_id on photos(id);
|
||||||
CREATE INDEX IF NOT EXISTS index_photo_path on photos(filepath);
|
CREATE INDEX IF NOT EXISTS index_photo_path on photos(filepath);
|
||||||
CREATE INDEX IF NOT EXISTS index_photo_created on photos(created);
|
CREATE INDEX IF NOT EXISTS index_photo_created on photos(created);
|
||||||
|
CREATE INDEX IF NOT EXISTS index_photo_extension on photos(extension);
|
||||||
|
|
||||||
-- Tag
|
-- Tag
|
||||||
CREATE INDEX IF NOT EXISTS index_tag_id on tags(id);
|
CREATE INDEX IF NOT EXISTS index_tag_id on tags(id);
|
||||||
|
@ -378,19 +380,18 @@ def hyphen_range(s):
|
||||||
raise OutOfOrder(s, low, high)
|
raise OutOfOrder(s, low, high)
|
||||||
return low, high
|
return low, high
|
||||||
|
|
||||||
def fit_into_bounds(iw, ih, fw, fh):
|
def fit_into_bounds(image_width, image_height, frame_width, frame_height):
|
||||||
'''
|
'''
|
||||||
Given the w+h of the image and the w+h of the frame,
|
Given the w+h of the image and the w+h of the frame,
|
||||||
return new w+h that fits the image into the frame
|
return new w+h that fits the image into the frame
|
||||||
while maintaining the aspect ratio and leaving blank space
|
while maintaining the aspect ratio.
|
||||||
everywhere else
|
|
||||||
'''
|
'''
|
||||||
ratio = min(fw/iw, fh/ih)
|
ratio = min(frame_width/image_width, frame_height/image_height)
|
||||||
|
|
||||||
w = int(iw * ratio)
|
new_width = int(image_width * ratio)
|
||||||
h = int(ih * ratio)
|
new_height = int(image_height * ratio)
|
||||||
|
|
||||||
return (w, h)
|
return (new_width, new_height)
|
||||||
|
|
||||||
def get_mimetype(filepath):
|
def get_mimetype(filepath):
|
||||||
extension = os.path.splitext(filepath)[1].replace('.', '')
|
extension = os.path.splitext(filepath)[1].replace('.', '')
|
||||||
|
@ -420,6 +421,8 @@ def normalize_filepath(filepath):
|
||||||
'''
|
'''
|
||||||
Remove some bad characters.
|
Remove some bad characters.
|
||||||
'''
|
'''
|
||||||
|
filepath = filepath.replace('/', os.sep)
|
||||||
|
filepath = filepath.replace('\\', os.sep)
|
||||||
filepath = filepath.replace('<', '')
|
filepath = filepath.replace('<', '')
|
||||||
filepath = filepath.replace('>', '')
|
filepath = filepath.replace('>', '')
|
||||||
return filepath
|
return filepath
|
||||||
|
@ -713,7 +716,7 @@ class PDBAlbumMixin:
|
||||||
album.add_photo(photo, commit=False)
|
album.add_photo(photo, commit=False)
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
self.sql.commit()
|
self.commit()
|
||||||
return album
|
return album
|
||||||
|
|
||||||
|
|
||||||
|
@ -1096,7 +1099,7 @@ class PDBTagMixin:
|
||||||
self.cur.execute('INSERT INTO tags VALUES(?, ?)', [tagid, tagname])
|
self.cur.execute('INSERT INTO tags VALUES(?, ?)', [tagid, tagname])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Commiting - new_tag')
|
log.debug('Commiting - new_tag')
|
||||||
self.sql.commit()
|
self.commit()
|
||||||
tag = Tag(self, [tagid, tagname])
|
tag = Tag(self, [tagid, tagname])
|
||||||
return tag
|
return tag
|
||||||
|
|
||||||
|
@ -1139,8 +1142,9 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin):
|
||||||
'''
|
'''
|
||||||
def __init__(self, databasename=DEFAULT_DBNAME, thumbnail_folder=DEFAULT_THUMBDIR, id_length=None):
|
def __init__(self, databasename=DEFAULT_DBNAME, thumbnail_folder=DEFAULT_THUMBDIR, id_length=None):
|
||||||
if id_length is None:
|
if id_length is None:
|
||||||
self.id_length = ID_LENGTH
|
self.id_length = DEFAULT_ID_LENGTH
|
||||||
self.databasename = databasename
|
self.databasename = databasename
|
||||||
|
self.database_abspath = os.path.abspath(databasename)
|
||||||
self.thumbnail_folder = os.path.abspath(thumbnail_folder)
|
self.thumbnail_folder = os.path.abspath(thumbnail_folder)
|
||||||
os.makedirs(thumbnail_folder, exist_ok=True)
|
os.makedirs(thumbnail_folder, exist_ok=True)
|
||||||
self.sql = sqlite3.connect(databasename)
|
self.sql = sqlite3.connect(databasename)
|
||||||
|
@ -1149,6 +1153,7 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin):
|
||||||
for statement in statements:
|
for statement in statements:
|
||||||
self.cur.execute(statement)
|
self.cur.execute(statement)
|
||||||
|
|
||||||
|
self.on_commit_queue = []
|
||||||
self._cached_frozen_children = None
|
self._cached_frozen_children = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -1157,6 +1162,15 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin):
|
||||||
def _uncache(self):
|
def _uncache(self):
|
||||||
self._cached_frozen_children = None
|
self._cached_frozen_children = None
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
while self.on_commit_queue:
|
||||||
|
task = self.on_commit_queue.pop()
|
||||||
|
print(task)
|
||||||
|
args = task.get('args', [])
|
||||||
|
kwargs = task.get('kwargs', {})
|
||||||
|
task['action'](*args, **kwargs)
|
||||||
|
self.sql.commit()
|
||||||
|
|
||||||
def digest_directory(self, directory, exclude_directories=None, exclude_filenames=None, commit=True):
|
def digest_directory(self, directory, exclude_directories=None, exclude_filenames=None, commit=True):
|
||||||
'''
|
'''
|
||||||
Create an album, and add the directory's contents to it.
|
Create an album, and add the directory's contents to it.
|
||||||
|
@ -1201,7 +1215,7 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin):
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Commiting - digest')
|
log.debug('Commiting - digest')
|
||||||
self.sql.commit()
|
self.commit()
|
||||||
return album
|
return album
|
||||||
|
|
||||||
def digest_new_files(
|
def digest_new_files(
|
||||||
|
@ -1209,7 +1223,7 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin):
|
||||||
directory,
|
directory,
|
||||||
exclude_directories=None,
|
exclude_directories=None,
|
||||||
exclude_filenames=None,
|
exclude_filenames=None,
|
||||||
recurse=True,
|
recurse=False,
|
||||||
commit=True
|
commit=True
|
||||||
):
|
):
|
||||||
'''
|
'''
|
||||||
|
@ -1248,7 +1262,7 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin):
|
||||||
photo = self.new_photo(filepath, commit=False)
|
photo = self.new_photo(filepath, commit=False)
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - digest_new_files')
|
log.debug('Committing - digest_new_files')
|
||||||
self.sql.commit()
|
self.commit()
|
||||||
|
|
||||||
|
|
||||||
def easybake(self, string):
|
def easybake(self, string):
|
||||||
|
@ -1309,7 +1323,7 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin):
|
||||||
tags = [create_or_get(t) for t in tag_parts]
|
tags = [create_or_get(t) for t in tag_parts]
|
||||||
for (higher, lower) in zip(tags, tags[1:]):
|
for (higher, lower) in zip(tags, tags[1:]):
|
||||||
try:
|
try:
|
||||||
lower.join(higher)
|
lower.join_group(higher)
|
||||||
note = ('join_group', '%s.%s' % (higher.name, lower.name))
|
note = ('join_group', '%s.%s' % (higher.name, lower.name))
|
||||||
output_notes.append(note)
|
output_notes.append(note)
|
||||||
except GroupExists:
|
except GroupExists:
|
||||||
|
@ -1447,7 +1461,7 @@ class GroupableMixin:
|
||||||
self.photodb.cur.execute('INSERT INTO tag_group_rel VALUES(?, ?)', [self.id, member.id])
|
self.photodb.cur.execute('INSERT INTO tag_group_rel VALUES(?, ?)', [self.id, member.id])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Commiting - add to group')
|
log.debug('Commiting - add to group')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def children(self):
|
def children(self):
|
||||||
self.photodb.cur.execute('SELECT * FROM tag_group_rel WHERE parentid == ?', [self.id])
|
self.photodb.cur.execute('SELECT * FROM tag_group_rel WHERE parentid == ?', [self.id])
|
||||||
|
@ -1491,7 +1505,7 @@ class GroupableMixin:
|
||||||
self.photodb.cur.execute('DELETE FROM tag_group_rel WHERE memberid == ?', [self.id])
|
self.photodb.cur.execute('DELETE FROM tag_group_rel WHERE memberid == ?', [self.id])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - delete tag')
|
log.debug('Committing - delete tag')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def parent(self):
|
def parent(self):
|
||||||
'''
|
'''
|
||||||
|
@ -1505,7 +1519,7 @@ class GroupableMixin:
|
||||||
parentid = fetch[SQL_TAGGROUP['parentid']]
|
parentid = fetch[SQL_TAGGROUP['parentid']]
|
||||||
return self.group_getter(id=parentid)
|
return self.group_getter(id=parentid)
|
||||||
|
|
||||||
def join(self, group, commit=True):
|
def join_group(self, group, commit=True):
|
||||||
'''
|
'''
|
||||||
Leave the current group, then call `group.add(self)`.
|
Leave the current group, then call `group.add(self)`.
|
||||||
'''
|
'''
|
||||||
|
@ -1528,7 +1542,7 @@ class GroupableMixin:
|
||||||
self.photodb.cur.execute('DELETE FROM tag_group_rel WHERE memberid == ?', [self.id])
|
self.photodb.cur.execute('DELETE FROM tag_group_rel WHERE memberid == ?', [self.id])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - leave group')
|
log.debug('Committing - leave group')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def walk_children(self):
|
def walk_children(self):
|
||||||
yield self
|
yield self
|
||||||
|
@ -1559,7 +1573,7 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
self.photodb.cur.execute('INSERT INTO album_photo_rel VALUES(?, ?)', [self.id, photo.id])
|
self.photodb.cur.execute('INSERT INTO album_photo_rel VALUES(?, ?)', [self.id, photo.id])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - add photo to album')
|
log.debug('Committing - add photo to album')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def add_tag_to_all(self, tag, nested_children=True):
|
def add_tag_to_all(self, tag, nested_children=True):
|
||||||
tag = self.photodb.get_tag(tag)
|
tag = self.photodb.get_tag(tag)
|
||||||
|
@ -1577,7 +1591,7 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
self.photodb.cur.execute('DELETE FROM album_photo_rel WHERE albumid == ?', [self.id])
|
self.photodb.cur.execute('DELETE FROM album_photo_rel WHERE albumid == ?', [self.id])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - delete album')
|
log.debug('Committing - delete album')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def edit(self, title=None, description=None, commit=True):
|
def edit(self, title=None, description=None, commit=True):
|
||||||
if title is None:
|
if title is None:
|
||||||
|
@ -1592,7 +1606,7 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
self.description = description
|
self.description = description
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - edit album')
|
log.debug('Committing - edit album')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def has_photo(self, photo):
|
def has_photo(self, photo):
|
||||||
if not isinstance(photo, Photo):
|
if not isinstance(photo, Photo):
|
||||||
|
@ -1620,10 +1634,12 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
return
|
return
|
||||||
self.photodb.cur.execute(
|
self.photodb.cur.execute(
|
||||||
'DELETE FROM album_photo_rel WHERE albumid == ? AND photoid == ?',
|
'DELETE FROM album_photo_rel WHERE albumid == ? AND photoid == ?',
|
||||||
[self.id, photo.id])
|
[self.id, photo.id]
|
||||||
|
)
|
||||||
|
if commit:
|
||||||
|
self.photodb.commit()
|
||||||
|
|
||||||
def walk_photos(self):
|
def walk_photos(self):
|
||||||
print('hi')
|
|
||||||
yield from self.photos()
|
yield from self.photos()
|
||||||
children = self.walk_children()
|
children = self.walk_children()
|
||||||
# The first yield is itself
|
# The first yield is itself
|
||||||
|
@ -1642,9 +1658,9 @@ class Photo(ObjectBase):
|
||||||
self.photodb = photodb
|
self.photodb = photodb
|
||||||
self.id = row_tuple[SQL_PHOTO['id']]
|
self.id = row_tuple[SQL_PHOTO['id']]
|
||||||
self.real_filepath = row_tuple[SQL_PHOTO['filepath']]
|
self.real_filepath = row_tuple[SQL_PHOTO['filepath']]
|
||||||
self.real_filepath = self.real_filepath.replace('/', os.sep)
|
self.real_filepath = normalize_filepath(self.real_filepath)
|
||||||
self.real_filepath = self.real_filepath.replace('\\', os.sep)
|
self.filepath = self.real_filepath
|
||||||
self.filepath = normalize_filepath(self.real_filepath)
|
self.basename = os.path.basename(self.real_filepath)
|
||||||
self.extension = row_tuple[SQL_PHOTO['extension']]
|
self.extension = row_tuple[SQL_PHOTO['extension']]
|
||||||
self.width = row_tuple[SQL_PHOTO['width']]
|
self.width = row_tuple[SQL_PHOTO['width']]
|
||||||
self.height = row_tuple[SQL_PHOTO['height']]
|
self.height = row_tuple[SQL_PHOTO['height']]
|
||||||
|
@ -1654,7 +1670,6 @@ class Photo(ObjectBase):
|
||||||
self.duration = row_tuple[SQL_PHOTO['duration']]
|
self.duration = row_tuple[SQL_PHOTO['duration']]
|
||||||
self.created = row_tuple[SQL_PHOTO['created']]
|
self.created = row_tuple[SQL_PHOTO['created']]
|
||||||
self.thumbnail = row_tuple[SQL_PHOTO['thumbnail']]
|
self.thumbnail = row_tuple[SQL_PHOTO['thumbnail']]
|
||||||
self.basename = self.real_filepath.split(os.sep)[-1]
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Photo:{id}'.format(id=self.id)
|
return 'Photo:{id}'.format(id=self.id)
|
||||||
|
@ -1683,7 +1698,7 @@ class Photo(ObjectBase):
|
||||||
self.photodb.cur.execute('INSERT INTO photo_tag_rel VALUES(?, ?)', [self.id, tag.id])
|
self.photodb.cur.execute('INSERT INTO photo_tag_rel VALUES(?, ?)', [self.id, tag.id])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - add photo tag')
|
log.debug('Committing - add photo tag')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def albums(self):
|
def albums(self):
|
||||||
'''
|
'''
|
||||||
|
@ -1711,7 +1726,7 @@ class Photo(ObjectBase):
|
||||||
self.photodb.cur.execute('DELETE FROM album_photo_rel WHERE photoid == ?', [self.id])
|
self.photodb.cur.execute('DELETE FROM album_photo_rel WHERE photoid == ?', [self.id])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - delete photo')
|
log.debug('Committing - delete photo')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
@time_me
|
@time_me
|
||||||
def generate_thumbnail(self, commit=True, **special):
|
def generate_thumbnail(self, commit=True, **special):
|
||||||
|
@ -1739,7 +1754,12 @@ class Photo(ObjectBase):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
(width, height) = image.size
|
(width, height) = image.size
|
||||||
(new_width, new_height) = fit_into_bounds(width, height, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT)
|
(new_width, new_height) = fit_into_bounds(
|
||||||
|
image_width=width,
|
||||||
|
image_height=height,
|
||||||
|
frame_width=THUMBNAIL_WIDTH,
|
||||||
|
frame_height=THUMBNAIL_HEIGHT,
|
||||||
|
)
|
||||||
if new_width < width:
|
if new_width < width:
|
||||||
image = image.resize((new_width, new_height))
|
image = image.resize((new_width, new_height))
|
||||||
image.save(hopeful_filepath, quality=50)
|
image.save(hopeful_filepath, quality=50)
|
||||||
|
@ -1751,10 +1771,10 @@ class Photo(ObjectBase):
|
||||||
try:
|
try:
|
||||||
if probe.video:
|
if probe.video:
|
||||||
size = fit_into_bounds(
|
size = fit_into_bounds(
|
||||||
iw=probe.video.video_width,
|
image_width=probe.video.video_width,
|
||||||
ih=probe.video.video_height,
|
image_height=probe.video.video_height,
|
||||||
fw=THUMBNAIL_WIDTH,
|
frame_width=THUMBNAIL_WIDTH,
|
||||||
fh=THUMBNAIL_HEIGHT,
|
frame_height=THUMBNAIL_HEIGHT,
|
||||||
)
|
)
|
||||||
size = '%dx%d' % size
|
size = '%dx%d' % size
|
||||||
duration = probe.video.duration
|
duration = probe.video.duration
|
||||||
|
@ -1778,7 +1798,7 @@ class Photo(ObjectBase):
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - generate thumbnail')
|
log.debug('Committing - generate thumbnail')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
return self.thumbnail
|
return self.thumbnail
|
||||||
|
|
||||||
|
@ -1811,6 +1831,9 @@ class Photo(ObjectBase):
|
||||||
|
|
||||||
@time_me
|
@time_me
|
||||||
def reload_metadata(self, commit=True):
|
def reload_metadata(self, commit=True):
|
||||||
|
'''
|
||||||
|
Load the file's height, width, etc as appropriate for this type of file.
|
||||||
|
'''
|
||||||
self.bytes = os.path.getsize(self.real_filepath)
|
self.bytes = os.path.getsize(self.real_filepath)
|
||||||
self.width = None
|
self.width = None
|
||||||
self.height = None
|
self.height = None
|
||||||
|
@ -1833,7 +1856,7 @@ class Photo(ObjectBase):
|
||||||
try:
|
try:
|
||||||
probe = ffmpeg.probe(self.real_filepath)
|
probe = ffmpeg.probe(self.real_filepath)
|
||||||
if probe and probe.video:
|
if probe and probe.video:
|
||||||
self.duration = probe.video.duration
|
self.duration = probe.format.duration or probe.video.duration
|
||||||
self.width = probe.video.video_width
|
self.width = probe.video.video_width
|
||||||
self.height = probe.video.video_height
|
self.height = probe.video.video_height
|
||||||
except:
|
except:
|
||||||
|
@ -1851,12 +1874,13 @@ class Photo(ObjectBase):
|
||||||
self.area = self.width * self.height
|
self.area = self.width * self.height
|
||||||
self.ratio = round(self.width / self.height, 2)
|
self.ratio = round(self.width / self.height, 2)
|
||||||
|
|
||||||
self.photodb.cur.execute('UPDATE photos SET width=?, height=?, area=?, ratio=?, duration=?, bytes=? WHERE id==?',
|
self.photodb.cur.execute(
|
||||||
|
'UPDATE photos SET width=?, height=?, area=?, ratio=?, duration=?, bytes=? WHERE id==?',
|
||||||
[self.width, self.height, self.area, self.ratio, self.duration, self.bytes, self.id],
|
[self.width, self.height, self.area, self.ratio, self.duration, self.bytes, self.id],
|
||||||
)
|
)
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - reload metadata')
|
log.debug('Committing - reload metadata')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def remove_tag(self, tag, commit=True):
|
def remove_tag(self, tag, commit=True):
|
||||||
tag = self.photodb.get_tag(tag)
|
tag = self.photodb.get_tag(tag)
|
||||||
|
@ -1870,7 +1894,39 @@ class Photo(ObjectBase):
|
||||||
)
|
)
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - remove photo tag')
|
log.debug('Committing - remove photo tag')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
|
def rename_file(self, new_filename, move=False, commit=True):
|
||||||
|
'''
|
||||||
|
Rename the file on the disk as well as in the database.
|
||||||
|
If `move` is True, allow this operation to move the file.
|
||||||
|
Otherwise, slashes will be considered an error.
|
||||||
|
'''
|
||||||
|
current_dir = os.path.normcase(os.path.dirname(self.real_filepath))
|
||||||
|
new_filename = normalize_filepath(new_filename)
|
||||||
|
new_dir = os.path.normcase(os.path.dirname(new_filename))
|
||||||
|
if new_dir == '':
|
||||||
|
new_dir = current_dir
|
||||||
|
new_abspath = os.path.join(new_dir, new_filename)
|
||||||
|
else:
|
||||||
|
new_abspath = os.path.abspath(new_filename)
|
||||||
|
new_dir = os.path.normcase(os.path.dirname(new_abspath))
|
||||||
|
if (new_dir != current_dir) and not move:
|
||||||
|
raise ValueError('Cannot move the file without param move=True')
|
||||||
|
new_basename = os.path.basename(new_abspath)
|
||||||
|
os.link(self.real_filepath, new_abspath)
|
||||||
|
self.photodb.cur.execute(
|
||||||
|
'UPDATE photos SET filepath = ? WHERE filepath == ?',
|
||||||
|
[new_abspath, self.real_filepath]
|
||||||
|
)
|
||||||
|
if commit:
|
||||||
|
os.remove(self.real_filepath)
|
||||||
|
self.photodb.commit()
|
||||||
|
else:
|
||||||
|
queue_action = {'action': os.remove, 'args': [self.real_filepath]}
|
||||||
|
self.photodb.on_commit_queue.append(queue_action)
|
||||||
|
self.real_filepath = new_abspath
|
||||||
|
self.basename = os.path.basename(new_abspath)
|
||||||
|
|
||||||
def tags(self):
|
def tags(self):
|
||||||
'''
|
'''
|
||||||
|
@ -1912,12 +1968,12 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
return hash(self.name)
|
return hash(self.name)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
r = 'Tag:{id}:{name}'.format(name=self.name, id=self.id)
|
rep = 'Tag:{id}:{name}'.format(name=self.name, id=self.id)
|
||||||
return r
|
return rep
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
r = 'Tag:{name}'.format(name=self.name)
|
rep = 'Tag:{name}'.format(name=self.name)
|
||||||
return r
|
return rep
|
||||||
|
|
||||||
def add_synonym(self, synname, commit=True):
|
def add_synonym(self, synname, commit=True):
|
||||||
synname = normalize_tagname(synname)
|
synname = normalize_tagname(synname)
|
||||||
|
@ -1937,7 +1993,7 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - add synonym')
|
log.debug('Committing - add synonym')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def convert_to_synonym(self, mastertag, commit=True):
|
def convert_to_synonym(self, mastertag, commit=True):
|
||||||
'''
|
'''
|
||||||
|
@ -1974,7 +2030,7 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
mastertag.add_synonym(self.name, commit=False)
|
mastertag.add_synonym(self.name, commit=False)
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - convert to synonym')
|
log.debug('Committing - convert to synonym')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def delete(self, delete_children=False, commit=True):
|
def delete(self, delete_children=False, commit=True):
|
||||||
log.debug('Deleting tag {tag:r}'.format(tag=self))
|
log.debug('Deleting tag {tag:r}'.format(tag=self))
|
||||||
|
@ -1985,7 +2041,7 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
self.photodb.cur.execute('DELETE FROM tag_synonyms WHERE mastername == ?', [self.name])
|
self.photodb.cur.execute('DELETE FROM tag_synonyms WHERE mastername == ?', [self.name])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - delete tag')
|
log.debug('Committing - delete tag')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def qualified_name(self):
|
def qualified_name(self):
|
||||||
'''
|
'''
|
||||||
|
@ -2015,7 +2071,7 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
self.photodb.cur.execute('DELETE FROM tag_synonyms WHERE name == ?', [synname])
|
self.photodb.cur.execute('DELETE FROM tag_synonyms WHERE name == ?', [synname])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - remove synonym')
|
log.debug('Committing - remove synonym')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def rename(self, new_name, apply_to_synonyms=True, commit=True):
|
def rename(self, new_name, apply_to_synonyms=True, commit=True):
|
||||||
'''
|
'''
|
||||||
|
@ -2026,7 +2082,7 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
existing = self.photodb.get_tag(new_name)
|
self.photodb.get_tag(new_name)
|
||||||
except NoSuchTag:
|
except NoSuchTag:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
@ -2044,7 +2100,7 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
self.name = new_name
|
self.name = new_name
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - rename tag')
|
log.debug('Committing - rename tag')
|
||||||
self.photodb.sql.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def synonyms(self):
|
def synonyms(self):
|
||||||
self.photodb.cur.execute('SELECT name FROM tag_synonyms WHERE mastername == ?', [self.name])
|
self.photodb.cur.execute('SELECT name FROM tag_synonyms WHERE mastername == ?', [self.name])
|
||||||
|
|
Loading…
Reference in a new issue