├── .gitignore ├── assets ├── guide.pdf ├── add.py ├── contributers.py └── update_readme.py ├── .github └── workflows │ ├── update-contributers.yml │ ├── update-readme.yml │ └── add-project.yml ├── CONTRIBUTING.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /assets/__pycache__/ 2 | /.venv/ -------------------------------------------------------------------------------- /assets/guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zitann/HarmonyOS-Haps/HEAD/assets/guide.pdf -------------------------------------------------------------------------------- /.github/workflows/update-contributers.yml: -------------------------------------------------------------------------------- 1 | name: Update Contributers SVG 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | name: 7 | description: '新增贡献者名称(可为空)' 8 | required: false 9 | type: string 10 | default: '' 11 | url: 12 | description: '新增贡献者主页URL(可为空)' 13 | required: false 14 | type: string 15 | default: '' 16 | 17 | jobs: 18 | update-contributers: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Check main repo 23 | run: | 24 | if [[ "${{ github.repository }}" != "Zitann/HarmonyOS-Haps" ]]; then 25 | echo "不是主仓库,跳过执行" 26 | exit 0 27 | fi 28 | 29 | - name: Checkout code 30 | uses: actions/checkout@v4 31 | 32 | - name: Set up Python 33 | uses: actions/setup-python@v4 34 | with: 35 | python-version: '3.9' 36 | 37 | - name: Install dependencies 38 | run: | 39 | python -m pip install --upgrade pip 40 | pip install requests 41 | 42 | - name: Update contributers SVG 43 | run: | 44 | if [[ -n "${{ github.event.inputs.name }}" && -n "${{ github.event.inputs.url }}" ]]; then 45 | python assets/contributers.py "${{ github.event.inputs.name }}" "${{ github.event.inputs.url }}" 46 | else 47 | python assets/contributers.py 48 | fi 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | 52 | - name: Commit changes 53 | uses: stefanzweifel/git-auto-commit-action@v5 54 | with: 55 | commit_message: "自动更新贡献者SVG" -------------------------------------------------------------------------------- /.github/workflows/update-readme.yml: -------------------------------------------------------------------------------- 1 | name: Update README 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | schedule: 10 | - cron: '0 14 * * *' # 每天UTC 14:00,即北京时间22:00 11 | workflow_dispatch: 12 | repository_dispatch: 13 | types: [update-readme] 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Check main repo 21 | run: | 22 | if [[ "${{ github.repository }}" != "Zitann/HarmonyOS-Haps" ]]; then 23 | echo "不是主仓库,跳过执行" 24 | exit 0 25 | fi 26 | 27 | - name: Checkout code 28 | uses: actions/checkout@v2 29 | 30 | - name: Set up Python 31 | uses: actions/setup-python@v2 32 | with: 33 | python-version: '3.9' 34 | 35 | - name: Install dependencies 36 | run: | 37 | python -m pip install --upgrade pip 38 | pip install requests 39 | 40 | - name: Update README 41 | run: python assets/update_readme.py 42 | env: 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | 45 | - name: Get updated apps 46 | run: | 47 | if [ -f .apps_str.txt ]; then 48 | apps_str=$(cat .apps_str.txt) 49 | echo "apps_str=$apps_str" >> $GITHUB_ENV 50 | rm -f .apps_str.txt 51 | else 52 | echo "apps_str=列表排序" >> $GITHUB_ENV 53 | fi 54 | 55 | - name: Check for changes 56 | id: changes 57 | run: | 58 | git diff --exit-code README.md || echo "changed=true" >> $GITHUB_OUTPUT 59 | 60 | - name: Commit changes 61 | if: steps.changes.outputs.changed == 'true' 62 | uses: stefanzweifel/git-auto-commit-action@v5 63 | with: 64 | commit_message: "自动更新: ${{ env.apps_str }}" -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | - [Aloereed](https://github.com/Aloereed) 2 | - [Amview](https://github.com/Amview) 3 | - [CatPawApp](https://github.com/CatPawApp) 4 | - [Chenlvin](https://github.com/Chenlvin) 5 | - [ErBWs](https://github.com/ErBWs) 6 | - [Gramony](https://github.com/Gramony) 7 | - [Harmoninux](https://github.com/harmoninux/HiSH) 8 | - [Jonk](https://github.com/aimilin6688) 9 | - [Kaiter-Plus](https://github.com/Kaiter-Plus) 10 | - [Luo-A-Chen](https://github.com/Luo-A-Chen) 11 | - [Luxcis](https://github.com/Luxcis) 12 | - [Open Harmony Play Ground](https://github.com/OHPG) 13 | - [Psyche](https://github.com/Chevey339) 14 | - [Servo](https://github.com/servo) 15 | - [SolidFaker](https://github.com/SolidFaker) 16 | - [SummerKaze](https://github.com/SummerKaze) 17 | - [SunboyTPB](https://github.com/SunboyTPB) 18 | - [SwimmingTiger](https://github.com/SwimmingTiger) 19 | - [XiaobaiStudio](https://github.com/xiaobaigroup) 20 | - [Yebingiscn](https://github.com/Yebingiscn) 21 | - [Zitann](https://github.com/Zitann) 22 | - [autobcb](https://github.com/autobcb) 23 | - [awaLiny2333](https://github.com/awaLiny2333) 24 | - [azhuge233](https://github.com/azhuge233) 25 | - [bgli100](https://github.com/bgli100) 26 | - [chashaochang](https://github.com/chashaochang) 27 | - [dgh1818](https://github.com/dgh1818) 28 | - [hackeris](https://github.com/hackeris) 29 | - [iMerryou](https://github.com/Merryou6) 30 | - [jiegec](https://github.com/jiegec) 31 | - [kdada](https://github.com/kdada) 32 | - [likuai2010](https://github.com/likuai2010) 33 | - [lxdklp](https://github.com/lxdklp) 34 | - [mgz0227](https://github.com/mgz0227) 35 | - [nimmi-ai](https://github.com/nimmi-ai) 36 | - [niuhuan](https://github.com/niuhuan) 37 | - [qinshah](https://github.com/qinshah) 38 | - [shanyan-wcx](https://github.com/shanyan-wcx) 39 | - [shokakucarrier](https://github.com/shokakucarrier) 40 | - [smdsbz](https://gitee.com/smdsbz) 41 | - [wly5556](https://github.com/wly5556) 42 | - [云享社](https://github.com/Edge-Music) 43 | -------------------------------------------------------------------------------- /assets/add.py: -------------------------------------------------------------------------------- 1 | # /// script 2 | # dependencies = [ 3 | # "requests", 4 | # ] 5 | # /// 6 | import os 7 | import re 8 | import sys 9 | import requests 10 | from datetime import datetime 11 | from dataclasses import dataclass 12 | import urllib3 13 | from urllib3.exceptions import InsecureRequestWarning 14 | import warnings 15 | from update_readme import get_latest_release_time 16 | 17 | warnings.filterwarnings( 18 | "ignore", 19 | category=DeprecationWarning, 20 | message=".*Parsing dates involving a day of month without a year.*", 21 | ) 22 | urllib3.disable_warnings(InsecureRequestWarning) 23 | README_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "README.md") 24 | 25 | 26 | @dataclass 27 | class Item: 28 | name: str 29 | url: str 30 | desc: str 31 | time: str 32 | 33 | 34 | def add_project(repo_url, name, desc, platform): 35 | """添加项目到README""" 36 | print(f"正在解析项目: {repo_url}") 37 | 38 | print(f"项目名称: {name}") 39 | print(f"项目描述: {desc}") 40 | releases_url = f"{repo_url}/releases" 41 | 42 | # 获取最新发布时间 43 | latest_time = get_latest_release_time(releases_url) 44 | 45 | print(f"最新发布时间: {latest_time}") 46 | 47 | # 读取README 48 | with open(README_PATH, "r", encoding="utf-8") as f: 49 | content = f.read() 50 | 51 | # 找到表格 52 | table_match = re.search(rf"### {platform}\s*\n((?:\|.*\n)+)", content) 53 | if not table_match: 54 | print("未找到项目列表表格") 55 | return False 56 | 57 | table = table_match.group(1) 58 | lines = table.strip().split("\n") 59 | 60 | # 构建新项目条目 61 | new_item = ( 62 | f"| [{name}]({repo_url}) | [Link]({releases_url}) | {desc} | {latest_time} |" 63 | ) 64 | 65 | # 检查是否已存在 66 | for line in lines: 67 | if name in line and repo_url in line: 68 | print(f"项目 {name} 已存在于列表中") 69 | return False 70 | 71 | lines.insert(2, new_item) 72 | 73 | # 重新组装表格 74 | new_table = "\n".join(lines) + "\n" 75 | new_content = content.replace(table, new_table) 76 | 77 | # 写入文件 78 | with open(README_PATH, "w", encoding="utf-8") as f: 79 | f.write(new_content) 80 | 81 | print(f"项目 {name} 已成功添加到列表中") 82 | return True 83 | 84 | 85 | def main(): 86 | if len(sys.argv) != 5: 87 | print("用法: python add.py <项目仓库URL> <项目名称> <项目描述> <平台>") 88 | sys.exit(1) 89 | repo_url = sys.argv[1].strip() 90 | name = sys.argv[2].strip() 91 | desc = sys.argv[3].strip() 92 | platform = sys.argv[4].strip() 93 | 94 | # 验证URL格式 95 | if not ( 96 | repo_url.startswith("https://github.com/") 97 | or repo_url.startswith("https://gitee.com/") 98 | ): 99 | print("请提供有效的GitHub或Gitee仓库URL") 100 | sys.exit(1) 101 | 102 | if add_project(repo_url, name, desc, platform): 103 | print("添加成功!") 104 | else: 105 | print("添加失败!") 106 | 107 | 108 | if __name__ == "__main__": 109 | main() 110 | -------------------------------------------------------------------------------- /.github/workflows/add-project.yml: -------------------------------------------------------------------------------- 1 | name: Add Project 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | repo_url: 7 | description: '项目仓库URL (GitHub或Gitee)' 8 | required: true 9 | type: string 10 | default: '' 11 | name: 12 | description: '项目名称' 13 | required: true 14 | type: string 15 | default: '' 16 | desc: 17 | description: '项目描述' 18 | required: true 19 | type: string 20 | default: '' 21 | platform: 22 | description: '平台类型' 23 | required: true 24 | type: choice 25 | options: 26 | - 一次开发,多端部署 27 | - 鸿蒙手机/平板 28 | - 鸿蒙电脑 29 | default: 一次开发,多端部署 30 | jobs: 31 | add-project: 32 | runs-on: ubuntu-latest 33 | 34 | steps: 35 | - name: Checkout code 36 | uses: actions/checkout@v4 37 | 38 | - name: Set up Python 39 | uses: actions/setup-python@v4 40 | with: 41 | python-version: '3.9' 42 | 43 | - name: Install dependencies 44 | run: | 45 | python -m pip install --upgrade pip 46 | pip install requests 47 | 48 | - name: Validate repo URL 49 | run: | 50 | if [[ ! "${{ github.event.inputs.repo_url }}" =~ ^https://(github|gitee)\.com/.+/.+ ]]; then 51 | echo "错误: 请提供有效的GitHub或Gitee仓库URL" 52 | echo "格式: https://github.com/username/projectname" 53 | echo "格式: https://gitee.com/username/projectname" 54 | exit 1 55 | fi 56 | 57 | - name: Add project to README 58 | run: python assets/add.py "${{ github.event.inputs.repo_url }}" "${{ github.event.inputs.name }}" "${{ github.event.inputs.desc }}" "${{ github.event.inputs.platform }}" 59 | env: 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | 62 | - name: Check for changes 63 | id: changes 64 | run: | 65 | if git diff --exit-code README.md; then 66 | echo "changed=false" >> $GITHUB_OUTPUT 67 | echo "没有检测到变更,可能项目已存在或添加失败" 68 | else 69 | echo "changed=true" >> $GITHUB_OUTPUT 70 | echo "检测到README.md变更" 71 | fi 72 | 73 | - name: Show changes 74 | if: steps.changes.outputs.changed == 'true' 75 | run: | 76 | echo "=== README.md 变更内容 ===" 77 | git diff README.md 78 | 79 | - name: Commit and push changes 80 | if: steps.changes.outputs.changed == 'true' 81 | uses: stefanzweifel/git-auto-commit-action@v5 82 | with: 83 | commit_message: "添加项目: ${{ github.event.inputs.repo_url }}" 84 | file_pattern: README.md 85 | 86 | - name: Create summary 87 | run: | 88 | if [[ "${{ steps.changes.outputs.changed }}" == "true" ]]; then 89 | echo "✅ 项目添加成功!" >> $GITHUB_STEP_SUMMARY 90 | echo "📝 已更新 README.md" >> $GITHUB_STEP_SUMMARY 91 | echo "🔗 添加的项目: ${{ github.event.inputs.repo_url }}" >> $GITHUB_STEP_SUMMARY 92 | else 93 | echo "❌ 项目添加失败或已存在" >> $GITHUB_STEP_SUMMARY 94 | echo "🔗 尝试添加的项目: ${{ github.event.inputs.repo_url }}" >> $GITHUB_STEP_SUMMARY 95 | fi 96 | 97 | - name: Trigger update-readme workflow 98 | if: steps.changes.outputs.changed == 'true' 99 | uses: peter-evans/repository-dispatch@v3 100 | with: 101 | token: ${{ secrets.GITHUB_TOKEN }} 102 | repository: Zitann/HarmonyOS-Haps 103 | event-type: update-readme -------------------------------------------------------------------------------- /assets/contributers.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import requests 4 | import base64 5 | import sys 6 | from time import sleep 7 | 8 | CONTRIBUTERS_PATH = os.path.join( 9 | os.path.dirname(os.path.dirname(__file__)), "CONTRIBUTING.md" 10 | ) 11 | SVG_PATH = os.path.join( 12 | os.path.dirname(os.path.dirname(__file__)), "assets", "contributers.svg" 13 | ) 14 | 15 | 16 | class Contributer: 17 | name: str 18 | url: str 19 | image: str 20 | 21 | 22 | def get_github_avatar_base64(url: str) -> str: 23 | token = os.environ.get("GITHUB_TOKEN") 24 | headers = { 25 | "Accept": "application/vnd.github.v3+json", 26 | "Authorization": f"Bearer {token}", 27 | } 28 | info_url = url.replace("https://github.com/", "https://api.github.com/users/") 29 | response = requests.get(info_url, headers=headers) 30 | if response.status_code == 200: 31 | avatar_url = response.json().get("avatar_url", "") 32 | if avatar_url: 33 | img_response = requests.get(avatar_url) 34 | if img_response.status_code == 200: 35 | return "data:image/png;base64," + base64.b64encode( 36 | img_response.content 37 | ).decode("utf-8") 38 | return "" 39 | return "" 40 | 41 | 42 | def get_gitee_avatar_base64(url: str) -> str: 43 | headers = {"User-Agent": "update-readme-script"} 44 | info_url = url.replace("https://gitee.com/", "https://gitee.com/api/v5/users/") 45 | response = requests.get(info_url, headers=headers) 46 | if response.status_code == 200: 47 | avatar_url = response.json().get("avatar_url", "") 48 | if avatar_url: 49 | img_response = requests.get(avatar_url) 50 | if img_response.status_code == 200: 51 | return "data:image/png;base64," + base64.b64encode( 52 | img_response.content 53 | ).decode("utf-8") 54 | return "" 55 | return "" 56 | 57 | 58 | def get_atomgit_avatar_base64(url: str) -> str: 59 | headers = {"User-Agent": "update-readme-script"} 60 | info_url = url.replace( 61 | "https://atomgit.com/", "https://atomgit.com/api/user/v1/un/detail?path=" 62 | ) 63 | response = requests.get(info_url, headers=headers) 64 | if response.status_code == 200: 65 | avatar_url = "https://file.atomgit.com/" + response.json().get("photo", "") 66 | if avatar_url: 67 | img_response = requests.get(avatar_url) 68 | if img_response.status_code == 200: 69 | return "data:image/png;base64," + base64.b64encode( 70 | img_response.content 71 | ).decode("utf-8") 72 | return "" 73 | return "" 74 | 75 | 76 | def get_contributers(): 77 | with open(CONTRIBUTERS_PATH, "r", encoding="utf-8") as f: 78 | content = f.read() 79 | 80 | # 匹配所有作者链接 81 | matches = re.findall( 82 | r"- \[([^\]]+)\]\((https?://(?:github|gitee|atomgit)\.com/[^)]+)\)", content 83 | ) 84 | return matches 85 | 86 | 87 | def get_contributer_info(contributers): 88 | contributers_info = [] 89 | for name, url in contributers: 90 | print(f"作者: {name}, 主页: {url}") 91 | contributer = Contributer() 92 | contributer.name = name 93 | contributer.url = url 94 | while True: 95 | try: 96 | if "github.com" in url: 97 | contributer.image = get_github_avatar_base64(url) 98 | elif "gitee.com" in url: 99 | contributer.image = get_gitee_avatar_base64(url) 100 | elif "atomgit.com" in url: 101 | contributer.image = get_atomgit_avatar_base64(url) 102 | break 103 | except requests.RequestException as e: 104 | sleep(5) 105 | contributers_info.append(contributer) 106 | return contributers_info 107 | 108 | 109 | def generate_svg(contributers_info): 110 | size = 64 # 头像尺寸 111 | gap = 16 # 间距 112 | cols = 8 # 每行数量 113 | rows = (len(contributers_info) + cols - 1) // cols 114 | width = cols * (size + gap) + gap 115 | height = rows * (size + gap) + gap 116 | 117 | svg = [ 118 | f'' 119 | ] 120 | 121 | for idx, contributer in enumerate(contributers_info): 122 | x = gap + (idx % cols) * (size + gap) 123 | y = gap + (idx // cols) * (size + gap) 124 | # SVG 标签用于跳转,显示头像,悬浮显示用户名 125 | svg.append( 126 | f'' 127 | f'' 128 | f"{contributer.name}" 129 | ) 130 | 131 | svg.append("") 132 | return "\n".join(svg) 133 | 134 | 135 | def add_contributer(name: str, url: str): 136 | contributers = get_contributers() 137 | contributers.append((name, url)) 138 | contributers.sort(key=lambda x: x[0]) 139 | with open(CONTRIBUTERS_PATH, "w", encoding="utf-8") as f: 140 | for contributer in contributers: 141 | f.write(f"- [{contributer[0]}]({contributer[1]})\n") 142 | 143 | 144 | if __name__ == "__main__": 145 | if len(sys.argv) == 3: 146 | name = sys.argv[1] 147 | url = sys.argv[2] 148 | add_contributer(name, url) 149 | print(f"已添加作者: {name}, 主页: {url}") 150 | contributers = get_contributers() 151 | contributers_info = get_contributer_info(contributers) 152 | svg_code = generate_svg(contributers_info) 153 | with open( 154 | SVG_PATH, 155 | "w", 156 | encoding="utf-8", 157 | ) as f: 158 | f.write(svg_code) 159 | -------------------------------------------------------------------------------- /assets/update_readme.py: -------------------------------------------------------------------------------- 1 | # /// script 2 | # dependencies = [ 3 | # "requests", 4 | # ] 5 | # /// 6 | import os 7 | import re 8 | import requests 9 | from datetime import datetime 10 | from dataclasses import dataclass 11 | import urllib3 12 | from urllib3.exceptions import InsecureRequestWarning 13 | import warnings 14 | from datetime import datetime 15 | 16 | warnings.filterwarnings( 17 | "ignore", 18 | category=DeprecationWarning, 19 | message=".*Parsing dates involving a day of month without a year.*", 20 | ) 21 | urllib3.disable_warnings(InsecureRequestWarning) 22 | README_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "README.md") 23 | 24 | 25 | @dataclass 26 | class Item: 27 | name: str 28 | url: str 29 | desc: str 30 | time: str 31 | 32 | 33 | def get_github_time(url): 34 | token = os.environ.get("GITHUB_TOKEN") 35 | headers = {"User-Agent": "update-readme-script", "Authorization": f"Bearer {token}"} 36 | resp = requests.get(url, headers=headers, verify=False) 37 | if resp.status_code == 200: 38 | html = resp.text 39 | # Github: 40 | m = re.search(r']+datetime="([^"]+)"', html) 41 | if m: 42 | dt = datetime.strptime(m.group(1), "%Y-%m-%dT%H:%M:%SZ") 43 | return dt.strftime("%m-%d") 44 | return None 45 | 46 | 47 | def get_gitee_time(url): 48 | headers = {"User-Agent": "update-readme-script"} 49 | resp = requests.get(url, headers=headers, verify=False) 50 | if resp.status_code == 200: 51 | html = resp.text 52 | # Gitee:
53 | m = re.search( 54 | r"
]*data-commit-date=['\"]([^'\"]+)['\"]", 55 | html, 56 | ) 57 | if m: 58 | dt = datetime.strptime(m.group(1).split(" +")[0], "%Y-%m-%d %H:%M:%S") 59 | return dt.strftime("%m-%d") 60 | return None 61 | 62 | 63 | def get_atomgit_time(url): 64 | headers = {"User-Agent": "update-readme-script"} 65 | url = url.replace("/tags?tab=release", "") 66 | resp = requests.get(url, headers=headers, verify=False) 67 | if resp.status_code == 200: 68 | html = resp.text 69 | m = re.search(r"type:\s*'PROJECT',\s*id:\s*'(\d+)'", html) 70 | id = m.group(1) if m else None 71 | if id: 72 | url = f"https://atomgit.com/api/v3/projects/{id}?_input_charset=utf-8" 73 | resp = requests.get(url, headers=headers, verify=False) 74 | if resp.status_code == 200: 75 | data = resp.json() 76 | # 2025-08-03T23:05:59+08:00 77 | dt = datetime.strptime(data["last_activity_at"], "%Y-%m-%dT%H:%M:%S%z") 78 | return dt.strftime("%m-%d") 79 | else: 80 | print(f"无法从AtomGit链接中获取项目ID: {url}") 81 | return None 82 | return None 83 | 84 | 85 | def get_latest_release_time(url): 86 | if "github.com" in url: 87 | return get_github_time(url) 88 | elif "gitee.com" in url: 89 | return get_gitee_time(url) 90 | elif "atomgit.com" in url: 91 | return get_atomgit_time(url) 92 | else: 93 | print(f"不支持的链接: {url}") 94 | return None 95 | 96 | 97 | def update(title): 98 | updated_apps = [] 99 | with open(README_PATH, "r", encoding="utf-8") as f: 100 | content = f.read() 101 | table_match = re.search(rf"### {re.escape(title)}\s*\n((?:\|.*\n)+)", content) 102 | table = table_match.group(1) 103 | title = table.split("\n")[0:2] 104 | lines = table.strip().split("\n")[2:] 105 | items = [] 106 | for line in lines: 107 | cols = line.split("|") 108 | if len(cols) >= 5: 109 | item = Item( 110 | name=cols[1].strip(), 111 | url=cols[2].strip(), 112 | desc=cols[3].strip(), 113 | time=cols[4].strip(), 114 | ) 115 | old_time = item.time 116 | if item.time == "archived": 117 | print(f"项目: {item.name},已归档") 118 | elif item.time == "updating": 119 | print(f"项目: {item.name},正在更新中,跳过") 120 | elif item.time == "close-source": 121 | print(f"项目: {item.name},已关闭,跳过") 122 | else: 123 | latest_time = get_latest_release_time( 124 | item.url.replace("[Link](", "").replace(")", "") 125 | ) 126 | print( 127 | f"项目: {item.name.split('(')[0].strip()},原时间: {item.time},最新发布时间: {latest_time}" 128 | ) 129 | if latest_time and latest_time != old_time: 130 | item.time = latest_time 131 | updated_apps.append(item.name) 132 | items.append(item) 133 | items.sort( 134 | key=lambda x: ( 135 | datetime.min 136 | if x.time in ("archived", "close-source") 137 | else ( 138 | datetime.max 139 | if x.time == "updating" 140 | else datetime.strptime(x.time, "%m-%d") 141 | ) 142 | ), 143 | reverse=True, 144 | ) 145 | new_table = title 146 | for item in items: 147 | new_table.append(f"| {item.name} | {item.url} | {item.desc} | {item.time} |") 148 | new_table = "\n".join(new_table) + "\n" 149 | new_content = content.replace(table, new_table) 150 | if new_content != content: 151 | with open(README_PATH, "w", encoding="utf-8") as f: 152 | f.write(new_content) 153 | return updated_apps 154 | else: 155 | return [] 156 | 157 | 158 | def report(updated_apps): 159 | """报告更新状态""" 160 | # 每一个都执行split('(')[0][1:-1] 并连接成字符串 161 | apps_str = ", ".join([app.split("(")[0][1:-1] for app in updated_apps]) 162 | try: 163 | api_url = f"https://api.chuckfang.com/github/GitHub更新{apps_str}?url=https://github.com/Zitann/HarmonyOS-Haps" 164 | requests.get(api_url, timeout=5) 165 | print(f"已通知API: 有软件更新,更新应用: {apps_str}") 166 | except Exception as e: 167 | print(f"通知API失败: {e}") 168 | 169 | 170 | if __name__ == "__main__": 171 | update_title = ["一次开发,多端部署", "鸿蒙手机/平板", "鸿蒙电脑"] 172 | updated_apps = [] 173 | for title in update_title: 174 | updated_apps.extend(update(title)) 175 | if updated_apps: 176 | print("README已更新") 177 | report(updated_apps) 178 | apps_str = ", ".join([app.split("(")[0][1:-1] for app in updated_apps]) 179 | with open(".apps_str.txt", "w", encoding="utf-8") as f: 180 | f.write(apps_str) 181 | else: 182 | print("README无需更新") 183 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

