
    j1@                        d dl mZ d dlZd dlZd dlZd dlZd dlmZmZ d dl	m
Z
 d dlmZ d dlmZmZmZmZ  G d d          Z G d	 d
          ZddZd dZd!dZd"dZd#dZd$dZdS )%    )annotationsN)BaseHTTPRequestHandlerThreadingHTTPServer)Path)Any)parse_qsquoteunquoteurlparsec                  6    e Zd ZddZdd
ZddZddZddZdS )
RedisCache	redis_url
str | Nonettlintc                   || _         d | _        |sd S 	 dd l}|j                            |d          | _        | j                                         d S # t          $ r'}t          j        d|           d | _        Y d }~d S d }~ww xY w)Nr   T)decode_responseszRedis cache disabled: %s)	r   clientredisRedisfrom_urlping	Exceptionloggingwarning)selfr   r   r   excs        moviebot\addons\nuvio_addon.py__init__zRedisCache.__init__   s     	F	LLL+..y4.PPDKK 	 	 	O6<<<DKKKKKKK	s   >A 
BB  Bkeystrreturn
Any | Nonec                x    | j         sd S | j                             |          }|rt          j        |          nd S N)r   getjsonloadsr   r    values      r   get_jsonzRedisCache.get_json   s>    { 	4$$$)3tz%   t3    r*   r   Nonec                    | j         r7| j                             || j        t          j        |d                     d S d S )NFensure_ascii)r   setexr   r'   dumpsr)   s      r   set_jsonzRedisCache.set_json"   sJ    ; 	TKc48TZE-R-R-RSSSSS	T 	Tr,   c                H    | j         sd S | j                             |          S r%   )r   r&   )r   r    s     r   get_textzRedisCache.get_text&   s%    { 	4{s###r,   c                Z    | j         r#| j                             || j        |           d S d S r%   )r   r1   r   r)   s      r   set_textzRedisCache.set_text+   s8    ; 	4Kc48U33333	4 	4r,   N)r   r   r   r   )r    r!   r"   r#   )r    r!   r*   r   r"   r-   )r    r!   r"   r   )r    r!   r*   r!   r"   r-   )__name__
__module____qualname__r   r+   r3   r5   r7    r,   r   r   r      s|           4 4 4 4T T T T$ $ $ $
4 4 4 4 4 4r,   r   c                  @    e Zd ZddZddZdd dZd!dZd"dZd#dZdS )$NuvioRepositorydb_pathr!   content_rootplaylist_mountc                    t          |                                                                          dz   | _        t          |                                          | _        |                    d          | _        d S )Nz?mode=ro/)r   resolveas_uridb_urir?   stripr@   )r   r>   r?   r@   s       r   r   zNuvioRepository.__init__1   sd    7mm++--4466C ..6688,22377r,   
media_typeid_kinditem_idseason
int | Noneepisodeplaylist_public_urlr"   list[dict[str, Any]]c                   |dk    rdn	|dk    rdnd}d}|                     |          }||g}	|dk    r |||d	z  }|	                    ||g           |d
z  }t          j        | j        d          5 }
t          j        |
_        |
                    ||	                                          }d d d            n# 1 swxY w Y   g }|D ]}t          |d         pd          
                                }|d         p	|d         pd}| d| }|dk    r3dt          |d                   ddt          |d                   dd| }|                    d||                    d           dt          |d                    dd           |S )N	webmoviesm.idimdb	m.imdb_id	m.tmdb_ida  
            SELECT e.access_key, e.filename, e.season, e.episode, e.cleaned_m3u8_path,
                   e.crawl_status, s.name AS server_name, e.source, m.title, m.year
            FROM episodes e
            JOIN movies m ON m.id = e.movie_id
            LEFT JOIN servers s ON s.id = e.server_id
            WHERE m.media_type = ? AND {id_column} = ? AND e.crawl_status = 'success'
        )	id_columntvz# AND e.season = ? AND e.episode = ?z$ ORDER BY e.source, s.priority, e.idTurisource server_namefilenameServerz - SrJ   02ErL   	WebMoviesrB   
