Matins completed

This commit is contained in:
catarrh committed 2026-08-01 02:43:24 +03:00
1 parent 79ac617aa8
commit 366aea76bb
27 files changed
+3200

No files matched your search

+105
View File
@@ -0,0 +1,105 @@
/**
* Search across all liturgical texts.
* Run with: npx tsx scripts/tools/search-texts.ts <query> [--lang en] [--type prayers]
*/
import { readFileSync, readdirSync, existsSync, statSync } from 'fs';
import { join, relative } from 'path';
const DATA_DIR = join(import.meta.dirname, '..', '..', 'static', 'data');
interface SearchResult {
file: string;
matches: { line: number; text: string }[];
}
function searchFile(filePath: string, query: string, relPath: string): SearchResult | null {
try {
const content = readFileSync(filePath, 'utf-8');
const matches: { line: number; text: string }[] = [];
const lines = content.split('\n');
const lowerQuery = query.toLowerCase();
for (let i = 0; i < lines.length; i++) {
if (lines[i].toLowerCase().includes(lowerQuery)) {
matches.push({ line: i + 1, text: lines[i].substring(0, 100) });
}
}
return matches.length > 0 ? { file: relPath, matches } : null;
} catch {
return null;
}
}
function searchDir(dirPath: string, query: string, basePath: string, results: SearchResult[]): void {
if (!existsSync(dirPath)) return;
for (const entry of readdirSync(dirPath)) {
const fullPath = join(dirPath, entry);
if (entry.startsWith('.')) continue;
if (statSync(fullPath).isDirectory()) {
searchDir(fullPath, query, basePath, results);
} else if (entry.endsWith('.json')) {
const result = searchFile(fullPath, query, relative(basePath, fullPath));
if (result) results.push(result);
}
}
}
function main() {
const args = process.argv.slice(2);
if (args.length === 0) {
console.log('Usage: npx tsx scripts/tools/search-texts.ts <query> [--lang en] [--type prayers]');
process.exit(1);
}
const query = args[0];
let lang = 'en';
let type = '';
for (let i = 1; i < args.length; i++) {
if (args[i] === '--lang' && args[i + 1]) lang = args[++i];
if (args[i] === '--type' && args[i + 1]) type = args[++i];
}
console.log(`\nSearching for: "${query}"`);
console.log(`Language: ${lang}`);
if (type) console.log(`Type: ${type}`);
console.log('');
const results: SearchResult[] = [];
// Search in specified language
const langDir = join(DATA_DIR, lang);
if (type) {
searchDir(join(langDir, type), query, langDir, results);
} else {
searchDir(langDir, query, langDir, results);
}
// Also search in shared
searchDir(join(DATA_DIR, 'shared'), query, DATA_DIR, results);
// Print results
if (results.length === 0) {
console.log('No matches found.');
} else {
console.log(`Found ${results.length} files with matches:\n`);
for (const result of results.slice(0, 20)) {
console.log(` ${result.file}`);
for (const match of result.matches.slice(0, 3)) {
console.log(` Line ${match.line}: ${match.text.substring(0, 80)}...`);
}
if (result.matches.length > 3) {
console.log(` ... and ${result.matches.length - 3} more matches`);
}
}
if (results.length > 20) {
console.log(`\n ... and ${results.length - 20} more files`);
}
}
}
main();
+128
View File
@@ -0,0 +1,128 @@
/**
* Show statistics about the data directory.
* Run with: npx tsx scripts/tools/stats.ts [--lang en]
*/
import { readFileSync, readdirSync, existsSync, statSync } from 'fs';
import { join } from 'path';
const DATA_DIR = join(import.meta.dirname, '..', '..', 'static', 'data');
interface Stats {
files: number;
jsonFiles: number;
textFiles: number;
totalSize: number;
languages: string[];
categories: Record<string, { files: number; size: number }>;
}
function scanDir(dirPath: string, stats: Stats): void {
if (!existsSync(dirPath)) return;
for (const entry of readdirSync(dirPath)) {
const fullPath = join(dirPath, entry);
if (entry.startsWith('.')) continue;
const stat = statSync(fullPath);
if (stat.isDirectory()) {
scanDir(fullPath, stats);
} else {
stats.files++;
stats.totalSize += stat.size;
if (entry.endsWith('.json')) stats.jsonFiles++;
if (entry.endsWith('.text')) stats.textFiles++;
}
}
}
function getCategoryStats(dirPath: string): Record<string, { files: number; size: number }> {
const categories: Record<string, { files: number; size: number }> = {};
if (!existsSync(dirPath)) return categories;
for (const entry of readdirSync(dirPath)) {
const fullPath = join(dirPath, entry);
if (entry.startsWith('.')) continue;
const stat = statSync(fullPath);
if (stat.isDirectory()) {
const subStats = getCategoryStats(fullPath);
for (const [key, value] of Object.entries(subStats)) {
const catKey = entry + '/' + key;
categories[catKey] = value;
}
} else if (entry.endsWith('.json')) {
categories[entry] = { files: 1, size: stat.size };
}
}
return categories;
}
function formatSize(bytes: number): string {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}
function main() {
const args = process.argv.slice(2);
let lang = '';
for (let i = 0; i < args.length; i++) {
if (args[i] === '--lang' && args[i + 1]) lang = args[++i];
}
console.log('\nData Statistics\n');
console.log(`Data directory: ${DATA_DIR}\n`);
// Get languages
const languages = readdirSync(DATA_DIR).filter(entry => {
const fullPath = join(DATA_DIR, entry);
return statSync(fullPath).isDirectory() && !entry.startsWith('.');
});
console.log(`Languages: ${languages.join(', ')}\n`);
// Overall stats
const overallStats: Stats = { files: 0, jsonFiles: 0, textFiles: 0, totalSize: 0, languages: [], categories: {} };
scanDir(DATA_DIR, overallStats);
console.log('Overall:');
console.log(` Total files: ${overallStats.files}`);
console.log(` JSON files: ${overallStats.jsonFiles}`);
console.log(` Text files: ${overallStats.textFiles}`);
console.log(` Total size: ${formatSize(overallStats.totalSize)}\n`);
// Per-language stats
if (lang) {
console.log(`\nDetails for language: ${lang}`);
const langDir = join(DATA_DIR, lang);
if (existsSync(langDir)) {
const langStats: Stats = { files: 0, jsonFiles: 0, textFiles: 0, totalSize: 0, languages: [], categories: {} };
scanDir(langDir, langStats);
console.log(` Files: ${langStats.files}`);
console.log(` Size: ${formatSize(langStats.totalSize)}`);
const categories = getCategoryStats(langDir);
if (Object.keys(categories).length > 0) {
console.log('\n Categories:');
for (const [name, stats] of Object.entries(categories).sort((a, b) => b[1].size - a[1].size)) {
console.log(` ${name}: ${stats.files} files, ${formatSize(stats.size)}`);
}
}
}
} else {
// Show summary for each language
console.log('Per-language summary:');
for (const language of languages) {
const langDir = join(DATA_DIR, language);
const langStats: Stats = { files: 0, jsonFiles: 0, textFiles: 0, totalSize: 0, languages: [], categories: {} };
scanDir(langDir, langStats);
console.log(` ${language}: ${langStats.files} files, ${formatSize(langStats.totalSize)}`);
}
}
}
main();