@@ -587,15 +587,16 @@ async def generate_local_exact_thumbnail(
587587 )
588588 return None
589589
590- t_byte_source = await defer_to_thread (
591- self .hs .get_reactor (),
592- self ._generate_thumbnail ,
593- thumbnailer ,
594- t_width ,
595- t_height ,
596- t_method ,
597- t_type ,
598- )
590+ with thumbnailer :
591+ t_byte_source = await defer_to_thread (
592+ self .hs .get_reactor (),
593+ self ._generate_thumbnail ,
594+ thumbnailer ,
595+ t_width ,
596+ t_height ,
597+ t_method ,
598+ t_type ,
599+ )
599600
600601 if t_byte_source :
601602 try :
@@ -657,15 +658,16 @@ async def generate_remote_exact_thumbnail(
657658 )
658659 return None
659660
660- t_byte_source = await defer_to_thread (
661- self .hs .get_reactor (),
662- self ._generate_thumbnail ,
663- thumbnailer ,
664- t_width ,
665- t_height ,
666- t_method ,
667- t_type ,
668- )
661+ with thumbnailer :
662+ t_byte_source = await defer_to_thread (
663+ self .hs .get_reactor (),
664+ self ._generate_thumbnail ,
665+ thumbnailer ,
666+ t_width ,
667+ t_height ,
668+ t_method ,
669+ t_type ,
670+ )
669671
670672 if t_byte_source :
671673 try :
@@ -749,119 +751,134 @@ async def _generate_thumbnails(
749751 )
750752 return None
751753
752- m_width = thumbnailer .width
753- m_height = thumbnailer .height
754-
755- if m_width * m_height >= self .max_image_pixels :
756- logger .info (
757- "Image too large to thumbnail %r x %r > %r" ,
758- m_width ,
759- m_height ,
760- self .max_image_pixels ,
761- )
762- return None
763-
764- if thumbnailer .transpose_method is not None :
765- m_width , m_height = await defer_to_thread (
766- self .hs .get_reactor (), thumbnailer .transpose
767- )
754+ with thumbnailer :
755+ m_width = thumbnailer .width
756+ m_height = thumbnailer .height
768757
769- # We deduplicate the thumbnail sizes by ignoring the cropped versions if
770- # they have the same dimensions of a scaled one.
771- thumbnails : Dict [Tuple [int , int , str ], str ] = {}
772- for requirement in requirements :
773- if requirement .method == "crop" :
774- thumbnails .setdefault (
775- (requirement .width , requirement .height , requirement .media_type ),
776- requirement .method ,
777- )
778- elif requirement .method == "scale" :
779- t_width , t_height = thumbnailer .aspect (
780- requirement .width , requirement .height
758+ if m_width * m_height >= self .max_image_pixels :
759+ logger .info (
760+ "Image too large to thumbnail %r x %r > %r" ,
761+ m_width ,
762+ m_height ,
763+ self .max_image_pixels ,
781764 )
782- t_width = min (m_width , t_width )
783- t_height = min (m_height , t_height )
784- thumbnails [
785- (t_width , t_height , requirement .media_type )
786- ] = requirement .method
787-
788- # Now we generate the thumbnails for each dimension, store it
789- for (t_width , t_height , t_type ), t_method in thumbnails .items ():
790- # Generate the thumbnail
791- if t_method == "crop" :
792- t_byte_source = await defer_to_thread (
793- self .hs .get_reactor (), thumbnailer .crop , t_width , t_height , t_type
765+ return None
766+
767+ if thumbnailer .transpose_method is not None :
768+ m_width , m_height = await defer_to_thread (
769+ self .hs .get_reactor (), thumbnailer .transpose
794770 )
795- elif t_method == "scale" :
796- t_byte_source = await defer_to_thread (
797- self .hs .get_reactor (), thumbnailer .scale , t_width , t_height , t_type
771+
772+ # We deduplicate the thumbnail sizes by ignoring the cropped versions if
773+ # they have the same dimensions of a scaled one.
774+ thumbnails : Dict [Tuple [int , int , str ], str ] = {}
775+ for requirement in requirements :
776+ if requirement .method == "crop" :
777+ thumbnails .setdefault (
778+ (requirement .width , requirement .height , requirement .media_type ),
779+ requirement .method ,
780+ )
781+ elif requirement .method == "scale" :
782+ t_width , t_height = thumbnailer .aspect (
783+ requirement .width , requirement .height
784+ )
785+ t_width = min (m_width , t_width )
786+ t_height = min (m_height , t_height )
787+ thumbnails [
788+ (t_width , t_height , requirement .media_type )
789+ ] = requirement .method
790+
791+ # Now we generate the thumbnails for each dimension, store it
792+ for (t_width , t_height , t_type ), t_method in thumbnails .items ():
793+ # Generate the thumbnail
794+ if t_method == "crop" :
795+ t_byte_source = await defer_to_thread (
796+ self .hs .get_reactor (),
797+ thumbnailer .crop ,
798+ t_width ,
799+ t_height ,
800+ t_type ,
801+ )
802+ elif t_method == "scale" :
803+ t_byte_source = await defer_to_thread (
804+ self .hs .get_reactor (),
805+ thumbnailer .scale ,
806+ t_width ,
807+ t_height ,
808+ t_type ,
809+ )
810+ else :
811+ logger .error ("Unrecognized method: %r" , t_method )
812+ continue
813+
814+ if not t_byte_source :
815+ continue
816+
817+ file_info = FileInfo (
818+ server_name = server_name ,
819+ file_id = file_id ,
820+ url_cache = url_cache ,
821+ thumbnail = ThumbnailInfo (
822+ width = t_width ,
823+ height = t_height ,
824+ method = t_method ,
825+ type = t_type ,
826+ ),
798827 )
799- else :
800- logger .error ("Unrecognized method: %r" , t_method )
801- continue
802-
803- if not t_byte_source :
804- continue
805-
806- file_info = FileInfo (
807- server_name = server_name ,
808- file_id = file_id ,
809- url_cache = url_cache ,
810- thumbnail = ThumbnailInfo (
811- width = t_width ,
812- height = t_height ,
813- method = t_method ,
814- type = t_type ,
815- ),
816- )
817828
818- with self .media_storage .store_into_file (file_info ) as (f , fname , finish ):
819- try :
820- await self .media_storage .write_to_file (t_byte_source , f )
821- await finish ()
822- finally :
823- t_byte_source .close ()
824-
825- t_len = os .path .getsize (fname )
826-
827- # Write to database
828- if server_name :
829- # Multiple remote media download requests can race (when
830- # using multiple media repos), so this may throw a violation
831- # constraint exception. If it does we'll delete the newly
832- # generated thumbnail from disk (as we're in the ctx
833- # manager).
834- #
835- # However: we've already called `finish()` so we may have
836- # also written to the storage providers. This is preferable
837- # to the alternative where we call `finish()` *after* this,
838- # where we could end up having an entry in the DB but fail
839- # to write the files to the storage providers.
829+ with self .media_storage .store_into_file (file_info ) as (
830+ f ,
831+ fname ,
832+ finish ,
833+ ):
840834 try :
841- await self .store .store_remote_media_thumbnail (
842- server_name ,
843- media_id ,
844- file_id ,
845- t_width ,
846- t_height ,
847- t_type ,
848- t_method ,
849- t_len ,
850- )
851- except Exception as e :
852- thumbnail_exists = await self .store .get_remote_media_thumbnail (
853- server_name ,
854- media_id ,
855- t_width ,
856- t_height ,
857- t_type ,
835+ await self .media_storage .write_to_file (t_byte_source , f )
836+ await finish ()
837+ finally :
838+ t_byte_source .close ()
839+
840+ t_len = os .path .getsize (fname )
841+
842+ # Write to database
843+ if server_name :
844+ # Multiple remote media download requests can race (when
845+ # using multiple media repos), so this may throw a violation
846+ # constraint exception. If it does we'll delete the newly
847+ # generated thumbnail from disk (as we're in the ctx
848+ # manager).
849+ #
850+ # However: we've already called `finish()` so we may have
851+ # also written to the storage providers. This is preferable
852+ # to the alternative where we call `finish()` *after* this,
853+ # where we could end up having an entry in the DB but fail
854+ # to write the files to the storage providers.
855+ try :
856+ await self .store .store_remote_media_thumbnail (
857+ server_name ,
858+ media_id ,
859+ file_id ,
860+ t_width ,
861+ t_height ,
862+ t_type ,
863+ t_method ,
864+ t_len ,
865+ )
866+ except Exception as e :
867+ thumbnail_exists = (
868+ await self .store .get_remote_media_thumbnail (
869+ server_name ,
870+ media_id ,
871+ t_width ,
872+ t_height ,
873+ t_type ,
874+ )
875+ )
876+ if not thumbnail_exists :
877+ raise e
878+ else :
879+ await self .store .store_local_thumbnail (
880+ media_id , t_width , t_height , t_type , t_method , t_len
858881 )
859- if not thumbnail_exists :
860- raise e
861- else :
862- await self .store .store_local_thumbnail (
863- media_id , t_width , t_height , t_type , t_method , t_len
864- )
865882
866883 return {"width" : m_width , "height" : m_height }
867884
0 commit comments