Ë
    ß<ØjV"  ã                   óB  — d Z ddlZddlZddlZddlZddlZddlmZ ddlm	Z	 ej                  j                  dd¬«        ee«      j                  «       j                  j                  ZdZd	ZdZd
efd„Zd
efd„Zd
efd„Zdd
efd„Zdd
efd„Zd„ Zedk(  r e«        yy)aE  
select_x_posts: SELECTOR de posts para X (Twitter) a partir de un pack.

De un pack (Output/packs/<clave>_<tema>/, con pack_manifest.json + img/) deriva
3 posts SFW-sugerentes y 2 posts explicitos, 4 imagenes cada uno, y los copia a
<pack>/_x_posts/<post>/ con un x_posts_manifest.json. Solo lee el manifest y la
carpeta img/ del pack; no toca Forge ni la GPU.

    python Engine/select_x_posts.py --pack "Output/packs/Furina_playa"
    python Engine/select_x_posts.py --pack "Output/packs/Furina_playa"         --sfw 2 --exp 1 --per-post 4

Reglas:
- load_approved: si ALGUN registro trae `verdict` no nulo, solo se toman los
  `aprobada`; si el pack aun no se ha auditado (todos `verdict` = null), se
  toman todos (un pack sin auditar es seleccionable entero).
- SFW desde stages {sugerente, spicy1}; explicito desde
  {spicy2, explicit1, explicit2}. Los packs viejos caen por `nivel`:
  spicy -> spicy1 y explicito -> explicit2.
- Variedad dentro de cada post: no repetir `pose_id` (ni `tema`) si hay
  alternativa; el sesgo es suave (una pose/tema repetido solo se elige cuando
  no queda nada mejor).
- Si un pool tiene menos imagenes de las necesarias, se toma lo que hay y el
  faltante queda escrito en x_posts_manifest.json (nunca falla la seleccion
  entera).
- Nombres: post1_sfw..postN_sfw y luego postN+1_exp.. (la numeracion sigue).
é    N)ÚPath©Ústage_for_recordúutf-8Úbackslashreplace)ÚencodingÚerrors)Ú	sugerenteÚspicy1)Úspicy2Ú	explicit1Ú	explicit2Úreturnc                 ó®  — t        | «      } | dz  }|j                  «       st        d| › �«      ‚t        j                  |j                  d¬«      «      }t        |t        «      st        d|› �«      ‚|D �cg c]  }t        |t        «      sŒ|‘Œ }}t        d„ |D «       «      }|r%|D �cg c]  }|j                  d«      dk(  sŒ|‘Œ c}S |S c c}w c c}w )	a+  Registros seleccionables del pack.

    Si algun registro trae `verdict` no nulo (el pack fue auditado), devuelve
    solo los `verdict == "aprobada"`. Si el pack aun no se ha auditado (todos
    `verdict` = null), devuelve TODOS los registros. Lanza si el manifest falta
    o no es una lista.
    úpack_manifest.jsonzsin pack_manifest.json en r   ©r   z+pack_manifest.json con forma inesperada en c              3   óB   K  — | ]  }|j                  d «      du–— Œ y­w©ÚverdictN©Úget©Ú.0Úrs     úEngine/select_x_posts.pyÚ	<genexpr>z load_approved.<locals>.<genexpr>@   s   è ø€ Ð@¹°1�!—%‘%˜	Ó"¨$Ô.¹ùs   ‚r   Úaprobada)r   ÚexistsÚFileNotFoundErrorÚjsonÚloadsÚ	read_textÚ
