""" 叶兴阳双语音标有声读物 PDF 下载站 Flask 路由器 — 干净 URL + SPA 回退 + API 接口 """ from flask import Flask, send_file, jsonify, request, abort, send_from_directory import os import json app = Flask(__name__, static_folder='.', static_url_path='') BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 预读索引,加快 /api/sources 响应 with open(os.path.join(BASE_DIR, 'data', 'index.json'), 'r', encoding='utf-8') as f: INDEX = json.load(f) # 构建 id → source 的快速查找 ID_MAP = {s['id']: s for s in INDEX['sources']} # ─── 页面路由 ──────────────────────────────────────── @app.route('/') @app.route('/index.html') def home(): return send_file('index.html') @app.route('/reader') def reader(): return send_file('reader.html') @app.route('/category/') def category(cat_id): """干净 URL 分类页 — 回退到 index.html,前端 JS 识别路由""" if cat_id not in ID_MAP: abort(404) return send_file('index.html') # ─── 数据 API ──────────────────────────────────────── @app.route('/api/sources') def api_sources(): """返回所有分类的基本信息(不含具体文件)""" return jsonify(INDEX) @app.route('/api/source/') def api_source(cat_id): """返回单个分类的元信息""" if cat_id not in ID_MAP: return jsonify({'error': '分类不存在'}), 404 src = dict(ID_MAP[cat_id]) return jsonify(src) @app.route('/api/files/') def api_files(cat_id): """返回某个分类的全部文件列表(按需合并分片)""" if cat_id not in ID_MAP: return jsonify({'error': '分类不存在'}), 404 src = ID_MAP[cat_id] all_files = [] for chunk in src['chunks']: chunk_path = os.path.join(BASE_DIR, 'data', chunk['f']) if os.path.isfile(chunk_path): with open(chunk_path, 'r', encoding='utf-8') as f: all_files.extend(json.load(f)) return jsonify(all_files) @app.route('/api/search/') def api_search(cat_id): """搜索指定分类的文件""" q = request.args.get('q', '').lower().strip() if cat_id not in ID_MAP: return jsonify({'error': '分类不存在'}), 404 src = ID_MAP[cat_id] results = [] for chunk in src['chunks']: chunk_path = os.path.join(BASE_DIR, 'data', chunk['f']) if os.path.isfile(chunk_path): with open(chunk_path, 'r', encoding='utf-8') as f: items = json.load(f) results.extend([item for item in items if q in item[0].lower()]) return jsonify(results) @app.route('/api/health') def api_health(): return jsonify({'status': 'ok', 'sources': len(INDEX['sources'])}) # ─── 静态文件 ──────────────────────────────────────── @app.route('/data/') def serve_data(filename): """托管 data/ 目录下的 JSON 数据文件""" data_dir = os.path.join(BASE_DIR, 'data') return send_from_directory(data_dir, filename) @app.route('/favicon.ico') def favicon(): return '', 204 # ─── 404 ──────────────────────────────────────────── @app.errorhandler(404) def not_found(e): return ''' 404 - 页面不存在

404

页面不存在

← 返回首页
''', 404 # ─── 启动 ──────────────────────────────────────────── if __name__ == '__main__': print(f'Server starting at http://0.0.0.0:7860') print(f'Routes: / /category/ /reader /api/sources /api/files/ /api/search/?q=') app.run(host='0.0.0.0', port=7860, debug=False)