working support for subfolders + versioning
This commit is contained in:
parent
e031c7738b
commit
2a4b2d585a
6 changed files with 78 additions and 45 deletions
107
src/api/app.py
107
src/api/app.py
|
@ -1,6 +1,7 @@
|
|||
from flask import Flask, request, jsonify, render_template, send_from_directory
|
||||
from urllib.parse import unquote
|
||||
from elasticsearch import Elasticsearch
|
||||
import json
|
||||
import os
|
||||
import ebooklib
|
||||
from ebooklib import epub
|
||||
|
@ -13,14 +14,33 @@ from src.core.index import index_files, get_progress
|
|||
from io import StringIO
|
||||
import sys
|
||||
import re
|
||||
# Application version
|
||||
APP_VERSION = "0.0.3 (2025 Apr 6th)"
|
||||
|
||||
app = Flask(__name__, static_folder='static')
|
||||
app = Flask(__name__, static_folder='static')
|
||||
|
||||
# Add version to all template renders
|
||||
@app.context_processor
|
||||
def inject_version():
|
||||
return {'app_version': APP_VERSION}
|
||||
|
||||
@app.after_request
|
||||
def add_cors_headers(response):
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT'
|
||||
response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
|
||||
|
||||
# Add version to all JSON responses
|
||||
if response.content_type == 'application/json':
|
||||
try:
|
||||
data = response.get_json()
|
||||
if isinstance(data, dict):
|
||||
data['version'] = APP_VERSION
|
||||
response.data = json.dumps(data).encode('utf-8')
|
||||
except:
|
||||
pass
|
||||
|
||||
return response
|
||||
|
||||
# Elasticsearch Configuration
|
||||
|
@ -245,49 +265,62 @@ def list_files():
|
|||
# Check if indexing is in progress
|
||||
indexing_in_progress = get_progress() is not None
|
||||
|
||||
# Walk through directory structure
|
||||
for root, dirs, files in os.walk(books_dir):
|
||||
# Skip hidden directories
|
||||
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
||||
# Get only top-level files and directories
|
||||
try:
|
||||
items = os.listdir(books_dir)
|
||||
except Exception as e:
|
||||
return render_template('files.html', error=f"Error listing directory: {str(e)}")
|
||||
|
||||
# Process directories first
|
||||
for item_name in sorted(items):
|
||||
item_path = os.path.join(books_dir, item_name)
|
||||
|
||||
# Get relative path from books_dir
|
||||
rel_path = os.path.relpath(root, books_dir)
|
||||
if rel_path == '.':
|
||||
rel_path = ''
|
||||
if os.path.isdir(item_path) and not item_name.startswith('.'):
|
||||
# Count files in this directory for display
|
||||
dir_file_count = 0
|
||||
for _, _, files in os.walk(item_path):
|
||||
dir_file_count += len(files)
|
||||
|
||||
# Add directories first
|
||||
for dir_name in sorted(dirs):
|
||||
dir_path = os.path.join(rel_path, dir_name)
|
||||
file_tree.append({
|
||||
'type': 'directory',
|
||||
'name': dir_name,
|
||||
'path': dir_path,
|
||||
'children': []
|
||||
'name': item_name,
|
||||
'path': item_name,
|
||||
'file_count': dir_file_count
|
||||
})
|
||||
|
||||
# Then process files
|
||||
for item_name in sorted(items):
|
||||
item_path = os.path.join(books_dir, item_name)
|
||||
|
||||
# Add files
|
||||
for file_name in sorted(files):
|
||||
file_path = os.path.join(books_dir, rel_path, file_name)
|
||||
if os.path.isfile(file_path):
|
||||
file_size = os.path.getsize(file_path)
|
||||
# Extract book title from filename if possible
|
||||
title = file_name
|
||||
if ' - ' in file_name: # Common pattern in filenames
|
||||
title_parts = file_name.split(' - ')
|
||||
if len(title_parts) > 1:
|
||||
title = ' - '.join(title_parts[:-1]) # Take all but last part
|
||||
|
||||
full_path = os.path.join(rel_path, file_name)
|
||||
file_tree.append({
|
||||
'type': 'file',
|
||||
'name': file_name,
|
||||
'title': title,
|
||||
'path': full_path,
|
||||
'size': file_size,
|
||||
'size_mb': round(file_size / (1024 * 1024), 2)
|
||||
})
|
||||
total_files += 1
|
||||
total_size += file_size
|
||||
if os.path.isfile(item_path):
|
||||
file_size = os.path.getsize(item_path)
|
||||
# Extract book title from filename if possible
|
||||
title = item_name
|
||||
if ' - ' in item_name: # Common pattern in filenames
|
||||
title_parts = item_name.split(' - ')
|
||||
if len(title_parts) > 1:
|
||||
title = ' - '.join(title_parts[:-1]) # Take all but last part
|
||||
|
||||
file_tree.append({
|
||||
'type': 'file',
|
||||
'name': item_name,
|
||||
'title': title,
|
||||
'path': item_name,
|
||||
'size': file_size,
|
||||
'size_mb': round(file_size / (1024 * 1024), 2)
|
||||
})
|
||||
total_files += 1
|
||||
total_size += file_size
|
||||
|
||||
# Count all files in all subdirectories for the total count
|
||||
for root, _, files in os.walk(books_dir):
|
||||
for file in files:
|
||||
if not os.path.basename(root).startswith('.') and not file.startswith('.'):
|
||||
if root != books_dir: # Don't double count top-level files
|
||||
total_files += 1
|
||||
file_path = os.path.join(root, file)
|
||||
if os.path.isfile(file_path):
|
||||
total_size += os.path.getsize(file_path)
|
||||
|
||||
total_size_mb = round(total_size / (1024 * 1024), 2)
|
||||
|
||||
|
|
|
@ -256,7 +256,7 @@
|
|||
</script>
|
||||
|
||||
<footer>
|
||||
<p>© 2025 Book Search Engine</p>
|
||||
<p>© 2025 Intari | Version {{ app_version }}</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -113,14 +113,14 @@
|
|||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Book Files</h1>
|
||||
<h1>Books Files</h1>
|
||||
</header>
|
||||
|
||||
<nav class="nav">
|
||||
<ul>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/files">File List</a></li>
|
||||
<li><a href="/index_books">Re-Index Books</a></li>
|
||||
<li><a href="/index_books">Re-Index Files</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
@ -152,7 +152,7 @@
|
|||
<li class="folder-item" onclick="toggleFolder(this, event)">
|
||||
<div class="folder-name">
|
||||
<span class="folder-icon">📁</span>
|
||||
{{ item.name }}
|
||||
{{ item.name }} <span class="file-name-muted">({{ item.file_count }} files)</span>
|
||||
</div>
|
||||
<div class="folder-contents" id="folder-{{ item.path|replace('/', '-') }}">
|
||||
<!-- Contents will be populated dynamically -->
|
||||
|
@ -326,7 +326,7 @@
|
|||
</div>
|
||||
|
||||
<footer>
|
||||
<p>© 2025 Intari</p>
|
||||
<p>© 2025 Intari | Version {{ app_version }}</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -70,7 +70,7 @@
|
|||
</div>
|
||||
|
||||
<footer>
|
||||
<p>© 2025 Intari</p>
|
||||
<p>© 2025 Intari | Version {{ app_version }}</p>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
</div>
|
||||
|
||||
<footer>
|
||||
<p>© 2025 Intari</p>
|
||||
<p>© 2025 Intari | Version {{ app_version }}</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -58,7 +58,7 @@
|
|||
</div>
|
||||
|
||||
<footer>
|
||||
<p>© 2025 Book Search Engine</p>
|
||||
<p>© 2025 Intari | Version {{ app_version }}</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue