forked from MinhQuan/MiscCorpo
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| adc1934e9c | |||
| 9f7824825c |
@@ -3,10 +3,12 @@ from flask import Flask
|
|||||||
from config import Config
|
from config import Config
|
||||||
from routes.transcriptionRoute import transcription_bp
|
from routes.transcriptionRoute import transcription_bp
|
||||||
from routes.scraperZLibraryRoute import scraperZLibraryRoute
|
from routes.scraperZLibraryRoute import scraperZLibraryRoute
|
||||||
|
from routes.headerRoute import header_bp
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
"""Application factory function"""
|
"""Application factory function"""
|
||||||
app = Flask(__name__, template_folder='views')
|
# static_folder=None → tắt hoàn toàn thư mục /static mặc định của Flask
|
||||||
|
app = Flask(__name__, template_folder='views', static_folder=None)
|
||||||
|
|
||||||
# Load configuration
|
# Load configuration
|
||||||
app.config.from_object(Config)
|
app.config.from_object(Config)
|
||||||
@@ -18,6 +20,7 @@ def create_app():
|
|||||||
Config.init_app()
|
Config.init_app()
|
||||||
|
|
||||||
# Register blueprints
|
# Register blueprints
|
||||||
|
app.register_blueprint(header_bp)
|
||||||
app.register_blueprint(transcription_bp)
|
app.register_blueprint(transcription_bp)
|
||||||
app.register_blueprint(scraperZLibraryRoute, url_prefix='/scraperZLibrary')
|
app.register_blueprint(scraperZLibraryRoute, url_prefix='/scraperZLibrary')
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# routes/headerRoute.py
|
||||||
|
from flask import Blueprint
|
||||||
|
|
||||||
|
# Blueprint để serve headerLoader.js từ views/header/
|
||||||
|
# → URL: /assets/header/headerLoader.js
|
||||||
|
header_bp = Blueprint(
|
||||||
|
'header',
|
||||||
|
__name__,
|
||||||
|
static_folder='../views/header',
|
||||||
|
static_url_path='/assets/header',
|
||||||
|
)
|
||||||
@@ -1,23 +1,30 @@
|
|||||||
# routes/scraperZLibraryRoute.py
|
# routes/scraperZLibraryRoute.py
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
from controllers.scraperZLibraryController import ScraperController
|
from controllers.scraperZLibraryController import ScraperController
|
||||||
|
|
||||||
# Create blueprint
|
# Blueprint với static_folder trỏ vào views/scraperZLibraryPages
|
||||||
scraperZLibraryRoute = Blueprint('scraperZLibrary', __name__)
|
# → Flask serve CSS/JS qua URL /scraperZLibrary/assets/scraper/...
|
||||||
|
# Lưu ý: static_url_path chỉ cần phần sau /scraperZLibrary/ (url_prefix đã được thêm khi register)
|
||||||
# Define routes
|
scraperZLibraryRoute = Blueprint(
|
||||||
scraperZLibraryRoute.route('/', methods=['GET'])(ScraperController.index)
|
'scraperZLibrary',
|
||||||
scraperZLibraryRoute.route('/api/search', methods=['POST'])(ScraperController.search_books)
|
__name__,
|
||||||
scraperZLibraryRoute.route('/api/download/txt', methods=['POST'])(ScraperController.download_txt)
|
static_folder='../views/scraperZLibraryPages',
|
||||||
scraperZLibraryRoute.route('/api/download/json', methods=['POST'])(ScraperController.download_json)
|
static_url_path='/assets/scraper',
|
||||||
scraperZLibraryRoute.route('/api/download/books', methods=['POST'])(ScraperController.download_books_zip) # New route
|
)
|
||||||
scraperZLibraryRoute.add_url_rule(
|
|
||||||
'/api/download/stream',
|
# Define routes
|
||||||
view_func=ScraperController.download_books_stream,
|
scraperZLibraryRoute.route('/', methods=['GET'])(ScraperController.index)
|
||||||
methods=['POST'],
|
scraperZLibraryRoute.route('/api/search', methods=['POST'])(ScraperController.search_books)
|
||||||
)
|
scraperZLibraryRoute.route('/api/download/txt', methods=['POST'])(ScraperController.download_txt)
|
||||||
scraperZLibraryRoute.add_url_rule(
|
scraperZLibraryRoute.route('/api/download/json', methods=['POST'])(ScraperController.download_json)
|
||||||
'/api/download/file/<token>',
|
scraperZLibraryRoute.route('/api/download/books', methods=['POST'])(ScraperController.download_books_zip) # New route
|
||||||
view_func=ScraperController.fetch_stored_file,
|
scraperZLibraryRoute.add_url_rule(
|
||||||
methods=['GET'],
|
'/api/download/stream',
|
||||||
)
|
view_func=ScraperController.download_books_stream,
|
||||||
|
methods=['POST'],
|
||||||
|
)
|
||||||
|
scraperZLibraryRoute.add_url_rule(
|
||||||
|
'/api/download/file/<token>',
|
||||||
|
view_func=ScraperController.fetch_stored_file,
|
||||||
|
methods=['GET'],
|
||||||
|
)
|
||||||
@@ -1,14 +1,20 @@
|
|||||||
# routes/transcriptionRoute.py
|
# routes/transcriptionRoute.py
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
from controllers.transcriptionController import TranscriptionController
|
from controllers.transcriptionController import TranscriptionController
|
||||||
|
|
||||||
# Create blueprint
|
# Blueprint với static_folder trỏ vào views/transcriptionPages
|
||||||
transcription_bp = Blueprint('transcription', __name__)
|
# → Flask serve CSS/JS qua URL /assets/transcription/...
|
||||||
|
transcription_bp = Blueprint(
|
||||||
# Define routes
|
'transcription',
|
||||||
transcription_bp.route('/', methods=['GET'])(TranscriptionController.index)
|
__name__,
|
||||||
transcription_bp.route('/upload-chunk', methods=['POST'])(TranscriptionController.upload_chunk)
|
static_folder='../views/transcriptionPages',
|
||||||
transcription_bp.route('/status/<job_id>', methods=['GET'])(TranscriptionController.status)
|
static_url_path='/assets/transcription',
|
||||||
transcription_bp.route('/transcript/<job_id>', methods=['GET'])(TranscriptionController.download_transcript)
|
)
|
||||||
transcription_bp.route('/view/<job_id>', methods=['GET'])(TranscriptionController.view_transcript)
|
|
||||||
transcription_bp.route('/jobs', methods=['GET'])(TranscriptionController.list_jobs)
|
# Define routes
|
||||||
|
transcription_bp.route('/', methods=['GET'])(TranscriptionController.index)
|
||||||
|
transcription_bp.route('/upload-chunk', methods=['POST'])(TranscriptionController.upload_chunk)
|
||||||
|
transcription_bp.route('/status/<job_id>', methods=['GET'])(TranscriptionController.status)
|
||||||
|
transcription_bp.route('/transcript/<job_id>', methods=['GET'])(TranscriptionController.download_transcript)
|
||||||
|
transcription_bp.route('/view/<job_id>', methods=['GET'])(TranscriptionController.view_transcript)
|
||||||
|
transcription_bp.route('/jobs', methods=['GET'])(TranscriptionController.list_jobs)
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<!-- static/header/header.html -->
|
|
||||||
<header class="app-header">
|
|
||||||
<nav class="header-nav">
|
|
||||||
<div class="nav-container">
|
|
||||||
<!-- Left: Brand -->
|
|
||||||
<div class="nav-left">
|
|
||||||
<a href="/" class="nav-brand">KYLONG.</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Center: Navigation -->
|
|
||||||
<div class="nav-center">
|
|
||||||
<ul class="nav-links">
|
|
||||||
<li>
|
|
||||||
<a href="/" class="nav-link" data-nav="transcription">Phiên Âm</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/scraperZLibrary" class="nav-link" data-nav="scraper">Z-Library</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Right: Utility -->
|
|
||||||
<div class="nav-right">
|
|
||||||
<span class="status-badge"><span class="dot"></span> Online</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
@@ -1,16 +1,45 @@
|
|||||||
// static/header/headerLoader.js
|
// views/header/headerLoader.js
|
||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
const CONFIG = {
|
const CONFIG = {
|
||||||
headerPath: "/static/header/header.html",
|
|
||||||
insertPosition: "afterbegin",
|
insertPosition: "afterbegin",
|
||||||
containerSelector: "body",
|
containerSelector: "body",
|
||||||
activeClass: "active",
|
activeClass: "active",
|
||||||
version: "1.0",
|
version: "1.1",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Header HTML inlined — không cần fetch file nữa
|
||||||
|
const headerHTML = `
|
||||||
|
<header class="app-header">
|
||||||
|
<nav class="header-nav">
|
||||||
|
<div class="nav-container">
|
||||||
|
<!-- Left: Brand -->
|
||||||
|
<div class="nav-left">
|
||||||
|
<a href="/" class="nav-brand">KYLONG.</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Center: Navigation -->
|
||||||
|
<div class="nav-center">
|
||||||
|
<ul class="nav-links">
|
||||||
|
<li>
|
||||||
|
<a href="/" class="nav-link" data-nav="transcription">Phiên Âm</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/scraperZLibrary" class="nav-link" data-nav="scraper">Z-Library</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right: Utility -->
|
||||||
|
<div class="nav-right">
|
||||||
|
<span class="status-badge"><span class="dot"></span> Online</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</header>`;
|
||||||
|
|
||||||
const styles = `
|
const styles = `
|
||||||
<style id="header-component-styles">
|
<style id="header-component-styles">
|
||||||
@import url('https://db.onlinewebfonts.com/c/5ac3fe7c6abd2f62067f266d89671492?family=HelveticaNowDisplay-Medium');
|
@import url('https://db.onlinewebfonts.com/c/5ac3fe7c6abd2f62067f266d89671492?family=HelveticaNowDisplay-Medium');
|
||||||
@@ -156,37 +185,21 @@
|
|||||||
</style>
|
</style>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// Inject header directly (no fetch needed)
|
||||||
|
function loadHeader() {
|
||||||
// Load header function
|
// Inject styles if not already present
|
||||||
async function loadHeader() {
|
if (!document.getElementById("header-component-styles")) {
|
||||||
try {
|
document.head.insertAdjacentHTML("beforeend", styles);
|
||||||
// Fetch header HTML
|
|
||||||
const response = await fetch(`${CONFIG.headerPath}?v=${CONFIG.version}`);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`Failed to load header: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerHTML = await response.text();
|
|
||||||
|
|
||||||
// Inject styles if not already present
|
|
||||||
if (!document.getElementById("header-component-styles")) {
|
|
||||||
document.head.insertAdjacentHTML("beforeend", styles);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert header
|
|
||||||
const container = document.querySelector(CONFIG.containerSelector);
|
|
||||||
container.insertAdjacentHTML(CONFIG.insertPosition, headerHTML);
|
|
||||||
|
|
||||||
// Highlight active link
|
|
||||||
highlightActiveLink();
|
|
||||||
|
|
||||||
console.log("✅ Header component loaded v" + CONFIG.version);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("❌ Error loading header:", error);
|
|
||||||
createFallbackHeader();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert header HTML inline
|
||||||
|
const container = document.querySelector(CONFIG.containerSelector);
|
||||||
|
container.insertAdjacentHTML(CONFIG.insertPosition, headerHTML);
|
||||||
|
|
||||||
|
// Highlight active link
|
||||||
|
highlightActiveLink();
|
||||||
|
|
||||||
|
console.log("✅ Header component loaded v" + CONFIG.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highlight current page link
|
// Highlight current page link
|
||||||
@@ -212,29 +225,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback header in case of error
|
|
||||||
function createFallbackHeader() {
|
|
||||||
const fallback = document.createElement("div");
|
|
||||||
fallback.style.cssText = `
|
|
||||||
padding: 15px 20px;
|
|
||||||
background: #fff;
|
|
||||||
border-bottom: 1px solid #e0e0e0;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
`;
|
|
||||||
fallback.innerHTML = `
|
|
||||||
<div style="max-width: 1200px; margin: 0 auto; display: flex; gap: 30px;">
|
|
||||||
<a href="/" style="color: #111; text-decoration: none;">📝 Phiên Âm</a>
|
|
||||||
<a href="/scraperZLibrary" style="color: #111; text-decoration: none;">📚 Z-Library Scraper</a>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
document.body.insertAdjacentElement("afterbegin", fallback);
|
|
||||||
document.body.style.paddingTop = "50px";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize when DOM is ready
|
// Initialize when DOM is ready
|
||||||
if (document.readyState === "loading") {
|
if (document.readyState === "loading") {
|
||||||
document.addEventListener("DOMContentLoaded", loadHeader);
|
document.addEventListener("DOMContentLoaded", loadHeader);
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
<title>Tìm Kiếm Sách Z-Library</title>
|
<title>Tìm Kiếm Sách Z-Library</title>
|
||||||
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/5ac3fe7c6abd2f62067f266d89671492?family=HelveticaNowDisplay-Medium" />
|
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/5ac3fe7c6abd2f62067f266d89671492?family=HelveticaNowDisplay-Medium" />
|
||||||
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/1aa3377e489837a26d019bba501e779d?family=HelveticaNowDisplayW01-Rg" />
|
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/1aa3377e489837a26d019bba501e779d?family=HelveticaNowDisplayW01-Rg" />
|
||||||
<link rel="stylesheet" href="/static/scraperZLibraryPages/scraperZLibraryMain.css" />
|
<link rel="stylesheet" href="/scraperZLibrary/assets/scraper/scraperZLibraryMain.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/scraperZLibraryPages/scraperZLibraryMain.js"></script>
|
<script src="/scraperZLibrary/assets/scraper/scraperZLibraryMain.js"></script>
|
||||||
<script src="/static/header/headerLoader.js?v=1.0"></script>
|
<script src="/assets/header/headerLoader.js?v=1.1"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<title>Phiên Âm</title>
|
<title>Phiên Âm</title>
|
||||||
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/5ac3fe7c6abd2f62067f266d89671492?family=HelveticaNowDisplay-Medium" />
|
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/5ac3fe7c6abd2f62067f266d89671492?family=HelveticaNowDisplay-Medium" />
|
||||||
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/1aa3377e489837a26d019bba501e779d?family=HelveticaNowDisplayW01-Rg" />
|
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/1aa3377e489837a26d019bba501e779d?family=HelveticaNowDisplayW01-Rg" />
|
||||||
<link rel="stylesheet" href="/static/transcriptionPages/transcriptionMain.css" />
|
<link rel="stylesheet" href="/assets/transcription/transcriptionMain.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/transcriptionPages/transcriptionMain.js"></script>
|
<script src="/assets/transcription/transcriptionMain.js"></script>
|
||||||
<script src="/static/header/headerLoader.js?v=1.0"></script>
|
<script src="/assets/header/headerLoader.js?v=1.1"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<title>Transcript - {{ filename }}</title>
|
<title>Transcript - {{ filename }}</title>
|
||||||
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/5ac3fe7c6abd2f62067f266d89671492?family=HelveticaNowDisplay-Medium" />
|
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/5ac3fe7c6abd2f62067f266d89671492?family=HelveticaNowDisplay-Medium" />
|
||||||
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/1aa3377e489837a26d019bba501e779d?family=HelveticaNowDisplayW01-Rg" />
|
<link rel="stylesheet" href="https://db.onlinewebfonts.com/c/1aa3377e489837a26d019bba501e779d?family=HelveticaNowDisplayW01-Rg" />
|
||||||
<link rel="stylesheet" href="/static/transcriptionPages/transcriptionReview.css" />
|
<link rel="stylesheet" href="/assets/transcription/transcriptionReview.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -24,6 +24,6 @@
|
|||||||
|
|
||||||
<div class="transcript">{{ content }}</div>
|
<div class="transcript">{{ content }}</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="/static/transcriptionPages/transcriptionReview.js"></script>
|
<script src="/assets/transcription/transcriptionReview.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user