o
    XhG                    @   s  d dl Zd dlZd dlZd dlZd dlZd dlZd dlZd dl	Zd dl
Z
d dlZd dlZd dlZd dlZd dlZdZejeZejedZejedZejedZejedZejdZejdZd	Zd
ZdZejdZ i Z!dZ"dZ#i Z$dd Z%G dd dej&j'Z(dd Z)e*dkre)  e+d e+d e+d e+d e+d e+d e,defe(Z-e+de  e-.  W d   dS 1 sw   Y  dS dS )    NA  ztaskmgr.htmlzauto-config.htmlz
about.htmlzandroid.html~/usr/local/binz~/appsz!http://berrystore.sw7ft.com/bins/z!http://berrystore.sw7ft.com/apps/z!http://berrystore.sw7ft.com/apks/z
~/.profilei,  
   c           	   
   C   s8  t   }|tv rt| \}}|| tk r|S zJtj| }tjj|td1}|jdkr@t	d|  d|j  	 W d   W dS |
  }||ft|< |W  d   W S 1 sYw   Y  W dS  tjjtjfy } z*t	d|  d|  |tv rt| \}}t	d|  |W  Y d}~S W Y d}~dS d}~ww )	z2Get data from cache or fetch from URL with timeouttimeout   zFailed to fetch 	: Status NzError fetching : zUsing stale cache for )timecacheCACHE_DURATIONurllibrequestRequesturlopenREQUEST_TIMEOUTstatusprintreaddecodeerrorURLErrorsocketr   )	url	cache_keycurrent_timecached_timecached_datar   responsedatae r!   L/var/www/vhosts/berrystore.sw7ft.com/httpdocs/apps/Sept14-TaskApp/taskapp.pyget_cached_or_fetch(   s2   
(r#   c                   @   s,  e Zd Zdd Zdd Zdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Zdd ZdIddZdd ZdIddZdIddZd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- ZdId.d/Zd0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; Zd<d= Z d>d? Z!d@dA Z"dBdC Z#dDdE Z$dFdG Z%dHS )JTaskManagerHandlerc           	      C   s>  t j| j}| jdrt j|j}|ddgd }|ddgd }|ddgd }|ddgd }|d	krE|rE| || n>|d
krQ|rQ| 	| n2|dkr^|r^| 
|| n%|dkrk|rk| || n|dkrx|rx| || n|dkr|r| | | jdd}| d | d| |   d S | jdr| d | dd |   |  }| j|  d S | jdkr|   d S | jdkr|   d S | jdkr|   d S | jdkr|   d S | jdr|   d S | jdkr|   d S | d | dd |   |  }| j|  d S )Nz/actionaction r   app_namepidapp_typeclistartstopinstalldeleteenable_auto_startdisable_auto_startReferer/i/  Locationz/auto-configr   Content-type	text/htmlz/aboutz/androidz/api/available-cliz/api/available-webz/api/app-detailsz/news)r   parseurlparsepath
startswithparse_qsqueryget	start_appstop_appinstall_app
delete_appenable_auto_start_appdisable_auto_start_appheaderssend_responsesend_headerend_headersgenerate_auto_config_htmlwfilewriteencodeserve_about_pageserve_android_pageserve_available_cli_jsonserve_available_web_jsonserve_app_detailsserve_news_pagegenerate_html)	selfparsed_pathparamsr%   r'   r(   r)   refererhtmlr!   r!   r"   do_GETH   s\   







zTaskManagerHandler.do_GETc              
   C   ~   z|   }| d | dd |   | j|  W dS  ty> } ztd|  | 	dd W Y d}~dS d}~ww )z1Serve available CLI apps as JSON for lazy loadingr   r4   r5   z"Error serving available CLI apps:   zError loading CLI appsN)
generate_available_cli_htmlrD   rE   rF   rH   rI   rJ   	Exceptionr   
send_errorrR   rV   r    r!   r!   r"   rM         
z+TaskManagerHandler.serve_available_cli_jsonc              
   C   rX   )z1Serve available web apps as JSON for lazy loadingr   r4   r5   z"Error serving available web apps: rY   zError loading web appsN)
 generate_available_web_apps_htmlrD   rE   rF   rH   rI   rJ   r[   r   r\   r]   r!   r!   r"   rN      r^   z+TaskManagerHandler.serve_available_web_jsonc           
   
   C   s  zct j| j}t j|j}|ddgd }|ddgd }|s,| dd W dS | ||}t j	|d	 }d
| d| }||d}| 
d | dd |   | jt|  W dS  ty }	 ztd|	  | dd W Y d}	~	dS d}	~	ww )z/Serve app details including overview.md contentr'   r&   r   r)   r*   i  zApp name requiredNz.zipz /action?action=install&app_name=
&app_type=)descriptioninstall_urlr   r4   zapplication/jsonzError serving app details: rY   zError loading app details)r   r6   r7   r8   r:   r;   r<   r\   get_app_descriptionquoterD   rE   rF   rH   rI   jsondumpsrJ   r[   r   )
rR   rS   rT   r'   r)   ra   app_encodedrb   r   r    r!   r!   r"   rO      s.   
z$TaskManagerHandler.serve_app_detailsc           	   
   C   sP  z\|dkrt jt| d}n
t jt| d}t j|}t jj|td*}|j	dkrD|
 d}| |}|W  d   W S d| dW  d   W S 1 sUw   Y  W dS  t jjt jjtjfy } ztd	| d
