
    jL                       d Z ddlmZ ddlmZmZ ddlmZ ddlm	Z	m
Z
mZmZmZmZmZ ddlmZmZ d_d	Zd`dZdadZdddddbdZdcdddZdedZdfd"Zdgd%Zdgd&Zdgd'Zdgd(Zdgd)Zdgd*Zdgd+Z d,d-iZ!d.d/d0d-g d1d2e!e!e!d3e!d4d,d0id,d5id6d,d-id,d7igd8d,d5id5d9d:d5d;d:d5d<d:d=d gd>d?Z"d@dAd0d-dBdCgd2e!d,d7idDd gd>d?Z#dEdFd0d-dGdHgd2e!e!dId gd>d?Z$dJdKd0e!d3e!d4e!d,d5id,d5ie!e!dLdMgd>d?Z%dNdOd0d-g dPd2e!e!d,d5id,d5ie!e!d,d7id,d7id3e!d4d,d5ie!dQd gd>d?Z&dRdSd0d-dGdTgd2e!e!e!d,d5id,d5idUd gd>d?Z'dVdWd0d-dTdXgdYdZd-g d[d2d,d5id,d5ie!d3e!d4d3e!d4d3e!d4d\d]d gd>d?Z(d^S )hzANative Spotify tools for Hermes (registered via plugins/spotify).    )annotations)AnyList)get_auth_status)SpotifyAPIErrorSpotifyAuthRequiredErrorSpotifyClientSpotifyErrornormalize_spotify_idnormalize_spotify_urinormalize_spotify_uris)
tool_errortool_resultreturnboolc                     	 t          t          d                              d                    S # t          $ r Y dS w xY w)Nspotify	logged_inF)r   r   get	Exception     :/home/ubuntu/.hermes/hermes-agent/plugins/spotify/tools.py_check_spotify_availabler      sM    OI..22;??@@@   uus   .1 
??r	   c                     t                      S N)r	   r   r   r   _spotify_clientr      s    ??r   excr   strc                0   t          | t          t          f          rt          t	          |                     S t          | t
                    r#t          t	          |           | j                  S t          dt          |           j         d|            S )N)status_codezSpotify tool failed: z: )	
isinstancer
   r   r   r   r   r!   type__name__)r   s    r   _spotify_tool_errorr%      s    #&>?@@ $#c((####'' A#c((@@@@Id3ii.@IICIIJJJr         2   )defaultminimummaximumrawr   r)   intr*   r+   c                   	 t          |           }n# t          $ r |}Y nw xY wt          |t          ||                    S r   )r-   r   maxmin)r,   r)   r*   r+   values        r   _coerce_limitr2   '   sR    C   wGU++,,,s    !!Fc                    t          | t                    r| S t          | t                    r2|                                                                 }|dv rdS |dv rdS |S )N>   1onyestrueT>   0noofffalseF)r"   r   r   striplower)r,   r)   cleaneds      r   _coerce_boolr?   /   sk    #t 
#s ))++##%%00041115Nr   	List[str]c                    | g S t          | t                    rd | D             S t          |                                           r"t          |                                           gng S )Nc                    g | ]D}t          |                                          #t          |                                          ES r   )r   r<   ).0items     r   
<listcomp>z_as_list.<locals>.<listcomp>?   s=    GGGdSYY__5F5FGD		!!GGGr   )r"   listr   r<   )r,   s    r   _as_listrG   ;   sf    
{	#t HGGcGGGG!$S!1!19CHHNNr9r   payloadactiondict | Nonec               :   t          | t                    r|                     d          sd S |dk    r1d|d|                     dd          |                     d          pdd	S |d
k    r1d|d|                     dd          |                     d          pddS d S )Nemptyget_currently_playingTFr!      messagez*Spotify is not currently playing anything.)successrI   
is_playingr!   rO   	get_statez-No active Spotify playback session was found.)rP   rI   has_active_devicer!   rO   )r"   dictr   )rH   rI   s     r   _describe_empty_playbackrU   C   s    gt$$ GKK,@,@ t(((";;}c::{{9--]1]
 
 	
 !&";;}c::{{9--`1`
 
 	
 4r   argsrT   c                ~   t          |                     d          pd                                                                          }t	                      }	 |dk    rK|                    |                     d                    }t          ||          }t          |p|          S |dk    rK|                    |                     d                    }t          ||          }t          |p|          S |dk    r|                     d          }t          |t                    rd	 |                                D             }nd }|                     d
          r0t          t          |                     d
                    d          nd }d }	|                     d          rt          |                     d                    }
d }|
                    d          sd|
v rd}n7|
                    d          sd|
v rd}n|
                    d          sd|
v rd}t          |
|          }	|                    |                     d          |	|||                     d                    }t          d||d          S |dk    r<|                    |                     d                    }t          d||d          S |dk    r<|                    |                     d                    }t          d||d          S |dk    r<|                    |                     d                    }t          d||d          S |dk    rt|                     d          t)          d           S |                    t-          | d                   |                     d          !          }t          d||d          S |d"k    rt          |                     d#          pd$                                                                          }|d%vrt)          d&          S |                    ||                     d          '          }t          d||d          S |d(k    r]|                    t3          |                     d#                    |                     d          '          }t          d||d          S |d)k    r|                     d*          t)          d+          S |                    t7          d,t9          d-t-          | d*                                       |                     d          .          }t          d||d          S |d/k    r|                     d0          }|                     d1          }|r|rt)          d2          S t          |                    t=          |                     d3          d45          |t-          |          nd |t-          |          nd 6                    S t)          d7|           S # t>          $ r}tA          |          cY d }~S d }~ww xY w)8NrI   rR   market)rX   )rI   rM   playoffsetc                    i | ]
\  }}|||S r   r   )rC   kvs      r   
<dictcomp>z,_handle_spotify_playback.<locals>.<dictcomp>h   s    !S!S!S41aQ]!Q]]]r   uristrackcontext_urizspotify:album:z/album/albumzspotify:playlist:z
/playlist/playlistzspotify:artist:z/artist/artist	device_idposition_ms)re   ra   r_   rZ   rf   TrP   rI   resultpause)re   nextpreviousseekz)position_ms is required for action='seek')rf   re   
set_repeatstate >   r:   r`   contextz)state must be one of: track, context, off)rn   re   set_shuffle
set_volumevolume_percentz2volume_percent is required for action='set_volume'r   d   )rs   re   recently_playedafterbeforez'Provide only one of 'after' or 'before'limitr&   r)   )rx   rv   rw   z!Unknown spotify_playback action: )!r   r   r<   r=   r   get_playback_staterU   r   rM   r"   rT   itemsr   rG   
startswithr   start_playbackpause_playback	skip_nextskip_previousr   rl   r-   rm   rq   r?   rr   r/   r0   get_recently_playedr2   r   r%   )rV   kwrI   clientrH   empty_resultrZ   payload_offsetr_   ra   raw_contextcontext_typerh   rn   rv   rw   r   s                    r   _handle_spotify_playbackr   Y   s   (##2{3399;;AACCFFK([  //txx7I7I/JJG3GFKKKL|6w777,,,22$((8:L:L2MMG3GFKKKL|6w777VXXh''F&$'' &!S!S6<<>>!S!S!S!%RVRZRZ[aRbRbl)(488F3C3C*D*DgNNNhlDKxx&& 	O!$((="9"9::#))*:;; ,yK?W?W#*LL ++,?@@ ,LT_D_D_#-LL ++,=>> ,*P[B[B[#+L3KNN**((;//'% HH]33 +  F 46VTTUUUW**TXXk5J5J*KKF46VTTUUUV%%0E0E%FFF46VTTUUUZ))DHH[4I4I)JJF46VTTUUUVxx&&.!"MNNN[[Sm1D-E-EQUQYQYZeQfQf[ggF46VTTUUU\!!))/R006688>>@@E777!"MNNN&&Udhh{>S>S&TTF46VTTUUU]""''l488G;L;L.M.MY]YaYabmYnYn'ooF46VTTUUU\!!xx())1!"VWWW&&c!Sc$O_J`FaFa=b=b6c6cosowow  yD  pE  pE&  F  FF46VTTUUU&&&HHW%%EXXh''F M M!"KLLLv99#DHHW$5$5rBBB$)$5c%jjj4&,&8s6{{{d  :       
 FfFFGGG ( ( ("3''''''''(s   AX )AX :F	X AX AX AX 
)X 4AX A X %<X "A"X )X /A+X AX A(X X 
X<#X71X<7X<c                   t          |                     d          pd                                                                          }t	                      }	 |dk    r!t          |                                          S |dk    rt          |                     d          pd                                          }|st          d          S |                    |t          |                     d                              }t          d	||d
          S t          d|           S # t          $ r}t          |          cY d }~S d }~ww xY w)NrI   rF   transferre   ro   z+device_id is required for action='transfer'rY   )re   rY   Trg   z Unknown spotify_devices action: )r   r   r<   r=   r   r   get_devicesr   transfer_playbackr?   r   r%   )rV   r   rI   r   re   rh   r   s          r   _handle_spotify_devicesr      sU   (##-v..4466<<>>FF(Vv1133444ZDHH[117R88>>@@I Q!"OPPP--	UYU]U]^dUeUeHfHf-ggF46VTTUUUEVEEFFF ( ( ("3''''''''(s2   &D( ?AD( A	D( D( (
E2E EEc                Z   t          |                     d          pd                                                                          }t	                      }	 |dk    r!t          |                                          S |dk    rpt          t          |                     d          pd          d           }|                    ||                     d                    }t          d|||d	          S t          d
|           S # t          $ r}t          |          cY d }~S d }~ww xY w)NrI   r   adduriro   re   )r   re   T)rP   rI   r   rh   zUnknown spotify_queue action: )r   r   r<   r=   r   r   	get_queuer   add_to_queuer   r   r%   )rV   r   rI   r   r   rh   r   s          r   _handle_spotify_queuer      s,   (##,u--3355;;==FF	(U??v//11222U??'DHHUOO,Ar(B(BDIIC((SDHH[<Q<Q(RRF46#Y_``aaaC6CCDDD ( ( ("3''''''''(s+   &D ?A5D 5D 
D*D%D*%D*c                   t                      }t          |                     d          pd                                          }|st	          d          S t          |                     d          p|                     d          pdg          }d |D             }|st	          d          S 	 t          |                    ||t          |                     d	          d
          t          dt          |                     d          pd                    |                     d          |                     d                              S # t          $ r}t          |          cY d }~S d }~ww xY w)Nqueryro   zquery is requiredtypesr#   r`   c                b    g | ],}|                                 d v |                                 -S )>   showrb   r`   rd   episoderc   	audiobook)r=   )rC   r1   s     r   rE   z*_handle_spotify_search.<locals>.<listcomp>   sO      W  W  WeEKKMM  NV  =V  =VEKKMM  =V  =V  =Vr   z[types must contain one or more of: album, artist, playlist, track, show, episode, audiobookrx   
   ry   r   rZ   rX   include_external)r   search_typesrx   rZ   rX   r   )r   r   r   r<   r   rG   r   searchr2   r/   r-   r   r%   )rV   r   r   r   	raw_typesr   r   s          r   _handle_spotify_searchr      s   F!!'R((..00E /-...'**Kdhhv.>.>K7)LLI W  Wy  W  W  WL ywxxx
