
    ?jAA                       d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	m
Z
 ddlZddlmZ ddlmZmZ dZd	Ze d
Ze dZe dZe G d d             Ze G d d             Ze G d d             Ze G d d             Z G d de      Z G d de      Zd.dZd/dZd0dZd1dZ d2dZ!d3dZ"d4dZ#e G d  d!             Z$d5d"Z%d6d#Z&d7d$Z'd8d%Z(d9d&Z)d:d'Z*d;d(Z+d:d)Z,d<d*Z-d=d+Z.d>d?d,Z/d@dAd-Z0y)Bu
  Google Play Store FDFE API — details, purchase, delivery, search.

Uses a pure-Python protobuf decoder (no gpapi / protobuf library needed).
Field numbers are based on live probing from our research repo and
validated against gpapi's googleplay.proto definitions.
    )annotationsN)	dataclassfield)AnyOptionalbuild_headers)ProtoDecoderextract_stringsz.https://android.clients.google.com/fdfe/searchz'https://android.clients.google.com/fdfez/detailsz	/purchasez	/deliveryc                  z    e Zd ZU ded<   dZded<   dZded<   dZded<   dZded	<   d
Zded<   d
Z	ded<   dZ
ded<   y
)
AppDetailsstrpackage title	developerversion_stringr   intversion_codeNOptional[str]rating	downloadsplay_url)__name__
__module____qualname____annotations__r   r   r   r   r   r   r        ?/home/ubuntu/.local/lib/python3.12/site-packages/gplaydl/api.pyr   r       sL    LE3OIsNCL# FM #I}#Hcr   r   c                  4    e Zd ZU ded<   dZded<   dZded<   y)		SplitInfor   namer   urlr   r   sizeN)r   r   r   r   r$   r%   r   r   r    r"   r"   ,   s    
ICMD#Mr   r"   c                      e Zd ZU dZded<   dZded<   dZded<   dZded<   d	Zd
ed<    e	e
      Zded<   edd       Zedd       Zedd       Zy)AdditionalFiler   r   	file_typer   r%   r   r   r$   Fboolgzippeddefault_factory