|  d| dW  Y d}~S d}~w ty } ztd| d
|  d| dW  Y d}~S d}~ww )z
        Fetch app description from overview.md file on the server.
        Returns formatted HTML description or fallback text.
        r*   z/overview.mdr   r   utf-8Nz <p>No description available for z.</p>zError fetching overview.md for r	   z!Error processing overview.md for )r   r6   urljoinAVAILABLE_APPS_URLWEB_APPS_URLr   r   r   r   r   r   r   markdown_to_htmlr   r   	HTTPErrorr   r   r   r[   )	rR   r'   r)   overview_urlr   r   contenthtml_contentr    r!   r!   r"   rc      s,   


(
z&TaskManagerHandler.get_app_descriptionc              
   C   s$  z| d}g }d}|D ]}| }|s#|r|d d}|d q|dr6|d|dd  d	 q|d
rI|d|dd  d q|dr\|d|dd  d q|dsf|dr}|so|d d}|d|dd  d qd|v rd|v rd|v rddl}|dd|}|d| d qd |v r|d d!d"d d#d"}|d| d qd$|v r|d$d%d"d$d&d"}|d| d q|r|d d}|d| d q|r|d d|W S  ty } zt	d'|  d| dW  Y d}~S d}~ww )(z
        Convert basic markdown to HTML for display in modal.
        Handles common markdown elements like headers, paragraphs, lists, and links.
        
Fz</ul>z<br>z# z<h2>   Nz</h2>z## z<h3>   z</h3>z### z<h4>   z</h4>z- z* z<ul>Tz<li>z</li>[z]()r   z\[([^\]]+)\]\(([^)]+)\)z#<a href="\2" target="_blank">\1</a>z<p>z</p>z**z<strong>   z	</strong>*z<em>z</em>z#Error converting markdown to HTML: )
splitstripappendr9   resubreplacejoinr[   r   )rR   markdown_textlines
html_linesin_listliner|   r    r!   r!   r"   rl      sZ   








z#TaskManagerHandler.markdown_to_htmlc              
   C   s   z#|   }| |}| d | dd |   | j|  W dS  tyC } zt	d|  | 
dd W Y d}~dS d}~ww )z/Serve the news page with content from news.jsonr   r4   r5   zError serving news page: rY   zError loading newsN)load_news_datagenerate_news_htmlrD   rE   rF   rH   rI   rJ   r[   r   r\   )rR   	news_data	news_htmlr    r!   r!   r"   rP   "  s   

z"TaskManagerHandler.serve_news_pagec              
   C   s   z3t jtd}t j|sg ddW S t|ddd}t|W  d   W S 1 s,w   Y  W dS  tyQ } zt	d|  g ddW  Y d}~S d}~ww )	z"Load news data from news.json filez	news.jsonr&   )newslast_updatedrrh   )encodingNzError loading news data: )
osr8   r   BASE_DIRexistsopenre   loadr[   r   )rR   news_file_pathfr    r!   r!   r"   r   4  s   (z!TaskManagerHandler.load_news_datac           
      C   s   zYd}| dr?|d D ]1}| |d }| dd}| dd}| dd}|d	|d
  d| d| d| d| d7 }qn|d7 }| dd}|rS|d| d7 }|d7 }|W S  tys }	 ztd|	  W Y d}	~	dS d}	~	ww )zGenerate HTML for the news pagea&  <!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1, user-scalable=no">
    <title>BB10 News</title>
    <style>
        body {
            background-color: #1e1e1e;
            color: white;
            font-family: "Slate Pro", Slate, "Myriad Pro", Helvetica, sans-serif;
            font-size: 14px;
            margin: 0;
            padding: 0;
        }
        .header {
            background-color: #2b2b2b;
            border-bottom: 2px solid #00769e;
            padding: 10px 20px;
            color: white;
            height: 60px;
            line-height: 40px;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            z-index: 1000;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        h1 {
            font-size: 20px;
            flex-grow: 1;
            text-align: center;
            margin: 0;
        }
        .hamburger {
            cursor: pointer;
            width: 30px;
            height: 25px;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
        }
        .hamburger div {
            width: 100%;
            height: 4px;
            background-color: white;
            border-radius: 2px;
        }
        .dropdown {
            position: relative;
            display: inline-block;
        }
        .dropdown-content {
            display: none;
            position: absolute;
            right: 0;
            top: 35px;
            background-color: #2b2b2b;
            min-width: 160px;
            box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
            z-index: 1001;
            border: 1px solid #00769e;
            border-radius: 4px;
        }
        .dropdown-content a {
            color: white;
            padding: 12px 16px;
            text-decoration: none;
            display: block;
        }
        .dropdown-content a:hover {
            background-color: #00769e;
        }
        .dropdown:hover .dropdown-content {
            display: block;
        }
        .content {
            padding: 80px 20px 20px 20px;
        }
        .news-item {
            background-color: #2b2b2b;
            border: 1px solid #00769e;
            border-radius: 8px;
            margin-bottom: 20px;
            padding: 20px;
        }
        .news-header {
            border-bottom: 1px solid #00769e;
            padding-bottom: 10px;
            margin-bottom: 15px;
        }
        .news-title {
            font-size: 18px;
            font-weight: bold;
            color: #00769e;
            margin: 0 0 5px 0;
        }
        .news-meta {
            font-size: 12px;
            color: #888;
        }
        .news-category {
            display: inline-block;
            background-color: #00769e;
            color: white;
            padding: 2px 8px;
            border-radius: 4px;
            font-size: 10px;
            margin-left: 10px;
        }
        .news-content {
            line-height: 1.6;
        }
        .news-content p {
            margin: 0 0 10px 0;
        }
        .news-content ul {
            margin: 10px 0;
            padding-left: 20px;
        }
        .news-content li {
            margin: 5px 0;
        }
        .news-content strong {
            color: #00769e;
        }
        .no-news {
            text-align: center;
            color: #888;
            font-style: italic;
            padding: 40px 20px;
        }
        .last-updated {
            text-align: center;
            color: #888;
            font-size: 12px;
            margin-top: 20px;
            padding-top: 20px;
            border-top: 1px solid #333;
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>BB10 News</h1>
        <div class="dropdown">
            <div class="hamburger">
                <div></div>
                <div></div>
                <div></div>
            </div>
            <div class="dropdown-content">
                <a href="/">Back to Task Manager</a>
                <a href="/auto-config">Auto Start Apps</a>
                <a href="/android">Android Apps</a>
                <a href="/about">About Sw7ft</a>
            </div>
        </div>
    </div>
    <div class="content">
        <h2>Latest Updates</h2>r   ro   dateUnknownauthorcategorygeneralzo
        <div class="news-item">
            <div class="news-header">
                <div class="news-title">titlezC</div>
                <div class="news-meta">
                    z by z1
                    <span class="news-category">zi</span>
                </div>
            </div>
            <div class="news-content">
                z"
            </div>
        </div>z
        <div class="no-news">
            <p>No news available at the moment.</p>
            <p>Check back soon for updates!</p>
        </div>r   r&   z>
        <div class="last-updated">
            Last updated: z
        </div>z
    </div>
</body>
</html>zError generating news HTML: Nz5<html><body><h1>Error loading news</h1></body></html>)r<   rl   r[   r   )
rR   r   rV   	news_itemcontent_htmldate_str
author_strcategory_strr   r    r!   r!   r"   r   A  sD    
&

z%TaskManagerHandler.generate_news_htmlc              
   C   s   z3t td}| }W d   n1 sw   Y  | d | dd |   | j|  W dS  t	yS } zt
