checkpoint

This commit is contained in:
voussoir 2016-10-17 22:13:12 -07:00
parent 0b85c309f8
commit de60770d20
3 changed files with 182 additions and 107 deletions

View file

@ -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:

View file

@ -14,7 +14,7 @@ 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):

View file

@ -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])