|
|
import os |
|
|
import tempfile |
|
|
from flask import Flask, render_template, request, send_file, flash |
|
|
from git import Repo |
|
|
import shutil |
|
|
import zipfile |
|
|
import re |
|
|
|
|
|
app = Flask(__name__) |
|
|
|
|
|
def download_github_files(repo_url, file_paths, github_token=None): |
|
|
"""从GitHub仓库下载指定路径的文件,并打包成zip。""" |
|
|
try: |
|
|
temp_dir = tempfile.mkdtemp() |
|
|
repo_name = repo_url.split('/')[-1].replace(".git", "") |
|
|
local_repo_path = os.path.join(temp_dir, repo_name) |
|
|
|
|
|
|
|
|
if github_token: |
|
|
repo_url_with_token = repo_url.replace("https://", f"https://{github_token}@") |
|
|
Repo.clone_from(repo_url_with_token, local_repo_path) |
|
|
else: |
|
|
Repo.clone_from(repo_url, local_repo_path) |
|
|
|
|
|
zip_file_path = os.path.join(temp_dir, f"{repo_name}_files.zip") |
|
|
with zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED) as zf: |
|
|
for file_path in file_paths: |
|
|
abs_file_path = os.path.join(local_repo_path, file_path) |
|
|
if os.path.exists(abs_file_path) and os.path.isfile(abs_file_path): |
|
|
zf.write(abs_file_path, os.path.basename(abs_file_path)) |
|
|
elif os.path.exists(abs_file_path) and os.path.isdir(abs_file_path): |
|
|
for root, dirs, files in os.walk(abs_file_path): |
|
|
for file in files: |
|
|
file_abs_path = os.path.join(root, file) |
|
|
zf.write(file_abs_path, os.path.relpath(file_abs_path, local_repo_path)) |
|
|
|
|
|
shutil.rmtree(local_repo_path) |
|
|
if os.path.exists(zip_file_path) and os.path.getsize(zip_file_path) > 0: |
|
|
return zip_file_path, f"{repo_name}_files.zip" |
|
|
else: |
|
|
return None, None |
|
|
except Exception: |
|
|
return None, None |
|
|
|
|
|
def parse_github_url(url): |
|
|
"""解析 GitHub URL,提取仓库 URL 和文件路径。""" |
|
|
match = re.match(r'https://github\.com/([^/]+)/([^/]+)/tree/([^/]+)(.*)', url) |
|
|
if match: |
|
|
owner, repo, branch, path = match.groups() |
|
|
repo_url = f'https://github.com/{owner}/{repo}.git' |
|
|
file_paths = [path.lstrip('/')] if path else [] |
|
|
return repo_url, file_paths |
|
|
else: |
|
|
return None, None |
|
|
|
|
|
@app.route('/', methods=['GET', 'POST']) |
|
|
def index(): |
|
|
if request.method == 'POST': |
|
|
repo_path = request.form.get('repo_path') |
|
|
github_token = request.form.get('github_token') |
|
|
if not repo_path: |
|
|
flash('请提供 GitHub 链接', 'error') |
|
|
return render_template('index.html') |
|
|
|
|
|
repo_url, file_paths = parse_github_url(repo_path) |
|
|
if not repo_url: |
|
|
flash('无效的 GitHub 链接', 'error') |
|
|
return render_template('index.html') |
|
|
|
|
|
zip_path, zip_filename = download_github_files(repo_url, file_paths, github_token) |
|
|
if zip_path: |
|
|
return send_file(zip_path, as_attachment=True, download_name=zip_filename) |
|
|
else: |
|
|
flash('下载失败,请检查链接和文件路径。', 'error') |
|
|
return render_template('index.html') |
|
|
|
|
|
return render_template('index.html') |
|
|
|
|
|
if __name__ == '__main__': |
|
|
port = int(os.getenv("PORT", 5000)) |
|
|
app.run(debug=False, host="0.0.0.0", port=port) |