d|  | dd W Y d}~dS d}~ww )	zServe the about.html page.r   Nr   r4   r5   zError loading about.html: rY   zError loading about.html)r   ABOUT_TEMPLATE_PATHr   rD   rE   rF   rH   rI   rJ   r[   r   r\   )rR   filerV   r    r!   r!   r"   rK     s   

z#TaskManagerHandler.serve_about_pagec           
      C   s&  zr|   }ttd}| }W d   n1 sw   Y  |s#d}n0d}|D ]'}tj|d }tj	t
|}| |}|d| d| d| d	| d
	7 }q'|d7 }|d|}| d | dd |   | j|  W dS  ty }	 ztd|	  | dd W Y d}	~	dS d}	~	ww )zMServe the android.html page, after populating it with the list of .apk files.r   Nz)<div class="no-apps">No APKs found.</div>z(<div id="apkContainer" class="app-grid">r   z:
                    <div class="app-card" data-category="z">
                        <div class="app-card-header">
                            <div class="app-icon">&#128241;</div>
                            <div class="app-info">
                                <div class="app-name">z=</div>
                                <div class="app-type">z</div>
                            </div>
                        </div>
                        <div class="app-actions">
                            <a href="zo" target="_blank" class="app-button">Download APK</a>
                        </div>
                    </div></div>z<!-- apks_list -->r   r4   r5   zError serving android.html: rY   zError serving android.html)fetch_android_apksr   ANDROID_TEMPLATE_PATHr   r   r8   splitextr   r6   ri   APKS_URLdetermine_apk_categoryr~   rD   rE   rF   rH   rI   rJ   r[   r   r\   )
rR   apksr   rV   	apks_htmlapkapk_nameapk_linkr   r    r!   r!   r"   rL   +  s@   



z%TaskManagerHandler.serve_android_pager*   c                 C   s&  zs|dkrt jt|}t}n|dkrt jt|}t}n
td|  W d S td|  t j	|}t jj
|td&}|jdkrXtd| d|j  	 W d    W d S | }W d    n1 sfw   Y  tj|s}t| td	|  tj||}t|d
}	|	| W d    n1 sw   Y  td| d|  t|dZ}
|dkrtj|d }tj||}tj|dd |
| td| d|  n'tjd}tjd}|
 D ]}|drM|dd  }|rLtj||}tjtj|dd |
|%}t|d
}||  W d    n	1 s-w   Y  W d    n	1 s=w   Y  td| d|  q|dr|dd  }|rtj||}tjtj|dd |
|%}t|d
}||  W d    n	1 sw   Y  W d    n	1 sw   Y  td| d|  q|dstj||}tjtj|dd |
|%}t|d
}||  W d    n	1 sw   Y  W d    n	1 sw   Y  td| d|  qW d    n	1 sw   Y  |dkrf|   |
 }|D ]D}|dsd|dr;tj||dd  }ntj||}tj|rdt|t j!t j"B t j#B t j$B t j%B  td| d q!t&| td|  W d S  t'y } ztd| d|  W Y d }~d S d }~ww ) Nr*   webzUnknown app type:zDownloading r   r   zFailed to download r   z#Created installation directory at: wbzDownloaded z to r   r   T)exist_okz
