Creating subtitle support on the web-app.

This commit is contained in:
Zoe Roux 2019-09-08 02:51:38 +02:00
parent 9527894fad
commit e5d3ea1257
8 changed files with 3489 additions and 11 deletions

View File

@ -31,7 +31,8 @@
],
"scripts": [
"./node_modules/jquery/dist/jquery.min.js",
"./node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
"./node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
"./src/libraries/subtitles.js"
]
},
"configurations": {

View File

@ -1,3 +1,5 @@
@import "../../libraries/subtitles";
.player
{
position: fixed;
@ -15,6 +17,20 @@
}
}
#hover
{
transition: opacity .2s linear;
opacity: 1;
visibility: visible;
&.idle
{
transition: opacity .6s linear, visibility 0s .6s;
opacity: 0;
visibility: hidden;
}
}
.back
{
position: fixed;
@ -267,7 +283,7 @@
overflow: hidden;
transition: width .2s cubic-bezier(0.4,0, 1, 1);
&::ng-deep > div
> div
{
top: 19px;
left: 10px;

View File

@ -1,15 +1,17 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { WatchItem } from "../../models/watch-item";
import { ActivatedRoute } from "@angular/router";
import { DomSanitizer, Title } from "@angular/platform-browser";
import { Location } from "@angular/common";
import { MatSliderChange } from "@angular/material/slider";
import { HtmlAstPath } from "@angular/compiler";
declare var SubtitleManager: any;
@Component({
selector: 'app-player',
templateUrl: './player.component.html',
styleUrls: ['./player.component.scss']
styleUrls: ['./player.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class PlayerComponent implements OnInit
{
@ -17,10 +19,11 @@ export class PlayerComponent implements OnInit
volume: number = 100;
seeking: boolean = false;
videoHider;
hours: number;
minutes: number;
seconds: number;
minutes: number = 0;
seconds: number = 0;
maxHours: number;
maxMinutes: number;
@ -51,9 +54,7 @@ export class PlayerComponent implements OnInit
this.initPlayBtn();
}
this.maxSeconds = Math.round(this.item.duration % 60);
this.maxMinutes = Math.round(this.item.duration / 60 % 60);
this.maxHours = Math.round(this.item.duration / 3600);
this.setDuration(this.item.duration);
this.title.setTitle(this.item.showTitle + " S" + this.item.seasonNumber + ":E" + this.item.episodeNumber + " - Kyoo");
});
@ -91,11 +92,15 @@ export class PlayerComponent implements OnInit
{
if (this.player.buffered.length > 0)
this.buffered.style.width = (this.player.buffered.end(this.player.buffered.length - 1) / this.item.duration * 100) + "%";
if (this.player.duration != undefined && this.player.duration != Infinity)
this.setDuration(this.player.duration);
};
let progressBar: HTMLElement = document.getElementById("progress-bar") as HTMLElement;
$(progressBar).click((event) =>
{
console.log("Duration: " + this.player.duration);
event.preventDefault();
let time: number = this.getTimeFromSeekbar(progressBar, event.pageX);
this.player.currentTime = time;
@ -134,8 +139,34 @@ export class PlayerComponent implements OnInit
let time: number = this.getTimeFromSeekbar(progressBar, event.pageX);
this.updateTime(time);
}
else
{
document.getElementById("hover").classList.remove("idle");
document.documentElement.style.cursor = "";
clearTimeout(this.videoHider);
this.videoHider = setTimeout(() =>
{
if (!this.player.paused)
{
document.getElementById("hover").classList.add("idle");
document.documentElement.style.cursor = "none";
}
}, 2000);
}
});
//Initialize the timout at the document initialization.
this.videoHider = setTimeout(() =>
{
if (!this.player.paused)
{
document.getElementById("hover").classList.add("idle");
document.documentElement.style.cursor = "none";
}
}, 2000);
document.addEventListener("fullscreenchange", () =>
{
if (document.fullscreenElement != null)
@ -151,6 +182,8 @@ export class PlayerComponent implements OnInit
});
$('[data-toggle="tooltip"]').tooltip({ trigger: "hover" });
SubtitleManager.add(this.player, "/api/subtitle/" + this.item.link + "-fre.ass", true);
}
getTimeFromSeekbar(progressBar: HTMLElement, pageX: number)
@ -158,6 +191,15 @@ export class PlayerComponent implements OnInit
return Math.max(0, Math.min((pageX - progressBar.offsetLeft) / progressBar.clientWidth, 1)) * this.item.duration;
}
setDuration(duration: number)
{
this.maxSeconds = Math.round(duration % 60);
this.maxMinutes = Math.round(duration / 60 % 60);
this.maxHours = Math.round(duration / 3600);
this.item.duration = duration;
}
updateTime(time: number)
{
this.hours = Math.round(time / 60 % 60);

View File

@ -0,0 +1,23 @@
.subtitle_container {
line-height: normal;
position: absolute;
pointer-events: none;
transform-origin: 0 0 0;
top: 0;
left: 0;
}
.subtitle_container text, .subtitle_container path {
dominant-baseline: text-before-edge;
text-anchor: start;
transform-box: view-box;
paint-order: stroke;
position: absolute;
top: 0;
left: 0;
}
.subtitle_container tspan {
white-space: pre;
}
.subtitle_container mask path {
fill: white;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
using Kyoo.InternalAPI;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SubtitleController : ControllerBase
{
private readonly ILibraryManager libraryManager;
public SubtitleController(ILibraryManager libraryManager)
{
this.libraryManager = libraryManager;
}
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}-{languageTag}.ass")]
public IActionResult GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag)
{
return PhysicalFile(@"D:\Videos\Devilman\Subtitles\fre\Devilman Crybaby S01E01.fre.ass", "text/x-ssa");
}
}
}

View File

@ -26,7 +26,7 @@ namespace Kyoo.Controllers
{
//Should check if video is playable on the client and transcode if needed.
//Should use the right mime type
return new PhysicalFileResult(episode.Path, "video/mp4");
return PhysicalFile(episode.Path, "video/mp4", true);
}
else
return NotFound();

View File

@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Web.Http;