isinstanceÚlistÚ
ValueErrorÚdictÚanyr   )Úpack_dirÚmanifestÚrecordsr   Úauditeds        r   Úload_approvedr,   0   sÓ   € ô �H‹~€HØÐ.Ñ.€HØ�?‰?ÔÜÐ"<¸X¸JÐ GÓHÐHÜ�j‰j˜×+Ñ+°WÐ+Ó=Ó>€GÜ�gœtÔ$ÜÐFÀxÀjÐQÓRÐRÙ!Ó9™'�Q¤Z°´4Õ%8Šq˜'€GÐ9ÜÑ@¹Ó@Ó@€GÙÙ"ÓE™7�a a§e¡e¨IÓ&6¸*Ó&D’˜7ÑEÐEØ€Nùò	 :ùò Fs   Á6CÂCÂ*CÃCc                 óF  — g }t        «       }t        «       }| �rt        |«      |k  rùd}d}t        | «      D ]_  \  }}d}	|j                  d«      }
t	        |j                  d«      xs g «      }|
�	|
|v r|	dz  }	|r	||v r|	dz  }	|�|	|k  sŒU|	}|}|	dk(  sŒ_ n | j                  |«      }|j                  |«       |j                  d«      }
|
�|j                  |
«       t	        |j                  d«      xs g «      }|r|j                  |«       | rt        |«      |k  rŒù|S )zæSaca hasta n registros de `remaining` (los consume) maximizando variedad.

    En cada paso elige el registro con menos choques: repetir `pose_id` pesa 2,
    repetir `tema` pesa 1. Con empate gana el primero (orden estable).
    r   NÚpose_idÚtemaé   é   )ÚsetÚlenÚ	enumerater   ÚtupleÚpopÚappendÚadd)Ú	remainingÚnÚpickedÚ	used_poseÚ	used_temaÚbest_iÚ
best_scoreÚiÚrecÚscoreÚpidr/   s               r   Ú_pick_varietyrD   F   s+  € ð €FÜ“€IÜ“€IÚ
œ˜F› ašØˆØˆ
Ü 	Ö*‰FˆAˆsØˆEØ—'‘'˜)Ó$ˆCÜ˜Ÿ™ ›Ò.¨BÓ/ˆDØˆ 3¨)Ñ#3Ø˜‘
�Ù˜ 	Ñ)Ø˜‘
�ØÐ! U¨ZÓ%7Ø"�
Ø�Ø˜A“:Ùð +ð �m‰m˜FÓ#ˆØ�‰�cÔØ�g‰g�iÓ ˆØˆ?Ø�M‰M˜#ÔÜ�S—W‘W˜V“_Ò*¨Ó+ˆÙØ�M‰M˜$Ôñ/ œ˜F› a›ð0 €Mó    c                 óH   — | D �cg c]  }t        |«      |v sŒ|‘Œ c}S c c}w )Nr   )r*   Ústagesr   s      r   Ú_poolrH   j   s'   € ÙÓ@‘w�!Ô"2°1Ó"5¸Ò"?ŠA�wÑ@Ð@ùÒ@s   …˜c                 ób  — t        j                  t        «      }dt        | t        «      t        dt        |«      «      fdt        | t        «      t        dt        |«      «      fg}t        dt        |«      «      }g }d}|D ]¡  \  }}	}
t        |	«      }|j                  |«       t        |
«      D ]q  }|dz  }t        ||«      }|D �cg c]'  }t        |j                  dd«      «      j                  ‘Œ) }}|j                  d|› d|› �||D �cg c]  }|sŒ|‘Œ	 c}d	œ«       Œs Œ£ |S c c}w c c}w )
a’  Reparte los registros en `sfw` posts SFW + `exp` posts explicitos.

    Cada item: {"post": "post1_sfw", "kind": "sfw", "files": [<nombres>]}.
    Los pools se barajan (semilla fija) y se reparten post a post, evitando
    repetir pose/tema dentro de un post cuando hay alternativa. Cada registro se
    usa como mucho una vez; si un pool se agota, los posts restantes salen
    cortos (o vacios).
    Úsfwr   Úexpr1   ÚfileÚ ÚpostÚ_)rN   ÚkindÚfiles)ÚrandomÚRandomÚSHUFFLE_SEEDrH   Ú