Extracted ~/usr/local/libr   zlib/rt   zExtracted library: zbin/zExtracted binary: r2   zExtracted file: zMade z executablezRemoved temporary zip file: zError installing app r	   )(r   r6   ri   rj   CLI_APPS_DIRrk   WEB_APPS_DIRr   r   r   r   r   r   r   r   r8   r   makedirsr   r   rI   zipfileZipFiler   
extractall
expandusernamelistr9   dirnameendswithensure_cli_pathschmodstatS_IRWXUS_IRGRPS_IXGRPS_IROTHS_IXOTHremover[   )rR   r'   r)   download_urlinstall_dirr   r   zip_datazip_pathr   zip_ref
app_folderextract_pathlib_dirbin_dirmemberlib_filetarget_pathsourcetargetbin_fileextracted_filesr   	file_pathr    r!   r!   r"   r?   [  s   



   
*&
"zTaskManagerHandler.install_appc                 C   s>   t tjdfD ]}tj|st| td|  qdS )zEnsure CLI paths existr   zCreated directory: N)r   r   r8   r   r   r   r   )rR   r8   r!   r!   r"   r     s   
z#TaskManagerHandler.ensure_cli_pathsc              
   C   s   zM|dkr$t jt|}t j|r!t | td|  W d S W d S |dkrHt jt|}t j|rKdd l}|	| td|  W d S W d S W d S  t
yj } ztd| d|  W Y d }~d S d }~ww )Nr*   zDeleted CLI app: r   r   zDeleted web app: zError deleting app r	   )r   r8   r   r   r   r   r   r   shutilrmtreer[   )rR   r'   r)   app_pathr   r    r!   r!   r"   r@     s&   

"zTaskManagerHandler.delete_appc              
   C   sd  z|dkrt jt|d}t j|rd }z5t|d&}| }td|}|r;t	|
d}td| d| d W d    n1 sEw   Y  W n tyf } ztd	|  W Y d }~W d S d }~ww |sttd
| d W d S tjd|gtjtjd}	td| d|	j  |t|	j< td| d|  td |	 d urtd|	j d |	 \}
}td|
   td|   W d S W d S td|  W d S t jt|}t j|r
t |t |jtjB  tj|gtjtjd}	td| d|	j  W d S td|  W d S  ty1 } ztd| d|  W Y d }~d S d }~ww )Nr   app.pyr   PORT\s*=\s*(\d+)rw   zFound port z in z/app.pyz Error reading port from app.py: zCould not find PORT in python3)stdoutstderrzStarted web app: z with PID: zUsing port z for rr   zERROR: Process z failed to start!zProcess output: zProcess errors: zWeb app not found: zStarted CLI app: zCLI app not found: zError starting app r	   )r   r8   r   r   r   r   r   r|   searchintgroupr   r[   
subprocessPopenPIPEr(   	app_portsr
   sleeppollcommunicater   r   r   r   st_modeS_IXUSR)rR   r'   r)   r   portr   ro   
port_matchr    processr   r   r!   r!   r"   r=     sZ   

"zTaskManagerHandler.start_appc                 C   s  z4t d| d|  tjt|d}tj|rzt|d}| }ddl}g d}|D ]l\}}	|	|||j
}
|
rzRt|
d}d	|  krOd
krn n=t d| d|	 d ttjtj}|d |d|f}|  |dkrt d| d |W   W  d   W W S W q/ ttfy   Y q/w q/W d   n1 sw   Y  W n ty } zt d|  W Y d}~nd}~ww ztjddgdtjd }| d}|D ]S}t||v r0d|v r0| }|D ]>}d|v r/z*t|dd }d	|  krd
kr!n nt d| d |W     W W S W q ttfy.   Y qw qqg }|D ]D}d|v rx| }|D ]5}d|v rvzt|dd }d|  kr_dkrfn n|| W qB ttfyu   Y qBw qBq5t|dkrt d|d   |d W W S |rt d|  d|v rW W dS t|W W S W n ty } zt d |  W Y d}~nd}~ww g d!}g }|D ]2}z%ttjtj}|d |d|f}|  |dkr|| W q ty   Y qw t|dkrt d"|d   |d W S |r,t d#|  d|v r'W dS t|W S t d$|  W dS  tyS } zt d%| d&|  W Y d}~dS d}~ww )'z[
        Detect the actual port a web app is running on by checking netstat output
        zDEBUG: Detecting port for PID z, app r   r   r   N))r   zPORT constant)zport\s*=\s*(\d+)zport variable)z'server_address\s*=\s*\([^,]+,\s*(\d+)\)zserver_address tuple)z!HTTPServer\(\s*\([^,]+,\s*(\d+)\)zHTTPServer tuple)zapp\.run\([^)]*port\s*=\s*(\d+)zapp.run)zTCPServer\([^)]*(\d+)\)	TCPServerrw   i   i  zDEBUG: Found port z in app.py (rv   g?z	127.0.0.1zDEBUG: Verified port z
 is activezError parsing app.py for port: netstatz-an   r   r   rq   LISTEN:z via netstat (PID match)@  i(#  z(DEBUG: Found single listening web port: z!DEBUG: Found multiple web ports: zDEBUG: netstat check failed: )r   i  r   iB  iC  iD  iE  iF  iG  iH  iI  iJ  z5DEBUG: Found single listening port via socket check: z.DEBUG: Multiple ports found via socket check: zDEBUG: No port found for PID zError detecting port for PID r	   ) r   r   r8   r   r   r   r   r   r|   r   
IGNORECASEr   r   r   AF_INETSOCK_STREAM
settimeout
connect_exclose
ValueError
IndexErrorr[   r   check_outputDEVNULLr   rz   ry   strr{   lenmin)rR   r(   r'   r   r   ro   r|   patternspatterndescr   r   sockresultr    outputr   r   partspart	web_portscommon_portslistening_portsr!   r!   r"   detect_app_port  s   	












z"TaskManagerHandler.detect_app_portc              
   C   s~   z!t t|tj td|  t|tv rtt|= W d S W d S  ty> } ztd| d|  W Y d }~d S d }~ww )NzStopped app with PID: zError stopping app r	   )r   killr   signalSIGTERMr   r   r[   )rR   r(   r    r!   r!   r"   r>     s   "zTaskManagerHandler.stop_appc           	   
   C   s   zZt td}| }W d    n1 sw   Y  |  }|  }d}d}|d ur,|nd}|d ur4|nd}|d|}|d|}|d|}|d|}d	}|d