list[dict]cookiesc                     | j                   dk(  S )N   )r(   selfs    r    is_asset_packzAdditionalFile.is_asset_pack<   s    ~~""r   c                "    | j                   rdS dS )Nz.apkz.obb)r3   r1   s    r    	extensionzAdditionalFile.extension@   s    ++v77r   c                B    ddddj                  | j                  d      S )Nmainpatchasset)r      r0   )getr(   r1   s    r    
type_labelzAdditionalFile.type_labelD   s     g'266t~~vNNr   N)returnr)   )r=   r   )r   r   r   r(   r   r   r%   r$   r*   r   listr.   propertyr3   r5   r<   r   r   r    r'   r'   3   s}    IsL#D#MCMGT5GZ5# # 8 8 O Or   r'   c                      e Zd ZU dZded<   dZded<   dZded<    ee      Z	d	ed
<    ee      Z
ded<    ee      Zded<   y)DeliveryResultr   r   download_urlr   r   download_sizesha1r+   r-   r.   zlist[SplitInfo]splitszlist[AdditionalFile]additional_filesN)r   r   r   rB   r   rC   rD   r   r>   r.   rE   rF   r   r   r    rA   rA   I   sN    L#M3D#N5GZ5#D9FO9-24-H*Hr   rA   c                      e Zd Zy)PlayAPIErrorN)r   r   r   r   r   r    rH   rH   S   s    r   rH   c                      e Zd ZdZy)AuthExpiredErroru8   Raised when the API returns 401 — token needs refresh.N)r   r   r   __doc__r   r   r    rJ   rJ   W   s    Br   rJ   c                x    | D ]5  \  }}}||k(  s|dk(  st        |t        t        f      s*t        |      c S  y)zGReturn raw bytes of the first length-delimited field with number *num*.r0   N
isinstancebytes	bytearrayfieldsnumfnwtvs        r    _first_bytesrW   `   s@     	B9qZE93E%F8O r   c                ^    | D ](  \  }}}||k(  s|dk(  st        j                  |      c S  y)Nr0   r   )r
   decode_stringrQ   s        r    _first_stringrZ   h   s:     1	B9q--a001 r   c                J    | D ]  \  }}}||k(  s|dk(  st        |      c S  y )Nr   )r   rQ   s        r    
_first_intr\   o   s2     	B9qq6M r   c           
         | D cg c]1  \  }}}||k(  r&|dk(  r!t        |t        t        f      rt        |      3 c}}}S c c}}}w )z7Return all length-delimited occurrences of field *num*.r0   rM   rQ   s        r    
_all_bytesr^   v   sN     #) RQ9qZE93E%F 	a  s   6Ac                    | }|D ]/  }t        |      j                         }t        ||      }|g c S |}1 t        |      j                         S )z:Walk a nested protobuf path, e.g. _navigate(raw, 1, 2, 4).)r
   read_all_orderedrW   )rawpathdata	field_numrR   subs         r    	_navigaterf   ~   sZ    D 	d#44669-;I ..00r   c                0    t        |       }d|d<   d|d<   |S )Nzapplication/x-protobufContent-TypeAcceptr   )authheaderss     r    _proto_headersrl      s%    D!G6GN0GHNr   c                    | D ]@  \  }}}||k(  s|dk(  st        j                  dt        j                  d|            d   c S  y )N   z<fz<Ir   )structunpackpackrQ   s        r    _first_floatrr      sL     @	B9q==v{{4';<Q??@ r   c                  p    e Zd ZU dZded<   dZded<   dZded<   dZded<   dZded	<   d
Z	ded<   d
Z
ded<   y
)_ParsedDetailsr   r   docidr   creatorr   r   r   r   Nr   r   r   )r   r   r   ru   r   r   rv   r   r   r   r   r   r   r    rt   rt      sF    E3OE3OGSL#NC FM #I}#r   rt   c                ~   t               }t        | ddd      }|s|S t        |d      |_        t        |d      |_        t        |d      |_        t        |d      }|rVt        |      j                         }t        |d      xs d|_	        |j                  st        |d      }|r|d	kD  r	|d
|_	        t        |d      }|r{t        |      j                         }t        |d      }|rTt        |      j                         }	t        |	d      xs d	|_        t        |	d      |_        t        |	d      xs d|_        |S )z7Parse details protobuf response into structured fields.r:   r0      rn            Nr   z.1f      =   )rt   rf   rZ   ru   r   rv   rW   r
   r`   r   rr   r\   r   r   r   )
ra   result
doc_fieldsrating_brfstardoc_details_bddapp_details_bads
             r    _parse_details_protor      s,   F31a(J Q/FL Q/FL":q1FN J+H(#446%b"-5}}A&Dq#'* !R0M-(99;$R+m,==?B",R"3"8qF$1"a$8F!,R4<FMr   c                0   t        |      }t        j                  t         d|  |d      }|j                  dk(  rt        d|        |j                  dk(  rt        d      |j                  dk7  rt        d	|j                   d
      |j                  S )z$Fetch raw protobuf details response.?doc=   rk   timeouti  zApp not found:   Auth token expired.   Failed to fetch details (HTTP ).)rl   httpxr;   DETAILS_URLstatus_coderH   rJ   content)r   rj   rk   resps       r    _fetch_details_rawr      s    T"G99}E'3WbQD3_WI67734553;D<L<L;MRPQQ<<r   c                    t        t        | |            }|j                  st        d      |j                  |j                  |j
                  |j                  fS )zHFetch app details. Returns (docid, title, version_code, version_string).5App not found or unavailable for this device profile.)r   r   ru   rH   r   r   r   r   rj   parseds      r    get_details_protor      sJ    !"4Wd"CDF<<RSS<<v':':F<Q<QQQr   c                   t        t        | |            }|j                  st        d      t	        |j                  xs | |j
                  |j                  |j                  |j                  |j                  |j                  d|        S )zReturn structured app details.r   z.https://play.google.com/store/apps/details?id=)r   r   r   r   r   r   r   r   )r   r   ru   rH   r   r   rv   r   r   r   r   r   s      r    get_detailsr      sz    !"4Wd"CDF<<RSS'll..,,((}}""A'K	 	r   c                    t        |      }d|d<   d|  d| }t        j                  t        ||d      }|j                  dvryy)	z6Acquire a free app (equivalent of clicking 'Install').z!application/x-www-form-urlencodedrh   zdoc=	&ot=1&vc=r   )rk   r   r   )r      N)r	   r   postPURCHASE_URLr   )r   r   rj   rk   bodyr   s         r    purchaser      sR    D!GAGN')L>2D::lGT2NDz) *r   c                z    dD ],  }t        | d|d      }|st        |d      s!t        |      c S  t        |       S )z-Parse a delivery response using ProtoDecoder.)   rn   rx   ry   r:   r0   r}   )rf   rZ   _extract_delivery_from_fields_extract_delivery_from_tree)ra   
