Spaces:
Running
Running
app_clean.py: Clean backend serving index_v2.html with all APIs preserved
Browse files- app_clean.py +69 -0
app_clean.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
VNEWS Clean Backend - serves static/index_v2.html directly.
|
| 3 |
+
No injection layers. All APIs from existing modules preserved.
|
| 4 |
+
Comments feature REMOVED per user request.
|
| 5 |
+
"""
|
| 6 |
+
import sys, os
|
| 7 |
+
|
| 8 |
+
# Import the full chain which registers all API endpoints on the FastAPI app
|
| 9 |
+
from app_main import app, _search_all, _clean
|
| 10 |
+
|
| 11 |
+
# Now override the root '/' to serve our clean frontend
|
| 12 |
+
from fastapi import Query, Request
|
| 13 |
+
from fastapi.responses import HTMLResponse, FileResponse, JSONResponse
|
| 14 |
+
from fastapi.staticfiles import StaticFiles
|
| 15 |
+
import os
|
| 16 |
+
|
| 17 |
+
# Remove old '/' route
|
| 18 |
+
app.router.routes = [r for r in app.router.routes if not (
|
| 19 |
+
getattr(r, 'path', None) == '/' and 'GET' in getattr(r, 'methods', set())
|
| 20 |
+
)]
|
| 21 |
+
|
| 22 |
+
# Remove comment endpoints (user requested removal)
|
| 23 |
+
app.router.routes = [r for r in app.router.routes if not (
|
| 24 |
+
getattr(r, 'path', None) in ('/api/short/comments', '/api/short/comment')
|
| 25 |
+
)]
|
| 26 |
+
|
| 27 |
+
# Mount static files
|
| 28 |
+
STATIC_DIR = os.path.join(os.path.dirname(__file__), 'static')
|
| 29 |
+
app.mount('/static', StaticFiles(directory=STATIC_DIR), name='static')
|
| 30 |
+
|
| 31 |
+
@app.get('/')
|
| 32 |
+
async def serve_index():
|
| 33 |
+
"""Serve the clean v2 frontend - single HTML file, no injection."""
|
| 34 |
+
index_path = os.path.join(STATIC_DIR, 'index_v2.html')
|
| 35 |
+
if os.path.exists(index_path):
|
| 36 |
+
return FileResponse(index_path, media_type='text/html')
|
| 37 |
+
return HTMLResponse('<h1>VNEWS</h1><p>index_v2.html not found</p>', status_code=500)
|
| 38 |
+
|
| 39 |
+
# Keep /api/hashtag/sources using direct search (not Google News)
|
| 40 |
+
# This was already overridden in app_main.py with _search_all
|
| 41 |
+
# Just make sure it's accessible
|
| 42 |
+
|
| 43 |
+
# Storage status endpoint
|
| 44 |
+
@app.get('/api/storage_status')
|
| 45 |
+
def storage_status():
|
| 46 |
+
"""Check if persistent storage is enabled."""
|
| 47 |
+
data_dir = '/data'
|
| 48 |
+
persistent = os.path.isdir(data_dir) and os.access(data_dir, os.W_OK)
|
| 49 |
+
return JSONResponse({'persistent': persistent, 'path': data_dir})
|
| 50 |
+
|
| 51 |
+
# Categories for the tab bar
|
| 52 |
+
@app.get('/api/categories')
|
| 53 |
+
def get_categories():
|
| 54 |
+
"""Return category list for frontend tab bar."""
|
| 55 |
+
return JSONResponse([]) # Categories moved into News tab, homepage shows media content
|
| 56 |
+
|
| 57 |
+
# Share page
|
| 58 |
+
@app.get('/s')
|
| 59 |
+
async def share_page(url: str = '', title: str = '', img: str = ''):
|
| 60 |
+
"""OG share page for social media."""
|
| 61 |
+
html = f'''<!DOCTYPE html><html><head>
|
| 62 |
+
<meta property="og:title" content="{_clean(title)}">
|
| 63 |
+
<meta property="og:url" content="{_clean(url)}">
|
| 64 |
+
<meta property="og:image" content="{_clean(img)}">
|
| 65 |
+
<meta property="og:type" content="article">
|
| 66 |
+
<meta property="og:site_name" content="VNEWS">
|
| 67 |
+
<meta http-equiv="refresh" content="0;url={_clean(url) or '/'}">
|
| 68 |
+
</head><body>Redirecting...</body></html>'''
|
| 69 |
+
return HTMLResponse(html)
|