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