payload_fn
add_fieldss      r    _parse_deliveryr     sG     $ =
sAz15
-
A60<<= 's++r   c                   t        | d      xs d}t        t        | d      t        | d      xs dt        | d            }t        | d      D ]  }t	        |      j                         }t        d |D        d	      }|d
k(  r:t        |d      }t        |d
      }|sO|j                  j                  ||d       n|dk(  stt        |d      }|s|j                  d      st        |d      xs d}	|j                  j                  t        |	t        |d
      xs |t        |d      xs d|d              t        | d      D ]  }
t	        |
      j                         }t        |d      }t        |d      }|s7|j                  j                  t        |xs dt        |j                         |t        |d
      xs d              t        | d      D ]  }t	        |      j                         }t        |d      }|s+|j                  d      s=t        |d      xs d}	|j                  j                  t        |	t        |d
      xs d||	d
k(                |S )z8Build DeliveryResult from parsed AppDeliveryData fields.   r   r}   r:   rn   )rB   rC   rD   rx   c              3  4   K   | ]  \  }}}|d k(  s|  yw)r:   Nr   ).0rT   rU   _s       r    	<genexpr>z0_extract_delivery_from_fields.<locals>.<genexpr>/  s     8YRQab8s   Nr0   )r#   valuehttps://F)r(   r   r%   r$   r*      split)r#   r$   r%      )r(   r%   r$   r*   )r\   rA   rZ   r^   r
   r`   nextr.   append
startswithrF   r'   rE   r"   len)rR   app_vcr   f4_bcff1_wtr#   r   r$   ftsplit_bsfaf_bafs                 r    r   r     sH   #(qF"61- +0q61%F 61% $0028"8$?A: Q'D!"a(E%%te&DEaZA&Cs~~j1A&+!''..~ !+B!2!<f#B*/a!0 * fb) 	'"335R#B"MM  9uS%7$89A&+!" 	 62& 
$002B"3>>*-B"'aB##**>A&+!a	, 
 Mr   c                    t        |       }|D cg c]  }|j                  d      sd|v s| }}|s*|D cg c]  }|j                  d      sd|v sd|v s|! }}t               }|r
|d   |_        |S c c}w c c}w )z=Fallback: scan all strings in the protobuf for download URLs.r   zandroid.clients.google.complaygoogr   )r   r   rA   rB   )ra   stringsscdn_urlsr   s        r    r   r   ^  s    c"G"eaall:&>C_cdCdeHe&d!!,,z*BRSW]abWbAddF&qkM fds    A6A6A6A;A;A;c                D   t        |      }t         d|  d| }t        j                  ||d      }|j                  dk(  rt        d      |j                  dk7  rt        d|j                   d	      t        |j                        }|j                  st        d
      |S )z8Fetch download URLs for base APK, splits, and OBB files.r   r   r   r   r   r   r   zDelivery failed (HTTP r   zYNo download URL returned. The app may require purchase or is unavailable for this device.)
rl   DELIVERY_URLr   r;   r   rJ   rH   r   r   rB   )r   r   rj   rk   r$   r   r   s          r    get_deliveryr   k  s    T"GN%y	,
@C99S'26D345533D4D4D3ERHIIT\\*F.
 	

 Mr   c                   t        |      }t        j                  t         d|  |d      }|j                  dk(  rt        d      |j                  dk7  rt        d|j                   d      t        |j                  d	d
d      }|sg S t               }t        |d      }|sg S t        |      j                         }t        |d	      }|sg S t        |      j                         }	t        |	d      D ];  }
t        |
      j                         }t        |d      }|s+|j                  |       = |sHt!        j"                  d      }t%        |      D ]%  }|j'                  |      s|j                  |       ' t)        |      S )z-Return split names from app details metadata.r   r   r   r   r   r   r   )r:   r0   rx   r|   r{   	   z^config\.[a-z])rl   r   r;   r   r   rJ   rH   rf   r   setrW   r
   r`   r^   rZ   addrecompiler   matchsorted)r   rj   rk   r   r   rE   r   r   r   r   file_bffsidsplit_patternr   s                  r    list_splitsr     sr   T"G99}E'3WbQD34553;D<L<L;MQOPP 4<<Aq1J	uF R0M		m	$	5	5	7B Q'M		m	$	5	5	7B R$ &!224B"JJsO	 

