@@ -3107,12 +3107,43 @@ def _decrypt_wechat_dat_v4(data: bytes, xor_key: int, aes_key: bytes) -> bytes:
31073107
31083108def _load_media_keys (account_dir : Path ) -> dict [str , Any ]:
31093109 p = account_dir / "_media_keys.json"
3110+ data : dict [str , Any ] = {}
31103111 if not p .exists ():
3111- return {}
3112- try :
3113- return json .loads (p .read_text (encoding = "utf-8" ))
3114- except Exception :
3115- return {}
3112+ data = {}
3113+ else :
3114+ try :
3115+ loaded = json .loads (p .read_text (encoding = "utf-8" ))
3116+ if isinstance (loaded , dict ):
3117+ data .update (loaded )
3118+ except Exception :
3119+ data = {}
3120+
3121+ # Newer key flows store image keys in the shared account key store, while
3122+ # the media decoder historically looked only at `_media_keys.json`. Read
3123+ # both so realtime v4 `.dat` images can decode immediately after key fetch.
3124+ if data .get ("xor" ) is None or not str (data .get ("aes" ) or "" ).strip ():
3125+ try :
3126+ from .key_store import get_account_keys_from_store
3127+
3128+ keys = get_account_keys_from_store (Path (account_dir ).name )
3129+ if isinstance (keys , dict ):
3130+ if data .get ("xor" ) is None :
3131+ xor_raw = str (keys .get ("image_xor_key" ) or keys .get ("xor_key" ) or "" ).strip ()
3132+ if xor_raw :
3133+ if xor_raw .lower ().startswith ("0x" ):
3134+ data ["xor" ] = int (xor_raw [2 :], 16 )
3135+ else :
3136+ try :
3137+ data ["xor" ] = int (xor_raw , 16 )
3138+ except Exception :
3139+ data ["xor" ] = int (xor_raw )
3140+ if not str (data .get ("aes" ) or "" ).strip ():
3141+ aes_raw = str (keys .get ("image_aes_key" ) or keys .get ("aes_key" ) or "" ).strip ()
3142+ if aes_raw :
3143+ data ["aes" ] = aes_raw [:16 ]
3144+ except Exception :
3145+ pass
3146+ return data
31163147
31173148
31183149def _get_resource_dir (account_dir : Path ) -> Path :
0 commit comments