access_keyz.m3u8)nametitleurl)formatextendsqlite3connectrE   Rowrow_factoryexecutefetchallr!   upperr   appendrstripr	   )r   rG   rH   rI   rJ   rL   rM   rU   queryparamsconnrowsstreamsrowrY   serverrd   s                    r   ru   zNuvioRepository.streams6   s+    &44FFTZIZIZ++`k	 y11'1&"49L::EMM67+,,,77_T[d333 	:t&{D<<v..7799D	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	:  	 	CX,"--3355F'F3z?FhF**&**ET!!VCH..VVVCI4G4GVVVuVVNN'"188==__c,FW@X@X___        5:B;;B?B?Nd   searchr   limitr   c           	        d}|g}|r8|dz  }d| d}|                     |||||                    d          g           |dz  }|                    |           t          j        | j        d          5 }t          j        |_        |                    ||          	                                }d d d            n# 1 swxY w Y   g }	|D ]w}
|
d         d	k    rd	nd
}t          |
          }|||
d         |
d         |
d         |
d         d}|
d         rt          |
d                   |d<   |	                    |           x|	S )Na  
            SELECT m.id, m.tmdb_id, m.imdb_id, m.media_type, m.title, m.original_title, m.year,
                   m.poster_url, m.backdrop_url, m.content, MAX(m.updated_at) AS updated_at
            FROM movies m
            WHERE m.media_type = ?
              AND EXISTS (
                  SELECT 1 FROM episodes e
                  WHERE e.movie_id = m.id AND e.crawl_status = 'success'
              )
        zl AND (m.title LIKE ? OR m.original_title LIKE ? OR m.tmdb_id = ? OR m.imdb_id = ? OR CAST(m.id AS TEXT) = ?)%
webmovies:z1 GROUP BY m.id ORDER BY m.updated_at DESC LIMIT ?TrW   rG   movieseriesrd   
poster_urlbackdrop_urlcontentidtyperc   poster
backgrounddescriptionyearreleaseInfo)rg   removeprefixro   rh   ri   rE   rj   rk   rl   rm   external_or_local_idr!   )r   rG   rz   r{   rq   rr   likers   rt   metasrv   	item_typemeta_idmetas                 r   catalogzNuvioRepository.catalogc   s   	 (L 	[  D  DE v===DMM4vvv7J7J<7X7XYZZZDDe_T[d333 	:t&{D<<v..7799D	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	:  	 	C#&|#4#?#?XI*3//G!Gl+!.1"9~ D 6{ 7&)#f+&6&6]#LLrx   dict[str, Any] | Nonec           
     N   |dk    rdn	|dk    rdnd}d| d}t          j        | j        d	          5 }t           j        |_        |                    |||f                                          }|s	 d d d            d S g }|d
k    r|                    d|d         f                                          }	t          |          }
|	D ]^}t          |d                   }t          |d                   }|
                    |
 d| d| |d         p	d|dd|d||d           _d d d            n# 1 swxY w Y   |d         dk    rdnd}t          |          }|||d         |d         |d         |d         d}|d         rt          |d                   |d<   |r||d<   |S )NrP   rQ   rR   rS   rT   z
            SELECT m.id, m.tmdb_id, m.imdb_id, m.media_type, m.title, m.original_title, m.year,
                   m.poster_url, m.backdrop_url, m.content
            FROM movies m
            WHERE m.media_type = ? AND z! = ?
            LIMIT 1
        TrW   rV   a  
                    SELECT season, episode, title
                    FROM episodes
                    WHERE movie_id = ? AND crawl_status = 'success'
                    GROUP BY season, episode
                    ORDER BY season, episode
                    r   rJ   rL   :rd   r^   r_   r`   )r   rd   rJ   rL   rG   r   r   r   r   r   r   r   r   videos)rh   ri   rE   rj   rk   rl   fetchonerm   r   r   ro   r!   )r   rG   rH   rI   rU   rq   rs   r   r   
