mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-19 19:51:20 -08:00
Refactor code structure for improved readability and maintainability
This commit is contained in:
1 parent
9378aa21ee
commit
a3416fcb33
15 files changed
+515
-308946
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
@@ -1,589 +0,0 @@
|
||||
var SubtitlesOctopus = function (options) {
|
||||
var supportsWebAssembly = false;
|
||||
try {
|
||||
if (typeof WebAssembly === "object"
|
||||
&& typeof WebAssembly.instantiate === "function") {
|
||||
const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
|
||||
if (module instanceof WebAssembly.Module)
|
||||
supportsWebAssembly = (new WebAssembly.Instance(module) instanceof WebAssembly.Instance);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
console.log("WebAssembly support detected: " + (supportsWebAssembly ? "yes" : "no"));
|
||||
|
||||
var self = this;
|
||||
self.canvas = options.canvas; // HTML canvas element (optional if video specified)
|
||||
self.lossyRender = options.lossyRender; // Speedup render for heavy subs
|
||||
self.isOurCanvas = false; // (internal) we created canvas and manage it
|
||||
self.video = options.video; // HTML video element (optional if canvas specified)
|
||||
self.canvasParent = null; // (internal) HTML canvas parent element
|
||||
self.fonts = options.fonts || []; // Array with links to fonts used in sub (optional)
|
||||
self.availableFonts = options.availableFonts || []; // Object with all available fonts (optional). Key is font name in lower case, value is link: {"arial": "/font1.ttf"}
|
||||
self.onReadyEvent = options.onReady; // Function called when SubtitlesOctopus is ready (optional)
|
||||
if (supportsWebAssembly) {
|
||||
self.workerUrl = options.workerUrl || 'subtitles-octopus-worker.js'; // Link to WebAssembly worker
|
||||
} else {
|
||||
self.workerUrl = options.legacyWorkerUrl || 'subtitles-octopus-worker-legacy.js'; // Link to legacy worker
|
||||
}
|
||||
self.subUrl = options.subUrl; // Link to sub file (optional if subContent specified)
|
||||
self.subContent = options.subContent || null; // Sub content (optional if subUrl specified)
|
||||
self.onErrorEvent = options.onError; // Function called in case of critical error meaning sub wouldn't be shown and you should use alternative method (for instance it occurs if browser doesn't support web workers).
|
||||
self.debug = options.debug || false; // When debug enabled, some performance info printed in console.
|
||||
self.lastRenderTime = 0; // (internal) Last time we got some frame from worker
|
||||
self.pixelRatio = window.devicePixelRatio || 1; // (internal) Device pixel ratio (for high dpi devices)
|
||||
|
||||
self.timeOffset = options.timeOffset || 0; // Time offset would be applied to currentTime from video (option)
|
||||
|
||||
self.hasAlphaBug = false;
|
||||
|
||||
(function() {
|
||||
if (typeof ImageData.prototype.constructor === 'function') {
|
||||
try {
|
||||
// try actually calling ImageData, as on some browsers it's reported
|
||||
// as existing but calling it errors out as "TypeError: Illegal constructor"
|
||||
new window.ImageData(new Uint8ClampedArray([0, 0, 0, 0]), 1, 1);
|
||||
return;
|
||||
} catch (e) {
|
||||
console.log("detected that ImageData is not constructable despite browser saying so");
|
||||
}
|
||||
}
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
window.ImageData = function () {
|
||||
var i = 0;
|
||||
if (arguments[0] instanceof Uint8ClampedArray) {
|
||||
var data = arguments[i++];
|
||||
}
|
||||
var width = arguments[i++];
|
||||
var height = arguments[i];
|
||||
|
||||
var imageData = ctx.createImageData(width, height);
|
||||
if (data) imageData.data.set(data);
|
||||
return imageData;
|
||||
}
|
||||
})();
|
||||
|
||||
self.workerError = function (error) {
|
||||
console.error('Worker error: ', error);
|
||||
if (self.onErrorEvent) {
|
||||
self.onErrorEvent(error);
|
||||
}
|
||||
if (!self.debug) {
|
||||
self.dispose();
|
||||
throw new Error('Worker error: ' + error);
|
||||
}
|
||||
};
|
||||
|
||||
// Not tested for repeated usage yet
|
||||
self.init = function () {
|
||||
if (!window.Worker) {
|
||||
self.workerError('worker not supported');
|
||||
return;
|
||||
}
|
||||
// Worker
|
||||
if (!self.worker) {
|
||||
self.worker = new Worker(self.workerUrl);
|
||||
self.worker.onmessage = self.onWorkerMessage;
|
||||
self.worker.onerror = self.workerError;
|
||||
}
|
||||
self.workerActive = false;
|
||||
self.createCanvas();
|
||||
self.setVideo(options.video);
|
||||
self.setSubUrl(options.subUrl);
|
||||
self.worker.postMessage({
|
||||
target: 'worker-init',
|
||||
width: self.canvas.width,
|
||||
height: self.canvas.height,
|
||||
URL: document.URL,
|
||||
currentScript: self.workerUrl,
|
||||
preMain: true,
|
||||
fastRender: self.lossyRender,
|
||||
subUrl: self.subUrl,
|
||||
subContent: self.subContent,
|
||||
fonts: self.fonts,
|
||||
availableFonts: self.availableFonts,
|
||||
debug: self.debug
|
||||
});
|
||||
};
|
||||
|
||||
self.createCanvas = function () {
|
||||
if (!self.canvas) {
|
||||
if (self.video) {
|
||||
self.isOurCanvas = true;
|
||||
self.canvas = document.createElement('canvas');
|
||||
self.canvas.className = 'libassjs-canvas';
|
||||
self.canvas.style.display = 'none';
|
||||
|
||||
self.canvasParent = document.createElement('div');
|
||||
self.canvasParent.className = 'libassjs-canvas-parent';
|
||||
self.canvasParent.appendChild(self.canvas);
|
||||
|
||||
if (self.video.nextSibling) {
|
||||
self.video.parentNode.insertBefore(self.canvasParent, self.video.nextSibling);
|
||||
}
|
||||
else {
|
||||
self.video.parentNode.appendChild(self.canvasParent);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!self.canvas) {
|
||||
self.workerError('Don\'t know where to render: you should give video or canvas in options.');
|
||||
}
|
||||
}
|
||||
}
|
||||
self.ctx = self.canvas.getContext('2d');
|
||||
self.bufferCanvas = document.createElement('canvas');
|
||||
self.bufferCanvasCtx = self.bufferCanvas.getContext('2d');
|
||||
|
||||
// test for alpha bug, where e.g. WebKit can render a transparent pixel
|
||||
// (with alpha == 0) as non-black which then leads to visual artifacts
|
||||
self.bufferCanvas.width = 1;
|
||||
self.bufferCanvas.height = 1;
|
||||
var testBuf = new Uint8ClampedArray([0, 255, 0, 0]);
|
||||
var testImage = new ImageData(testBuf, 1, 1);
|
||||
self.bufferCanvasCtx.clearRect(0, 0, 1, 1);
|
||||
self.ctx.clearRect(0, 0, 1, 1);
|
||||
var prePut = self.ctx.getImageData(0, 0, 1, 1).data;
|
||||
self.bufferCanvasCtx.putImageData(testImage, 0, 0);
|
||||
self.ctx.drawImage(self.bufferCanvas, 0, 0);
|
||||
var postPut = self.ctx.getImageData(0, 0, 1, 1).data;
|
||||
self.hasAlphaBug = prePut[1] != postPut[1];
|
||||
if (self.hasAlphaBug) {
|
||||
console.log("Detected a browser having issue with transparent pixels, applying workaround");
|
||||
}
|
||||
};
|
||||
|
||||
self.setVideo = function (video) {
|
||||
self.video = video;
|
||||
if (self.video) {
|
||||
var timeupdate = function () {
|
||||
self.setCurrentTime(video.currentTime + self.timeOffset);
|
||||
}
|
||||
self.video.addEventListener("timeupdate", timeupdate, false);
|
||||
self.video.addEventListener("playing", function () {
|
||||
self.setIsPaused(false, video.currentTime + self.timeOffset);
|
||||
}, false);
|
||||
self.video.addEventListener("pause", function () {
|
||||
self.setIsPaused(true, video.currentTime + self.timeOffset);
|
||||
}, false);
|
||||
self.video.addEventListener("seeking", function () {
|
||||
self.video.removeEventListener("timeupdate", timeupdate);
|
||||
}, false);
|
||||
self.video.addEventListener("seeked", function () {
|
||||
self.video.addEventListener("timeupdate", timeupdate, false);
|
||||
self.setCurrentTime(video.currentTime + self.timeOffset);
|
||||
}, false);
|
||||
self.video.addEventListener("ratechange", function () {
|
||||
self.setRate(video.playbackRate);
|
||||
}, false);
|
||||
self.video.addEventListener("timeupdate", function () {
|
||||
self.setCurrentTime(video.currentTime + self.timeOffset);
|
||||
}, false);
|
||||
self.video.addEventListener("waiting", function () {
|
||||
self.setIsPaused(true, video.currentTime + self.timeOffset);
|
||||
}, false);
|
||||
|
||||
document.addEventListener("fullscreenchange", self.resizeWithTimeout, false);
|
||||
document.addEventListener("mozfullscreenchange", self.resizeWithTimeout, false);
|
||||
document.addEventListener("webkitfullscreenchange", self.resizeWithTimeout, false);
|
||||
document.addEventListener("msfullscreenchange", self.resizeWithTimeout, false);
|
||||
window.addEventListener("resize", self.resizeWithTimeout, false);
|
||||
|
||||
// Support Element Resize Observer
|
||||
if (typeof ResizeObserver !== "undefined") {
|
||||
self.ro = new ResizeObserver(self.resizeWithTimeout);
|
||||
self.ro.observe(self.video);
|
||||
}
|
||||
|
||||
if (self.video.videoWidth > 0) {
|
||||
self.resize();
|
||||
}
|
||||
else {
|
||||
self.video.addEventListener("loadedmetadata", function (e) {
|
||||
e.target.removeEventListener(e.type, arguments.callee);
|
||||
self.resize();
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.getVideoPosition = function () {
|
||||
var videoRatio = self.video.videoWidth / self.video.videoHeight;
|
||||
var width = self.video.offsetWidth, height = self.video.offsetHeight;
|
||||
var elementRatio = width / height;
|
||||
var realWidth = width, realHeight = height;
|
||||
if (elementRatio > videoRatio) realWidth = Math.floor(height * videoRatio);
|
||||
else realHeight = Math.floor(width / videoRatio);
|
||||
|
||||
var x = (width - realWidth) / 2;
|
||||
var y = (height - realHeight) / 2;
|
||||
|
||||
return {
|
||||
width: realWidth,
|
||||
height: realHeight,
|
||||
x: x,
|
||||
y: y
|
||||
};
|
||||
};
|
||||
|
||||
self.setSubUrl = function (subUrl) {
|
||||
self.subUrl = subUrl;
|
||||
};
|
||||
|
||||
self.renderFrameData = null;
|
||||
function renderFrames() {
|
||||
var data = self.renderFramesData;
|
||||
var beforeDrawTime = performance.now();
|
||||
self.ctx.clearRect(0, 0, self.canvas.width, self.canvas.height);
|
||||
for (var i = 0; i < data.canvases.length; i++) {
|
||||
var image = data.canvases[i];
|
||||
self.bufferCanvas.width = image.w;
|
||||
self.bufferCanvas.height = image.h;
|
||||
var imageBuffer = new Uint8ClampedArray(image.buffer);
|
||||
if (self.hasAlphaBug) {
|
||||
for (var j = 3; j < imageBuffer.length; j = j + 4) {
|
||||
imageBuffer[j] = (imageBuffer[j] >= 1) ? imageBuffer[j] : 1;
|
||||
}
|
||||
}
|
||||
var imageData = new ImageData(imageBuffer, image.w, image.h);
|
||||
self.bufferCanvasCtx.putImageData(imageData, 0, 0);
|
||||
self.ctx.drawImage(self.bufferCanvas, image.x, image.y);
|
||||
}
|
||||
if (self.debug) {
|
||||
var drawTime = Math.round(performance.now() - beforeDrawTime);
|
||||
console.log(Math.round(data.spentTime) + ' ms (+ ' + drawTime + ' ms draw)');
|
||||
self.renderStart = performance.now();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lossy Render Mode
|
||||
*
|
||||
*/
|
||||
function renderFastFrames() {
|
||||
var data = self.renderFramesData;
|
||||
var beforeDrawTime = performance.now();
|
||||
self.ctx.clearRect(0, 0, self.canvas.width, self.canvas.height);
|
||||
for (var i = 0; i < data.bitmaps.length; i++) {
|
||||
var image = data.bitmaps[i];
|
||||
self.ctx.drawImage(image.bitmap, image.x, image.y);
|
||||
}
|
||||
if (self.debug) {
|
||||
var drawTime = Math.round(performance.now() - beforeDrawTime);
|
||||
console.log(data.bitmaps.length + ' bitmaps, libass: ' + Math.round(data.libassTime) + 'ms, decode: ' + Math.round(data.decodeTime) + 'ms, draw: ' + drawTime + 'ms');
|
||||
self.renderStart = performance.now();
|
||||
}
|
||||
}
|
||||
|
||||
self.workerActive = false;
|
||||
self.frameId = 0;
|
||||
self.onWorkerMessage = function (event) {
|
||||
//dump('\nclient got ' + JSON.stringify(event.data).substr(0, 150) + '\n');
|
||||
if (!self.workerActive) {
|
||||
self.workerActive = true;
|
||||
if (self.onReadyEvent) {
|
||||
self.onReadyEvent();
|
||||
}
|
||||
}
|
||||
var data = event.data;
|
||||
switch (data.target) {
|
||||
case 'stdout': {
|
||||
console.log(data.content);
|
||||
break;
|
||||
}
|
||||
case 'console-log': {
|
||||
console.log.apply(console, JSON.parse(data.content));
|
||||
break;
|
||||
}
|
||||
case 'console-debug': {
|
||||
console.debug.apply(console, JSON.parse(data.content));
|
||||
break;
|
||||
}
|
||||
case 'console-info': {
|
||||
console.info.apply(console, JSON.parse(data.content));
|
||||
break;
|
||||
}
|
||||
case 'console-warn': {
|
||||
console.warn.apply(console, JSON.parse(data.content));
|
||||
break;
|
||||
}
|
||||
case 'console-error': {
|
||||
console.error.apply(console, JSON.parse(data.content));
|
||||
break;
|
||||
}
|
||||
case 'stderr': {
|
||||
console.error(data.content);
|
||||
break;
|
||||
}
|
||||
case 'window': {
|
||||
window[data.method]();
|
||||
break;
|
||||
}
|
||||
case 'canvas': {
|
||||
switch (data.op) {
|
||||
case 'getContext': {
|
||||
self.ctx = self.canvas.getContext(data.type, data.attributes);
|
||||
break;
|
||||
}
|
||||
case 'resize': {
|
||||
self.resize(data.width, data.height);
|
||||
break;
|
||||
}
|
||||
case 'renderCanvas': {
|
||||
if (self.lastRenderTime < data.time) {
|
||||
self.lastRenderTime = data.time;
|
||||
self.renderFramesData = data;
|
||||
window.requestAnimationFrame(renderFrames);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'renderFastCanvas': {
|
||||
if (self.lastRenderTime < data.time) {
|
||||
self.lastRenderTime = data.time;
|
||||
self.renderFramesData = data;
|
||||
window.requestAnimationFrame(renderFastFrames);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'setObjectProperty': {
|
||||
self.canvas[data.object][data.property] = data.value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw 'eh?';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'tick': {
|
||||
self.frameId = data.id;
|
||||
self.worker.postMessage({
|
||||
target: 'tock',
|
||||
id: self.frameId
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'custom': {
|
||||
if (self['onCustomMessage']) {
|
||||
self['onCustomMessage'](event);
|
||||
} else {
|
||||
throw 'Custom message received but client onCustomMessage not implemented.';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'setimmediate': {
|
||||
self.worker.postMessage({
|
||||
target: 'setimmediate'
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'get-events': {
|
||||
console.log(data.target);
|
||||
console.log(data.events);
|
||||
break;
|
||||
}
|
||||
case 'get-styles': {
|
||||
console.log(data.target);
|
||||
console.log(data.styles);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw 'what? ' + data.target;
|
||||
}
|
||||
};
|
||||
|
||||
self.resize = function (width, height, top, left) {
|
||||
var videoSize = null;
|
||||
top = top || 0;
|
||||
left = left || 0;
|
||||
if ((!width || !height) && self.video) {
|
||||
videoSize = self.getVideoPosition();
|
||||
width = videoSize.width * self.pixelRatio;
|
||||
height = videoSize.height * self.pixelRatio;
|
||||
var offset = self.canvasParent.getBoundingClientRect().top - self.video.getBoundingClientRect().top;
|
||||
top = videoSize.y - offset;
|
||||
left = videoSize.x;
|
||||
}
|
||||
if (!width || !height) {
|
||||
if (!self.video) {
|
||||
console.error('width or height is 0. You should specify width & height for resize.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
self.canvas.width != width ||
|
||||
self.canvas.height != height ||
|
||||
self.canvas.style.top != top ||
|
||||
self.canvas.style.left != left
|
||||
) {
|
||||
self.canvas.width = width;
|
||||
self.canvas.height = height;
|
||||
|
||||
if (videoSize != null) {
|
||||
self.canvasParent.style.position = 'relative';
|
||||
self.canvas.style.display = 'block';
|
||||
self.canvas.style.position = 'absolute';
|
||||
self.canvas.style.width = videoSize.width + 'px';
|
||||
self.canvas.style.height = videoSize.height + 'px';
|
||||
self.canvas.style.top = top + 'px';
|
||||
self.canvas.style.left = left + 'px';
|
||||
self.canvas.style.pointerEvents = 'none';
|
||||
}
|
||||
|
||||
self.worker.postMessage({
|
||||
target: 'canvas',
|
||||
width: self.canvas.width,
|
||||
height: self.canvas.height
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
self.resizeWithTimeout = function () {
|
||||
self.resize();
|
||||
setTimeout(self.resize, 100);
|
||||
};
|
||||
|
||||
self.runBenchmark = function () {
|
||||
self.worker.postMessage({
|
||||
target: 'runBenchmark'
|
||||
});
|
||||
};
|
||||
|
||||
self.customMessage = function (data, options) {
|
||||
options = options || {};
|
||||
self.worker.postMessage({
|
||||
target: 'custom',
|
||||
userData: data,
|
||||
preMain: options.preMain
|
||||
});
|
||||
};
|
||||
|
||||
self.setCurrentTime = function (currentTime) {
|
||||
self.worker.postMessage({
|
||||
target: 'video',
|
||||
currentTime: currentTime
|
||||
});
|
||||
};
|
||||
|
||||
self.setTrackByUrl = function (url) {
|
||||
self.worker.postMessage({
|
||||
target: 'set-track-by-url',
|
||||
url: url
|
||||
});
|
||||
};
|
||||
|
||||
self.setTrack = function (content) {
|
||||
self.worker.postMessage({
|
||||
target: 'set-track',
|
||||
content: content
|
||||
});
|
||||
};
|
||||
|
||||
self.freeTrack = function (content) {
|
||||
self.worker.postMessage({
|
||||
target: 'free-track'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
self.render = self.setCurrentTime;
|
||||
|
||||
self.setIsPaused = function (isPaused, currentTime) {
|
||||
self.worker.postMessage({
|
||||
target: 'video',
|
||||
isPaused: isPaused,
|
||||
currentTime: currentTime
|
||||
});
|
||||
};
|
||||
|
||||
self.setRate = function (rate) {
|
||||
self.worker.postMessage({
|
||||
target: 'video',
|
||||
rate: rate
|
||||
});
|
||||
};
|
||||
|
||||
self.dispose = function () {
|
||||
self.worker.postMessage({
|
||||
target: 'destroy'
|
||||
});
|
||||
|
||||
self.worker.terminate();
|
||||
self.workerActive = false;
|
||||
// Remove the canvas element to remove residual subtitles rendered on player
|
||||
if (self.video) {
|
||||
self.video.parentNode.removeChild(self.canvasParent);
|
||||
}
|
||||
};
|
||||
|
||||
self.createEvent = function (event) {
|
||||
self.worker.postMessage({
|
||||
target: 'create-event',
|
||||
event: event
|
||||
});
|
||||
};
|
||||
|
||||
self.getEvents = function () {
|
||||
self.worker.postMessage({
|
||||
target: 'get-events'
|
||||
});
|
||||
};
|
||||
|
||||
self.setEvent = function (event, index) {
|
||||
self.worker.postMessage({
|
||||
target: 'set-event',
|
||||
event: event,
|
||||
index: index
|
||||
});
|
||||
};
|
||||
|
||||
self.removeEvent = function (index) {
|
||||
self.worker.postMessage({
|
||||
target: 'remove-event',
|
||||
index: index
|
||||
});
|
||||
};
|
||||
|
||||
self.createStyle = function (style) {
|
||||
self.worker.postMessage({
|
||||
target: 'create-style',
|
||||
style: style
|
||||
});
|
||||
};
|
||||
|
||||
self.getStyles = function () {
|
||||
self.worker.postMessage({
|
||||
target: 'get-styles'
|
||||
});
|
||||
};
|
||||
|
||||
self.setStyle = function (style, index) {
|
||||
self.worker.postMessage({
|
||||
target: 'set-style',
|
||||
style: style,
|
||||
index: index
|
||||
});
|
||||
};
|
||||
|
||||
self.removeStyle = function (index) {
|
||||
self.worker.postMessage({
|
||||
target: 'remove-style',
|
||||
index: index
|
||||
});
|
||||
};
|
||||
|
||||
self.init();
|
||||
};
|
||||
|
||||
if (typeof SubtitlesOctopusOnLoad == 'function') {
|
||||
SubtitlesOctopusOnLoad();
|
||||
}
|
||||
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
exports = module.exports = SubtitlesOctopus
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
[Script Info]
|
||||
Title:
|
||||
ScriptType: v4.00+
|
||||
WrapStyle: 0
|
||||
PlayResX: 640
|
||||
PlayResY: 480
|
||||
ScaledBorderAndShadow: yes
|
||||
|
||||
[V4+ Styles]
|
||||
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
||||
Style: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,10,0
|
||||
Style: Alt,Times New Roman,40,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,8,10,10,10,0
|
||||
|
||||
[Events]
|
||||
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
|
||||
Comment: 0,0:00:00.00,0:00:05.00,Default,,0000,0000,0000,,This line is a comment and should not display on rendered output. This file is intended to be rendered on a 640x480 video, preferably a single solid colour, or maybe a checkerboard pattern.
|
||||
Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0000,0000,0000,,This is a test of the ASS format and some basic features in it.
|
||||
Dialogue: 0,0:00:05.00,0:00:07.00,Default,,0000,0000,0000,,This and the previous line should both show at the bottom of the video in 20 pixel high white Arial with a 2 pixel black outline and 2 pixel offset shadow. This line is long so it should automatically be broken into several lines that are approximately even length, with upper lines being longer.
|
||||
Dialogue: 0,0:00:07.00,0:00:09.00,Default,,0000,0000,0000,,Now going to test conflict resolution. {By the way, this is a common abuse, "inline-comments" in override tag groups. They should not be rendered and not generate errors, just be ignored.}
|
||||
Dialogue: 0,0:00:07.50,0:00:09.00,Default,,0000,0000,0000,,This line should be above the previous.
|
||||
Dialogue: 0,0:00:09.00,0:00:11.00,Default,,0000,0000,0000,,{\an1}This line should be lower-left aligned using the \an1 override.
|
||||
Dialogue: 0,0:00:11.00,0:00:13.00,Default,,0000,0000,0000,,{\an9}Upper right
|
||||
Dialogue: 0,0:00:12.00,0:00:14.00,Alt,,0000,0000,0000,,This one should be below the "Upper right" line and be centered on screen. It should also be in 40 pixel high Times New Roman.
|
||||
Dialogue: 0,0:00:14.00,0:00:16.00,Alt,,0000,0000,0000,,{\fs10}This should also be a toptitle in Times New Roman, but much smaller. Using an override tag to change size.
|
||||
Dialogue: 0,0:00:16.00,0:00:18.00,Alt,,0000,0000,0000,,{\a5}Top-left using the legacy \a5 tag
|
||||
Dialogue: 0,0:00:18.00,0:00:20.00,Default,,0000,0000,0000,,{\an5}This line is centered on screen.\NAt the bottom of the screen should be two lines in different layers, they are rendered on top of each other because conflict resolution only considers lines in the same layer.
|
||||
Dialogue: 0,0:00:18.00,0:00:20.00,Default,,0000,0000,0000,,This is in layer 0
|
||||
Dialogue: 1,0:00:18.00,0:00:20.00,Default,,0000,0000,0000,,And this line is in layer 1
|
||||
Dialogue: 0,0:00:20.00,0:00:22.00,Default,,0000,0000,0000,,Another line in layer 0
|
||||
Dialogue: 1,0:00:20.00,0:00:22.00,Default,,0050,0000,0020,,And this line is in layer 1, but has changed its margins so it isn't exactly centered, and it's raised above the other line.
|
||||
Dialogue: 0,0:00:22.00,0:00:24.00,Default,,0000,0000,0000,,Switching {\fnTimes New Roman}font inline, {\r}and resetting styles
|
||||
Dialogue: 0,0:00:24.00,0:00:26.00,Default,,0000,0000,0000,,Also {\rAlt}switching to a different style {\r}inline
|
||||
Dialogue: 0,0:00:26.00,0:00:28.00,Default,,0000,0000,0000,,{\an5\pos(258,131)}Positioning... this line should be in an odd place
|
||||
Dialogue: 0,0:00:26.00,0:00:28.00,Default,,0000,0000,0000,,{\an5\pos(222,338)\frz29.559}So should this one, and be rotated
|
||||
Dialogue: 0,0:00:28.00,0:00:30.00,Default,,0000,0000,0000,,{\pos(371,314)\frz338.403\frx42\fry30\org(187,165)}Some more rotation tricks, this time in 3D and with a different origin
|
||||
Dialogue: 0,0:00:30.00,0:00:32.00,Default,,0000,0000,0000,,{\an5\t(\frz360)}This line is animated and rotates 360 degrees over its duration
|
||||
Dialogue: 0,0:00:32.00,0:00:34.00,Default,,0000,0000,0000,,{\an5\move(182,157,414,311)}This line moves
|
||||
Dialogue: 0,0:00:34.00,0:00:36.00,Default,,0000,0000,0000,,{\an5\clip(126,192,487,241)}This line is only partially visible\Nso if you can see this, \clip is handled incorrectly
|
||||
Dialogue: 0,0:00:36.00,0:00:38.00,Default,,0000,0000,0000,,{\an5\clip(m 178 212 l 163 249 212 302 257 232 309 249 366 241 392 285 473 267 487 210 421 241 353 219 207 258)}And this line has a funnily-shaped clip area
|
||||
Dialogue: 0,0:00:38.00,0:00:40.00,Default,,0000,0000,0000,,{\an5\pos(321,193)}Here should be a pretty feather with a thin border and no shadow:
|
||||
Dialogue: 0,0:00:38.00,0:00:40.00,Default,,0000,0000,0000,,{\an5\bord1\shad0\p1\fscx300\fscy300\pos(316,312)}m 0 0 b 33 -3 48 -7 61 -19 b 53 -7 31 -1 1 2 m 9 0 b 9 -5 10 -6 14 -12 b 9 -5 10 -3 10 0 m 10 -1 b 10 -5 11 -8 16 -12 b 17 -12 18 -13 22 -14 b 18 -10 16 -6 15 -1 b 17 -6 19 -10 23 -14 l 26 -15 b 22 -11 20 -6 19 -2 b 24 -11 27 -14 28 -15 b 31 -16 35 -16 39 -16 b 37 -14 36 -10 36 -5 b 36 -9 38 -14 39 -16 b 41 -16 43 -16 45 -15 b 44 -13 43 -10 43 -7 l 29 -3 m 43 -7 b 44 -11 45 -13 47 -15 b 46 -13 46 -11 46 -9 b 46 -11 47 -13 49 -15 b 51 -15 48 -13 48 -9 b 49 -11 49 -14 52 -16 b 55 -16 53 -17 51 -11 l 48 -8 m 54 -13 b 53 -14 54 -15 54 -16 b 54 -15 54 -14 55 -13 b 57 -13 60 -12 62 -14 b 61 -12 55 -12 53 -12 b 55 -11 56 -10 61 -10 b 61 -7 53 -9 52 -11 b 53 -8 55 -7 58 -6 b 57 -5 56 -4 54 -3 b 49 -5 48 -6 47 -9 b 47 -6 50 -4 53 -2 b 49 -3 47 -6 45 -8 b 46 -6 49 -3 52 -1 b 46 2 45 3 43 3 b 40 0 39 -3 40 -6 b 39 -3 39 1 42 3 b 40 6 36 1 34 -4 b 35 -1 36 2 38 5 b 32 7 26 9 22 8 b 19 5 17 2 16 -1 b 17 3 19 5 20 7 b 17 4 16 2 15 0 b 15 2 17 5 19 8 b 15 9 13 3 12 0 l 25 -2 l 42 -7 m 12 0 b 13 3 13 7 17 9 b 12 7 10 1 10 0
|
||||
Dialogue: 0,0:00:40.00,0:00:42.00,Default,,0000,0000,0000,,Some other basic font style tests:\NNormal, {\b1}Boldface{\r}, {\i1}Italics{\r}, {\u1}Underline{\r}, {\s1}Strikethrough
|
||||
Dialogue: 0,0:00:42.00,0:00:44.00,Default,,0000,0000,0000,,There should be no linebreak here,\nbut there should be one here\Nso this is on a separate line.
|
||||
Dialogue: 0,0:00:44.00,0:00:46.00,Default,,0000,0000,0000,,This line is pushed left by adding some hard spaces to the right\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h
|
||||
Dialogue: 0,0:00:44.00,0:00:46.00,Default,,0000,0000,0000,, Regular spaces at line start/end are ignored, so this line is centered
|
||||
Dialogue: 0,0:00:46.00,0:00:48.00,Default,,0000,0000,0000,,{\an8\q2}This is a long line but it is not broken into several because it's using the \q override tag which changes the line-wrapping mode for a single line. The tag can take several values, 0 is the default which is "smart wrapping" with top lines longer, 1 is regular wrapping, 2 is no wrapping and 3 is smart-wrapping with bottom lines longer.
|
||||
Dialogue: 0,0:00:46.00,0:00:48.00,Default,,0000,0000,0000,,{\an5\q1}This is a long line using the \q1 override tag to get "dumb" wrapping, make as long lines as possible and first wrap when it'd go off screen. This is mostly visible when the last line generated is short.
|
||||
Dialogue: 0,0:00:46.00,0:00:48.00,Default,,0000,0000,0000,,{\q3}And this line uses the \q3 wrapping style, which is similar to the \q0 default smart-wrap style, but has lower lines longer than the upper ones.
|
||||
Dialogue: 0,0:00:48.00,0:00:50.00,Default,,0000,0000,0000,,{\an5}{\bord0\t(\bord10)}This text has a growing border\N{\r\shad0\t(\shad10)}This text has an increasing shadow\N{\r\t(\fry360)}This text is rotating around the Y axis\N{\r\t(\frz720)}This text rotates {\t(\frx360)}and this one even more
|
||||
Dialogue: 0,0:00:50.00,0:00:52.00,Default,,0000,0000,0000,,{\an5\bord0\shad0}All of this has no border or shadow...\N{\1c&H0000FF&}This is bright red, {\1c&H00FF00&}green, {\1c&HFF0000}blue{\1c&HFFFFFF&}\N{\1a&H80&}50% transparent
|
||||
Dialogue: 0,0:00:52.00,0:00:54.00,Default,,0000,0000,0000,,{\fsp10}Large inter-letter spacing
|
||||
Dialogue: 0,0:00:54.00,0:00:56.00,Default,,0000,0000,0000,,{\shad0}No shadow here, just regular border, {\be1}but this is \be1 blurred edges!
|
||||
Dialogue: 0,0:00:56.00,0:00:58.00,Default,,0000,0000,0000,,{\t(1000,2000,\alpha&HFF&)}Fading out after 1 sec on screen, using \alpha. Everything should fade.
|
||||
Dialogue: 0,0:00:58.00,0:01:00.00,Default,,0000,0000,0000,,{\fad(1000,1000)}Fading in and out using \fad
|
||||
Dialogue: 0,0:01:00.00,0:01:02.00,Default,,0000,0000,0000,,{\k10}And {\k5}now {\k20}for {\kf50}ka{\kf20}ra{\K70}o{\K10}ke{\k0}!
|
||||
Dialogue: 0,0:01:02.00,0:01:04.00,Default,,0000,0000,0000,,{\an5\t()\clip(69,215,573,267)\t(1000,2000,3,\clip(573,267,573,267))}And the last thing on the programme, an animated rectangular \clip, delayed by 1 second. And it even uses acceleration...!
|
||||
@@ -1,49 +0,0 @@
|
||||
[Script Info]
|
||||
; // 此字幕由爱幕生成
|
||||
Synch Point:1
|
||||
ScriptType:v4.00+
|
||||
Collisions:Normal
|
||||
|
||||
[V4+ Styles]
|
||||
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
||||
Style: Default, Microsoft YaHei, 20, &H00FFFFFF, &H000092FE, &H00000000, &H82000000, 0, 0, 0, 0, 100, 100, 0, 0, 1, 1, 2, 2, 10, 10, 30, 134
|
||||
Style: Style1, Microsoft YaHei, 20, &H0000DCFC, &H0000DCFC, &H00000000, &H82000000, 0, 0, 0, 0, 100, 100, 1, 0, 1, 1, 2, 2, 10, 10, 30, 134
|
||||
Style: Style2, ZCOOL KuaiLe, 20, &H0000DDA4, &H0000DDA4, &H00334D19, &H82000000, 0, 0, 0, 0, 100, 100, 1, 0, 4, 1, 3, 2, 10, 10, 50, 134
|
||||
Style: Style3, Source Han Sans CN Medium, 28, &H009E14AB, &H009E14AB, &H00009EFB, &H82000000, 0, 0, 0, 0, 100, 100, 1, 0, 1, 1, 2, 2, 10, 10, 100, 134
|
||||
|
||||
[Events]
|
||||
Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text
|
||||
Dialogue: 0,0:00:00.31,0:00:00.84,Style1,NTP,0000,0000,0000,,那一天\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}あの日
|
||||
Dialogue: 0,0:00:01.28,0:00:02.22,Style2,NTP,0000,0000,0000,,星星降落的日子\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}星が降った日
|
||||
Dialogue: 0,0:00:03.15,0:00:04.41,Style3,NTP,0000,0000,0000,,那简直是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}それはまるで
|
||||
Dialogue: 0,0:00:04.45,0:00:04.97,Default,NTP,0000,0000,0000,,简直\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}まるで
|
||||
Dialogue: 0,0:00:05.12,0:00:06.30,Default,NTP,0000,0000,0000,,像梦中的景色一样\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}夢の景色のように
|
||||
Dialogue: 0,0:00:07.44,0:00:08.98,Default,NTP,0000,0000,0000,,美丽的景色\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}美しい眺めだった
|
||||
Dialogue: 0,0:00:24.60,0:00:25.09,Default,NTP,0000,0000,0000,,放学后\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}放課後
|
||||
Dialogue: 0,0:00:25.70,0:00:26.26,Default,NTP,0000,0000,0000,,不好\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}悪い
|
||||
Dialogue: 0,0:00:26.48,0:00:27.68,Default,NTP,0000,0000,0000,,我今天开始打工\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}おれ今日これからバイト
|
||||
Dialogue: 0,0:00:29.34,0:00:31.69,Default,NTP,0000,0000,0000,,已经讨厌这样的乡下了\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}もうこんな田舎嫌だよー
|
||||
Dialogue: 0,0:00:31.97,0:00:33.53,Default,NTP,0000,0000,0000,,讨厌这样的人生\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}こんな人生嫌だ
|
||||
Dialogue: 0,0:00:33.93,0:00:37.97,Default,NTP,0000,0000,0000,,来世请让我成为东京的帅哥吧\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}来世は東京のイケメン男子にしてくださーい
|
||||
Dialogue: 0,0:00:42.08,0:00:42.87,Default,NTP,0000,0000,0000,,哪里\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}どこ
|
||||
Dialogue: 0,0:00:43.05,0:00:44.17,Default,NTP,0000,0000,0000,,那么说来\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}そういえば
|
||||
Dialogue: 0,0:00:44.55,0:00:47.08,Default,NTP,0000,0000,0000,,我觉得好像一直做着奇怪的梦\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}ずっと変な夢を見てたような気がするんだけど
|
||||
Dialogue: 0,0:00:48.32,0:00:50.63,Default,NTP,0000,0000,0000,,别人的人生中…梦\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}別の人の人生の…夢
|
||||
Dialogue: 0,0:00:51.45,0:00:52.74,Default,NTP,0000,0000,0000,,这是什么\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}何だ これ
|
||||
Dialogue: 0,0:00:54.78,0:00:55.44,Default,NTP,0000,0000,0000,,这个,这个\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}これって
|
||||
Dialogue: 0,0:00:56.72,0:00:57.72,Default,NTP,0000,0000,0000,,这难道是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}これってもしかして
|
||||
Dialogue: 0,0:00:58.08,0:00:59.33,Default,NTP,0000,0000,0000,,我们在梦中\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}俺達は夢の中で
|
||||
Dialogue: 0,0:01:00.14,0:01:01.20,Default,NTP,0000,0000,0000,,替换着\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}入れ替わってる
|
||||
Dialogue: 0,0:01:07.37,0:01:08.30,Default,NTP,0000,0000,0000,,确实的事情\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}確かなことが
|
||||
Dialogue: 0,0:01:08.76,0:01:09.54,Default,NTP,0000,0000,0000,,只有一个\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}一つだけある
|
||||
Dialogue: 0,0:01:10.33,0:01:11.04,Default,NTP,0000,0000,0000,,我们是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}私達は
|
||||
Dialogue: 0,0:01:11.42,0:01:12.32,Default,NTP,0000,0000,0000,,见面的话绝对\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}会えば絶対
|
||||
Dialogue: 0,0:01:12.68,0:01:13.53,Default,NTP,0000,0000,0000,,马上就明白\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}すぐにわかる
|
||||
Dialogue: 0,0:01:14.25,0:01:15.28,Default,NTP,0000,0000,0000,,我想说\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}言おうと思ったんだ
|
||||
Dialogue: 0,0:01:16.08,0:01:17.58,Default,NTP,0000,0000,0000,,你是世界的无论在哪里\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}お前が世界のどこにいても
|
||||
Dialogue: 0,0:01:17.95,0:01:19.05,Default,NTP,0000,0000,0000,,一定要去见你\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}必ず会いに行くって
|
||||
Dialogue: 0,0:01:20.14,0:01:20.94,Default,NTP,0000,0000,0000,,你是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}あなたは
|
||||
Dialogue: 0,0:01:21.36,0:01:21.80,Default,NTP,0000,0000,0000,,谁\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}誰
|
||||
Dialogue: 0,0:01:22.20,0:01:22.76,Default,NTP,0000,0000,0000,,你是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}お前は
|
||||
Dialogue: 0,0:01:23.48,0:01:24.04,Default,NTP,0000,0000,0000,,谁\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}誰だ
|
||||
Dialogue: 0,0:01:25.69,0:01:26.47,Default,NTP,0000,0000,0000,,你的名字是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}君の名は
|
||||
Reference in new issue
Block a user