| @@ 214-331 (lines=118) @@ | ||
| 211 | return True |
|
| 212 | ||
| 213 | ||
| 214 | @click.command('update') |
|
| 215 | @click.option('--album', help='Update the image album.') |
|
| 216 | @click.option('--location', help=('Update the image location. Location ' |
|
| 217 | 'should be the name of a place, like "Las ' |
|
| 218 | 'Vegas, NV".')) |
|
| 219 | @click.option('--time', help=('Update the image time. Time should be in ' |
|
| 220 | 'YYYY-mm-dd hh:ii:ss or YYYY-mm-dd format.')) |
|
| 221 | @click.option('--title', help='Update the image title.') |
|
| 222 | @click.option('--debug', default=False, is_flag=True, |
|
| 223 | help='Override the value in constants.py with True.') |
|
| 224 | @click.argument('paths', nargs=-1, |
|
| 225 | required=True) |
|
| 226 | def _update(album, location, time, title, paths, debug): |
|
| 227 | """Update a file's EXIF. Automatically modifies the file's location and file name accordingly. |
|
| 228 | """ |
|
| 229 | constants.debug = debug |
|
| 230 | has_errors = False |
|
| 231 | result = Result() |
|
| 232 | ||
| 233 | files = set() |
|
| 234 | for path in paths: |
|
| 235 | path = os.path.expanduser(path) |
|
| 236 | if os.path.isdir(path): |
|
| 237 | files.update(FILESYSTEM.get_all_files(path, None)) |
|
| 238 | else: |
|
| 239 | files.add(path) |
|
| 240 | ||
| 241 | for current_file in files: |
|
| 242 | if not os.path.exists(current_file): |
|
| 243 | has_errors = True |
|
| 244 | result.append((current_file, False)) |
|
| 245 | log.warn('Could not find %s' % current_file) |
|
| 246 | log.all('{"source":"%s", "error_msg":"Could not find %s"}' % |
|
| 247 | (current_file, current_file)) |
|
| 248 | continue |
|
| 249 | ||
| 250 | current_file = os.path.expanduser(current_file) |
|
| 251 | ||
| 252 | # The destination folder structure could contain any number of levels |
|
| 253 | # So we calculate that and traverse up the tree. |
|
| 254 | # '/path/to/file/photo.jpg' -> '/path/to/file' -> |
|
| 255 | # ['path','to','file'] -> ['path','to'] -> '/path/to' |
|
| 256 | current_directory = os.path.dirname(current_file) |
|
| 257 | destination_depth = -1 * len(FILESYSTEM.get_folder_path_definition()) |
|
| 258 | destination = os.sep.join( |
|
| 259 | os.path.normpath( |
|
| 260 | current_directory |
|
| 261 | ).split(os.sep)[:destination_depth] |
|
| 262 | ) |
|
| 263 | ||
| 264 | media = Media.get_class_by_file(current_file, get_all_subclasses()) |
|
| 265 | if not media: |
|
| 266 | continue |
|
| 267 | ||
| 268 | updated = False |
|
| 269 | if location: |
|
| 270 | update_location(media, current_file, location) |
|
| 271 | updated = True |
|
| 272 | if time: |
|
| 273 | update_time(media, current_file, time) |
|
| 274 | updated = True |
|
| 275 | if album: |
|
| 276 | media.set_album(album) |
|
| 277 | updated = True |
|
| 278 | ||
| 279 | # Updating a title can be problematic when doing it 2+ times on a file. |
|
| 280 | # You would end up with img_001.jpg -> img_001-first-title.jpg -> |
|
| 281 | # img_001-first-title-second-title.jpg. |
|
| 282 | # To resolve that we have to track the prior title (if there was one. |
|
| 283 | # Then we massage the updated_media's metadata['base_name'] to remove |
|
| 284 | # the old title. |
|
| 285 | # Since FileSystem.get_file_name() relies on base_name it will properly |
|
| 286 | # rename the file by updating the title instead of appending it. |
|
| 287 | remove_old_title_from_name = False |
|
| 288 | if title: |
|
| 289 | # We call get_metadata() to cache it before making any changes |
|
| 290 | metadata = media.get_metadata() |
|
| 291 | title_update_status = media.set_title(title) |
|
| 292 | original_title = metadata['title'] |
|
| 293 | if title_update_status and original_title: |
|
| 294 | # @TODO: We should move this to a shared method since |
|
| 295 | # FileSystem.get_file_name() does it too. |
|
| 296 | original_title = re.sub(r'\W+', '-', original_title.lower()) |
|
| 297 | original_base_name = metadata['base_name'] |
|
| 298 | remove_old_title_from_name = True |
|
| 299 | updated = True |
|
| 300 | ||
| 301 | if updated: |
|
| 302 | updated_media = Media.get_class_by_file(current_file, |
|
| 303 | get_all_subclasses()) |
|
| 304 | # See comments above on why we have to do this when titles |
|
| 305 | # get updated. |
|
| 306 | if remove_old_title_from_name and len(original_title) > 0: |
|
| 307 | updated_media.get_metadata() |
|
| 308 | updated_media.set_metadata_basename( |
|
| 309 | original_base_name.replace('-%s' % original_title, '')) |
|
| 310 | ||
| 311 | dest_path = FILESYSTEM.process_file(current_file, destination, |
|
| 312 | updated_media, move=True, allowDuplicate=True) |
|
| 313 | log.info(u'%s -> %s' % (current_file, dest_path)) |
|
| 314 | log.all('{"source":"%s", "destination":"%s"}' % (current_file, |
|
| 315 | dest_path)) |
|
| 316 | # If the folder we moved the file out of or its parent are empty |
|
| 317 | # we delete it. |
|
| 318 | FILESYSTEM.delete_directory_if_empty(os.path.dirname(current_file)) |
|
| 319 | FILESYSTEM.delete_directory_if_empty( |
|
| 320 | os.path.dirname(os.path.dirname(current_file))) |
|
| 321 | result.append((current_file, dest_path)) |
|
| 322 | # Trip has_errors to False if it's already False or dest_path is. |
|
| 323 | has_errors = has_errors is True or not dest_path |
|
| 324 | else: |
|
| 325 | has_errors = False |
|
| 326 | result.append((current_file, False)) |
|
| 327 | ||
| 328 | result.write() |
|
| 329 | ||
| 330 | if has_errors: |
|
| 331 | sys.exit(1) |
|
| 332 | ||
| 333 | ||
| 334 | @click.group() |
|
| @@ 214-331 (lines=118) @@ | ||
| 211 | return True |
|
| 212 | ||
| 213 | ||
| 214 | @click.command('update') |
|
| 215 | @click.option('--album', help='Update the image album.') |
|
| 216 | @click.option('--location', help=('Update the image location. Location ' |
|
| 217 | 'should be the name of a place, like "Las ' |
|
| 218 | 'Vegas, NV".')) |
|
| 219 | @click.option('--time', help=('Update the image time. Time should be in ' |
|
| 220 | 'YYYY-mm-dd hh:ii:ss or YYYY-mm-dd format.')) |
|
| 221 | @click.option('--title', help='Update the image title.') |
|
| 222 | @click.option('--debug', default=False, is_flag=True, |
|
| 223 | help='Override the value in constants.py with True.') |
|
| 224 | @click.argument('paths', nargs=-1, |
|
| 225 | required=True) |
|
| 226 | def _update(album, location, time, title, paths, debug): |
|
| 227 | """Update a file's EXIF. Automatically modifies the file's location and file name accordingly. |
|
| 228 | """ |
|
| 229 | constants.debug = debug |
|
| 230 | has_errors = False |
|
| 231 | result = Result() |
|
| 232 | ||
| 233 | files = set() |
|
| 234 | for path in paths: |
|
| 235 | path = os.path.expanduser(path) |
|
| 236 | if os.path.isdir(path): |
|
| 237 | files.update(FILESYSTEM.get_all_files(path, None)) |
|
| 238 | else: |
|
| 239 | files.add(path) |
|
| 240 | ||
| 241 | for current_file in files: |
|
| 242 | if not os.path.exists(current_file): |
|
| 243 | has_errors = True |
|
| 244 | result.append((current_file, False)) |
|
| 245 | log.warn('Could not find %s' % current_file) |
|
| 246 | log.all('{"source":"%s", "error_msg":"Could not find %s"}' % |
|
| 247 | (current_file, current_file)) |
|
| 248 | continue |
|
| 249 | ||
| 250 | current_file = os.path.expanduser(current_file) |
|
| 251 | ||
| 252 | # The destination folder structure could contain any number of levels |
|
| 253 | # So we calculate that and traverse up the tree. |
|
| 254 | # '/path/to/file/photo.jpg' -> '/path/to/file' -> |
|
| 255 | # ['path','to','file'] -> ['path','to'] -> '/path/to' |
|
| 256 | current_directory = os.path.dirname(current_file) |
|
| 257 | destination_depth = -1 * len(FILESYSTEM.get_folder_path_definition()) |
|
| 258 | destination = os.sep.join( |
|
| 259 | os.path.normpath( |
|
| 260 | current_directory |
|
| 261 | ).split(os.sep)[:destination_depth] |
|
| 262 | ) |
|
| 263 | ||
| 264 | media = Media.get_class_by_file(current_file, get_all_subclasses()) |
|
| 265 | if not media: |
|
| 266 | continue |
|
| 267 | ||
| 268 | updated = False |
|
| 269 | if location: |
|
| 270 | update_location(media, current_file, location) |
|
| 271 | updated = True |
|
| 272 | if time: |
|
| 273 | update_time(media, current_file, time) |
|
| 274 | updated = True |
|
| 275 | if album: |
|
| 276 | media.set_album(album) |
|
| 277 | updated = True |
|
| 278 | ||
| 279 | # Updating a title can be problematic when doing it 2+ times on a file. |
|
| 280 | # You would end up with img_001.jpg -> img_001-first-title.jpg -> |
|
| 281 | # img_001-first-title-second-title.jpg. |
|
| 282 | # To resolve that we have to track the prior title (if there was one. |
|
| 283 | # Then we massage the updated_media's metadata['base_name'] to remove |
|
| 284 | # the old title. |
|
| 285 | # Since FileSystem.get_file_name() relies on base_name it will properly |
|
| 286 | # rename the file by updating the title instead of appending it. |
|
| 287 | remove_old_title_from_name = False |
|
| 288 | if title: |
|
| 289 | # We call get_metadata() to cache it before making any changes |
|
| 290 | metadata = media.get_metadata() |
|
| 291 | title_update_status = media.set_title(title) |
|
| 292 | original_title = metadata['title'] |
|
| 293 | if title_update_status and original_title: |
|
| 294 | # @TODO: We should move this to a shared method since |
|
| 295 | # FileSystem.get_file_name() does it too. |
|
| 296 | original_title = re.sub(r'\W+', '-', original_title.lower()) |
|
| 297 | original_base_name = metadata['base_name'] |
|
| 298 | remove_old_title_from_name = True |
|
| 299 | updated = True |
|
| 300 | ||
| 301 | if updated: |
|
| 302 | updated_media = Media.get_class_by_file(current_file, |
|
| 303 | get_all_subclasses()) |
|
| 304 | # See comments above on why we have to do this when titles |
|
| 305 | # get updated. |
|
| 306 | if remove_old_title_from_name and len(original_title) > 0: |
|
| 307 | updated_media.get_metadata() |
|
| 308 | updated_media.set_metadata_basename( |
|
| 309 | original_base_name.replace('-%s' % original_title, '')) |
|
| 310 | ||
| 311 | dest_path = FILESYSTEM.process_file(current_file, destination, |
|
| 312 | updated_media, move=True, allowDuplicate=True) |
|
| 313 | log.info(u'%s -> %s' % (current_file, dest_path)) |
|
| 314 | log.all('{"source":"%s", "destination":"%s"}' % (current_file, |
|
| 315 | dest_path)) |
|
| 316 | # If the folder we moved the file out of or its parent are empty |
|
| 317 | # we delete it. |
|
| 318 | FILESYSTEM.delete_directory_if_empty(os.path.dirname(current_file)) |
|
| 319 | FILESYSTEM.delete_directory_if_empty( |
|
| 320 | os.path.dirname(os.path.dirname(current_file))) |
|
| 321 | result.append((current_file, dest_path)) |
|
| 322 | # Trip has_errors to False if it's already False or dest_path is. |
|
| 323 | has_errors = has_errors is True or not dest_path |
|
| 324 | else: |
|
| 325 | has_errors = False |
|
| 326 | result.append((current_file, False)) |
|
| 327 | ||
| 328 | result.write() |
|
| 329 | ||
| 330 | if has_errors: |
|
| 331 | sys.exit(1) |
|
| 332 | ||
| 333 | ||
| 334 | @click.group() |
|