(6==% 1 12>>>q#dhhx005A667788H%%!XX&899 ) 
 
   	  ( ( ("3''''''''(s   .BE 
E1E,&E1,E1c                T   t          |                     d          pd                                                                          }t	                      }	 |dk    rvt          |                    t          |                     d          d          t          dt          |                     d          pd                                        S |d	k    rit          t          |                     d
          pd          d          }t          |                    ||                     d                              S |dk    rt          |                     d          pd                                          }|st          d          S t          |                    |t          |                     d                    t          |                     d                    |                     d                              S |dk    rt          t          |                     d
          pd          d          }t          t!          |                     d                              }t          |                    |||                     d                              S |dk    rt          t          |                     d
          pd          d          }t          t!          |                     d                              }t          |                    |||                     d                              S |dk    rt          t          |                     d
          pd          d          }t          |                    ||                     d          |                     d          |                     d          |                     d                              S t          d|           S # t(          $ r}t+          |          cY d }~S d }~ww xY w) NrI   rF   rx   r&   ry   r   rZ   )rx   rZ   r   playlist_idro   rc   rX   )r   rX   createnamez$name is required for action='create'publiccollaborativedescription)r   r   r   r   	add_itemsr_   position)r   r_   r   remove_itemssnapshot_id)r   r_   r   update_details)r   r   r   r   r   z"Unknown spotify_playlists action: )r   r   r<   r=   r   r   get_my_playlistsr2   r/   r-   r   get_playlistr   create_playlistr?   r   rG   add_playlist_itemsremove_playlist_itemsupdate_playlist_detailsr   r%   )rV   r   rI   r   r   r   r_   r   s           r   _handle_spotify_playlistsr      s   (##-v..4466<<>>FF.(Vv66#DHHW$5$5rBBB1c$((8"4"4"9::;;  7        U??.s488M3J3J3Pb/Q/QS]^^Kv22{SWS[S[\dSeSe2ffgggXtxx''-2..4466D J!"HIIIv55#DHHX$6$677*488O+D+DEE HH]33	  6        [  .s488M3J3J3Pb/Q/QS]^^K)(488F3C3C*D*DEEDv88'*--  9       
 ^##.s488M3J3J3Pb/Q/QS]^^K)(488F3C3C*D*DEEDv;;' HH]33  <       
 %%%.s488M3J3J3Pb/Q/QS]^^Kv=='XXf%%xx))"hh77 HH]33  >        GvGGHHH ( ( ("3''''''''(sO   A;P A.P AP A8P 	BP (BP B*P 2P 
