Adding subtitle swap fonctionality inside the web app player.

This commit is contained in:
Zoe Roux 2019-09-17 02:39:26 +02:00
parent 1ce584d087
commit 7cf9a6fe6b
7 changed files with 83 additions and 22 deletions

View File

@ -64,7 +64,7 @@
<button *ngIf="this.item.audios.length > 0" mat-icon-button data-toggle="tooltip" data-placement="top" title="Select audio track">
<mat-icon>music_note</mat-icon>
</button>
<button *ngIf="this.item.subtitles.length > 0" mat-icon-button data-toggle="tooltip" data-placement="top" title="Select subtitle track">
<button *ngIf="this.item.subtitles.length > 0" mat-icon-button [matMenuTriggerFor]="subtitles" data-toggle="tooltip" data-placement="top" title="Select subtitle track">
<mat-icon>closed_caption</mat-icon>
</button>
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Cast">
@ -79,6 +79,24 @@
</div>
</div>
</div>
<mat-menu #subtitles="matMenu">
<button mat-menu-item (click)="selectSubtitle(null)">
<span>None</span>
</button>
<div *ngFor="let subtitle of this.item.subtitles">
<button mat-menu-item *ngIf="subtitle.codec == 'ass'; else elseBlock" (click)="selectSubtitle(subtitle)">
<span>{{subtitle.language}}</span>
</button>
<ng-template #elseBlock>
<button mat-menu-item disabled>
<span>{{subtitle.language}}</span>
</button>
</ng-template>
</div>
</mat-menu>
</div>
</div>
</div>

View File

@ -1,5 +1,5 @@
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { WatchItem } from "../../models/watch-item";
import { WatchItem, Track } from "../../models/watch-item";
import { ActivatedRoute } from "@angular/router";
import { DomSanitizer, Title } from "@angular/platform-browser";
import { Location } from "@angular/common";
@ -20,6 +20,7 @@ export class PlayerComponent implements OnInit
volume: number = 100;
seeking: boolean = false;
videoHider;
selectedSubtitle: Track;
hours: number;
minutes: number = 0;
@ -100,7 +101,6 @@ export class PlayerComponent implements OnInit
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;
@ -182,8 +182,6 @@ 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)
@ -281,6 +279,36 @@ export class PlayerComponent implements OnInit
}
}
selectSubtitle(subtitle: Track)
{
this.selectedSubtitle = subtitle;
if (subtitle == null)
{
SubtitleManager.remove(this.player);
}
else
{
if (subtitle.codec == "ass")
SubtitleManager.add(this.player, this.getSubtitleLink(subtitle), true);
}
}
getSubtitleLink(subtitle: Track): string
{
let link: string = "/api/subtitle/" + this.item.link + "-" + subtitle.language;
if (subtitle.isForced)
link += "-forced";
//The extension is not necesarry but we add this because it allow the user to quickly download the file in the good format if he wants.
if (subtitle.codec == "ass")
link += ".ass";
else if (subtitle.codec == "subrip")
link += ".srt"
return link;
}
getThumb(url: string)
{

View File

@ -15,15 +15,15 @@ export interface WatchItem
previousEpisode: string;
nextEpisode: Episode;
audio: Stream[];
subtitles: Stream[];
audio: Track[];
subtitles: Track[];
}
export interface Stream
export interface Track
{
title: string;
language: string;
isDefault: boolean;
isForced: boolean;
format: string;
codec: string;
}

View File

@ -18,10 +18,23 @@ namespace Kyoo.Controllers
this.transcoder = transcoder;
}
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}-{languageTag}.{format?}")]
public IActionResult GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag, string format)
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}-{languageTag}.{codec?}")]
public IActionResult GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag, string codec)
{
Track subtitle = libraryManager.GetSubtitle(showSlug, seasonNumber, episodeNumber, languageTag);
Track subtitle = libraryManager.GetSubtitle(showSlug, seasonNumber, episodeNumber, languageTag, false);
if (subtitle == null)
return NotFound();
//Should use appropriate mime type here
return PhysicalFile(subtitle.Path, "text/x-ssa");
}
//This one is never called.
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}-{languageTag}-{disposition}.{codec?}")] //Disposition can't be tagged as optional because there is a parametter after him.
public IActionResult GetForcedSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag, string disposition, string codec)
{
Track subtitle = libraryManager.GetSubtitle(showSlug, seasonNumber, episodeNumber, languageTag, disposition == "forced");
if (subtitle == null)
return NotFound();

View File

@ -18,7 +18,7 @@ namespace Kyoo.InternalAPI
//Internal HTML read
(List<Track> audios, List<Track> subtitles) GetStreams(long episodeID);
Track GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag);
Track GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag, bool forced);
//Public read
IEnumerable<Library> GetLibraries();

View File

@ -73,7 +73,7 @@ namespace Kyoo.InternalAPI
CREATE TABLE tracks(
id INTEGER PRIMARY KEY UNIQUE,
episodeID INTEGER,
streamType TEXT,
streamType INTEGER,
title TEXT,
language TEXT,
codec TEXT,
@ -203,21 +203,21 @@ namespace Kyoo.InternalAPI
while (reader.Read())
{
Track stream = Track.FromReader(reader);
Track track = Track.FromReader(reader);
if (stream.type == StreamType.Audio)
audios.Add(stream);
else if (stream.type == StreamType.Subtitle)
subtitles.Add(stream);
if (track.type == StreamType.Audio)
audios.Add(track);
else if (track.type == StreamType.Subtitle)
subtitles.Add(track);
}
return (audios, subtitles);
}
}
public Track GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag)
public Track GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag, bool forced)
{
string query = "SELECT tracks.* FROM tracks JOIN episodes ON tracks.episodeID = episodes.id JOIN shows ON episodes.showID = shows.id WHERE shows.slug = $showSlug AND episodes.seasonNumber = $seasonNumber AND episodes.episodeNumber = $episodeNumber AND tracks.language = $languageTag;";
string query = "SELECT tracks.* FROM tracks JOIN episodes ON tracks.episodeID = episodes.id JOIN shows ON episodes.showID = shows.id WHERE shows.slug = $showSlug AND episodes.seasonNumber = $seasonNumber AND episodes.episodeNumber = $episodeNumber AND tracks.language = $languageTag AND tracks.isForced = $forced;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
@ -225,6 +225,7 @@ namespace Kyoo.InternalAPI
cmd.Parameters.AddWithValue("$seasonNumber", seasonNumber);
cmd.Parameters.AddWithValue("$episodeNumber", episodeNumber);
cmd.Parameters.AddWithValue("$languageTag", languageTag);
cmd.Parameters.AddWithValue("$forced", forced);
SQLiteDataReader reader = cmd.ExecuteReader();
if (reader.Read())

View File

@ -1,5 +1,6 @@
using Kyoo.Models.Watch;
using Newtonsoft.Json;
using System;
using System.Runtime.InteropServices;
namespace Kyoo.Models
@ -44,7 +45,7 @@ namespace Kyoo.Models
public static Track FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Track(reader["streamType"] as StreamType? ?? StreamType.Unknow,
return new Track((StreamType)Enum.ToObject(typeof(StreamType), reader["streamType"]),
reader["title"] as string,
reader["language"] as string,
reader["isDefault"] as bool? ?? false,