init
This commit is contained in:
209
epub-parser/statistics.py
Executable file
209
epub-parser/statistics.py
Executable file
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Скрипт для получения статистики по главам EPUB книги.
|
||||
|
||||
Использование:
|
||||
python statistics.py <путь_к_epub_файлу>
|
||||
python statistics.py book.epub
|
||||
"""
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any, List
|
||||
from ebooklib import epub
|
||||
|
||||
# Импортируем функции из app.py
|
||||
from app import parse_epub_content, calculate_chapter_tokens
|
||||
|
||||
|
||||
def sanitize_filename(title: str, max_length: int = 100) -> str:
|
||||
"""Очищает название книги для использования в имени файла.
|
||||
|
||||
Удаляет недопустимые символы и ограничивает длину имени файла.
|
||||
|
||||
Args:
|
||||
title: Название книги для очистки.
|
||||
max_length: Максимальная длина имени файла.
|
||||
|
||||
Returns:
|
||||
Безопасное имя файла.
|
||||
"""
|
||||
if not title:
|
||||
return 'book_statistics'
|
||||
|
||||
# Удаляем недопустимые символы для имени файла
|
||||
# Оставляем буквы, цифры, пробелы, дефисы, подчеркивания
|
||||
sanitized = re.sub(r'[<>:"/\\|?*]', '', title)
|
||||
|
||||
# Заменяем множественные пробелы на один
|
||||
sanitized = re.sub(r'\s+', ' ', sanitized)
|
||||
|
||||
# Убираем пробелы в начале и конце
|
||||
sanitized = sanitized.strip()
|
||||
|
||||
# Ограничиваем длину
|
||||
if len(sanitized) > max_length:
|
||||
sanitized = sanitized[:max_length].rstrip()
|
||||
|
||||
# Если после очистки ничего не осталось, используем дефолтное имя
|
||||
if not sanitized:
|
||||
sanitized = 'book_statistics'
|
||||
|
||||
return sanitized
|
||||
|
||||
|
||||
def format_statistics(title: str, author: str, chapters: List[Dict[str, Any]]) -> Dict[str, Any]:
|
||||
"""Форматирует статистику по книге и главам.
|
||||
|
||||
Args:
|
||||
title: Название книги.
|
||||
author: Автор книги.
|
||||
chapters: Список глав с данными.
|
||||
|
||||
Returns:
|
||||
Словарь со статистикой в формате JSON.
|
||||
"""
|
||||
# Статистика по главам
|
||||
chapters_stats: List[Dict[str, Any]] = []
|
||||
total_chars = 0
|
||||
total_tokens = 0
|
||||
|
||||
for chapter in chapters:
|
||||
chapter_text = chapter.get('text', '')
|
||||
chapter_title = chapter.get('chapterTitle', 'Глава без названия')
|
||||
chapter_number = chapter.get('chapterNumber', 0)
|
||||
footnotes_count = chapter.get('footnotesCount', 0)
|
||||
token_count = chapter.get('tokenCount', 0)
|
||||
|
||||
# Подсчитываем символы (включая пробелы)
|
||||
char_count = len(chapter_text)
|
||||
|
||||
# Если tokenCount не был подсчитан, подсчитываем сейчас
|
||||
if token_count == 0 and chapter_text:
|
||||
chapter_data = {
|
||||
'text': chapter_text,
|
||||
'chapterTitle': chapter_title,
|
||||
'chapterId': chapter.get('chapterId', ''),
|
||||
'chapterNumber': chapter_number,
|
||||
'filePath': chapter.get('filePath', ''),
|
||||
'footnotes': chapter.get('footnotes', [])
|
||||
}
|
||||
token_count = calculate_chapter_tokens(chapter_data)
|
||||
|
||||
total_chars += char_count
|
||||
total_tokens += token_count
|
||||
|
||||
chapters_stats.append({
|
||||
'chapterNumber': chapter_number,
|
||||
'chapterTitle': chapter_title,
|
||||
'characters': char_count,
|
||||
'tokens': token_count,
|
||||
'footnotesCount': footnotes_count,
|
||||
'filePath': chapter.get('filePath', '')
|
||||
})
|
||||
|
||||
# Общая статистика
|
||||
result: Dict[str, Any] = {
|
||||
'book': {
|
||||
'title': title,
|
||||
'author': author,
|
||||
'totalChapters': len(chapters),
|
||||
'totalCharacters': total_chars,
|
||||
'totalTokens': total_tokens
|
||||
},
|
||||
'chapters': chapters_stats
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
"""Основная функция скрипта."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Получение статистики по главам EPUB книги',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Примеры использования:
|
||||
python statistics.py book.epub
|
||||
python statistics.py /path/to/book.epub --output stats.json
|
||||
python statistics.py book.epub --stdout
|
||||
"""
|
||||
)
|
||||
parser.add_argument(
|
||||
'epub_file',
|
||||
type=str,
|
||||
help='Путь к EPUB файлу'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-o', '--output',
|
||||
type=str,
|
||||
default=None,
|
||||
help='Путь к выходному JSON файлу (если не указан, создается файл с названием книги)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--stdout',
|
||||
action='store_true',
|
||||
help='Вывести результат в stdout вместо сохранения в файл'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--compact',
|
||||
action='store_true',
|
||||
help='Сохранить JSON в компактном формате (без отступов)'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Проверяем существование файла
|
||||
epub_path = Path(args.epub_file)
|
||||
if not epub_path.exists():
|
||||
print(f"Ошибка: Файл '{epub_path}' не найден.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if not epub_path.is_file():
|
||||
print(f"Ошибка: '{epub_path}' не является файлом.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
# Читаем и парсим EPUB
|
||||
book = epub.read_epub(str(epub_path))
|
||||
title, author, metadata, chapters = parse_epub_content(book)
|
||||
|
||||
# Формируем статистику
|
||||
statistics = format_statistics(title, author, chapters)
|
||||
|
||||
# Выводим результат
|
||||
if args.compact:
|
||||
json_output = json.dumps(statistics, ensure_ascii=False)
|
||||
else:
|
||||
json_output = json.dumps(statistics, ensure_ascii=False, indent=2)
|
||||
|
||||
# Определяем путь к выходному файлу
|
||||
if args.stdout:
|
||||
# Выводим в stdout
|
||||
print(json_output)
|
||||
else:
|
||||
if args.output:
|
||||
# Используем указанный путь
|
||||
output_path = Path(args.output)
|
||||
else:
|
||||
# Создаем имя файла на основе названия книги
|
||||
safe_title = sanitize_filename(title)
|
||||
output_path = Path(f"{safe_title}_statistics.json")
|
||||
|
||||
# Сохраняем в файл
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write(json_output)
|
||||
print(f"Статистика сохранена в файл: {output_path}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Ошибка при обработке EPUB файла: {e}", file=sys.stderr)
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user