Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add video playback #74

Merged
merged 1 commit into from Oct 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
134 changes: 134 additions & 0 deletions components/VideoPlayer.vue
@@ -0,0 +1,134 @@
<template>
<v-container fill-height fluid class="pa-0">
<div ref="videoContainer">
<video ref="videoPlayer" :poster="poster" autoplay></video>
</div>
</v-container>
</template>

<script lang="ts">
import Vue from 'vue';
import { stringify } from 'qs';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import shaka from 'shaka-player/dist/shaka-player.ui';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered adding the shaka-player types? ( first hit: https://github.com/niklaskorz/shaka-player/tree/feature/generate-typescript-typedefs/test/typescript )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have, but unfortunately that repository is severely out of date. We also prefer to stick with the upstream versions of packages.

The Shaka team does intend to ship typings very soon, however, so this will be fixed when the next version of Shaka Player is released (but that's a guess based on recent activity on their repository)

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import muxjs from 'mux.js';
import 'shaka-player/dist/controls.css';

declare global {
interface Window {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
muxjs: any;
}
}

export default Vue.extend({
props: {
item: {
type: Object,
required: true
},
poster: {
type: String,
default: ''
}
},
data() {
return {
source: '',
player: null as any,
ui: null as any
};
},
watch: {
async source(newSource) {
if (this.player) {
try {
await this.player.load(newSource);
} catch (e) {
console.error('Error code', e.code, 'object', e);
}
}
}
},
async mounted() {
try {
const response = await this.$api.mediaInfo.getPostedPlaybackInfo({
itemId: this.$route.params.itemId,
userId: this.$auth.user.Id,
deviceProfileDto: {
DeviceProfile: this.$playbackProfile
}
});

let mediaSource;
if (response?.data?.MediaSources) {
mediaSource = response.data.MediaSources[0];
} else {
throw new Error("This item can't be played.");
}

if (mediaSource.SupportsDirectStream) {
const directOptions: Record<string, any> = {
Static: true,
mediaSourceId: mediaSource.Id,
deviceId: this.$store.state.deviceProfile.deviceId,
api_key: this.$store.state.user.accessToken
};

if (mediaSource.ETag) {
directOptions.Tag = mediaSource.ETag;
}

if (mediaSource.LiveStreamId) {
directOptions.LiveStreamId = mediaSource.LiveStreamId;
}

const params = stringify(directOptions);
this.source = `${this.$axios.defaults.baseURL}/Videos/${mediaSource.Id}/stream.${mediaSource.Container}?${params}`;
} else if (
mediaSource.SupportsTranscoding &&
mediaSource.TranscodingUrl
) {
this.source = this.$axios.defaults.baseURL + mediaSource.TranscodingUrl;
}
window.muxjs = muxjs;
shaka.polyfill.installAll();
if (shaka.Player.isBrowserSupported()) {
// Everything looks good!
this.player = new shaka.Player(this.$refs.videoPlayer);
this.ui = new shaka.ui.Overlay(
this.player,
this.$refs.videoContainer,
this.$refs.videoPlayer
);
} else {
this.$nuxt.error({
message: this.$t('browserNotSupported') as string
});
}
} catch (error) {
this.$nuxt.error({
statusCode: 404,
message: error
});
}
},
beforeDestroy() {
if (this.player) {
window.muxjs = undefined;
this.player.unload();
this.player.destroy();
}
}
});
</script>

<style scoped>
video {
width: 100vw;
height: 100vh;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you have tested this, but just to be sure... have you considered overflowing in some browsers?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't, but we probably need to account for safe areas, yeah.

</style>
27 changes: 14 additions & 13 deletions locales/en-US.json
@@ -1,34 +1,35 @@
{
"alphabetically": "Alphabetically",
"releaseDate": "Release date",
"endDate": "End date",
"rating": "Rating",
"badRequest": "Bad request. Try again",
"browserNotSupported": "Your browser is not supported for playing this file.",
"continueListening": "Continue listening",
"continueWatching": "Continue watching",
"episodeNumber": "Episode {episodeNumber}",
"endDate": "End date",
"endsAt": "Ends at {time}",
"episodeNumber": "Episode {episodeNumber}",
"home": "Home",
"incorrectUsernameOrPassword": "Incorrect username or password",
"itemNotFound": "Item not found",
"libraryEmpty": "This library is empty",
"libraryNotFound": "Library not found",
"login": "Login",
"logout": "Logout",
"more": "More",
"moreLikeThis": "More like this",
"password": "Password",
"play": "Play",
"playType": "Play {mediaType}",
"present": "Present",
"rating": "Rating",
"releaseDate": "Release date",
"serverAddress": "Server address",
"serverAddressMustBeUrl": "Server address must be a valid URL",
"serverAddressRequired": "Server address is required",
"serverNotFound": "Server not found",
"settings": "Settings",
"unexpectedError": "Unexpected error",
"usernameRequired": "Username is required",
"serverAddress": "Server address",
"username": "Username",
"password": "Password",
"playType": "Play {mediaType}",
"signIn": "Sign in",
"unexpectedError": "Unexpected error",
"upNext": "Up next",
"libraryNotFound": "Library not found",
"itemNotFound": "Item not found",
"libraryEmpty": "This library is empty"
"username": "Username",
"usernameRequired": "Username is required"
}
60 changes: 32 additions & 28 deletions locales/fi.json
@@ -1,30 +1,34 @@
{
"badRequest": "Virheellinen pyyntö. Yritä uudelleen",
"continueListening": "Jatka kuuntelua",
"continueWatching": "Jatka katselua",
"episodeNumber": "Jakso {episodeNumber}",
"endsAt": "Päättyy {time}",
"home": "Koti",
"incorrectUsernameOrPassword": "Väärä käyttäjätunnus tai salasana",
"login": "Kirjaudu",
"logout": "Kirjaudu ulos",
"more": "Lisää",
"moreLikeThis": "Lisää samanlaisia",
"play": "Toista",
"present": "Nykyinen",
"serverAddressMustBeUrl": "Palvelinosoitteen on oltava kelvollinen URL-osoite",
"serverAddressRequired": "Palvelinosoite vaaditaan",
"serverNotFound": "Palvelinta ei löydy",
"settings": "Asetukset",
"unexpectedError": "Odottamaton virhe",
"usernameRequired": "Käyttäjänimi vaaditaan",
"serverAddress": "Palvelinosoite",
"username": "Käyttäjätunnus",
"password": "Salasana",
"playType": "Toista {mediaType}",
"signIn": "Kirjaudu sisään",
"upNext": "Seuraava",
"libraryNotFound": "Kirjastoa ei löydy",
"itemNotFound": "Kohdetta ei löydy",
"libraryEmpty": "Kirjasto on tyhjä"
"alphabetically": "",
"badRequest": "Virheellinen pyyntö. Yritä uudelleen",
"continueListening": "Jatka kuuntelua",
"continueWatching": "Jatka katselua",
"endDate": "",
"endsAt": "Päättyy {time}",
"episodeNumber": "Jakso {episodeNumber}",
"home": "Koti",
"incorrectUsernameOrPassword": "Väärä käyttäjätunnus tai salasana",
"itemNotFound": "Kohdetta ei löydy",
"libraryEmpty": "Kirjasto on tyhjä",
"libraryNotFound": "Kirjastoa ei löydy",
"login": "Kirjaudu",
"logout": "Kirjaudu ulos",
"more": "Lisää",
"moreLikeThis": "Lisää samanlaisia",
"password": "Salasana",
"play": "Toista",
"playType": "Toista {mediaType}",
"present": "Nykyinen",
"rating": "",
"releaseDate": "",
"serverAddress": "Palvelinosoite",
"serverAddressMustBeUrl": "Palvelinosoitteen on oltava kelvollinen URL-osoite",
"serverAddressRequired": "Palvelinosoite vaaditaan",
"serverNotFound": "Palvelinta ei löydy",
"settings": "Asetukset",
"signIn": "Kirjaudu sisään",
"unexpectedError": "Odottamaton virhe",
"upNext": "Seuraava",
"username": "Käyttäjätunnus",
"usernameRequired": "Käyttäjänimi vaaditaan"
}
59 changes: 32 additions & 27 deletions locales/nl.json
@@ -1,29 +1,34 @@
{
"badRequest": "Onjuist verzoek. Probeer het opnieuw",
"continueListening": "Verder luisteren",
"continueWatching": "Verder kijken",
"home": "Home",
"incorrectUsernameOrPassword": "Onjuiste gebruikersnaam en/of wachtwoord",
"login": "Inloggen",
"logout": "Uitloggen",
"more": "Meer",
"play": "Afspelen",
"serverAddressMustBeUrl": "Server adres moet een geldige URL zijn",
"serverAddressRequired": "Server adres is verplicht",
"serverNotFound": "Server niet gevonden",
"settings": "Instellingen",
"unexpectedError": "Onverwachte fout",
"upNext": "Volgende",
"usernameRequired": "Gebruikersnaam is verplicht",
"itemNotFound": "Item niet gevonden",
"libraryNotFound": "Bibliotheek niet gevonden",
"signIn": "Inloggen",
"password": "Wachtwoord",
"username": "Gebruikersnaam",
"serverAddress": "Server adres",
"episodeNumber": "Aflevering {episodeNumber}",
"playType": "Speel {mediaType}",
"present": "Huidig",
"moreLikeThis": "Meer zoals dit",
"endsAt": "Eindigt om {time}"
"alphabetically": "",
"badRequest": "Onjuist verzoek. Probeer het opnieuw",
"continueListening": "Verder luisteren",
"continueWatching": "Verder kijken",
"endDate": "",
"endsAt": "Eindigt om {time}",
"episodeNumber": "Aflevering {episodeNumber}",
"home": "Home",
"incorrectUsernameOrPassword": "Onjuiste gebruikersnaam en/of wachtwoord",
"itemNotFound": "Item niet gevonden",
"libraryEmpty": "",
"libraryNotFound": "Bibliotheek niet gevonden",
"login": "Inloggen",
"logout": "Uitloggen",
"more": "Meer",
"moreLikeThis": "Meer zoals dit",
"password": "Wachtwoord",
"play": "Afspelen",
"playType": "Speel {mediaType}",
"present": "Huidig",
"rating": "",
"releaseDate": "",
"serverAddress": "Server adres",
"serverAddressMustBeUrl": "Server adres moet een geldige URL zijn",
"serverAddressRequired": "Server adres is verplicht",
"serverNotFound": "Server niet gevonden",
"settings": "Instellingen",
"signIn": "Inloggen",
"unexpectedError": "Onverwachte fout",
"upNext": "Volgende",
"username": "Gebruikersnaam",
"usernameRequired": "Gebruikersnaam is verplicht"
}
57 changes: 32 additions & 25 deletions locales/pl.json
@@ -1,27 +1,34 @@
{
"badRequest": "Błędne żądanie. Spróbuj ponownie",
"continueListening": "Kontynuuj słuchanie",
"continueWatching": "Kontynuuj odtwarzanie",
"home": "Start",
"incorrectUsernameOrPassword": "Błędna nazwa użytkownika lub hasło",
"login": "Logowanie",
"logout": "Wyloguj",
"more": "Więcej",
"play": "Odtwarzaj",
"serverAddressMustBeUrl": "Adres serwera musi być poprawnym adresem URL",
"serverAddressRequired": "Adres serwera jest wymagany",
"serverNotFound": "Serwer nie został znaleziony",
"settings": "Ustawienia",
"unexpectedError": "Niespodziewany błąd",
"usernameRequired": "Nazwa użytkownika jest wymagana",
"serverAddress": "Adres serwera",
"username": "Nazwa użytkownika",
"password": "Hasło",
"signIn": "Zaloguj",
"upNext": "Następnie",
"libraryNotFound": "Biblioteka nie została znaleziona",
"itemNotFound": "Nie znaleziono",
"episodeNumber": "Odcinek {episodeNumber}",
"playType": "Odtwarzaj {mediaType}",
"present": "Teraz"
"alphabetically": "",
"badRequest": "Błędne żądanie. Spróbuj ponownie",
"continueListening": "Kontynuuj słuchanie",
"continueWatching": "Kontynuuj odtwarzanie",
"endDate": "",
"endsAt": "",
"episodeNumber": "Odcinek {episodeNumber}",
"home": "Start",
"incorrectUsernameOrPassword": "Błędna nazwa użytkownika lub hasło",
"itemNotFound": "Nie znaleziono",
"libraryEmpty": "",
"libraryNotFound": "Biblioteka nie została znaleziona",
"login": "Logowanie",
"logout": "Wyloguj",
"more": "Więcej",
"moreLikeThis": "",
"password": "Hasło",
"play": "Odtwarzaj",
"playType": "Odtwarzaj {mediaType}",
"present": "Teraz",
"rating": "",
"releaseDate": "",
"serverAddress": "Adres serwera",
"serverAddressMustBeUrl": "Adres serwera musi być poprawnym adresem URL",
"serverAddressRequired": "Adres serwera jest wymagany",
"serverNotFound": "Serwer nie został znaleziony",
"settings": "Ustawienia",
"signIn": "Zaloguj",
"unexpectedError": "Niespodziewany błąd",
"upNext": "Następnie",
"username": "Nazwa użytkownika",
"usernameRequired": "Nazwa użytkownika jest wymagana"
}