添加字幕本地预览

This commit is contained in:
Harvey committed 2019-11-14 14:00:24 +08:00
1 parent 2878705e72
commit 9cf1571ef8
15 files changed
+279 -81

No files matched your search

+2 -2
View File
@@ -30,5 +30,5 @@
"Web fullscreen": "网页全屏",
"Exit web fullscreen": "退出网页全屏",
"Mini player": "迷你播放器",
"This does not seem to support full screen functionality": "似乎不支持全屏功能"
}
"Does not support fullscreen": "不支持全屏"
}
+1 -1
View File
@@ -30,5 +30,5 @@
"Web fullscreen": "網頁全屏",
"Exit web fullscreen": "退出網頁全屏",
"Mini player": "迷你播放器",
"This does not seem to support full screen functionality": "似乎不支持全屏功能"
"Does not support fullscreen": "不支持全屏"
}
+2 -1
View File
@@ -123,7 +123,8 @@ class Artplayer extends Emitter {
fullscreenWeb: false,
subtitleOffset: false,
miniProgressBar: false,
localPreview: false,
localVideo: false,
localSubtitle: false,
autoPip: false,
networkMonitor: false,
layers: [],
@@ -14,7 +14,7 @@ export default function fullscreenMix(art, player) {
};
const screenfullError = () => {
notice.show(i18n.get('This does not seem to support full screen functionality'));
notice.show(i18n.get('Does not support fullscreen'));
};
if (player.fullscreenIsEnabled) {
@@ -4,6 +4,7 @@ export default function switchMix(art, player) {
Object.defineProperty(player, 'switchQuality', {
value: (url, name = 'unknown') => {
if (url !== template.$video.src) {
URL.revokeObjectURL(template.$video.src);
const { currentTime, playing } = player;
return player.attachUrl(url).then(() => {
option.url = url;
@@ -26,6 +27,7 @@ export default function switchMix(art, player) {
Object.defineProperty(player, 'switchUrl', {
value: (url, name = 'unknown') => {
if (url !== template.$video.src) {
URL.revokeObjectURL(template.$video.src);
const { playing } = player;
return player.attachUrl(url).then(() => {
option.url = url;
+8 -3
View File
@@ -1,6 +1,7 @@
import { errorHandle, hasOwnProperty } from '../utils';
import subtitleOffset from './subtitleOffset';
import localPreview from './localPreview';
import localVideo from './localVideo';
import localSubtitle from './localSubtitle';
import miniProgressBar from './miniProgressBar';
import networkMonitor from './networkMonitor';
import autoPip from './autoPip';
@@ -20,8 +21,12 @@ export default class Plugins {
this.add(miniProgressBar);
}
if (option.localPreview) {
this.add(localPreview);
if (option.localVideo) {
this.add(localVideo);
}
if (option.localSubtitle) {
this.add(localSubtitle);
}
if (option.networkMonitor) {
@@ -0,0 +1,76 @@
import { append, setStyle, setStyles, errorHandle, getExt, vttToBlob, srtToVtt, assToVtt } from '../utils';
export default function localSubtitle(art) {
const {
events: { proxy },
notice,
i18n,
subtitle,
} = art;
const notSupport = 'Only supports subtitle files in .ass, .vtt and .srt format';
i18n.update({
'zh-cn': {
[notSupport]: '只支持 .ass、.vtt 和 .srt 格式的字幕文件',
},
'zh-tw': {
[notSupport]: '只支持 .ass、.vtt 和 .srt 格式的字幕文件',
},
});
function loadSubtitle(file) {
if (file) {
const type = getExt(file.name);
if (['ass', 'vtt', 'srt'].includes(type)) {
const reader = new FileReader();
proxy(reader, 'load', event => {
const text = event.target.result;
switch (type) {
case 'srt': {
const url = vttToBlob(srtToVtt(text));
subtitle.switch(url, file.name);
break;
}
case 'ass': {
const url = vttToBlob(assToVtt(text));
subtitle.switch(url, file.name);
break;
}
case 'vtt': {
const url = vttToBlob(text);
subtitle.switch(url, file.name);
break;
}
default:
break;
}
});
reader.readAsText(file);
} else {
const tip = i18n.get(notSupport);
notice.show(tip, true, 3000);
errorHandle(false, tip);
}
}
}
return {
name: 'localSubtitle',
attach(target) {
const $input = append(target, '<input type="file">');
setStyle(target, 'position', 'relative');
setStyles($input, {
position: 'absolute',
width: '100%',
height: '100%',
left: '0',
top: '0',
opacity: '0',
});
proxy($input, 'change', () => {
const file = $input.files[0];
loadSubtitle(file);
});
},
};
}
@@ -1,41 +1,33 @@
export default function localPreview(art) {
const { append, setStyle, setStyles, sleep, errorHandle } = art.constructor.utils;
import { append, setStyle, setStyles, errorHandle, getExt } from '../utils';
export default function localVideo(art) {
const {
events: { proxy },
option,
notice,
i18n,
template,
player,
} = art;
const notSupport = 'Playback of this file format is not supported';
i18n.update({
'zh-cn': {
'Playback of this file format is not supported': '不支持播放该文件格式',
'Load local video successfully': '加载本地视频成功',
[notSupport]: '不支持播放该文件格式',
},
'zh-tw': {
'Playback of this file format is not supported': '不支持播放該文件格式',
'Load local video successfully': '加載本地視頻成功',
[notSupport]: '不支持播放該文件格式',
},
});
function loadVideo(file) {
if (file) {
const type = getExt(file.name);
const canPlayType = template.$video.canPlayType(file.type);
if (canPlayType === 'maybe' || canPlayType === 'probably') {
const url = URL.createObjectURL(file);
player.playbackRate = false;
player.aspectRatio = false;
template.$video.src = url;
sleep(1000).then(() => {
player.currentTime = 0;
});
option.url = url;
art.emit('switch', url);
notice.show(i18n.get('Load local video successfully'));
player.switchUrl(url, file.name);
} else {
const tip = `${i18n.get('Playback of this file format is not supported')}: ${file.type}`;
const tip = `${i18n.get(notSupport)}: ${file.type || type}`;
notice.show(tip, true, 3000);
errorHandle(false, tip);
}
@@ -44,7 +36,6 @@ export default function localPreview(art) {
proxy(template.$player, 'dragover', e => {
e.preventDefault();
notice.show(i18n.get('Load local video successfully'));
});
proxy(template.$player, 'drop', e => {
@@ -54,7 +45,7 @@ export default function localPreview(art) {
});
return {
name: 'localPreview',
name: 'localVideo',
attach(target) {
const $input = append(target, '<input type="file">');
setStyle(target, 'position', 'relative');
+5 -1
View File
@@ -32,7 +32,8 @@ export default {
fullscreenWeb: 'boolean',
subtitleOffset: 'boolean',
miniProgressBar: 'boolean',
localPreview: 'boolean',
localVideo: 'boolean',
localSubtitle: 'boolean',
autoPip: 'boolean',
networkMonitor: 'boolean',
plugins: ['function'],
@@ -46,6 +47,7 @@ export default {
style: 'object|undefined',
click: 'function|undefined',
mounted: 'function|undefined',
tooltip: 'string|undefined',
},
],
contextmenu: [
@@ -57,6 +59,7 @@ export default {
style: 'object|undefined',
click: 'function|undefined',
mounted: 'function|undefined',
tooltip: 'string|undefined',
},
],
quality: [
@@ -75,6 +78,7 @@ export default {
style: 'object|undefined',
click: 'function|undefined',
mounted: 'function|undefined',
tooltip: 'string|undefined',
position: (value, type, paths) => {
const position = ['top', 'left', 'right'];
return errorHandle(
+2 -2
View File
@@ -19,10 +19,10 @@ export default class Subtitle {
return '';
}
switch(url) {
switch(url, name = 'unknown') {
const { i18n, notice } = this.art;
return this.init(url).then(blobUrl => {
notice.show(i18n.get('Switch subtitle'));
notice.show(`${i18n.get('Switch subtitle')}: ${name}`);
return blobUrl;
});
}
+5 -1
View File
@@ -1,4 +1,4 @@
import { append, setStyles, setStyle, remove, errorHandle, hasOwnProperty } from './index';
import { append, setStyles, setStyle, remove, errorHandle, hasOwnProperty, tooltip } from './index';
export default function component(art, parent, target, getOption, callback, title) {
const option = typeof getOption === 'function' ? getOption(art) : getOption;
@@ -20,6 +20,10 @@ export default function component(art, parent, target, getOption, callback, titl
setStyles($element, option.style);
}
if (option.tooltip) {
tooltip($element, option.tooltip);
}
const childs = Array.from(target.children);
$element.dataset.index = option.index || componentID;
const nextChild = childs.find(item => Number(item.dataset.index) >= Number($element.dataset.index));