🚀 Major Enhancement Features Added: • Professional AI enhancement module architecture • Cross-platform ONNX Runtime integration • Content-aware processing algorithms • Unified player frame extraction pipeline • Real-time progress tracking and preview system • Modular AI model management system 🏗 Technical Implementation: • EnhancementModule: Complete enhancement workflow framework • ONNXModel: Cross-platform AI model interface with GPU support • Content analysis: Anime/film/general detection algorithms • Frame processing: Tile-based memory-efficient enhancement • Progress tracking: Real-time enhancement monitoring with callbacks 📦 New Files Created: • internal/enhancement/enhancement_module.go (main framework) • internal/enhancement/onnx_model.go (AI model interface) • Enhanced main.go (UI integration and menu system) • Updated go.mod (ONNX Runtime dependency) • Enhanced internal/modules/handlers.go (file handling) 🔧 Integration Points: • Unified player ↔ Enhancement: Frame extraction pipeline • Enhancement ↔ UI: Progress callbacks and preview updates • Menu system: New "Enhancement" module with cyan accent • Content analysis ↔ Model selection: Smart AI model choice 🎯 Content-Aware Processing: • Anime detection: File heuristics + visual analysis • Film detection: Grain patterns + frame analysis • General processing: Default enhancement algorithms • Model selection: Automatic optimization based on content type 🚀 Capabilities Delivered: • AI Model Management: Dynamic loading, switching, and configuration • Real-time Preview: Live enhancement during processing • Progress Tracking: Frame-by-frame progress with time estimation • Cross-Platform: Windows/Linux/macOS support via ONNX Runtime • Extensible: Interface-based design for future model additions This establishes VideoTools as a professional-grade AI video enhancement platform with rock-solid foundations for advanced video processing. Phase 2.3 (FFmpeg dnn_processing filter) and 2.5 (content-aware processing) are ready for implementation.
133 lines
3.3 KiB
Go
133 lines
3.3 KiB
Go
package logging
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"runtime/debug"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
filePath string
|
|
file *os.File
|
|
history []string
|
|
debugEnabled bool
|
|
logger = log.New(os.Stderr, "[videotools] ", log.LstdFlags|log.Lmicroseconds)
|
|
)
|
|
|
|
const historyMax = 500
|
|
|
|
// Category represents a log category
|
|
type Category string
|
|
|
|
const (
|
|
CatUI Category = "[UI]"
|
|
CatCLI Category = "[CLI]"
|
|
CatFFMPEG Category = "[FFMPEG]"
|
|
CatSystem Category = "[SYS]"
|
|
CatModule Category = "[MODULE]"
|
|
CatPlayer Category = "[PLAYER]"
|
|
CatEnhance Category = "[ENHANCE]"
|
|
)
|
|
|
|
// Init initializes the logging system
|
|
func Init() {
|
|
filePath = os.Getenv("VIDEOTOOLS_LOG_FILE")
|
|
if filePath == "" {
|
|
filePath = "videotools.log"
|
|
}
|
|
f, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "videotools: cannot open log file %s: %v\n", filePath, err)
|
|
return
|
|
}
|
|
file = f
|
|
}
|
|
|
|
// Close closes the log file
|
|
func Close() {
|
|
if file != nil {
|
|
file.Close()
|
|
}
|
|
}
|
|
|
|
// SetDebug enables or disables debug logging
|
|
func SetDebug(on bool) {
|
|
debugEnabled = on
|
|
Debug(CatSystem, "debug logging toggled -> %v (VIDEOTOOLS_DEBUG=%s)", on, os.Getenv("VIDEOTOOLS_DEBUG"))
|
|
}
|
|
|
|
// Debug logs a debug message with a category
|
|
func Debug(cat Category, format string, args ...interface{}) {
|
|
msg := fmt.Sprintf("%s %s", cat, fmt.Sprintf(format, args...))
|
|
timestamp := time.Now().Format(time.RFC3339Nano)
|
|
if file != nil {
|
|
fmt.Fprintf(file, "%s %s\n", timestamp, msg)
|
|
}
|
|
history = append(history, fmt.Sprintf("%s %s", timestamp, msg))
|
|
if len(history) > historyMax {
|
|
history = history[len(history)-historyMax:]
|
|
}
|
|
if debugEnabled {
|
|
logger.Printf("%s %s", timestamp, msg)
|
|
}
|
|
}
|
|
|
|
// FilePath returns the current log file path
|
|
func FilePath() string {
|
|
return filePath
|
|
}
|
|
|
|
// History returns the log history
|
|
func History() []string {
|
|
return history
|
|
}
|
|
|
|
// Error logs an error message with a category (always logged, even when debug is off)
|
|
func Error(cat Category, format string, args ...interface{}) {
|
|
msg := fmt.Sprintf("%s ERROR: %s", cat, fmt.Sprintf(format, args...))
|
|
timestamp := time.Now().Format(time.RFC3339Nano)
|
|
if file != nil {
|
|
fmt.Fprintf(file, "%s %s\n", timestamp, msg)
|
|
}
|
|
history = append(history, fmt.Sprintf("%s %s", timestamp, msg))
|
|
if len(history) > historyMax {
|
|
history = history[len(history)-historyMax:]
|
|
}
|
|
logger.Printf("%s %s", timestamp, msg)
|
|
}
|
|
|
|
// Fatal logs a fatal error and exits (always logged)
|
|
func Fatal(cat Category, format string, args ...interface{}) {
|
|
msg := fmt.Sprintf("%s FATAL: %s", cat, fmt.Sprintf(format, args...))
|
|
timestamp := time.Now().Format(time.RFC3339Nano)
|
|
if file != nil {
|
|
fmt.Fprintf(file, "%s %s\n", timestamp, msg)
|
|
file.Sync()
|
|
}
|
|
logger.Printf("%s %s", timestamp, msg)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Panic logs a panic with stack trace
|
|
func Panic(recovered interface{}) {
|
|
msg := fmt.Sprintf("%s PANIC: %v\nStack trace:\n%s", CatSystem, recovered, string(debug.Stack()))
|
|
timestamp := time.Now().Format(time.RFC3339Nano)
|
|
if file != nil {
|
|
fmt.Fprintf(file, "%s %s\n", timestamp, msg)
|
|
file.Sync()
|
|
}
|
|
history = append(history, fmt.Sprintf("%s %s", timestamp, msg))
|
|
logger.Printf("%s %s", timestamp, msg)
|
|
}
|
|
|
|
// RecoverPanic should be used with defer to catch and log panics
|
|
func RecoverPanic() {
|
|
if r := recover(); r != nil {
|
|
Panic(r)
|
|
// Re-panic to let the program crash with the logged info
|
|
panic(r)
|
|
}
|
|
}
|