SFW_STAGESÚmaxÚintÚEXPLICIT_STAGESr$   ÚshuffleÚrangerD   r   r   Únamer7   )r*   rJ   rK   Úper_postÚrngÚgroupsÚpostsÚindexrP   ÚpoolÚcountr9   rO   Úchosenr   rQ   Úfs                    r   Úselect_postsre   n   s*  € ô �-‰-œÓ
%€Cà	”�gœzÓ*¬C°´3°s³8Ó,<Ð=Ø	”�gœÓ/´°Q¼¸C»Ó1AÐBð€Fô �1”c˜(“mÓ$€HØ€EØ€EÛ#Ñˆˆd�EÜ˜“Jˆ	Ø�‰�IÔÜ�u–ˆAØ�Q‰JˆEÜ" 9¨hÓ7ˆFÙ;AÓB¹6°a”T˜!Ÿ%™% ¨Ó+Ó,×1Ó1¸6ˆEÐBØ�L‰LØ˜u˜g Q t fÐ-ØÙ%*Ó0¡U ªaš! UÑ0ñõ ñ	 ð $ð €Lùò Cùò 1s   Ã,D'ÄD,ÄD,c           	      ó¼  — t        | «      } | dz  }| dz  }|j                  dd¬«       t        dt        |«      «      }g }d}|D ]Ö  }|d   }||z  }	|	j                  dd¬«       g }
|j	                  dg «      D ]T  }|sŒ||z  }|j                  «       r+t        j                  ||	|z  «       |
j                  |«       ŒFt        d|› d	�«       ŒV t        d|t        |
«      z
  «      }||z  }|j                  ||j	                  d
«      |
t        |
«      |dœ«       ŒØ | j                  |||dœ}|dz  }|j                  t        j                  |dd¬«      d¬«       |S )aI  Copia los ficheros elegidos y escribe el manifest.

    Copia pack_dir/img/<nombre> -> pack_dir/_x_posts/<post>/<nombre> y escribe
    pack_dir/_x_posts/x_posts_manifest.json. Devuelve la ruta del manifest. Una
    imagen ausente se salta con aviso (no aborta). `per_post` solo se usa para
    calcular el faltante por post.
    ÚimgÚ_x_postsT)ÚparentsÚexist_okr   rN   rQ   z[!] falta la imagen z
; se omiterP   )rN   rP   rQ   rb   Ú	shortfall)Úpackr\   r_   rk   zx_posts_manifest.jsonFr1   )Úensure_asciiÚindentr   r   )r   ÚmkdirrV   rW   r   r   ÚshutilÚcopy2r7   Úprintr3   r[   Ú
write_textr    Údumps)r(   r_   r\   Úimg_dirÚout_rootÚentriesÚtotal_shortfallrN   r[   Údest_dirÚcopiedÚfnameÚsrcrk   r)   Úmanifest_paths                   r   Úwrite_postsr~   Ž   sz  € ô �H‹~€HØ˜Ñ€GØ˜*Ñ$€HØ‡N�N˜4¨$€NÔ/Ü�1”c˜(“mÓ$€Hà€GØ€OÛˆØ�F‰|ˆØ˜d‘?ˆØ�‰˜t¨dˆÔ3ØˆØ—X‘X˜g rÖ*ˆEÙØØ˜E‘/ˆCØ�z‰zŒ|Ü—‘˜S (¨UÑ"2Ô3Ø—‘˜eÕ$äÐ,¨S¨E°Ð<Õ=ð +ô ˜˜8¤c¨&£kÑ1Ó2ˆ	Ø˜9Ñ$ˆØ�‰ØØ—H‘H˜VÓ$ØÜ˜“[Ø"ñ
õ 	ð! ð2 —‘ØØØ$ñ	€Hð Ð6Ñ6€MØ×ÑÜ�
‰
�8¨%¸Ô:ÀWð ô NàÐrE   c            	      óš  — t        j                  d¬«      } | j                  ddd¬«       | j                  dt        dd	¬
«       | j                  dt        dd¬
«       | j                  dt        dd¬
«       | j	                  «       }t        |j                  «      }|j                  «       st        d|› �«      ‚|dz  j                  «       st        d|› �«      ‚t        |«      }t        j                  |dz  j                  d¬«      «      }t        d„ |D «       «      }|rt        d|› dt!        |«      › �«       nBt#        d„ |D «       «      rt        dt!        |«      › �«       nt        dt!        |«      › d�«       t%        ||j&                  |j(                  |j*                  ¬«      }t-        |||j*                  ¬«      }t        d„ |D «       «      }|d k(  rt        d!«       |D ]4  }	d"j/                  |	d#   «      xs d$}
t        d%|	d&   › d'|	d(   › d)|
› �«       Œ6 t        d*|› d+t!        |«      › d,|d-z  › �«       t        d.|› �«       y )/Nz#Selector de posts para X (PlumLoom))Údescriptionz--packTz0carpeta del pack (con pack_manifest.json e img/))ÚrequiredÚhelpz--sfwé   z posts SFW-sugerentes (default 3))ÚtypeÚdefaultr‚   z--expr0   zposts explicitos (default 2)z
--per-posté   zimagenes por post (default 4)z#[!] no existe la carpeta del pack: r   z[!] sin pack_manifest.json en r   r   c              3   óJ   K  — | ]  }|j                  d «      dk(  sŒd–— Œ y­w)r   r   r1   Nr   r   s     r   r   zmain.<locals>.<genexpr>Ó   s!   è ø€ ÐH™g˜¨¯©¨yÓ)9¸ZÓ)G”1™gùs   ‚#œ#z[i] pack auditado: z aprobadas de c              3   ód   K  — | ](  }t        |t        «      sŒ|j                  d «      du–— Œ* y­wr   )r#   r&   r   r   s     r   r   zmain.<locals>.<genexpr>Ö   s(   è ø€ ÐN±3¨a¼*ÀQÌÕ:MˆQ�U‰U�9Ó TÔ)±3ùs   ‚0˜0z&[i] pack auditado sin aprobadas: 0 de z[i] pack sin auditar: z
 registros)rJ   rK   r\   )r\   c              3   ó8   K  — | ]  }t        |d    «      –— Œ y­w)rQ   N)r3   )r   rN   s     r   r   zmain.<locals>.<genexpr>Þ   s   è ø€ Ð5©u t”�D˜‘M×"©uùs   ‚r   z$[!] no hay imagenes para seleccionarz, rQ   Ú-z  rN   z (rP   z): z[OK] z imagenes en z
 posts -> rh   z[OK] manifest: )ÚargparseÚArgumentParserÚadd_argumentrW   Ú
