44import logging
55import threading
66from picframe import get_image_meta
7+ from picframe .video_streamer import VIDEO_EXTENSIONS , get_video_info
78
89
910class ImageCache :
1011
1112 EXTENSIONS = ['.png' , '.jpg' , '.jpeg' , '.heif' , '.heic' ]
12- VIDEO_EXTENSIONS = ['.mp4' , '.mkv' , '.flv' , '.mov' , '.avi' , '.webm' , '.hevc' ]
1313 EXIF_TO_FIELD = {'EXIF FNumber' : 'f_number' ,
1414 'Image Make' : 'make' ,
1515 'Image Model' : 'model' ,
@@ -380,7 +380,7 @@ def __get_modified_files(self, modified_folders):
380380 for dir , _date in modified_folders :
381381 for file in os .listdir (dir ):
382382 base , extension = os .path .splitext (file )
383- if (extension .lower () in (ImageCache .EXTENSIONS + ImageCache . VIDEO_EXTENSIONS )
383+ if (extension .lower () in (ImageCache .EXTENSIONS + VIDEO_EXTENSIONS )
384384 # have to filter out all the Apple junk
385385 and '.AppleDouble' not in dir and not file .startswith ('.' )):
386386 full_file = os .path .join (dir , file )
@@ -402,7 +402,12 @@ def __insert_file(self, file, file_id=None):
402402 base , extension = os .path .splitext (file_only )
403403
404404 # Get the file's meta info and build the INSERT statement dynamically
405- meta = self .__get_exif_info (file )
405+ meta = {}
406+ ext = os .path .splitext (file )[1 ].lower ()
407+ if ext in VIDEO_EXTENSIONS : # no exif info available
408+ meta = self .__get_video_info (file )
409+ else :
410+ meta = self .__get_exif_info (file )
406411 meta_insert = self .__get_meta_sql_from_dict (meta )
407412 vals = list (meta .values ())
408413 vals .insert (0 , file )
@@ -468,17 +473,14 @@ def __purge_missing_files_and_folders(self):
468473 self .__purge_files = False
469474
470475 def __get_exif_info (self , file_path_name ):
471- ext = os .path .splitext (file_path_name )[1 ].lower ()
472- if ext in ImageCache .VIDEO_EXTENSIONS : # no exif info available
473- return {'width' : 100 , 'height' : 100 } # return early with min info for videos TODO duration available in video_info
474476 exifs = get_image_meta .GetImageMeta (file_path_name )
475477 # Dict to store interesting EXIF data
476478 # Note, the 'key' must match a field in the 'meta' table
477479 e = {}
478480
479481 e ['orientation' ] = exifs .get_orientation ()
480482
481- width , height = exifs .get_size ()
483+ width , height = exifs .size
482484 ext = os .path .splitext (file_path_name )[1 ].lower ()
483485 if ext not in ('.heif' , '.heic' ) and e ['orientation' ] in (5 , 6 , 7 , 8 ):
484486 width , height = height , width # swap values
@@ -521,6 +523,59 @@ def __get_exif_info(self, file_path_name):
521523
522524 return e
523525
526+ def __get_video_info (self , file_path_name : str ) -> dict :
527+ """
528+ Extracts metadata information from a video file.
529+
530+ This method retrieves video metadata using the `get_video_info` function and
531+ organizes it into a dictionary. The metadata includes dimensions, orientation,
532+ and other optional EXIF and IPTC data if available.
533+
534+ Args:
535+ file_path_name (str): The full path to the video file.
536+
537+ Returns:
538+ dict: A dictionary containing the meta keys.
539+ Note, the 'key' must match a field in the 'meta' table
540+ """
541+ meta = get_video_info (file_path_name )
542+
543+ # Dict to store interesting EXIF data
544+ # Note, the 'key' must match a field in the 'meta' table
545+ e : dict = {}
546+
547+ # Orientation is set to 1 by default, as video files rarely have this info.
548+ e ['orientation' ] = 1
549+
550+ width , height = meta .dimensions
551+ e ['width' ] = width
552+ e ['height' ] = height
553+
554+ # Attempt to retrieve additional metadata if available in meta
555+ e ['f_number' ] = getattr (meta , 'f_number' , None )
556+ e ['make' ] = getattr (meta , 'make' , None )
557+ e ['model' ] = getattr (meta , 'model' , None )
558+ e ['exposure_time' ] = getattr (meta , 'exposure_time' , None )
559+ e ['iso' ] = getattr (meta , 'iso' , None )
560+ e ['focal_length' ] = getattr (meta , 'focal_length' , None )
561+ e ['rating' ] = getattr (meta , 'rating' , None )
562+ e ['lens' ] = getattr (meta , 'lens' , None )
563+ e ['exif_datetime' ] = meta .exif_datetime if not None else os .path .getmtime (file_path_name )
564+
565+ if meta .gps_coords is not None :
566+ lat , lon = meta .gps_coords
567+ else :
568+ lat , lon = None , None
569+ e ['latitude' ] = round (lat , 4 ) if lat is not None else lat # TODO sqlite requires (None,) to insert NULL
570+ e ['longitude' ] = round (lon , 4 ) if lon is not None else lon
571+
572+ # IPTC
573+ e ['tags' ] = getattr (meta , 'tags' , None )
574+ e ['title' ] = getattr (meta , 'title' , None )
575+ e ['caption' ] = getattr (meta , 'caption' , None )
576+
577+ return e
578+
524579
525580# If being executed (instead of imported), kick it off...
526581if __name__ == "__main__" :
0 commit comments