From 5630669c1795f21f410ef855ebafbc3d153a5d84 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Sat, 23 Aug 2025 12:10:48 +0800 Subject: [PATCH] bugfix --- README.md | 57 +++++++++++++++++++ downloadmgr/.download.py.swp | Bin 0 -> 12288 bytes downloadmgr/__init__.py | 0 downloadmgr/download.py | 106 +++++++++++++++++++++++++++++++++++ downloadmgr/init.py | 6 ++ models/download.xlsx | Bin 0 -> 18167 bytes pyproject.toml | 4 ++ setup.cfg | 16 ++++++ wwwroot/add_new_download.ui | 26 +++++++++ wwwroot/download_url.dspy | 8 +++ wwwroot/list_downloading.ui | 22 ++++++++ wwwroot/task_info.ui | 26 +++++++++ 12 files changed, 271 insertions(+) create mode 100644 downloadmgr/.download.py.swp create mode 100644 downloadmgr/__init__.py create mode 100644 downloadmgr/download.py create mode 100644 downloadmgr/init.py create mode 100644 models/download.xlsx create mode 100644 pyproject.toml create mode 100644 setup.cfg create mode 100644 wwwroot/add_new_download.ui create mode 100644 wwwroot/download_url.dspy create mode 100644 wwwroot/list_downloading.ui create mode 100644 wwwroot/task_info.ui diff --git a/README.md b/README.md index e69de29..daa9393 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,57 @@ +# DownloadMgr +a web ui for aria2 + +## Dependent +* [apppublic](https://git.opencomputing.cn/yumoqing/apppublic) +* [sqlor](https://git.opencomputing.cn/yumoqing/sqlor) +* [ahserver](https://git.opencomputing.cn/yumoqing/ahserver) +* [appbase](https://git.opencomputing.cn/yumoqing/appbase) +* [rbac](https://git.opencomputing.cn/yumoqing/rbac) +* [uapi](https://git.opencomputing.cn/yumoqing/uapi) +* [bricks](https://git.opencomputing.cn/yumoqing/bricks) + +also depentent on +* [xls2ddl](https://git.opencomputing.cn/yumoqing/xls2ddl) +use it to translates database definintion excel file to database ddl sql file +and translate table information to CRUD UI for bricks. + +## Install +``` +pip install git+https://git.opencomputing.cn/yumoqing/downloadmgr +``` + +## Usage + +in your web app +``` +from downloadmgr.init import load_downloadmgr +# call the load_downloadmgr() before the web server start listening + +``` + +## examples: +``` +from ahserver.webapp import webapp +from ahserver.serverenv import ServerEnv +from appbase.init import load_appbase +from rbac.init import load_rbac +from downloadmgr.init import load_downloadmgr + +def get_module_dbanme(modulename): + return 'mydb' # assume all modules use same database 'mydb' + +def init(): + env = ServerEnv() + env.get_module_dbname = get_module_dbname + load_appbase() + load_rbac() + load_downloadmgr() + +if __name__ == '__main__': + webapp(init) +``` + +## database table +downloadmgr use a table named "download", it record the user download infomation + + diff --git a/downloadmgr/.download.py.swp b/downloadmgr/.download.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..cd163d80af72356ac2b4c2a0bc32f04373246d8d GIT binary patch literal 12288 zcmeI2ONbmr7{@EVN0X@W5MFV-PCL54d+Me#3-QM(c_g3}n zBg^U;PjyXJ1mq#0}!FbWt2i~>dhqkvJsC}0#Y3fx`_Wa&2c29|tBvFxSdylw1U+?tb7 zz$jo8FbWt2i~>dhqkvJsC}0#Y3K#{90=J<8UclJdI~i-;jm6{t|K;ERzdy*>FW@V1 z0d#-|j)N(%8(iDT*k$l3_yi0<1fB=Gz|T7v`vH6lE`g81yWk!08aM$O;E(OF1HJ~I zfe*kMP~a3e2@Zfg;Q9lMeFH9lRp5eY&;pMG4zAzN*cI>-_z`>o-UB`0f|tM%@C4Wa zwu7rR#(o7~g7?AOAOuf=319;TuHDDjpWu6N5u69-KnKi&mw^Qy1;5>ky@QKj08WD! zK?7X52m1w|gLB|5@FwuU(_lAv7<>o6d<4#eRqz66gJ%Kx>>w~7qkvK1KUbi}YPFj5 zLM6DMOC_SNBjOcDtob6%!X&o4)`n;gUWqrliR^iqizoKPz?wk!yc3@(`*Kfl(b6VG z)|W9494S;k%Baa(^}>wn3H(LjpK?!&-pWnnO&(V1MQb@XMVU}j!AVZgC|E_oPpDSY)Rp3-@A z5;EOaLTdZUrpqvZJx{I2J})O$#mqKsW}=0f3R8N&@+@r?N2eP`BKCR$_USf^yNN^h z`D3(}dqqQKms?ThR)onn5{T|_Gu6E`IrPJZpni=Gm4yW&5}AOjB4Mk|?PyO`x=GPX zR)m%h-4?WXBX-C@?s>dC2bbT#mhxb!jEymqVV5f>OENDyD&mD~k+<7u@RMFj%M9{H z+6Xx~kCW1iwE2q6SjKP??a*e?pLBqM)KjWD^luwL3^aM^?qX084yRV}d93GgH@>DQN4EGaX%%%G!(C3n?oh!hPvw6a7VPU1|gWp>aZwI=9GLnV?nnzxklmU{J)pif0Zcekz5 zINrR~F58OKuneoyhh~!`Qlr|J9w|ybc_0s?GHoH~;muhQk|UDVQCuXxkDyt-h4R@G z4jpI?eCqk)@Fc&;gQ*?{)K@3EZYg|l8>qFJ$9bq$Yf(k8xf=*piLz0}{vYCuePQW@ zuBt@3QRPVS8%diFqghA`5mP=4t2r?D-0TrsisimgS(7&!x)YLvLae+-|DwmdCHt`( zD~n2neq21*?80hPbX*tdp1E#bK8sEWeLuoC9-l6X>#+r7CevB%EutW<2-FvS!U}lU zOB0##le%FhUTNxID~8YWaXRUppp#Pal|zbLEG(z#Y`+tQz7q_K_ORoyg%z_=2`{fH G*Vtd2zvG7h literal 0 HcmV?d00001 diff --git a/downloadmgr/__init__.py b/downloadmgr/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/downloadmgr/download.py b/downloadmgr/download.py new file mode 100644 index 0000000..1e6eb6f --- /dev/null +++ b/downloadmgr/download.py @@ -0,0 +1,106 @@ +import time +import json +from appPublic.dictObject import DictObject +from sqlor.dbpools import DBPools +from ahserver.serverenv import ServerEnv, get_serverenv + +class DownloadMgr: + def __init__(self,request): + self.request = request + self.env = request['run_ns'] + self.uapi = self.env.UAPI(request, **self.env) + self.uappid = 'downloader' + + async def save_finished_task(self, taskid): + db = DBPools() + userid = await self.env.get_user() + dbname = self.env.get_module_dbname('downloadmgr') + async with db.sqlorContext(dbname) as sor: + ns = { + "id": taskid, + "finish_time": time.time(), + } + await sor.U('download', ns) + + async def save_task(self, taskid): + db = DBPools() + userid = await self.env.get_user() + dbname = self.env.get_module_dbname('downloadmgr') + async with db.sqlorContext(dbname) as sor: + ns = { + "id": taskid, + "userid": userid, + "start_time": time.time() + } + await sor.C('download', ns) + + async def get_user_tasks(self): + db = DBPools() + userid = await self.env.get_user() + dbname = self.env.get_module_dbname('downloadmgr') + async with db.sqlorContext(dbname) as sor: + sql = """select * from download +where userid=${userid}$ +and finish_time is NULL""" + ns = { + 'userid': userid + } + recs = await sor.sqlExe(sql, ns) + return recs + return [] + + async def uapicall(self, apiname, ns): + userid = await self.env.get_user() + x = self.uapi.call(self.uappname, + apiname, + userid, + ns) + d = json.loads(x.decode('utf-8') + return DictObject(**d) + + async download(self, url): + try: + d = await self.uapicall('addUrl', {'url':url}) + await self.save_task(d.result) + return d.result + except Exception as e: + self.env.exception(f'{url=},{e}\n{format_exc()}') + raise e + + async def delete_file(self, filename): + pass + + async remove_task(self, taskid): + await self.uapicall('remove-task', {'taskid':taskid}) + return True + + async def file_downloaded(self, filename): + pass + + async def check_download_finished(self, status): + s = status + if s.totalLength == s.completedLength: + await self.save_finished_task(s.gid) + await self.file_downloaded(s.info.name) + await self.remove_task(s.gid) + await self.delete_file(s.info.name) + + async def get_task_status(self, tid): + d = await self.uapicall('get_task_status', {'taskid':tid}) + await self.check_downlaod_finished(d.result) + rzt = d.result + rzt.filename = rzt.info.name + return rzt + + async get_tasks_status(self): + recs = await self.get_user_tasks(userid) + urls = [r.id for r in recs] + try: + d = await self.uapicall('get_task_status', {'taskid':tid}) + await self.check_downlaod_finished(d.result) + return d.result + except Exception as e: + self.env.exception(f'{e=}\n{format_exc()}') + raise e + + diff --git a/downloadmgr/init.py b/downloadmgr/init.py new file mode 100644 index 0000000..c3c99a6 --- /dev/null +++ b/downloadmgr/init.py @@ -0,0 +1,6 @@ +from downloadmgr.download import DownloadMgr +from ahserver.serverenv import ServerEnv + +def load_downloadmgr(): + env = ServerEnv() + env.DownloadMgr = DownloadMgr diff --git a/models/download.xlsx b/models/download.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b623e6cb4e8e5e2a0de3560febdbf1be8a0d1850 GIT binary patch literal 18167 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 U%-zqJ6$J=61", "wheel"] +build-backend = "setuptools.build_meta" + diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..5f49547 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,16 @@ +[metadata] +name=downloadmgr +version = 0.0.1 +description = a web ui for aria2 +author = "yu moqing" +author_email = "yumoqing@gmail.com" +readme = "README.md" +license = "MIT" +[options] +packages = find: +requires_python = ">=3.8" +install_requires = + apppublic + sqlor + ahserver + diff --git a/wwwroot/add_new_download.ui b/wwwroot/add_new_download.ui new file mode 100644 index 0000000..bd9ba6d --- /dev/null +++ b/wwwroot/add_new_download.ui @@ -0,0 +1,26 @@ +{ + "widgettype":"Form", + "options":{ + "width":"100%", + "height":"100%", + "fields":[ + { + "name":"url", + "label":"下载地址", + "uitype":"text", + "required":true + } + ] + }, + "binds":[ + { + "wid":"self", + "event":"submit", + "actiontype":"urlwidget", + "target":"self", + "options":{ + "url":"{{entire_url('./download_url.dspy')}}" + } + } + ] +} diff --git a/wwwroot/download_url.dspy b/wwwroot/download_url.dspy new file mode 100644 index 0000000..9fa4396 --- /dev/null +++ b/wwwroot/download_url.dspy @@ -0,0 +1,8 @@ +# +dmgr = DownloadMgr(request) +try: + x = await dmgr.download(params_kw.url) + return UiMessage(title='download', message=f'download submited') +except Exception as e: + exception(f'{params_kw.url} download failed,{e=}\n{format_exc()}') + return UiError(title='download error', message=f'{params_kw.url} download failed,{e=}') diff --git a/wwwroot/list_downloading.ui b/wwwroot/list_downloading.ui new file mode 100644 index 0000000..2a4573b --- /dev/null +++ b/wwwroot/list_downloading.ui @@ -0,0 +1,22 @@ +{ + "widgettype":"DynamicColumn", + "options":{ + "width":"100%", + "height":"100%" + }, + "subwidgets":[ +{% set dmgr = DownloadMgr(request) %} +{for task in dmgr.get_user_tasks() %} + { + "widgettype":"urlwidget", + "options":{ + "params":{ + "taskid":"{{task.id}}" + }, + "url":"{{entire_url('task_info.ui')}}" + } + } +{% if not loop.last %},{% endif %} +{% endfor %} + ] +} diff --git a/wwwroot/task_info.ui b/wwwroot/task_info.ui new file mode 100644 index 0000000..25fedda --- /dev/null +++ b/wwwroot/task_info.ui @@ -0,0 +1,26 @@ +{% set dmgr=DownloadMgr(request) %} +{% set status=dmgr.get_task_status(params_kw.taskid) %} +{ + "widgettype":"VBox", + "options":{ + "cwidth":16, + "cheight":14, + "css":"card" + }, + "subwidgets":[ + { + "widgettype":"Title3", + "options:{ + "text":"{{status.filename}}", + "wrap":true, + "halign":"left" + } + }, + { + "widgettype":"Text", + "options":{ + "text":"{{status.completedLength}}/{{status.totalLength}}" + } + } + ] +}