5 | 6 | Logo 7 | 8 | 9 |

鸿蒙Next Hap安装包合集

10 |

11 | 欢迎来到鸿蒙Next HAP安装包合集仓库!本仓库汇集了各类适用于鸿蒙Next系统的HAP安装包,旨在为用户提供便捷的应用下载和更新资源。 12 |

13 | 14 |

15 | 16 | 17 | 18 | [![Contributors][contributors-shield]][contributors-url] 19 | [![Forks][forks-shield]][forks-url] 20 | [![Stargazers][stars-shield]][stars-url] 21 | [![Issues][issues-shield]][issues-url] 22 | 23 | ### 目录 24 | - [声明](#声明) 25 | - [安装工具](#安装工具) 26 | - [一次开发,多端部署](#一次开发,多端部署) 27 | - [鸿蒙手机/平板](#鸿蒙手机/平板) 28 | - [鸿蒙电脑](#鸿蒙电脑) 29 | - [反馈](#反馈) 30 | - [鸣谢(不分先后)](#鸣谢不分先后) 31 | - [Star History](#star-history) 32 | 33 | ### 声明 34 | 35 | 本仓库的所有内容仅供学习交流使用。如果您认为该内容侵犯了您的权益,请在 issue 中与我们联系,我们将立即删除相关内容。 36 | 37 | ### 安装工具 38 | 39 | **小白调试助手** 40 | 41 | **下载链接:**[Link](https://github.com/likuai2010/auto-installer/releases/latest) 42 | 43 | 小白调试助手(Auto-Installer)是一款免费、跨平台的鸿蒙应用开发调试工具。**本仓库安装包均推荐使用此工具安装。** 44 | 45 | [点击下载教程文档](https://github.com/Zitann/HarmonyOS-Haps/raw/refs/heads/main/assets/guide.pdf) 46 | 47 | [点击查看视频教程](https://www.bilibili.com/video/BV1hkZ7YnEMd/) 48 | 49 | ### 一次开发,多端部署 50 | 51 | | 软件 | 下载链接 | 描述 | 更新 | 52 | | ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | 53 | | [Gramony](https://github.com/Gramony/Gramony) | [Link](https://t.me/GramonyApp) | ✈ 鸿蒙版,下载地址为 ✈ 群组 | updating | 54 | | [PiliPlus](https://github.com/qinshah/PiliPlus) | [Link](https://github.com/qinshah/PiliPlus/releases) | BiliBili第三方客户端 | 12-21 | 55 | | [HiSH](https://github.com/harmoninux/HiSH) | [Link](https://github.com/harmoninux/HiSH/releases) | 在鸿蒙手机、平板和PC上运行 Linux Shell | 12-20 | 56 | | [植物大战僵尸杂交版](https://github.com/Kaiter-Plus/ohos-pvz_zj) | [Link](https://github.com/Kaiter-Plus/ohos-pvz_zj/releases) | 将热门PC游戏“植物大战僵尸杂交版”移植到鸿蒙平台的版本 | 12-20 | 57 | | [Kazumi](https://github.com/ErBWs/Kazumi) | [Link](https://github.com/ErBWs/Kazumi/releases) | 一款基于自定义规则来采集番剧资源,并支持 Anime4K 实时超分辨率的在线观看应用。 | 12-14 | 58 | | [Melotopia](https://github.com/Chenlvin/Melotopia-HMOS) | [Link](https://github.com/Chenlvin/Melotopia-HMOS/releases) | ✨ 鸿蒙原生音乐播放器|🚀 全场景设备适配 本项目为第三方应用, 应用本身不提供在线服务, 仅提供UI界面 | 12-14 | 59 | | [Audiobookshelf](https://github.com/shanyan-wcx/Audiobookshelf-HarmonyOS) | [Link](https://github.com/shanyan-wcx/Audiobookshelf-HarmonyOS/releases) | 一款用于连接 Audiobookshelf 私人有声书服务器的鸿蒙Next客户端。暂不支持播客。 | 12-02 | 60 | | [冲浪喵](https://github.com/awaLiny2333/LinysBrowser_NEXT) | [Link](https://github.com/awaLiny2333/LinysBrowser_NEXT/releases) | 一款为鸿蒙NEXT开发的、轻量化的网页浏览器。 | 11-29 | 61 | | [CanPlayerHap](https://github.com/Merryou6/CanPlayerHap) | [Link](https://github.com/Merryou6/CanPlayerHap/releases) | 鸿蒙NEXT上基于web运行ons galgame 演示视频 https://b23.tv/rNW0GNB | 11-26 | 62 | | [FinVideo](https://github.com/OHPG/FinVideo) | [Link](https://github.com/OHPG/FinVideo/releases) | 一款在鸿蒙Next上使用的 Jellyfin 视频播放器,用于连接和播放在线影音库。 | 11-17 | 63 | | [Etohos](https://github.com/niuhuan/etohos) | [Link](https://github.com/niuhuan/etohos/releases) | 一个基于flutter的鸿蒙系统应用,用来接入EasyTier网络。 | 11-12 | 64 | | [Harmonic](https://github.com/shanyan-wcx/Harmonic) | [Link](https://github.com/shanyan-wcx/Harmonic/releases) | 一款连接 Navidrome 个人音乐服务器的鸿蒙原生客户端,用于在手机、平板、车机等设备上播放您的音乐库。 | 10-26 | 65 | | [自由文档](https://github.com/qinshah/free_book) | [Link](https://github.com/qinshah/free_book/releases) | 一款简单、自由好用的轻量级富文本文档编辑器 | 10-17 | 66 | | [Minecraft Box](https://github.com/lxdklp/MCB_OHOS) | [Link](https://github.com/lxdklp/MCB_OHOS/releases) | Minecraft Java 服务器管理工具 | 10-11 | 67 | | [OTP Token](https://github.com/SolidFaker/ohtotptoken) | [Link](https://github.com/SolidFaker/ohtotptoken/releases) | 一款支持TOTP、HOTP、Steam令牌和Forti令牌的开源双因素认证(2FA)令牌生成器。 | 09-22 | 68 | | [selineRead](https://atomgit.com/liquid/openSelineRead) | [Link](https://atomgit.com/liquid/openSelineRead/tags?tab=release) | SelineRead 是一款专为鸿蒙系统设计的开源电子书下载工具,让用户能便捷地从 Z-Library 等书源搜索并下载喜爱的书籍。 | 09-09 | 69 | | [JellyFin](https://github.com/chashaochang/JellyFin_HarmonyOS) | [Link](https://github.com/chashaochang/JellyFin_HarmonyOS/releases) | 非官方的 Jellyfin 客户端,将 Jellyfin 的体验带到鸿蒙设备上,能让你随心所欲地控制、管理和流媒体你的媒体资源。 | 08-02 | 70 | | [流心视频](https://github.com/Yebingiscn/SweetVideo) | [Link](https://github.com/Yebingiscn/SweetVideo/releases) | 一款运行在HarmonyOS Next上的原生视频播放器,支持播放多种视频、音频及字幕格式。基于开源项目[流心视频](https://gitee.com/lqsxy/sweetvideo/tree/master)二次开发 | 07-31 | 71 | | [S1-Orange](https://github.com/wly5556/S1-Orange) | [Link](https://github.com/wly5556/S1-Orange/releases/) | 一款专为鸿蒙Next平台开发的 stage1st.com 论坛移动客户端。 | 07-30 | 72 | | [ClashBox](https://github.com/xiaobaigroup/hapapp) | [Link](https://github.com/xiaobaigroup/hapapp/releases) | ClashBox 是首款为鸿蒙 HarmonyOS NEXT 平台打造的代理软件,基于 Mihomo 内核,致力于提供稳定、美观且支持多设备的一流代理体验。 | 07-08 | 73 | | [Moonlight](https://gitee.com/smdsbz/moonlight-ohos) | [Link](https://gitee.com/smdsbz/moonlight-ohos/releases) | 在 HarmonyOS Next 上的另一个 Sunshine 客户端实现。 | 04-03 | 74 | | [云享社](https://github.com/Edge-Music/Core) | [Link](https://github.com/Edge-Music/Core/releases) | 一个在鸿蒙NEXT上,可连接多个音乐平台和私有数据源的统一音乐播放器。 | close-source | 75 | 76 | ### 鸿蒙手机/平板 77 | 78 | | 软件 | 下载链接 | 描述 | 更新 | 79 | | ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | 80 | | [immich](https://github.com/dgh1818/immich_ohos) | [Link](https://github.com/dgh1818/immich_ohos/releases) | 一款连接 Immich 私人照片和视频备份服务器的鸿蒙客户端,用于在鸿蒙设备上浏览和管理个人媒体库。 | 12-21 | 81 | | [Wake](https://github.com/azhuge233/Wake-HarmonyOS) | [Link](https://github.com/azhuge233/Wake-HarmonyOS/releases) | 一款运行在鸿蒙Next平台上的网络唤醒(Wake-on-LAN)应用。 | 12-17 | 82 | | [Kelivo](https://github.com/Chevey339/kelivo) | [Link](https://github.com/Chevey339/kelivo/releases) | 一个Flutter LLM聊天客户端。支持Android、iOS和Harmony Next。 | 12-13 | 83 | | [Pica Comic](https://github.com/nimmi-ai/PicaComic_ohos) | [Link](https://github.com/nimmi-ai/PicaComic_ohos/releases) | 一款使用 Flutter 构建的多源漫画应用。 | 12-12 | 84 | | [KeePassHO](https://github.com/aimilin6688/KeePassHO) | [Link](https://github.com/aimilin6688/KeePassHO/releases) | 本地密码管理软件,支持 keepass 系列的数据库,现在已经实现了 密码管理和TOTP 功能。 | 12-08 | 85 | | [轻阅读](https://github.com/autobcb/read) | [Link](https://github.com/autobcb/read/releases) | 一款可通过自部署服务端,在手机、平板等多种设备上同步阅读进度的开源阅读应用。 | 12-04 | 86 | | [开源阅读](https://github.com/mgz0227/legado-Harmony) | [Link](https://github.com/mgz0227/legado-Harmony/releases) | 一款支持自定义书源规则,可抓取任意网页内容进行阅读的开源应用。 | 11-30 | 87 | | [PixEz](https://github.com/bgli100/pixez-flutter-ohos) | [Link](https://github.com/bgli100/pixez-flutter-ohos/releases) | 一款支持免代理直连及查看动图的第三方Pixiv flutter客户端 | 11-20 | 88 | | [soc-search](https://github.com/Amview/soc-search) | [Link](https://github.com/Amview/soc-search/releases) | 一款可以搜索和查询安兔兔、Geekbench等主流平台SoC(处理器)性能跑分排行的工具。 | 09-23 | 89 | | [包名解析](https://github.com/SummerKaze/AppBundleNameForShared) | [Link](https://github.com/SummerKaze/AppBundleNameForShared/releases) | 一款用于从华为应用商城分享链接中提取应用包名的鸿蒙工具。 | 09-14 | 90 | | [KDAuth](https://github.com/kdada/Authenticator) | [Link](https://github.com/kdada/Authenticator/releases) | 一款支持标准和 Steam 令牌的双因子认证(2FA)密码生成工具。 | 08-25 | 91 | | [awesome_blbl](https://github.com/Luo-A-Chen/AwesomeResume) | [Link](https://github.com/Luo-A-Chen/AwesomeResume/releases) | 使用鸿蒙flutter3.22版本开发的第三方B站 | 08-02 | 92 | | [微型课程表](https://github.com/SunboyTPB/Micro-Course) | [Link](https://github.com/SunboyTPB/Micro-Course/releases) | 一款基于 ArkUI-X 开发的、用于轻松管理课程表的开源应用。 | 07-09 | 93 | | [Neon](https://github.com/shokakucarrier/neon-ohos) | [Link](https://github.com/shokakucarrier/neon-ohos/releases) | 一个使用 Flutter 构建融合、跨平台 Nextcloud 客户端的开发框架。 | 07-01 | 94 | | [LocalSend](https://github.com/Aloereed/localsend-ohos) | [Link](https://github.com/Aloereed/localsend-ohos/releases) | LocalSend鸿蒙NEXT实现,本地网络文件和消息分享工具,无需互联网连接即可安全传输。 | 04-15 | 95 | | [影视猫](https://github.com/CatPawApp/CatPawOpen) | [Link](https://github.com/CatPawApp/CatPawOpen/releases) | 影视猫,与 TVBox 类似的聚合类影视播放工具,靠配置接口拉取第三方视频源。 | 01-15 | 96 | | [RetroArch](https://github.com/likuai2010/auto-installer/releases/tag/0.0.0) | [Link](https://github.com/likuai2010/auto-installer/releases/download/0.0.0/RetroArch-default-unsigned.hap) | 一款能够在多种设备上流畅运行PSP游戏的高性能开源模拟器。 | archived | 97 | | [ppsspp](https://github.com/likuai2010/auto-installer/releases/tag/0.0.0) | [Link](https://github.com/likuai2010/auto-installer/releases/download/0.0.0/ppsspp-default-unsigned.hap) | 一个能够让你在多种设备上运行大量经典游戏的多功能模拟器前端。 | archived | 98 | | [宝可梦图鉴](https://github.com/Luxcis/Pokedex_Next) | [Link](https://github.com/Luxcis/Pokedex_Next/releases) | 一款用于查询宝可梦、招式及特性详细信息的图鉴应用。 | archived | 99 | 100 | ### 鸿蒙电脑 101 | 102 | | 软件 | 下载链接 | 描述 | 更新 | 103 | | ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | 104 | | [Servo](https://github.com/servo/servo) | [Link](https://github.com/servo/servo/releases) | Servo 是一个用 Rust 语言编写的浏览器内核的浏览器 | 12-16 | 105 | | [Harmonix](https://github.com/hackeris/Harmonix) | [Link](https://github.com/hackeris/Harmonix/releases) | 一个能在鸿蒙PC上运行 aarch64/x86_64/riscv64 Linux 程序的终端 | 08-30 | 106 | | [Termony](https://github.com/jiegec/Termony) | [Link](https://github.com/jiegec/Termony/releases) | 一款为鸿蒙操作系统提供的终端模拟器,允许用户运行常见的Linux命令和程序。 | 06-15 | 107 | | [aria2](https://github.com/SwimmingTiger/aria2-ohos) | [Link](https://github.com/SwimmingTiger/aria2-ohos/releases) | 一个能在鸿蒙PC上通过命令行使用的Aria2下载工具。 | 06-11 | 108 | 109 | ### 反馈 110 | 111 | 如果您在使用过程中遇到无法使用的HAP安装包,或者发现有其他有用的HAP安装包,欢迎在issue中进行说明。我们将尽快处理您的反馈,确保资源的有效性和更新。同时,我们非常感谢您的贡献,帮助我们不断改进和丰富本仓库的内容。 112 | 113 | ### 鸣谢(按ASCII排序) 114 | 115 | [![Contributiors](assets/contributers.svg)](https://github.com/Zitann/HarmonyOS-Haps/tree/main?tab=contributing-ov-file#) 116 | 117 | ### Star History 118 | 119 | [![Star History Chart](https://api.star-history.com/svg?repos=Zitann/HarmonyOS-Haps&type=Date)](https://star-history.com/#Zitann/HarmonyOS-Haps&Date) 120 | 121 | 122 | 123 | [your-project-path]:Zitann/HarmonyOS-Haps 124 | [contributors-shield]: https://img.shields.io/github/contributors/Zitann/HarmonyOS-Haps.svg?style=flat-square 125 | [contributors-url]: https://github.com/Zitann/HarmonyOS-Haps/graphs/contributors 126 | [forks-shield]: https://img.shields.io/github/forks/Zitann/HarmonyOS-Haps.svg?style=flat-square 127 | [forks-url]: https://github.com/Zitann/HarmonyOS-Haps/network/members 128 | [stars-shield]: https://img.shields.io/github/stars/Zitann/HarmonyOS-Haps.svg?style=flat-square 129 | [stars-url]: https://github.com/Zitann/HarmonyOS-Haps/stargazers 130 | [issues-shield]: https://img.shields.io/github/issues/Zitann/HarmonyOS-Haps.svg?style=flat-square 131 | [issues-url]: https://img.shields.io/github/issues/Zitann/HarmonyOS-Haps.svg 132 | --------------------------------------------------------------------------------