parse_argsr   rl   Úis_dirÚ
SystemExitr   r,   r    r!   r"   Úsumrr   r3   r'   re   rJ   rK   r\   r~   Újoin)ÚpÚargsr(   r*   ÚrawÚapprovedr_   r}   ÚtotalrN   rQ   s              r   Úmainr˜   Â   s  € Ü×ÑÐ,QÔR€AØ‡N�N�8 dØJð ô Là‡N�N�7¤¨aÐ6X€NÔYØ‡N�N�7¤¨aÐ6T€NÔUØ‡N�N�<¤c°1Ð;Z€NÔ[Ø�<‰<‹>€Dä�D—I‘I‹€HØ�?‰?ÔÜÐ>¸x¸jÐIÓJÐJØÐ+Ñ+×3Ñ3Ô5ÜÐ9¸(¸ÐDÓEÐEä˜HÓ%€GÜ
�*‰*�hÐ!5Ñ5×@Ñ@È'Ð@ÓRÓ
S€CÜÑH™gÓHÓH€HÙÜÐ# H :¨^¼CÀ»H¸:ÐFÕGÜ	ÑN±3ÓNÔ	NÜÐ6´s¸3³x°jÐAÕBäÐ&¤s¨7£| n°JÐ?Ô@ä˜ d§h¡h°D·H±HÀtÇ}Á}ÔU€EÜ ¨%¸$¿-¹-ÔH€MäÑ5©uÓ5Ó5€EØ�‚zÜÐ4Ô5ÛˆØ—	‘	˜$˜w™-Ó(Ò/¨CˆÜ��4˜‘<�.  4¨¡< .°°E°7Ð;Õ<ð ô 
ˆE�%�˜¤c¨%£j \°¸HÀzÑ<QÐ;RÐ
SÔTÜ	ˆO˜M˜?Ð
+Õ,rE   Ú__main__)rƒ   r0   r†   )r†   )Ú__doc__r‹   r    rR   rp   ÚsysÚpathlibr   rG   r   ÚstdoutÚreconfigureÚ__file__ÚresolveÚparentÚBASE_DIRrU   rX   rT   r$   r,   rD   rH   re   r~   r˜   Ú__name__© rE   r   Ú<module>r¥      sÃ   ðñó6 Û Û Û Û 
Ý å #à ‡
�
× Ñ  Ð0BÐ Ô Cá�‹>×!Ñ!Ó#×*Ñ*×1Ñ1€à$€
Ø6€ð €ð˜tó ð,! 4ó !ðHA˜dó Añ°tó ñ@1°ó 1òh#-ðL ˆzÒÙ…Fð rE   