P'P"P'"P'c                J   t          |                     d          pd                                                                          }t	                      }	 t          t          |                     d          p|                     d          pd          d          }|dk    r7t          |                    ||                     d                              S |d	k    rt          |                    |t          |                     d
          d          t          dt          |                     d          pd                    |                     d                              S t          d|           S # t          $ r}t          |          cY d }~S d }~ww xY w)NrI   r   album_ididro   rb   rX   )r   rX   tracksrx   r&   ry   r   rZ   )r   rx   rZ   rX   zUnknown spotify_albums action: )r   r   r<   r=   r   r   r   	get_albumget_album_tracksr2   r/   r-   r   r   r%   )rV   r   rI   r   r   r   s         r   _handle_spotify_albumsr     s   (##,u--3355;;==FF('DHHZ,@,@,XDHHTNN,XVX(Y(Y[bccU??v//$((S[J\J\/]]^^^Xv66!#DHHW$5$5rBBB1c$((8"4"4"9::;;xx))	  7        DFDDEEE ( ( ("3''''''''(s,   BE? BE? -E? ?
F"	FF"F"c                   t          |                     d          pd                                                                          }|dvrt	          d          S t          |                     d          pd                                                                          }|dk    rdnd	t                      }	 |dk    rt          |                     d
          d          }t          dt          |                     d          pd                    }|                     d          }|dk    r%t          |
                    |||                    S t          |                    |||                    S |dk    rht          t          |                     d          p|                     d                              }t          |                    |                    S |dk    rfdt          |                     d          p|                     d                    D             }	|	st	          d          S |dk    r#t          |                    |	                    S t          |                    |	                    S t	          d|           S # t"          $ r}
