
    !0DiB                     f   S SK r S SKrS SK7  S SKrS SKrS SKJrJrJr  Sr	S\
S\
4S jrS\
S\
4S	 jrS
 r0 S/ SQ_SS/_SS/_S/ SQ_SS/_S/ SQ_SSS/_S/ SQ_S/ SQ_S/ SQ_S / S!Q_S"S#S$/_S%S&S'/_S(S)/_S*S+/_S,S-/_S.S//_0 S0S1S2/_S3S#S4/_S5S6/_S7/ S8Q_S9/ S:Q_S;/ S<Q_S=/ S>Q_S?/ S@Q_SASB/_SCSD/_SE/ SFQ_SGS$SH/_SISJ/_SKSLSM/_SNS;/_SOSPSQ/_SQSR/_ESS/ STQ0ErSU\4SV jrSW\SX\
S\
4SY jrSW\4SZ jrS[\S\\S]\SS4S^ jrSX\
SW\4S_ jrSX\
SW\4S` jrSlSX\
Sa\
4Sb jjrSlSX\
Sc\
Sa\
4Sd jjrSmSe jr\Sf:X  a  \" Sg5      r\" Sh5      r\R=                  5        H  u  rr \ R=                  5        H  u  r!r"\#" \!5        \" \!\"5      r$\RK                  \!S5      (       ac  \#" Si5        \\!   R=                  5        HD  u  r&r'\$RK                  \&S5      (       d  0 \$\&'   \'R=                  5        H  u  r(r)\)\$\&   \('   M     MF     \" \"5      u  r*r+\" \$\*\+5        \#" 5         \," Sj\! Sk3\$5        M     M     gg)n    N)*)ConnectTimeoutReadTimeoutConnectionError   ­textreturnc                 N    U R                  [        S5      R                  SS5      $ )z0Remove all soft hyphen characters from a string. z[p])replaceSOFT_HYPHEN)r   s    6t:\var\www\ffxiv\extras\json\XIVAPI\get_xivapi_data.pystrip_soft_hyphenr      s     <<R(00;;    keyc                     [        U 5      n [        R                  " SU 5      nU(       a5  UR                  S5       SUR                  S5       3R	                  SS5      $ U R	                  SS5      $ )zm
Convert keys like 'Abbreviation@lang(de)' to 'Abbreviation_de',
remove '@as(html)', and strip soft hyphens.
z^(.*?)@lang\((.*?)\)$   _   z	@as(html)r   )r   rematchgroupr   )r   r   s     r   normalize_keyr      sc    
 C
 CHH-s3E++a.!5;;q>"23;;KLL;;{B''r   c                 ^   [        U [        5      (       a  [        U 5      $ [        U [        5      (       a  [        U 5      $ [        U [        5      (       a  U  Vs/ s H  n[        U5      PM     sn$ [        U [        5      (       d  U $ U R                  S0 5      nU R                  S0 5      nUR                  5        VVs0 s H  u  pE[        U5      [        U5      _M     nnnUR                  5        VVs0 s H  u  pE[        U5      [        U5      _M     nnn[        U5      nUR                  5        H*  u  pEXH;  a  XXU'   M  SU-   n	X;   a  SU	-   n	X;   a  M  XXU	'   M,     U R                  5        H$  u  pEUS;  d  M  [        U5      U[        U5      '   M&     U$ s  snf s  snnf s  snnf )z7Recursively normalize and merge fields/transient dicts.fields	transientt)r   r   )

isinstancestrr   intlistnormalize_dictdictgetitemsr   )
ditem
raw_fieldsraw_transientkvnormalized_fieldsnormalized_transientmergednew_keys
             r   r"   r"      s   !S ##!S1v!T123t$33ax$JEE+r*M 9C8H8H8J8Ja.++8J   9F8K8K8M8Ma.++8M   #$F$**,?1I AgG#- #7O - 	++'5a'8F=#$  M= 4s   F !F#7!F)Achievement)zAchievementCategory.OrderIconPointsTypeAchievementCategoryzAchievementKind.OrderAchievementKindOrderAction)AdditionalCooldownGroup	Cast100msClassJobLevelr:   CooldownGroupEffectRanger1   IsPlayerActionIsPvPIsRoleActionPrimaryCostTypePrimaryCostValueRangeRecast100msSecondaryCostTypezStatusGainSelf.IconAozActionTransientNumberBNpcName)PronounPossessivePronounArticle	Adjective
