File size: 4,311 Bytes
0e33261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/**
 * Video Subtitle OCR Application
 * Extracts hard-coded subtitles from videos using transformers.js OCR
 */

import { pipeline, env } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.8.0';

// Configure transformers.js
env.allowLocalModels = false;
env.useBrowserCache = true;

// ============================================
// STATE MANAGEMENT
// ============================================

const state = {
    // Video
    videoFile: null,
    videoDuration: 0,
    videoWidth: 0,
    videoHeight: 0,
    
    // Subtitle Box
    subtitleBox: {
        x: 10,      // percentage
        y: 75,      // percentage
        width: 80,  // percentage
        height: 15, // percentage
        aspectRatio: 5.33
    },
    isDragging: false,
    isResizing: false,
    resizeHandle: null,
    dragStart: { x: 0, y: 0, boxX: 0, boxY: 0 },
    
    // Language
    selectedLanguage: 'eng',
    
    // Time Range
    startTime: 0,
    endTime: 0,
    
    // Processing
    ocrPipeline: null,
    isProcessing: false,
    processingCancelled: false,
    
    // Results
    subtitles: [],
    currentSubtitleIndex: -1
};

// Language configurations for OCR
const LANGUAGE_CONFIGS = {
    eng: { name: 'English', code: 'en' },
    jpn: { name: 'Japanese', code: 'ja' },
    kor: { name: 'Korean', code: 'ko' },
    chi_sim: { name: 'Chinese (Simplified)', code: 'zh' },
    chi_tra: { name: 'Chinese (Traditional)', code: 'zh-Hant' },
    tha: { name: 'Thai', code: 'th' }
};

// ============================================
// DOM ELEMENTS
// ============================================

const elements = {
    // Pages
    setupPage: document.getElementById('setup-page'),
    processingPage: document.getElementById('processing-page'),
    resultsPage: document.getElementById('results-page'),
    
    // Upload
    uploadZone: document.getElementById('upload-zone'),
    videoInput: document.getElementById('video-input'),
    
    // Preview
    previewSection: document.getElementById('preview-section'),
    videoPreview: document.getElementById('video-preview'),
    subtitleOverlay: document.getElementById('subtitle-overlay'),
    subtitleBox: document.getElementById('subtitle-box'),
    
    // Controls
    xPosition: document.getElementById('x-position'),
    yPosition: document.getElementById('y-position'),
    width: document.getElementById('width'),
    height: document.getElementById('height'),
    xValue: document.getElementById('x-value'),
    yValue: document.getElementById('y-value'),
    widthValue: document.getElementById('width-value'),
    heightValue: document.getElementById('height-value'),
    aspectLock: document.getElementById('aspect-lock'),
    resetBox: document.getElementById('reset-box'),
    autoDetect: document.getElementById('auto-detect'),
    
    // Language
    languageSection: document.getElementById('language-section'),
    langButtons: document.querySelectorAll('.lang-btn'),
    
    // Time
    timeSection: document.getElementById('time-section'),
    startHours: document.getElementById('start-hours'),
    startMinutes: document.getElementById('start-minutes'),
    startSeconds: document.getElementById('start-seconds'),
    startMs: document.getElementById('start-ms'),
    endHours: document.getElementById('end-hours'),
    endMinutes: document.getElementById('end-minutes'),
    endSeconds: document.getElementById('end-seconds'),
    endMs: document.getElementById('end-ms'),
    setStartCurrent: document.getElementById('set-start-current'),
    setEndCurrent: document.getElementById('set-end-current'),
    timeRangeSlider: document.getElementById('time-range-slider'),
    rangeFill: document.getElementById('range-fill'),
    startThumb: document.getElementById('start-thumb'),
    endThumb: document.getElementById('end-thumb'),
    sliderStartTime: document.getElementById('slider-start-time'),
    sliderEndTime: document.getElementById('slider-end-time'),
    
    // Process
    processSection: document.getElementById('process-section'),
    processBtn: document.getElementById('process-btn'),
    
    // Processing
    progressFill: document.getElementById('progress-fill'),
    progressText: document.getElementById('progress-text'),
    progressPercent: document.getElementById('progress-percent'),
    frames