t%          |
          cY d}
~
S d}
~
ww xY w)zEUnified handler for saved tracks + saved albums (formerly two tools).kindro   >   albumsr   z#kind must be one of: tracks, albumsrI   rF   r   r`   rb   rx   r&   ry   r   rZ   rX   )rx   rZ   rX   saver_   r{   )r_   removec                0    g | ]}t          |          S r   )r   )rC   rD   	item_types     r   rE   z+_handle_spotify_library.<locals>.<listcomp>;  s$    tttT'i88tttr   idsz)ids/items is required for action='remove')	track_ids)	album_idsz Unknown spotify_library action: N)r   r   r<   r=   r   r   r2   r/   r-   r   get_saved_tracksget_saved_albumsr   rG   save_library_itemsremove_saved_tracksremove_saved_albumsr   r%   )rV   r   r   rI   r   rx   rZ   rX   r_   r   r   r   s              @r   _handle_spotify_libraryr   '  s   txx%2&&,,..4466D'''?@@@(##-v..4466<<>>F8++IF(V!$((7"3"3R@@@EC 2 2 7a8899FXXh''Fx"6#:#:v^d#:#e#efffv66U6Z`6aabbbV)(488F3C3C3XtxxPWGXGX*Y*Y[deeDv88d8CCDDDXttttXdhhW\ooNraeaiaijqararEsEstttC O!"MNNNx"6#=#=#=#L#LMMMv99C9HHIIIEVEEFFF ( ( ("3''''''''(sE   >BJ% $J% ?A-J% -AJ% (J% 0"J% J% %
K/K=KKr#   stringspotify_playbackz]Control Spotify playback, inspect the active playback state, or fetch recently played tracks.object)rR   rM   rY   ri   rj   rk   rl   rm   rq   rr   ru   )r#   enumarray)r#   r{   integerzRFor set_repeat use track/context/off. For set_shuffle use boolean-like true/false.boolean)r   oneOfz.For recently_played: number of tracks (max 50))r#   r   z:For recently_played: Unix ms cursor (after this timestamp)z;For recently_played: Unix ms cursor (before this timestamp))rI   re   rX   ra   r_   rZ   rf   rn   rs   rx   rv   rw   )r#   
propertiesrequired)r   r   
parametersspotify_deviceszHList Spotify Connect devices or transfer playback to a different device.rF   r   )rI   re   rY   spotify_queuez6Inspect the user's Spotify queue or add an item to it.r   r   )rI   r   re   spotify_searchzVSearch the Spotify catalog for tracks, albums, artists, playlists, shows, or episodes.)r   r   r#   rx   rZ   rX   r   r   spotify_playlistsz<List, inspect, create, update, and modify Spotify playlists.)rF   r   r   r   r   r   )rI   r   rX   rx   rZ   r   r   r   r   r_   r   r   spotify_albumsz-Fetch Spotify album metadata or album tracks.r   )rI   r   r   rX   rx   rZ   spotify_libraryz\List, save, or remove the user's saved Spotify tracks or albums. Use `kind` to select which.r   zWhich library to operate on)r#   r   r   )rF   r   r   )r   rI   rx   rZ   rX   r_   r   r{   r   N)r   r   )r   r	   )r   r   r   r   )
r,   r   r)   r-   r*   r-   r+   r-   r   r-   )F)r,   r   r)   r   r   r   )r,   r   r   r@   )rH   r   rI   r   r   rJ   )rV   rT   r   r   ))__doc__
__future__r   typingr   r   hermes_cli.authr   plugins.spotify.clientr   r   r	   r
   r   r   r   tools.registryr   r   r   r   r%   r2   r?   rG   rU   r   r   r   r   r   r   r   COMMON_STRINGSPOTIFY_PLAYBACK_SCHEMASPOTIFY_DEVICES_SCHEMASPOTIFY_QUEUE_SCHEMASPOTIFY_SEARCH_SCHEMASPOTIFY_PLAYLISTS_SCHEMASPOTIFY_ALBUMS_SCHEMASPOTIFY_LIBRARY_SCHEMAr   r   r   <module>r      sN   G G " " " " " "         + + + + + +                  3 2 2 2 2 2 2 2      K K K K /1SU - - - - - -	 	 	 	 	: : : :   ,N( N( N( N(b( ( ( ("( ( ( (( ( ( (,1( 1( 1( 1(h( ( ( (&( ( ( (> " r'  2C  2C  2C  D  D&#($}==x("I.%y  GM  OW  FX  [a  cl  Zm  En  o  o%y1'8hii'8tuu(9vww
 
 J!   0 ]'&*1EFF&Y'
 

 J    K'%@@ &
 

 J    k"%>>!i(y)# -
 
 I   &  Q'1y1y1yzz(#i(y)!(y)$i0$}==+(
 
 J!   0 B'%1BCC%#i(y)
 
 J   $ q%(/CTqrr'1K1K1KLLi(y)#$}==#m<<%>>	
 	
 X&     r   