BuddySkill
BuddyLevelIsActiveClassJob)JobIndex
PartyBonus	Unknown11ClassJobCategory).ACNADVALCARCARMASTBLMBLUBRDBSMBTNCNJCRPCULDNCDRGDRKFSHGLAGNBGSMLNCLTWMCHMINMNKMRDNINPCTPGLPLDRDMROGRPRSAMSCHSGESMNTHMUnknown0Unknown1Unknown2VPRWARWHMWVRContentFinderCondition)AllianceRouletteClassJobLevelRequiredClassJobLevelSynczContent.sheetz!ContentMemberType.HealersPerPartyz ContentMemberType.MeleesPerPartyz ContentMemberType.RangedPerPartyzContentMemberType.TanksPerPartyExpertRouletteFeastTeamRouletteGuildHestRouletteHighLevelRouletteItemLevelRequiredItemLevelSyncLevelCapRouletteLevelingRouletteMSQRouletteMentorRouletteNormalRaidRouletteTrialRouletteSortKeyr1   mageContentMemberType)HealersPerPartyMeleesPerPartyRangedPerPartyTanksPerPartyCraftActionr:   r1   	CraftLevezItemCount[]RepeatsDynamicEvent	EventTypeDeepDungeonzPomanderSlot[].IconDeepDungeonStatuszFloorEffectUI.IconDeepDungeon4GimmickEffect
StatusIconEurekaMagiaActionzAction.StatusGainSelf.IconMaxUsesFateClassJobLevelMaxInstanceContentzBGM.FileItem)zBaseParamValueSpecial[]zBaseParamValue[]Block	BlockRateCanBeHq	DamageMag
DamagePhys
DefenseMagDefensePhysIsAdvancedMeldingPermittedIsUniqueIsUntradablezItemUICategory.Icon
LevelEquip	LevelItemMateriaSlotCountRarityLeve)AllowanceCostr:   	ExpReward	GilRewardLevel)Map	TerritoryXYZr   )OffsetXOffsetY
SizeFactorIdMirageStoreSetItem)z	Body.IconzBracelets.IconzEarrings.Iconz	Feet.Iconz
Hands.Iconz	Head.Iconz	Legs.IconzMainHand.IconzNecklace.IconzOffHand.Iconz	Ring.IconMirageStoreSetItemLookupzItem[].IconOrchestrionPathFileQuest)r:   r:   EventIconTyper   IconSpecialzInstanceContentUnlock.row_idIsRepeatablezIssuerLocation.Map.OffsetXzIssuerLocation.Map.OffsetYzIssuerLocation.Map.SizeFactorzIssuerLocation.RadiuszIssuerLocation.XzIssuerLocation.YzIssuerLocation.ZzIssuerStart.PronounzItemCountReward[]zIssuerLocation.Map.IdItemRewardTypezOptionalItemCountReward[]zOptionalItemIsHQReward[]QuestParamsStatusStatusCategorySubmarineExplorationRankReqTerritoryTypeBgNameTraitTreasureHuntRankMaxPartySizeTreasureHuntTexturer{   TreasureSpot)zLocation.Map.OffsetXzLocation.Map.OffsetYzLocation.Map.SizeFactorz
Location.Xz
Location.Yz
Location.Zspecc                     [        U R                  5       5      n[        U5      S:  a  gUS   nUS   n[        U[        5      (       a  [        U[        5      (       d  gX#4$ )z
For a dict element like {"Unknown0": "", "Icon": ""}:
  - first key is treated as old/original field name ("Unknown0")
  - second key is treated as new/final field name ("Icon")
r   )NNr   r   )r!   keyslenr   r   )r   r   old_keyr/   s       r   _decode_rename_dictr      sY     		D
4y1}1gG1gGgs##:gs+C+Cr   r   sheetc                 B   SnSn/ SQnU  GH{  n[        U[        5      (       a  [        U5      S:  a  US   S:X  a|  US   n[        U[        5      (       aB  [	        U5      u  pxU=(       d+    U(       a"  [        [        UR                  5       5      5      OSn	OUn	U	(       d  M  U H  n
X9 S	U
 S
3-  nM     M  [        U[        5      (       aB  [	        U5      u  pxU=(       d+    U(       a"  [        [        UR                  5       5      5      OSn	O&[        U[        5      (       a  U(       a  US   OSn	OUn	U	(       d  GM4  U	S;   a
  X) S3-  nGMD  U	[        R                  U/ 5      ;   a
  X) S3-  nGMh  U H  n
X) S	U
 S
3-  nM     GM~     US:X  a  USS $ USS USS -   $ )u  
Build the ?fields= and &transient= query parts from translation_filenames.json.

Supported element types in `fields`:
  - "FieldName" (str)
      → normal field, language-expanded (unless in special list/IGNORELIST)
  - {"OldKey": "", "NewKey": ""}
      → non-transient rename spec:
         * OldKey is used in the API request.
         * later, OldKey* is renamed to NewKey*.
  - [{"OldKey": "", "NewKey": ""}, "transient"]
      → transient rename spec:
         * OldKey is requested as transient for all langs.
         * later, transient OldKey* is renamed to NewKey*.
  - ["FieldName", "transient"]
      → classic transient field, requested for all langs.
r   z&transient=)deenfrjar   r   r   r   Nz@lang(z),)%zTerritoryType.Map.Idr   PlaceNameIconzScreenImage.ImageIconObjective0IconObjective1PlaceNameRegionIconzMap.IdIndexIcon1z	Name.IconIcon2QuestRedoUIWideQuestRedoUILargeQuestRedoUISmall	StampIcon	Excellent	FailImageGoodGreatPoorIconMainIconOffMapIconUiIconIconMapIconDutyFinderr   Imager1   IconReputation	IconLarge	IconSmall
IconLarge2
IconSmall2BottomImageTopImage,)
r   r!   r   r#   r   nextiterr   
IGNORELISTr$   )r   r   resultresult2langsr   	base_specold_newfieldlangs              r   get_language_fieldsr     s   & FG$EdD!!c$i1naK9OQI)T**/	:	T	T)..*:%; <t!WF4&33  dD!!+D1ICFtDdiik!23Ed###DGE E  
 
 qk!FjnnUB//qk!F G6$r22 Y ^ -cr{#2;"%%r   c                 z   0 n0 nU  H  n[        U[        5      (       a%  [        U5      u  pEU(       a  U(       a  XQU'   M9  M;  M=  [        U[        5      (       d  MT  [	        U5      S:  d  Me  US   S:X  d  Mp  US   n[        U[        5      (       d  M  [        U5      u  pEU(       d  M  U(       d  M  XRU'   M     X4$ )u   
Build two mappings from the config:

  Non-transient rename:
    {"OldKey":"", "NewKey":""}
      → field_rename[OldKey] = NewKey

  Transient rename:
    [{"OldKey":"", "NewKey":""}, "transient"]
      → transient_rename[OldKey] = NewKey
r   r   r   r   )r   r#   r   r!   r   )r   field_renametransient_renamer   r  newr  s          r   build_rename_mapsr     s     LdD!!*40HCs$'S! s d##D	Q47k;QQI)T**.y9333,/S)  ))r   rows	field_maptransient_mapc                    U(       a  U R                  5        H  u  p4[        UR                  5       5      nUR                  5        HO  u  pgUS-   nU H?  n	X:X  d  U	R                  U5      (       d  M   Xy[	        U5      S -   n
XI   XJ'   X:w  d  M=  XI	 MA     MQ     M     U(       a  U R                  5        H  u  p4[        UR                  5       5      nUR                  5        H  u  pgUS-   nSU-   nUS-   nU Hl  n	X:X  d  U	R                  U5      (       a  Xy[	        U5      S -   n
O.X:X  d  U	R                  U5      (       a  Xy[	        U5      S -   n
OM]  XI   XJ'   X:w  d  Mj  XI	 Mn     M     M     gg)u  
Apply rename maps to the normalized rows in-place.

field_map (OldKey -> NewKey) applies to normal keys:
  - OldKey        → NewKey
  - OldKey_de     → NewKey_de
  - OldKey_en_foo → NewKey_en_foo

transient_map (OldKey -> NewKey) applies to transient keys:
  - OldKey*       → NewKey*           (when only transient exists)
  - tOldKey*      → NewKey*           (collision-produced transient keys,
                                       dropping the leading 't' as requested)
r   Nr   )r%   r!   r   
startswithr   )r  r  r  row_idrowr   r  r  prefixr   r/   t_prefixt_prefix_with_underscores                r   apply_rename_mapsr!     sR    ::<KF
#D%OO-sCzS^^F%;%;"%CHI"6'*x"> #   . ( ::<KF
#D)//1s9+3c>(CzS^^F%;%;"%CHI"6CNN;S,T,T #&CMN(;"; #&8CL~H   2 ( r   c                 :    SU  S[        X5       3n[        U5      $ )N'https://xivapi.akurosia.de/api/1/sheet/?fields=)r  _handle_request)r   r   base_urls      r   get_translated_sheetsr'  6  s'    8xH[\bHjGklH8$$r   c           	          SU  S[          S[        X5       3n[        R                  " U5      nUR	                  5         UR                  5       $ )Nr#  /r$  )idr  requestsr$   raise_for_statusjson)r   r   r&  responses       r   get_id_from_translated_sheetsr/  <  sH    8qHM`agMoLpqH||H%H==?r   languagec                 (    SU  SU 3n[        U5      $ )Nr#  
?language=)r%  )r   r0  r&  s      r   	get_sheetr3  C  s    8z(TH8$$r   r*  c                     SU  SU SU 3n[         R                  " U5      nUR                  5         UR                  5       $ )Nr#  r)  r2  )r+  r$   r,  r-  )r   r*  r0  r&  r.  s        r   get_id_from_sheetr5  H  s@    8qJxjYH||H%H==?r   c                 b   S nS n0 n Xb  SU 3OS-   nSnXq:  a'   [         R                  " USS9nUR                  5          WR                  5       n
U
R                  S/ 5      nU(       d   U$ [        S U 5       5      nU H3  nU(       a  US    SUS    3nO[        US   5      n[        U5      X^'   M5     US   S   nX4:X  a   U$ UnM  ! [        [        [
        4 aC  n	US-  nXq:  a  e [        SU	 SU S	U S
U S3	5        [        R                  " U5         S n	A	OS n	A	ff = fXq:  a  GM  N)Nz&after=r   r   x   )timeoutr   zRequest failed (z). Retrying r)  z in zs...r  c              3   J   #    U  H  oR                  S S5      S:g  v   M     g7f)	subrow_idr   N)r$   ).0rs     r   	<genexpr>"_handle_request.<locals>.<genexpr>g  s     Cd%%Q/14ds   !#r  .r:  r  )r+  r$   r,  r   r   r   printtimesleepr-  anyr   r"   )r&  max_retriesretry_delayafterafter2all_rowsurlattemptr.  edatar  has_subrowsr  r   s                  r   r%  r%  O  sk   EFH
/@GE7+bI#	(#<<S9))+ }}xx#  O CdCCCXq[)9(:;#h-(*3/HM  R"? O C  #KA (1)(<y+dS^R__cde

;''( #s   %C D%"9D  D%__main__z./translation_filenames.jsonz!./get_xivapi_data_additional.jsonzApply translations from jsonzP:/extras/json/xivapi_data/z.json)r   )
   r   )-r+  r   	ffxiv_akurequests_cacherA  requests.exceptionsr   r   r   r   r   r   r   r"   r  r#   r   r!   r  r  r!  r'  r/  r3  r5  r%  __name__readJsonFile_inputtranslationsr%   r   rL  r   r   r@  resultsr$   r   data_rowd_keyd_valuer  r  writeJsonFile r   r   <module>r]     sA    	    L L <C <C <
	(s 	(s 	(%P5J5345 y5  J	5 8*5 H5 <,5 75  A5  a5* a+5, OV,-5. -+/50 [M152 )*354 ./556  ,758 6	B95: _01;5< 
|=5>  F?5D HE5F 0G5H 
5I5J  ZK5N O5P xQ5R  hS5Z v'([5\ YK]5^ dF^_5` gYa5b )>?c5d J<e5f  #g5
zd  I& I&S I&S I&X*d *@3%D 3%T 3%$ 3%4 3%l% %d % d %S %C %
S c S 'T z89F CDL<<>4!ZZ\ME6 %L+E6:G t,,45%1%%8%>%>%@MC";;sD11')*2..*:w.5U+ +; &A (9'@$I}gy-@G7weDgN3 * "	 r   