Files
ohm_streaming/static/js/utils.js
T
root 1fe7392063 feat: Complete Sonarr integration with security enhancements
This commit adds comprehensive Sonarr webhook integration and implements
critical security improvements identified in code review.

## Sonarr Integration
- Full webhook support for Grab, Download, Rename, Delete, and Test events
- HMAC SHA256 signature verification for webhook authentication
- Series mapping system (Sonarr TVDB ID → Anime Provider URL)
- 11 new API endpoints for configuration, mappings, search, and downloads
- Comprehensive test suite (31 tests, all passing)
- Complete documentation in docs/SONARR_INTEGRATION.md

## Security Enhancements
- CORS restricted to specific origins (user's IP: 192.168.1.204:3000)
- Path traversal prevention via sanitize_filename() and is_safe_filename()
- Structured logging infrastructure (replaced all print() statements)
- Environment-based configuration with .env support
- Filename sanitization prevents malicious path attacks

## New Features
- Lpayer and Sibnet downloader support
- Kitsu API integration for anime metadata
- Recommendation engine based on download history
- Latest releases endpoint for new anime
- Modular web interface with component-based templates

## Configuration
- Centralized settings via app/config.py with pydantic-settings
- Sonarr config auto-created in config/ directory
- Example configurations provided for easy setup

## Tests
- 31 Sonarr integration tests (23 functionality + 9 security)
- 100+ tests passing in core test files
- Security utilities fully tested

## Documentation
- Updated CLAUDE.md with Sonarr and testing info
- Added IMPROVEMENTS_2024-01-24.md analysis
- Added SONARR_IMPLEMENTATION.md technical summary

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <[email protected]>
Co-Authored-By: Happy <[email protected]>
2026-01-24 21:25:47 +00:00

93 lines
2.4 KiB
JavaScript

/**
* Utility functions
*/
/**
* Format bytes to human readable format
*/
function formatBytes(bytes) {
if (!bytes) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
/**
* Format bytes per second to speed
*/
function formatSpeed(bytesPerSecond) {
return formatBytes(bytesPerSecond) + '/s';
}
/**
* Escape HTML to prevent XSS
*/
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
/**
* Translate download status to French
*/
function translateStatus(status) {
const translations = {
'pending': 'En attente',
'downloading': 'Téléchargement',
'paused': 'En pause',
'completed': 'Terminé',
'failed': 'Échoué',
'cancelled': 'Annulé'
};
return translations[status] || status;
}
/**
* Extract series name from filename (for grouping)
*/
function extractSeriesName(filename) {
let name = filename;
// Remove file extension
name = name.replace(/\.[^/.]+$/, '');
// Remove episode numbers and patterns
name = name
.replace(/[-_ ]?(E(?:p)?|Episode|Épisode|Saison|Season)[-_: ]?\d+/gi, '')
.replace(/[-_ ]?S\d{2}E\d{2}/gi, '')
.replace(/\[.*?\]/g, '')
.replace(/\(.*\)/g, '')
.replace(/[-_ ]?\d{3,4}p/gi, '')
.replace(/[-_ ]?(VOSTFR|VF|MULTI)/gi, '')
.replace(/\s+/g, ' ') // Replace multiple spaces with single space
.replace(/[-_]+$/, '') // Remove trailing dashes/underscores
.trim();
// If nothing left or too short, use original filename without extension
if (!name || name.length < 3) {
return filename.replace(/\.[^/.]+$/, '');
}
return name;
}
/**
* Get day string for grouping
*/
function getDayString(dateString) {
const date = new Date(dateString);
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
if (date.toDateString() === today.toDateString()) {
return "Aujourd'hui";
} else if (date.toDateString() === yesterday.toDateString()) {
return "Hier";
} else {
return date.toLocaleDateString('fr-FR', { weekday: 'long', day: 'numeric', month: 'short' });
}
}