|d
 }|W S  tyt } ztd|  W Y d }~dS d }~ww )Nr   z9<div id="available-cli-loading">Loading CLI apps...</div>z9<div id="available-web-loading">Loading web apps...</div>r&   z<!-- manage_apps -->z<!-- installed_apps -->z<!-- available_cli_apps -->z<!-- available_web_apps -->a  
            <script>
            // ES5 compatible lazy loading
            function loadAvailableApps() {
                // Load CLI apps
                var cliContainer = document.getElementById('available-cli-loading');
                if (cliContainer) {
                    var xhr1 = new XMLHttpRequest();
                    xhr1.open('GET', '/api/available-cli', true);
                    xhr1.onreadystatechange = function() {
                        if (xhr1.readyState === 4) {
                            if (xhr1.status === 200) {
                                cliContainer.innerHTML = xhr1.responseText;
                            } else {
                                cliContainer.innerHTML = '<p>Error loading CLI apps</p>';
                            }
                        }
                    };
                    xhr1.send();
                }

                // Load web apps
                var webContainer = document.getElementById('available-web-loading');
                if (webContainer) {
                    var xhr2 = new XMLHttpRequest();
                    xhr2.open('GET', '/api/available-web', true);
                    xhr2.onreadystatechange = function() {
                        if (xhr2.readyState === 4) {
                            if (xhr2.status === 200) {
                                webContainer.innerHTML = xhr2.responseText;
                            } else {
                                webContainer.innerHTML = '<p>Error loading web apps</p>';
                            }
                        }
                    };
                    xhr2.send();
                }
            }

            // Load available apps after page loads
            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', loadAvailableApps);
            } else {
                loadAvailableApps();
            }
            </script>
            z</body>zError loading HTML template: z><html><body><h1>Error loading HTML template</h1></body></html>)r   HTML_TEMPLATE_PATHr   generate_manage_apps_htmlgenerate_installed_apps_htmlr~   r[   r   )	rR   r   rV   manage_apps_htmlinstalled_apps_htmlavailable_cli_htmlavailable_web_htmllazy_scriptr    r!   r!   r"   rQ     s,   
/z TaskManagerHandler.generate_htmlc              
   C   s  zd|v r| d}t|dkr|d  dd }|W S nVd|v r8| d}t|dkr7|d   d }|W S n;d|v rsd|v rX| d}t|dkrW|d  dd }|W S nd|v rs| d}t|dkrs|d  dd }|W S d|vrd	| vr|  d }|W S |dr|dd
d}tj|}|r|W S |  rtj|  d W S dW S  t	y } zt
d| d|  W Y d}~dS d}~ww )a  
        Extract a user-friendly app name from a command string.
        Examples:
        - 'python3 /data/apps/myapp/app.py' -> 'myapp'
        - '/usr/local/bin/tool' -> 'tool'
        - 'python3 /data/apps/webserver/app.py' -> 'webserver'
        - 'myapp' -> 'myapp'
        /data/apps/rw   r2   r   /usr/local/bin/r   z/apps//data/pythonr&   zUnknown Appz(Error extracting app name from command 'z': N)ry   r   lowerr   r~   rstripr   r8   basenamer[   r   )rR   cmdr  app_partr'   	clean_cmdr    r!   r!   r"   extract_app_name_from_command  sN   	




$z0TaskManagerHandler.extract_app_name_from_commandc              
   C   s@  z|   }tdt| d |sW dS d}|D ]j\}}| |}t|}d }|tv r0t| }n$d|v s8d|v rT| ||}|rT|t|< |}td| d| d	| d
 |r\d| dnd}	|d|d   d| d|	 d7 }|rz|d| d7 }|d| d7 }q|W S  ty }
 ztd|
  W Y d }
