├── Dockerfile ├── LICENSE ├── README.md └── dandan.py /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:alpine 2 | 3 | RUN pip install uvicorn fastapi arrow requests bs4 4 | 5 | COPY dandan.py /dandan.py 6 | 7 | EXPOSE 8080 8 | 9 | CMD [ "python", "dandan.py", "host=0.0.0.0", "port=8080" ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2080 IllyaTheHath 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 弹弹play资源搜索节点API 2 | 3 | ### Using Docker Commands 4 | ``` 5 | docker run -d \ 6 | -p 8080:8080 --name=dandan_api --restart=always \ 7 | illyathehath/dandan-api 8 | ``` 9 | 10 | ### Using Docker Compose 11 | ``` 12 | version: "3" 13 | services: 14 | dandan: 15 | image: illyathehath/dandan-api 16 | # build: . 17 | restart: always 18 | ports: 19 | - "8080:8080" 20 | ``` 21 | 22 | 在此只做了docker的封装,api的实现取自 https://pastebin.ubuntu.com/p/mGP7JRpBtd/ , 修改过安卓搜索bug的版本:https://pastebin.ubuntu.com/p/b33zZ3pvVr/ 23 | -------------------------------------------------------------------------------- /dandan.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import uvicorn 3 | from typing import Optional 4 | from fastapi import FastAPI 5 | import requests 6 | from bs4 import BeautifulSoup 7 | import arrow 8 | 9 | app = FastAPI() 10 | dmhy_base_uri = "https://share.dmhy.org" 11 | dmhy_type_and_subgroup_uri = f"{dmhy_base_uri}/topics/advanced-search?team_id=0&sort_id=0&orderby=" 12 | dmhy_list_uri = f"{dmhy_base_uri}/topics/list/page/{{3}}?keyword={{0}}&sort_id={{1}}&team_id={{2}}&order=date-desc" 13 | unknown_subgroup_id = -1 14 | unknown_subgroup_name = "未知字幕组" 15 | 16 | def parse_list_tr(tr): 17 | td0 = tr.select("td")[0] 18 | td1 = tr.select("td")[1] 19 | td2 = tr.select("td")[2] 20 | td3 = tr.select("td")[3] 21 | td4 = tr.select("td")[4] 22 | c1 = len(td2.select("a")) 23 | td1_a0 = td1.select("a")[0] 24 | td2_a0 = td2.select("a")[0] 25 | td2_a_last = td2.select("a")[-1] 26 | td3_a0 = td3.select("a")[0] 27 | 28 | return { 29 | "Title": td2_a_last.text.strip(), 30 | "TypeId": int(td1_a0["href"].replace("/topics/list/sort_id/", "")), 31 | "TypeName": td1_a0.text.strip(), 32 | "SubgroupId": unknown_subgroup_id if c1 != 2 else int(td2_a0["href"].replace("/topics/list/team_id/", "")), 33 | "SubgroupName": unknown_subgroup_name if c1 != 2 else td2_a0.text.strip(), 34 | "Magnet": td3_a0["href"], 35 | "PageUrl": dmhy_base_uri + td2_a_last["href"], 36 | "FileSize": td4.text.strip(), 37 | "PublishDate": arrow.get(td0.select("span")[0].text.strip()).format("YYYY-MM-DD HH:mm:ss") 38 | } 39 | 40 | 41 | @app.get("/") 42 | def read_root(): 43 | return {"Hello": "World"} 44 | 45 | 46 | @app.get("/subgroup") 47 | def subgroup(): 48 | res = requests.get(dmhy_type_and_subgroup_uri) 49 | res.encoding = "utf-8" 50 | soup = BeautifulSoup(res.text, 'html.parser') 51 | options = soup.select("select#AdvSearchTeam option") 52 | subgroups = [{"Id": int(o["value"]), "Name": o.text} for o in options] 53 | subgroups.append({"Id": unknown_subgroup_id, "Name": unknown_subgroup_name}) 54 | return {"Subgroups": subgroups} 55 | 56 | 57 | @app.get("/type") 58 | def type(): 59 | res = requests.get(dmhy_type_and_subgroup_uri) 60 | res.encoding = "utf-8" 61 | soup = BeautifulSoup(res.text, 'html.parser') 62 | options = soup.select("select#AdvSearchSort option") 63 | return {"Types": [{"Id": int(o["value"]), "Name": o.text} for o in options]} 64 | 65 | 66 | @app.get("/list") 67 | def listPage(keyword: str, subgroup: Optional[str] = None, type: Optional[str] = None, r: Optional[str] = None, page: Optional[int] = 1): 68 | res = requests.get(dmhy_list_uri.format(keyword, type, subgroup, page)) 69 | res.encoding = "utf-8" 70 | soup = BeautifulSoup(res.text, 'html.parser') 71 | trs = soup.select("table#topic_list tbody tr") 72 | has_more = True if soup.select("div.nav_title > a:contains('下一頁')") else False 73 | 74 | return {"HasMore": has_more, "Resources": [parse_list_tr(tr) for tr in trs]} 75 | 76 | 77 | if __name__ == "__main__": 78 | for arg in sys.argv: 79 | if arg.startswith("host="): 80 | run_host = arg.replace("host=", "") 81 | continue 82 | if arg.startswith("port="): 83 | run_port = int(arg.replace("port=", "")) 84 | continue 85 | 86 | uvicorn.run(app, host=run_host, port=run_port, debug=False) 87 | --------------------------------------------------------------------------------