myetv-player 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build.js +9 -3
- package/dist/myetv-player.js +174 -69
- package/dist/myetv-player.min.js +5346 -5719
- package/package.json +2 -1
- package/src/subtitles.js +174 -69
package/build.js
CHANGED
|
@@ -147,14 +147,20 @@ function buildJavaScript() {
|
|
|
147
147
|
function minifyJSNative() {
|
|
148
148
|
const jsFile = './dist/myetv-player.js';
|
|
149
149
|
const minFile = './dist/myetv-player.min.js';
|
|
150
|
+
|
|
150
151
|
try {
|
|
151
152
|
let code = fs.readFileSync(jsFile, 'utf8');
|
|
153
|
+
|
|
152
154
|
code = code.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
153
|
-
code = code.replace(
|
|
154
|
-
|
|
155
|
+
code = code.replace(/^\s*\/\/.*$/gm, '');
|
|
156
|
+
|
|
157
|
+
code = code.replace(/\n\s*\n\s*\n/g, '\n\n');
|
|
158
|
+
|
|
159
|
+
code = code.replace(/ +/g, ' ');
|
|
160
|
+
|
|
155
161
|
fs.writeFileSync(minFile, code);
|
|
156
162
|
console.log(`✓ JS (minified native) created: ${minFile}`);
|
|
157
|
-
console.log(`
|
|
163
|
+
console.log(` File size: ${(code.length / 1024).toFixed(2)} KB`);
|
|
158
164
|
} catch (err) {
|
|
159
165
|
console.log('✗ Native JS minification failed:', err.message);
|
|
160
166
|
}
|
package/dist/myetv-player.js
CHANGED
|
@@ -4827,10 +4827,10 @@ createCustomSubtitleOverlay() {
|
|
|
4827
4827
|
'bottom: 80px;' +
|
|
4828
4828
|
'left: 50%;' +
|
|
4829
4829
|
'transform: translateX(-50%);' +
|
|
4830
|
-
'z-index:
|
|
4830
|
+
'z-index: 999;' +
|
|
4831
4831
|
'color: white;' +
|
|
4832
4832
|
'font-family: Arial, sans-serif;' +
|
|
4833
|
-
'font-size: clamp(12px, 4vw, 18px);' +
|
|
4833
|
+
'font-size: clamp(12px, 4vw, 18px);' +
|
|
4834
4834
|
'font-weight: bold;' +
|
|
4835
4835
|
'text-align: center;' +
|
|
4836
4836
|
'text-shadow: 2px 2px 4px rgba(0, 0, 0, 1);' +
|
|
@@ -4857,52 +4857,29 @@ createCustomSubtitleOverlay() {
|
|
|
4857
4857
|
if (this.options.debug) console.log('✅ Custom subtitle overlay created with responsive settings');
|
|
4858
4858
|
}
|
|
4859
4859
|
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
var trackElements = document.querySelectorAll('track[kind="subtitles"], track[kind="captions"]');
|
|
4863
|
-
var loadPromises = [];
|
|
4864
|
-
|
|
4865
|
-
if (this.options.debug) console.log('📥 Loading ' + trackElements.length + ' subtitle files...');
|
|
4866
|
-
|
|
4867
|
-
for (var i = 0; i < trackElements.length; i++) {
|
|
4868
|
-
var track = trackElements[i];
|
|
4869
|
-
|
|
4870
|
-
(function (trackElement, index) {
|
|
4871
|
-
var promise = fetch(trackElement.src)
|
|
4872
|
-
.then(function (response) {
|
|
4873
|
-
return response.text();
|
|
4874
|
-
})
|
|
4875
|
-
.then(function (srtText) {
|
|
4876
|
-
var subtitles = self.parseCustomSRT(srtText);
|
|
4877
|
-
self.customSubtitles.push({
|
|
4878
|
-
label: trackElement.label || 'Track ' + (index + 1),
|
|
4879
|
-
language: trackElement.srclang || 'unknown',
|
|
4880
|
-
subtitles: subtitles
|
|
4881
|
-
});
|
|
4860
|
+
customTimeToSeconds(timeString) {
|
|
4861
|
+
if (!timeString) return 0;
|
|
4882
4862
|
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
}
|
|
4886
|
-
})
|
|
4887
|
-
.catch(function (error) {
|
|
4888
|
-
if (self.options.debug) {
|
|
4889
|
-
console.error('❌ Error loading ' + trackElement.src + ':', error);
|
|
4890
|
-
}
|
|
4891
|
-
});
|
|
4863
|
+
var parts = timeString.split(',');
|
|
4864
|
+
if (parts.length !== 2) return 0;
|
|
4892
4865
|
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
}
|
|
4866
|
+
var time = parts[0];
|
|
4867
|
+
var millis = parts[1];
|
|
4896
4868
|
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
console.log('✅ All custom subtitle tracks loaded');
|
|
4900
|
-
}
|
|
4869
|
+
var timeParts = time.split(':');
|
|
4870
|
+
if (timeParts.length !== 3) return 0;
|
|
4901
4871
|
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4872
|
+
var hours = parseInt(timeParts[0], 10);
|
|
4873
|
+
var minutes = parseInt(timeParts[1], 10);
|
|
4874
|
+
var seconds = parseInt(timeParts[2], 10);
|
|
4875
|
+
var milliseconds = parseInt(millis, 10);
|
|
4876
|
+
|
|
4877
|
+
if (isNaN(hours) || isNaN(minutes) || isNaN(seconds) || isNaN(milliseconds)) {
|
|
4878
|
+
console.error('❌ customTimeToSeconds failed for:', timeString);
|
|
4879
|
+
return 0;
|
|
4880
|
+
}
|
|
4881
|
+
|
|
4882
|
+
return hours * 3600 + minutes * 60 + seconds + milliseconds / 1000;
|
|
4906
4883
|
}
|
|
4907
4884
|
|
|
4908
4885
|
parseCustomSRT(srtText) {
|
|
@@ -4921,9 +4898,9 @@ parseCustomSRT(srtText) {
|
|
|
4921
4898
|
if (timeMatch) {
|
|
4922
4899
|
var startTime = this.customTimeToSeconds(timeMatch[1]);
|
|
4923
4900
|
var endTime = this.customTimeToSeconds(timeMatch[2]);
|
|
4924
|
-
var text =
|
|
4901
|
+
var text = lines.slice(2).join('\n').trim().replace(/<[^>]*>/g, '');
|
|
4925
4902
|
|
|
4926
|
-
if (text.length > 0 && startTime < endTime) {
|
|
4903
|
+
if (text && text.length > 0 && startTime < endTime) {
|
|
4927
4904
|
subtitles.push({
|
|
4928
4905
|
start: startTime,
|
|
4929
4906
|
end: endTime,
|
|
@@ -4934,20 +4911,97 @@ parseCustomSRT(srtText) {
|
|
|
4934
4911
|
}
|
|
4935
4912
|
}
|
|
4936
4913
|
|
|
4914
|
+
if (this.options.debug) console.log('✅ Parsed ' + subtitles.length + ' subtitles');
|
|
4937
4915
|
return subtitles;
|
|
4938
4916
|
}
|
|
4939
4917
|
|
|
4940
|
-
|
|
4941
|
-
var
|
|
4942
|
-
var
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4918
|
+
loadCustomSubtitleTracks() {
|
|
4919
|
+
var self = this;
|
|
4920
|
+
var tracks = this.video.querySelectorAll('track[kind="subtitles"]');
|
|
4921
|
+
if (tracks.length === 0) return;
|
|
4922
|
+
|
|
4923
|
+
tracks.forEach(function (track, index) {
|
|
4924
|
+
var src = track.getAttribute('src');
|
|
4925
|
+
var label = track.getAttribute('label') || 'Unknown';
|
|
4926
|
+
var srclang = track.getAttribute('srclang') || '';
|
|
4927
|
+
|
|
4928
|
+
// CREA L'OGGETTO PRIMA E AGGIUNGILO SUBITO
|
|
4929
|
+
var trackObj = {
|
|
4930
|
+
label: label,
|
|
4931
|
+
language: srclang,
|
|
4932
|
+
subtitles: [],
|
|
4933
|
+
trackIndex: index
|
|
4934
|
+
};
|
|
4935
|
+
self.customSubtitles.push(trackObj);
|
|
4936
|
+
|
|
4937
|
+
fetch(src)
|
|
4938
|
+
.then(function (response) {
|
|
4939
|
+
return response.text();
|
|
4940
|
+
})
|
|
4941
|
+
.then(function (srtText) {
|
|
4942
|
+
var normalizedText = srtText.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
4943
|
+
var blocks = normalizedText.trim().split('\n\n');
|
|
4944
|
+
|
|
4945
|
+
for (var i = 0; i < blocks.length; i++) {
|
|
4946
|
+
var block = blocks[i].trim();
|
|
4947
|
+
if (!block) continue;
|
|
4948
|
+
var lines = block.split('\n');
|
|
4949
|
+
|
|
4950
|
+
if (lines.length >= 3) {
|
|
4951
|
+
var timeLine = lines[1].trim();
|
|
4952
|
+
var timeMatch = timeLine.match(/(\d{2}:\d{2}:\d{2},\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2},\d{3})/);
|
|
4953
|
+
|
|
4954
|
+
if (timeMatch) {
|
|
4955
|
+
var startParts = timeMatch[1].split(',');
|
|
4956
|
+
var startTimeParts = startParts[0].split(':');
|
|
4957
|
+
var startTime = parseInt(startTimeParts[0], 10) * 3600 + parseInt(startTimeParts[1], 10) * 60 + parseInt(startTimeParts[2], 10) + parseInt(startParts[1], 10) / 1000;
|
|
4958
|
+
|
|
4959
|
+
var endParts = timeMatch[2].split(',');
|
|
4960
|
+
var endTimeParts = endParts[0].split(':');
|
|
4961
|
+
var endTime = parseInt(endTimeParts[0], 10) * 3600 + parseInt(endTimeParts[1], 10) * 60 + parseInt(endTimeParts[2], 10) + parseInt(endParts[1], 10) / 1000;
|
|
4962
|
+
|
|
4963
|
+
var text = lines.slice(2).join('\n').trim().replace(/<[^>]*>/g, '');
|
|
4964
|
+
|
|
4965
|
+
if (text && text.length > 0 && !isNaN(startTime) && !isNaN(endTime) && startTime < endTime) {
|
|
4966
|
+
trackObj.subtitles.push({
|
|
4967
|
+
start: startTime,
|
|
4968
|
+
end: endTime,
|
|
4969
|
+
text: text
|
|
4970
|
+
});
|
|
4971
|
+
}
|
|
4972
|
+
}
|
|
4973
|
+
}
|
|
4974
|
+
}
|
|
4949
4975
|
|
|
4950
|
-
|
|
4976
|
+
if (self.options.debug) {
|
|
4977
|
+
console.log('✅ Loaded ' + trackObj.subtitles.length + ' subtitles for ' + label);
|
|
4978
|
+
}
|
|
4979
|
+
})
|
|
4980
|
+
.catch(function (error) {
|
|
4981
|
+
console.error('❌ Error loading ' + label + ':', error);
|
|
4982
|
+
});
|
|
4983
|
+
});
|
|
4984
|
+
}
|
|
4985
|
+
|
|
4986
|
+
sanitizeSubtitleText(text) {
|
|
4987
|
+
if (!text) return '';
|
|
4988
|
+
|
|
4989
|
+
// Remove HTML tags
|
|
4990
|
+
var sanitized = text.replace(/<[^>]*>/g, '');
|
|
4991
|
+
|
|
4992
|
+
// Remove styling tags common in SRT files
|
|
4993
|
+
sanitized = sanitized.replace(/{\\.*?}/g, '');
|
|
4994
|
+
sanitized = sanitized.replace(/\\N/g, '\n');
|
|
4995
|
+
|
|
4996
|
+
// Clean up multiple spaces
|
|
4997
|
+
sanitized = sanitized.replace(/\s+/g, ' ').trim();
|
|
4998
|
+
|
|
4999
|
+
// Decode HTML entities if present
|
|
5000
|
+
var tempDiv = document.createElement('div');
|
|
5001
|
+
tempDiv.innerHTML = sanitized;
|
|
5002
|
+
sanitized = tempDiv.textContent || tempDiv.innerText || sanitized;
|
|
5003
|
+
|
|
5004
|
+
return sanitized;
|
|
4951
5005
|
}
|
|
4952
5006
|
|
|
4953
5007
|
enableCustomSubtitleTrack(trackIndex) {
|
|
@@ -5040,28 +5094,39 @@ detectTextTracks() {
|
|
|
5040
5094
|
enableSubtitleTrack(trackIndex) {
|
|
5041
5095
|
if (trackIndex < 0 || trackIndex >= this.textTracks.length) return;
|
|
5042
5096
|
|
|
5097
|
+
// Disable all tracks first
|
|
5043
5098
|
this.disableAllTracks();
|
|
5044
5099
|
|
|
5100
|
+
// Enable ONLY the custom subtitle system (not native browser)
|
|
5045
5101
|
var success = this.enableCustomSubtitleTrack(trackIndex);
|
|
5046
5102
|
|
|
5047
5103
|
if (success) {
|
|
5048
5104
|
this.currentSubtitleTrack = this.textTracks[trackIndex].track;
|
|
5049
5105
|
this.subtitlesEnabled = true;
|
|
5050
5106
|
|
|
5107
|
+
// Make sure native tracks stay DISABLED
|
|
5108
|
+
if (this.video.textTracks && this.video.textTracks[trackIndex]) {
|
|
5109
|
+
this.video.textTracks[trackIndex].mode = 'disabled'; // Keep native disabled
|
|
5110
|
+
}
|
|
5111
|
+
|
|
5051
5112
|
this.updateSubtitlesButton();
|
|
5052
5113
|
this.populateSubtitlesMenu();
|
|
5053
5114
|
|
|
5054
5115
|
if (this.options.debug) {
|
|
5055
|
-
console.log('✅
|
|
5116
|
+
console.log('✅ Custom subtitles enabled:', this.textTracks[trackIndex].label);
|
|
5056
5117
|
}
|
|
5057
5118
|
|
|
5058
|
-
// Trigger
|
|
5119
|
+
// Trigger subtitle change event
|
|
5059
5120
|
this.triggerEvent('subtitlechange', {
|
|
5060
5121
|
enabled: true,
|
|
5061
5122
|
trackIndex: trackIndex,
|
|
5062
5123
|
trackLabel: this.textTracks[trackIndex].label,
|
|
5063
5124
|
trackLanguage: this.textTracks[trackIndex].language
|
|
5064
5125
|
});
|
|
5126
|
+
} else {
|
|
5127
|
+
if (this.options.debug) {
|
|
5128
|
+
console.error('❌ Failed to enable custom subtitles for track', trackIndex);
|
|
5129
|
+
}
|
|
5065
5130
|
}
|
|
5066
5131
|
}
|
|
5067
5132
|
|
|
@@ -5084,11 +5149,15 @@ disableSubtitles() {
|
|
|
5084
5149
|
}
|
|
5085
5150
|
|
|
5086
5151
|
disableAllTracks() {
|
|
5087
|
-
if (this.video.textTracks)
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5152
|
+
if (!this.video || !this.video.textTracks) return;
|
|
5153
|
+
|
|
5154
|
+
// Disable all native tracks
|
|
5155
|
+
for (var i = 0; i < this.video.textTracks.length; i++) {
|
|
5156
|
+
this.video.textTracks[i].mode = 'hidden';
|
|
5091
5157
|
}
|
|
5158
|
+
|
|
5159
|
+
// Also disable custom subtitles
|
|
5160
|
+
this.disableCustomSubtitles();
|
|
5092
5161
|
}
|
|
5093
5162
|
|
|
5094
5163
|
getAvailableSubtitles() {
|
|
@@ -5169,25 +5238,61 @@ updateSubtitlesUI() {
|
|
|
5169
5238
|
bindSubtitleEvents() {
|
|
5170
5239
|
var self = this;
|
|
5171
5240
|
|
|
5241
|
+
if (this.video.textTracks) {
|
|
5242
|
+
this.isChangingSubtitles = false; // flag to prevent loops
|
|
5243
|
+
|
|
5244
|
+
this.video.textTracks.addEventListener('change', function () {
|
|
5245
|
+
// ignore changes initiated by the player itself
|
|
5246
|
+
if (self.isChangingSubtitles) {
|
|
5247
|
+
return;
|
|
5248
|
+
}
|
|
5249
|
+
|
|
5250
|
+
// only update ui
|
|
5251
|
+
self.updateSubtitlesUI();
|
|
5252
|
+
});
|
|
5253
|
+
}
|
|
5254
|
+
|
|
5255
|
+
// Add timeupdate listener for custom subtitle display
|
|
5256
|
+
this.video.addEventListener('timeupdate', () => {
|
|
5257
|
+
if (this.customSubtitlesEnabled) {
|
|
5258
|
+
this.updateCustomSubtitleDisplay();
|
|
5259
|
+
}
|
|
5260
|
+
});
|
|
5261
|
+
|
|
5262
|
+
// Menu click events
|
|
5172
5263
|
var subtitlesMenu = this.controls && this.controls.querySelector('.subtitles-menu');
|
|
5173
5264
|
if (subtitlesMenu) {
|
|
5174
5265
|
subtitlesMenu.addEventListener('click', function (e) {
|
|
5175
|
-
|
|
5266
|
+
var option = e.target.closest('.subtitles-option');
|
|
5267
|
+
if (!option) return;
|
|
5268
|
+
|
|
5269
|
+
self.isChangingSubtitles = true; // active flag
|
|
5270
|
+
|
|
5271
|
+
var trackIndex = option.getAttribute('data-track');
|
|
5272
|
+
if (trackIndex === 'off') {
|
|
5273
|
+
self.disableSubtitles();
|
|
5274
|
+
} else {
|
|
5275
|
+
self.enableSubtitleTrack(parseInt(trackIndex));
|
|
5276
|
+
}
|
|
5277
|
+
|
|
5278
|
+
setTimeout(function () {
|
|
5279
|
+
self.isChangingSubtitles = false; // disable flag
|
|
5280
|
+
}, 100);
|
|
5176
5281
|
});
|
|
5177
5282
|
}
|
|
5178
5283
|
}
|
|
5179
5284
|
|
|
5180
|
-
|
|
5181
5285
|
handleSubtitlesMenuClick(e) {
|
|
5182
|
-
|
|
5286
|
+
var option = e.target.closest('.subtitles-option');
|
|
5287
|
+
if (!option) return; // This prevents button clicks from toggling
|
|
5183
5288
|
|
|
5184
|
-
var
|
|
5289
|
+
var trackIndex = option.getAttribute('data-track');
|
|
5185
5290
|
|
|
5186
|
-
if (
|
|
5291
|
+
if (trackIndex === 'off') {
|
|
5187
5292
|
this.disableSubtitles();
|
|
5188
5293
|
} else {
|
|
5189
|
-
|
|
5190
|
-
this.enableSubtitleTrack(trackIndex);
|
|
5294
|
+
// Don't check for 'toggle' - just enable the track
|
|
5295
|
+
this.enableSubtitleTrack(parseInt(trackIndex));
|
|
5191
5296
|
}
|
|
5192
5297
|
|
|
5193
5298
|
this.updateSubtitlesButton();
|