video_rowsbase_idrv   rJ   rL   r   r   r   s                    r   r   zNuvioRepository.meta   s   %44FFTZIZIZ++`k	 )2	   _T[d333 	t&{DLLW(=>>GGIIE 		 	 	 	 	 	 	 	
 FT!!!\\ 4[N	 	 (**  /u55% 
 
C X//F!#i.11GMM%,"A"Av"A"A"A"A%(\%Q5Q5Q5Q5QW5Q5Q5Q&,'.	    +	 	 	 	 	 	 	 	 	 	 	 	 	 	 	<  %\2g==GG8	&u--'NL)/ +
 
 = 	5"%eFm"4"4D 	$#DNs   ?D3 B'D33D7:D7rb   c                   t          j        | j        d          5 }|                    d|f                                          }d d d            n# 1 swxY w Y   |r|d         sd S |                     |d                   }|                                r|                                sd S |                    d          S )NTrW   zXSELECT cleaned_m3u8_path FROM episodes WHERE access_key = ? AND crawl_status = 'success'r   utf-8)encoding)	rh   ri   rE   rl   r   _db_playlist_path_to_fileexistsis_file	read_text)r   rb   rs   rv   paths        r   playlist_contentz NuvioRepository.playlist_content   s    _T[d333 	t,,j  hjj 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	
  	#a& 	4--c!f55{{}} 	DLLNN 	4~~w~///s   *AAAr   c                    d| j          d}|                    |          r| j        |                    d          z  S | j        | j         z  |                    d          z  S )NrB   )r@   
startswithr?   lstrip)r   r>   prefixs      r   r   z)NuvioRepository._db_playlist_path_to_file   sg    +T(+++f%% 	;$w~~c':'::: 4#669L9LLLr,   )r>   r!   r?   r!   r@   r!   )rG   r!   rH   r!   rI   r!   rJ   rK   rL   rK   rM   r!   r"   rN   )Nry   )rG   r!   rz   r   r{   r   r"   rN   )rG   r!   rH   r!   rI   r!   r"   r   )rb   r!   r"   r   )r>   r!   r"   r   )	r8   r9   r:   r   ru   r   r   r   r   r;   r,   r   r=   r=   0   s        8 8 8 8
+ + + +Z& & & & &P5 5 5 5n0 0 0 0M M M M M Mr,   r=   r   r!   r"   3tuple[str, str, str, int | None, int | None] | Nonec                   t          j        d|           }|sd S |                    d                                          }|dv rdnd}t	          |                    d                                        dd          }|                    d          }|d	         d
k    rt          |          dk    r|d         }t          |          dk    r/|d                                         rt          |d                   nd }t          |          dk    r/|d                                         rt          |d                   nd }|d
|||fS |d	         dk    rt          |          dk    r|d         }	t          |          dk    r/|d                                         rt          |d                   nd }t          |          dk    r/|d                                         rt          |d                   nd }|d|	||fS |
                    d          rt          |          dk    r/|d                                         rt          |d                   nd }t          |          dk    r/|d                                         rt          |d                   nd }|d|d	         ||fS |                                r|d
|d d fS d S )Nz^/stream/([^/]+)/(.+)\.json$   >   r   moviesr   rV      rB   r   r   tmdb      rP   ttrR   )rematchgrouplowerr
   replacesplitlenisdigitr   r   )
r   r   raw_typerG   rI   partstmdb_idrJ   rL   movie_ids
             r   parse_stream_requestr      s   H4d;;E t{{1~~##%%H$(;;;Jekk!nn%%--c377GMM#EQx6c%jjAoo("%e**//eAh6F6F6H6H/U1Xd#&u::??uQx7G7G7I7I?#eAh---t67FG;;Qx;3u::??8"%e**//eAh6F6F6H6H/U1Xd#&u::??uQx7G7G7I7I?#eAh---t;&'AA$ ="%e**//eAh6F6F6H6H/U1Xd#&u::??uQx7G7G7I7I?#eAh---t658VW<< 767D$664r,   tuple[str, str, str] | Nonec                F   t          j        d|           }|sd S |                    d                                          }|dv rdnd}t	          |                    d                                        dd          }|                    d          }|d	         d
k    rt          |          dk    r|d
|d         fS |d	         dk    rt          |          dk    r|d|d         fS |                    d          r|d|d	         fS |	                                r|d
|fS d S )Nz^/meta/([^/]+)/(.+)\.json$r   >   r   r   r   rV   r   rB   r   r   r   rP   r   rR   )
r   r   r   r   r
   r   r   r   r   r   )r   r   r   rG   rI   r   s         r   parse_meta_requestr      s/   H2D99E t{{1~~##%%H$(;;;Jekk!nn%%--c377GMM#EQx6c%jjAoo658++Qx;3u::??;a00$ ,658++ +67**4r,   rv   sqlite3.Rowc                ^    | d         r| d         S | d         rd| d          S d| d          S )Nimdb_idr   tmdb:r~   r   r;   )rv   s    r   r   r     sH    
9~ 9~
9~ ('s9~'''#D	###r,   configdictr-   c           	        |                      dd          }t          |                      dd                    }|                      dd|           |                      d          pt          |                      d          t          |                      d	d
                              t          | d         |                      dd          |                      dd                     G fddt                    }t          j        d||           t          ||f|                                           d S )Nhostz0.0.0.0portiX  
public_urlzhttp://localhost:rM   r   	cache_ttli,  r>   r?   .r@   z/m3u8c                  \    e Zd Z fdZdfdZdfdZdfdZdfd	ZddZdS ) run_nuvio_addon.<locals>.Handlerc                   t          | j                  }t          |j                  }|dk    r|                     ddi          S |dk    r"|                     t	                              S |                    d          r|                     |          S |                    d          r|                     |          S |                    d          r|                     ||j	                  S t          j        d|          }|r(|                     |                    d	                    S |                     d
d           d S )Nz/healthstatusokz/manifest.jsonz/meta/z/stream/z	/catalog/z^/(?:playlist/)?([^/]+)\.m3u8$r     z	Not found)r   r   r
   
_send_jsonmanifestr   _handle_meta_handle_stream_handle_catalogrq   r   r   _handle_playlistr   
send_error)r   parsedr   playlist_matchaddon_public_urls       r   do_GETz'run_nuvio_addon.<locals>.Handler.do_GET  s>   di((F6;''Dy  $'7888'''x0@'A'ABBBx(( /((...z** 1**4000{++ @++D&,???X&GNNN F,,^-A-A!-D-DEEEOOC-----r,   r   r!   c           
     t   t          |          }|s|                     dg i          S |\  }}}}}d| d| d| d|pd d|pd 
}                    |          }	|	|                     |	          S d                    |||||          i}
                    ||
           |                     |
          S )Nru   znuvio:stream:r   r   )r   r   r+   ru   r3   )r   r   requestrG   rH   rI   rJ   rL   	cache_keycachedpayloadcacherM   repos              r   r   z/run_nuvio_addon.<locals>.Handler._handle_stream'  s    *400G 8	2777<C9J&'e
eeWeeweeSTeeW^WcbceeI^^I..F!v... $,,z7GVU\^q"r"rsGNN9g...??7+++r,   c                V   t          |          }|s|                     dd i          S |\  }}}d| d| d| }	                    |          }||                     |          S d
                    |||          i}	                    ||           |                     |          S )Nr   znuvio:meta:r   )r   r   r+   r   r3   )r   r   r   rG   rH   rI   r   r   r   r   r   s            r   r   z-run_nuvio_addon.<locals>.Handler._handle_meta4  s    (..G 7~666+2(JFjFF7FFWFFI^^I..F!v...tyyWgFFGGNN9g...??7+++r,   rq   c                R   t          ||          }|s|                     dg i          S |\  }}d| d|pd }	                    |          }||                     |          S d
                    ||          i}	                    ||           |                     |          S )Nr   znuvio:catalog:r   rZ   )parse_catalog_requestr   r+   r   r3   )r   r   rq   r   rG   rz   r   r   r   r   r   s            r   r   z0run_nuvio_addon.<locals>.Handler._handle_catalogA  s    +D%88G 6}555!(JDDDflDDI^^I..F!v...Z @ @AGNN9g...??7+++r,   rb   c                   d| }                     |          }|E                    |          }||                     dd           d S                     ||           |                     d           |                     dd           |                     dd           |                                  | j                            |	                    d	                     d S )
Nznuvio:playlist:r   zPlaylist not found   Content-Typez,application/vnd.apple.mpegurl; charset=utf-8zCache-Controlzpublic, max-age=60r   )
r5   r   r   r7   send_responsesend_headerend_headerswfilewriteencode)r   rb   r   r   r   r   s       r   r   z1run_nuvio_addon.<locals>.Handler._handle_playlistN  s    6*66InnY//G//
;;?OOC)=>>>Fy'222s###^-[\\\_.BCCCJW^^G4455555r,   r   dict[str, Any]c                j   t          j        |d                              d          }|                     d           |                     dd           |                     dt          t          |                               |                                  | j        	                    |           d S )NFr/   r   r   r   zapplication/json; charset=utf-8zContent-Length)
r'   r2   r   r   r   r!   r   r   r   r   )r   r   bodys      r   r   z+run_nuvio_addon.<locals>.Handler._send_json]  s    :gE:::AA'JJDs###^-NOOO-s3t99~~>>>JT"""""r,   N)r   r!   )r   r!   rq   r!   )rb   r!   )r   r   )	r8   r9   r:   r   r   r   r   r   r   )r   r   rM   r   s   r   Handlerr     s        	. 	. 	. 	. 	.$	, 	, 	, 	, 	, 	, 	, 	,	, 	, 	, 	, 	, 	, 	,	, 	, 	, 	, 	, 	, 	,	6 	6 	6 	6 	6 	6 	6	# 	# 	# 	# 	# 	#r,   r   z#Serving Nuvio addon at http://%s:%s)	r&   r   r   r=   r   r   infor   serve_forever)r   r   r   r   r   r   rM   r   s       @@@@r   run_nuvio_addonr     s^   ::fi((Dvzz&$''((Dzz,0JD0J0JKK **%:;;O?Ovzz+..FJJ{C4P4P0Q0QRRE6),fjj.M.MvzzZjlsOtOtuuDO# O# O# O# O# O# O# O# O# O#( O# O# O#b L6dCCCtg..<<>>>>>r,   rq   tuple[str, str | None] | Nonec                   t          j        d|           }|sd S |                    d                                          }|dv rdnd}|                    d          pd}d }|                    d          r|                    d	d          d         }|Et          |          }|                    d
          p|                    d          }|r|d         nd }||rt          |          nd fS )Nz,^/catalog/([^/]+)/webmovies(?:/(.+))?\.json$r   >   r   r   r   rV   r   rZ   zsearch==rz   rq   r   )	r   r   r   r   r   r   r   r&   r
   )	r   rq   r   r   rG   extrarz   rr   search_valuess	            r   r   r   i  s    HDdKKE t{{1~~##%%H$(;;;JKKNN bEF	"" (S!$$Q'~%

8,,C

70C0C%2<q!!&:wvd::r,   r   r   c                T    ddddg dddgddd	d
ddgddddd
ddgdgg ddddd	S )Nznet.dongnq.webmoviesz1.0.0ra   z+Streams from the WebMovies crawler database)streamr   r   r   r   rP   zWebMovies Moviesrz   T)rc   
isRequired)r   r   rc   r   zWebMovies TVShows)r   r   r~   F)configurableconfigurationRequired)	r   versionrc   r   	resourcestypescatalogs
idPrefixesbehaviorHintsr;   )r   s    r   r   r   z  s    $D2228$K9K`hx|W}W}V~[:Mbjz~YY  YA  B  B
 433*/%PP  r,   )r   r!   r"   r   )r   r!   r"   r   )rv   r   r"   r!   )r   r   r"   r-   )r   r!   rq   r!   r"   r   )r   r!   r"   r   )
__future__r   r'   r   r   rh   http.serverr   r   pathlibr   typingr   urllib.parser   r	   r
   r   r   r=   r   r   r   r   r   r   r;   r,   r   <module>r     s   " " " " " "   				  C C C C C C C C             ; ; ; ; ; ; ; ; ; ; ; ; 4  4  4  4  4  4  4  4FcM cM cM cM cM cM cM cML   6   &$ $ $ $Z? Z? Z? Z?z; ; ; ;"     r,   