~
dS d }
~
ww )NzDEBUG: Found z
 processeszM<div class="no-apps">No running apps detected. Try refreshing the page.</div>r&   r   r  zDetected port z for existing process z (rv   #<div class="app-address">127.0.0.1:r   8   <div class="app-address" style="opacity: 0.3;">—</div>zR
                <div class="app-card">
                    <div class="app-icon">r   z`</div>
                    <div class="app-info">
                        <div class="app-name"></div>
                        zI
                    </div>
                    <div class="app-actions">3
                        <a href="http://127.0.0.1:/" target="_blank" class="launch-btn">LAUNCH</a>z:
                        <a href="/action?action=stop&pid=zM" class="stop-btn">STOP</a>
                    </div>
                </div>z!Error generating processes HTML: z8<div class="error-message">Error loading processes</div>)	get_python_processesr   r   r!  r   r   r  upperr[   )rR   	processes
cards_htmlr(   r  r'   pid_intr   detected_portaddress_infor    r!   r!   r"   generate_processes_html  sN   



	
z*TaskManagerHandler.generate_processes_htmlc                 C   sH  z|  td}|  }t }i }|D ]\}}| |}d|v s$d|v r-|| |||< qd}d}	t}
|D ]\}}d|v rSd}|}	|d ||d< |
tt|<  nq6t	|}|r_|
d	 |sdW d
S d}|D ]\}}|dkrqqhtj|}||v }d}d}|r||}|rt|tv rtt| }n|r| t||}|r|tt|< |}|rdnd}|rdnd}|rd| dnd}|d| d| d| d| d| d7 }|r|r|d| d7 }|dkr|d| d| d7 }n|d7 }n|dkr|d| d 7 }|d!7 }qh|W S  ty# } ztd"|  W Y d}~d#S d}~ww )$z
        Generate HTML for the Manage Apps section showing all web apps with start/stop toggle buttons.
        Shows both running and stopped web apps with appropriate buttons.
        r   r   r  FN
taskapp.pyTtaskapp)r0  r   zc<div class="no-apps">No web apps installed. Install web apps from the Available Apps section.</div>r&   runningstoppedRunningStoppedr"  r   r#  z*
                <div class="app-card app-z" data-app-name="z" data-app-type="web">
                    <div class="app-icon">&#9881;</div>
                    <div class="app-info">
                        <div class="app-name">r$  z1
                        <div class="app-status">zO</div>
                    </div>
                    <div class="app-actions">r%  r&  zF
                        <button class="stop-btn" onclick="toggleApp('z', 'stop', 'z')">STOP</button>zE
                        <span class="system-app-label">SYSTEM</span>zG
                        <button class="start-btn" onclick="toggleApp('z', 'start', '')">START</button>z2
                    </div>
                </div>z#Error generating manage apps HTML: z:<div class="error-message">Error loading manage apps</div>)scan_apps_directoryr   r'  setr!  addPORTr   r   listr{   r   r6   rd   r<   r  r[   r   )rR   web_appsrunning_processesrunning_app_namesrunning_app_pidsr(   r  r'   taskapp_runningtaskapp_pidtaskapp_portall_web_appsr*  appr)   rg   
is_runningr   r,  status_classstatus_textr-  r    r!   r!   r"   r  C  s   


	








z,TaskManagerHandler.generate_manage_apps_htmlc           
   
   C   s  zX|  td}|  td}|| }|sW dS d}|D ];\}}tj|}|dkr*dnd}|d|d   d	| d
| d7 }|dkrJ|d| d7 }|d| d| d7 }q|W S  tyr }	 ztd|	  W Y d }	~	dS d }	~	w ty }	 ztd|	  W Y d }	~	dS d }	~	ww )Nr*   r   z3<div class="no-apps">No installed apps found.</div>r&   zWeb AppzCLI Appz
                <div class="app-card">
                    <div class="app-card-header">
                        <div class="app-icon">r   zh</div>
                        <div class="app-info">
                            <div class="app-name">z9</div>
                            <div class="app-type">zn</div>
                        </div>
                    </div>
                    <div class="app-actions">z@
                        <a href="/action?action=start&app_name=z8&app_type=web" class="app-button start-button">Start</a>zA
                        <a href="/action?action=delete&app_name=r`   zX" class="app-button delete">Delete</a>
                    </div>
                </div>z&Error generating installed apps HTML: z=<div class="error-message">Error loading installed apps</div>)	r5  r   r   r   r6   rd   r(  r[   r   )
rR   cli_appsr:  all_appsr*  rB  r)   rg   display_typer    r!   r!   r"   r    sH   


z/TaskManagerHandler.generate_installed_apps_htmlc              
      sV  z|dkrdt jt|d d ndt jt| d ttd}| }W d    n1 s1w   Y  d| d}d| d}t fd	d
|D rXt	d| d W d S ttd}|
d| d |
  |
| d W d    n1 s~w   Y  t	d| d W d S  ty } zt	d| d|  W Y d }~d S d }~ww )Nr   	python3 "r   z" &
r   # <<< Auto-Start for  >>># <<< End Auto-Start for c                 3   s     | ]}   |  v V  qd S N)rz   ).0r   app_commandr!   r"   	<genexpr>  s    z;TaskManagerHandler.enable_auto_start_app.<locals>.<genexpr>zAuto-start for z is already enabled.arq   zEnabled auto-start for .zError enabling auto start for r	   )r   r8   r   r   r   r   PROFILE_FILE	readlinesanyr   rI   r[   )rR   r'   r)   r   profile_contentsAUTO_START_MARKER_STARTAUTO_START_MARKER_ENDr    r!   rO  r"   rA     s,   

"z(TaskManagerHandler.enable_auto_start_appc           
   
   C   s4  z|t jtstt d W d S d| d}d| d}ttd}| }W d    n1 s1w   Y  g }d}|D ]}| |krGd}q<| |krPd}q<|sW|| q<ttd}|	| W d    n1 smw   Y  td	| d
 W d S  t