#45 / 	A""1%

1	 &>r   c                   g }||kD  r|S 	 t        |       j                         }t        |d      }t        |d      }|rd|v rd|vr|r||t        |d      dgS |D ]Z  \  }}}	|dk(  st	        |	t
        t        f      s$t        |	      dkD  s3|j                  t        t        |	      |dz   |             \ |S # t        $ r |cY S w xY w)	zFRecursively find DocV2 entries (docid at f1, title at f5) in protobuf.r:   rn   . ry   )r   r   rv   r0      )
r
   r`   	ExceptionrZ   rN   rO   rP   r   extend_find_docv2)
rc   depth	max_depthresultsrR   f1_strf5_str_fnrU   rV   s
             r    r   r     s    Gyd#446 61%F61%F#-Cv$5&"VfVW@XYZZ H
R7z!eY%78SVb[NN;uQxIFGH N  s   B: :CCc                   t        |      }t        j                  t         d|  d|d      }|j                  dk(  rt        d      |j                  dk7  rt        d|j                   d	      t        |j                        }t               }g }|D ]=  }|d
   }	|	|vst        |      |k  s|j                  |	       |j                  |       ? |S )zTSearch Google Play via FDFE protobuf API. Returns list of {package, title, creator}.z?q=z&c=3r   r   r   r   r   zSearch failed (HTTP r   r   )rl   r   r;   
SEARCH_URLr   rJ   rH   r   r   r   r   r   r   )
queryrj   limitrk   r   docsseenr   docpkgs
             r    search_appsr     s    T"G99
|3ugT2GRPD345531$2B2B1C1EFFt||$DUDG  )nd?s7|e3HHSMNN3	 
 Nr   )rR   list[tuple[int, int, Any]]rS   r   r=   zOptional[bytes])rR   r   rS   r   r=   r   )rR   r   rS   r   r=   zOptional[int])rR   r   rS   r   r=   zlist[bytes])ra   rO   rb   r   r=   r   )rj   dictr=   r   )rR   r   rS   r   r=   zOptional[float])ra   rO   r=   rt   )r   r   rj   r   r=   rO   )r   r   rj   r   r=   ztuple[str, str, int, str])r   r   rj   r   r=   r   )r   r   r   r   rj   r   r=   None)ra   rO   r=   rA   )rR   r   r=   rA   )r   r   r   r   rj   r   r=   rA   )r   r   rj   r   r=   z	list[str])r   
   )rc   rO   r   r   r   r   r=   r-   )r   )r   r   rj   r   r   r   r=   r-   )1rK   
__future__r   r   ro   dataclassesr   r   typingr   r   r   gplaydl.authr	   gplaydl.protobufr
   r   r   FDFE_URLr   r   r   r   r"   r'   rA   r   rH   rJ   rW   rZ   r\   r^   rf   rl   rr   rt   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    <module>r      sP   # 	  (    & :=
4
(#9%9%       O O O* I I I	9 		| 		1  $ $ $!H
R*.	,<~
2'\*r   