y }	 ztd| d|	  W Y d }	~	d S d }	~	ww )Nz does not exist.rJ  rK  rL  r   FTwzDisabled auto-start for rS  zError disabling auto start for r	   )r   r8   r   rT  r   r   rU  rz   r{   
writelinesr[   )
rR   r'   rX  rY  r   profile_linesupdated_linesskipr   r    r!   r!   r"   rB     s:   

"z)TaskManagerHandler.disable_auto_start_appc              
         zN|   }|d u rW dS tdd | tdD   fdd|D }|s'W dS d}|D ]}tj|d	 }|d
| d|d	   d| d7 }q+|d7 }|W S  tyh } zt	d|  W Y d }~dS d }~ww )Nz,<p>Error loading Command Line Utilities.</p>c                 s       | ]\}}|V  qd S rM  r!   rN  rB  _r!   r!   r"   rQ        zATaskManagerHandler.generate_available_cli_html.<locals>.<genexpr>r*   c                    8   g | ]}t j|d   vrt j|d  dkr|qS r   r0  r   r8   r   rN  zinstalled_cli_appsr!   r"   
<listcomp>     8 zBTaskManagerHandler.generate_available_cli_html.<locals>.<listcomp>z+<p>No Command Line Utilities available.</p><div class="apps-container">r   ;
                <div class="app-item" onclick="openModal('zO', 'cli')" style="cursor: pointer;">
                    <div class="app-icon">1</div>
                    <div class="app-name">v</div>
                    <div class="app-click-hint">Click for details</div>
                </div>
                r   z*Error generating available CLI apps HTML: )
fetch_available_zipsr6  r5  r   r   r8   r   r(  r[   r   rR   available_zips	apps_htmlzip_filer'   r    r!   ri  r"   rZ     2   
z.TaskManagerHandler.generate_available_cli_htmlc              
      r_  )Nz<p>Error loading Web Apps.</p>c                 s   r`  rM  r!   ra  r!   r!   r"   rQ  4  rc  zFTaskManagerHandler.generate_available_web_apps_html.<locals>.<genexpr>r   c                    rd  re  rf  rg  installed_web_appsr!   r"   rk  6  rl  zGTaskManagerHandler.generate_available_web_apps_html.<locals>.<listcomp>z<p>No Web Apps available.</p>rm  r   rn  zO', 'web')" style="cursor: pointer;">
                    <div class="app-icon">ro  rp  r   z*Error generating available Web Apps HTML: )
fetch_web_appsr6  r5  r   r   r8   r   r(  r[   r   rr  r!   rw  r"   r_   .  rv  z3TaskManagerHandler.generate_available_web_apps_htmlc              	   C   sr   |  }g dg dg dg dg dg dg dg dd	}| D ]\}}|D ]}||v r5|    S q)q#d
S )z
        Determine the category of an APK based on its name.
        This is a simple categorization - you can enhance this logic.
        )utiltoolmanagercleaner	optimizerbatteryr   system)emulatoremuretroarcadeconsolenintendosegaplaystation)launcherhomedesktopthemeicon)browserr   chromefirefoxoperainternet)officedocumentpdfnotecalendartasktodoeditor)chatmessagemailemailsocialwhatsapptelegramdiscord)coder  idegitterminalsshftp	developer)gameplaypuzzler%   	adventurestrategyrpgracing)UtilityEmulatorLauncherBrowserProductivityCommunicationsCodingGamer  )r  items)rR   r   	apk_lower
categoriesr   keywordskeywordr!   r!   r"   r   K  s"   z)TaskManagerHandler.determine_apk_categoryc              
   C   sn   t td}|du rg S ztd|}dd |D }|W S  ty6 } ztd|  g W  Y d}~S d}~ww )z
        Fetch and parse the listing of .apk files from APKS_URL.
        Returns a list of filenames (e.g. ['myapp.apk', 'anotherapp.apk', ...]).
        android_apksNzhref=["\']([^"\']+\.apk)["\']c                 S      g | ]}t j|qS r!   r   r8   r  )rN  rR  r!   r!   r"   rk  u      z9TaskManagerHandler.fetch_android_apks.<locals>.<listcomp>zError parsing Android APKs: )r#   r   r|   findallr[   r   )rR   rp   	apk_filesr    r!   r!   r"   r   h  s   
z%TaskManagerHandler.fetch_android_apksc              
   C   l   t td}|d u rd S ztd|}dd |D }|W S  ty5 } ztd|  W Y d }~d S d }~ww )Navailable_cli_zipshref=["\']([^"\']+\.zip)["\']c                 S   r  r!   r  rg  r!   r!   r"   rk    r  z;TaskManagerHandler.fetch_available_zips.<locals>.<listcomp>z"Error parsing available CLI zips: )r#   rj   r|   r  r[   r   rR   rp   	zip_filesr    r!   r!   r"   rq  {     
z'TaskManagerHandler.fetch_available_zipsc              
   C   r  )Navailable_web_appsr  c                 S   r  r!   r  rg  r!   r!   r"   rk    r  z5TaskManagerHandler.fetch_web_apps.<locals>.<listcomp>zError parsing web apps: )r#   rk   r|   r  r[   r   r  r!   r!   r"   ry    r  z!TaskManagerHandler.fetch_web_appsc                 C   s  g }zt jddgdt jd }| d}|D ]h}| r| }t|dkr|d }d|d	d
 }d| v pPd|v pPd|v pPd|v pP|	doPd|v}|rd|v rg|
dtd }	||	d
 }nd|v rz|
dtd }	||	d
 }|||f qW |S  t jy1   zt jg ddt jd }| d}|D ]l}| r| }t|dkr|d }d|d	d
 }d| v pd|v pd|v pd|v p|	dod|v}|rd|v r|
dtd }	||	d
 }nd|v r	|
dtd }	||	d
 }|||f qW Y |S  ty0 }
 ztd|
  W Y d
}
~
Y |S d
}
~
ww  tyK }
 ztd|
  W Y d
}
~
|S d
}
~
ww )z_
        IMPROVED: Better process detection for QNX - looks for all relevant processes
        pidinarr   r   rq   rr   r    rw   Nr  r  r  r   .pyr/  r  )r  z-fz%a %A %n %pz$Error getting processes (fallback): zError getting processes: )r   r   r   r   rz   ry   r   r   r  r   findr{   CalledProcessErrorr[   r   )rR   r)  r  r   r   r  r(   r  is_relevantindexr    r!   r!   r"   r'    s   C

z'TaskManagerHandler.get_python_processesc              
   C   s   g }zKt j|s|W S t |D ]9\}}}|D ]1}|dkr1|dkr0t j||}||df q|dsIt jt j|||}	||	df qqW |S  tyg }
 zt	d|
  W Y d }
~
|S d }
~
ww )Nr   r   r  r*   zError scanning apps directory: )
r   r8   r   walkrelpathr{   r   r   r[   r   )rR   	directoryr)   appsrootdirsfilesr   r   rel_pathr    r!   r!   r"   r5    s.   
z&TaskManagerHandler.scan_apps_directoryc           	      C   s  zrt td}| }W d   n1 sw   Y  |  }|s#d}nGd}|d7 }|D ]:\}}|dkretj|}| |rR|d| d|  d	| d
| d	7 }q+|d| d|  d| d
| d	7 }q+|d7 }|	d|}|W S  t
y } ztd|  W Y d}~dS d}~ww )z
        Generate the HTML for the auto-config page, showing web apps
        with options to enable or disable auto start.
        r   Nz#<p>No installed web apps found.</p>z<table>z:<tr><th>App Name</th><th>Type</th><th>Auto Start</th></tr>r   z<tr><td>z	</td><td>z=</td><td><a href="/action?action=disable_auto_start&app_name=r`   z"">Disable Auto Start</a></td></tr>z<</td><td><a href="/action?action=enable_auto_start&app_name=z!">Enable Auto Start</a></td></tr>z</table>z<!-- installed_apps_auto -->z)Error loading auto-config HTML template: zE<html><body><h1>Error loading auto-config template</h1></body></html>)r   AUTO_CONFIG_TEMPLATE_PATHr   get_all_installed_appsr   r6   rd   is_auto_start_enabledr(  r~   r[   r   )	rR   r   rV   rG  rt  rB  r)   rg   r    r!   r!   r"   rG     s0   

(&z,TaskManagerHandler.generate_auto_config_htmlc                 C   s    |  td}|  td}|| S )Nr*   r   )r5  r   r   )rR   rF  r:  r!   r!   r"   r    s   z)TaskManagerHandler.get_all_installed_appsc              
   C   s   z<t jts
W dS ttd}| }W d   n1 sw   Y  |D ]}dt jt|d d|v r9 W dS q%W dS  tyY } zt	d| d	|  W Y d}~dS d}~ww )
z\
        Check if auto-start is enabled for the given app by inspecting ~/.profile.
        Fr   NrI  r   z" &TzError checking auto-start for r	   )
r   r8   r   rT  r   rU  r   r   r[   r   )rR   r'   r   r\  r   r    r!   r!   r"   r    s    
z(TaskManagerHandler.is_auto_start_enabledN)r*   )&__name__
__module____qualname__rW   rM   rN   rO   rc   rl   rP   r   r   rK   rL   r?   r   r@   r=   r  r>   rQ   r!  r.  r  r  rA   rB   rZ   r_   r   r   rq  ry  r'  r5  rG   r  r  r!   r!   r!   r"   r$   F   sJ    ?"B ^
0Z

9~
K92k
*O!r$   c                  C   s   t jdd} | t j}t|vr%tdt d td tdt d t|vr?tdt d td	 tdt d d S d S )
NPATHr&   z	Warning: z is not in your PATH.zAdd to ~/.profile:zexport PATH="z:$PATH"zNote: z?If you want to run web apps from command line, consider adding:)r   environr<   ry   pathsepr   r   r   )current_pathpathsr!   r!   r"   
check_path3  s   r  __main__z"Starting optimized Task Manager...zPerformance improvements:z%- Caching network requests (5min TTL)z - Timeout handling (10s timeout)z- Optimized pidin usagez!- Lazy loading for available appsr&   zServing on port )/http.serverhttpsocketserverr   r   r  urllib.parser   r|   urllib.requestr   r   r
   	threadingr   re   r8  r8   r   __file__r   r   r  r  r   r   r   r   r   rj   rk   r   rT  r   r   r   r   r#   serverBaseHTTPRequestHandlerr$   r  r  r   r   httpdserve_foreverr!   r!   r!   r"   <module>   sr               x
"