mirror of
https://github.com/jellyfin/jellyfin-vue.git
synced 2025-03-04 11:47:34 +00:00
feat(item): use of track selector component
This commit is contained in:
parent
c51ecc49b3
commit
e588c50863
@ -157,16 +157,7 @@
|
||||
</v-row>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<div
|
||||
v-if="
|
||||
item &&
|
||||
((item.MediaSources && item.MediaSources.length > 1) ||
|
||||
videoTracks.length > 0 ||
|
||||
audioTracks.length > 0 ||
|
||||
subtitleTracks.length > 0)
|
||||
"
|
||||
class="mt-2"
|
||||
>
|
||||
<div v-if="item && item.MediaSources" class="mt-2">
|
||||
<v-row v-if="item.MediaSources.length > 1" align="center">
|
||||
<v-col
|
||||
cols="12"
|
||||
@ -200,7 +191,7 @@
|
||||
</v-select>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-if="videoTracks.length > 0" align="center">
|
||||
<v-row align="center">
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="2"
|
||||
@ -213,28 +204,15 @@
|
||||
<label class="text--secondary">{{ $t('video') }}</label>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="10">
|
||||
<v-select
|
||||
v-model="currentVideoTrack"
|
||||
:items="getItemizedSelect(videoTracks)"
|
||||
:disabled="videoTracks.length <= 1"
|
||||
outlined
|
||||
filled
|
||||
flat
|
||||
dense
|
||||
single-line
|
||||
hide-details
|
||||
class="text-truncate"
|
||||
>
|
||||
<template slot="selection" slot-scope="{ item: i }">
|
||||
{{ i.value.DisplayTitle }}
|
||||
</template>
|
||||
<template slot="item" slot-scope="{ item: i }">
|
||||
{{ i.value.DisplayTitle }}
|
||||
</template>
|
||||
</v-select>
|
||||
<track-selector
|
||||
:item="item"
|
||||
:media-source-index="currentSourceIndex"
|
||||
:type="'Video'"
|
||||
@input="currentVideoTrack = $event"
|
||||
></track-selector>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-if="audioTracks.length > 0" align="center">
|
||||
<v-row align="center">
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="2"
|
||||
@ -247,40 +225,12 @@
|
||||
<label class="text--secondary">{{ $t('audio') }}</label>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="10">
|
||||
<v-select
|
||||
v-if="audioTracks.length > 0"
|
||||
v-model="currentAudioTrack"
|
||||
:items="getItemizedSelect(audioTracks)"
|
||||
:disabled="audioTracks.length <= 1"
|
||||
outlined
|
||||
filled
|
||||
flat
|
||||
dense
|
||||
single-line
|
||||
hide-details
|
||||
class="text-truncate"
|
||||
>
|
||||
<template slot="selection" slot-scope="{ item: i }">
|
||||
{{ i.value.DisplayTitle }}
|
||||
</template>
|
||||
<template slot="item" slot-scope="{ item: i, on, attrs }">
|
||||
<v-list-item v-bind="attrs" two-line v-on="on">
|
||||
<v-list-item-avatar>
|
||||
<v-icon
|
||||
v-text="getSurroundIcon(i.value.ChannelLayout)"
|
||||
></v-icon>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{
|
||||
i.value.DisplayTitle
|
||||
}}</v-list-item-title>
|
||||
<v-list-item-subtitle>
|
||||
{{ getLanguageName(i.value.Language) }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-select>
|
||||
<track-selector
|
||||
:item="item"
|
||||
:media-source-index="currentSourceIndex"
|
||||
:type="'Audio'"
|
||||
@input="currentAudioTrack = $event"
|
||||
></track-selector>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row align="center">
|
||||
@ -296,40 +246,12 @@
|
||||
<label class="text--secondary">{{ $t('subtitles') }}</label>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="10">
|
||||
<v-select
|
||||
v-model="currentSubtitleTrack"
|
||||
:items="getItemizedSelect(subtitleTracks)"
|
||||
:placeholder="
|
||||
subtitleTracks.length === 0
|
||||
? $t('noSubtitleAvailable')
|
||||
: $t('noSubtitleSelected')
|
||||
"
|
||||
:disabled="subtitleTracks.length === 0"
|
||||
clearable
|
||||
outlined
|
||||
filled
|
||||
flat
|
||||
dense
|
||||
single-line
|
||||
hide-details
|
||||
class="text-truncate"
|
||||
>
|
||||
<template slot="selection" slot-scope="{ item: i }">
|
||||
{{ i.value.DisplayTitle }}
|
||||
</template>
|
||||
<template slot="item" slot-scope="{ item: i, on, attrs }">
|
||||
<v-list-item v-bind="attrs" two-line v-on="on">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{
|
||||
i.value.DisplayTitle
|
||||
}}</v-list-item-title>
|
||||
<v-list-item-subtitle>
|
||||
{{ getLanguageName(i.value.Language) }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-select>
|
||||
<track-selector
|
||||
:item="item"
|
||||
:media-source-index="currentSourceIndex"
|
||||
:type="'Subtitle'"
|
||||
@input="currentSubtitleTrack = $event"
|
||||
></track-selector>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
@ -382,20 +304,18 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { mapActions } from 'vuex';
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- Temporary module while waiting for fixes to language names on the server
|
||||
// @ts-ignore
|
||||
import langs from 'langs';
|
||||
import {
|
||||
BaseItemDto,
|
||||
BaseItemPerson,
|
||||
MediaSourceInfo,
|
||||
MediaStream
|
||||
MediaSourceInfo
|
||||
} from '@jellyfin/client-axios';
|
||||
import imageHelper from '~/mixins/imageHelper';
|
||||
import formsHelper from '~/mixins/formsHelper';
|
||||
import itemHelper from '~/mixins/itemHelper';
|
||||
import TrackSelector from '~/components/Item/TrackSelector.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: { TrackSelector },
|
||||
mixins: [imageHelper, formsHelper, itemHelper],
|
||||
async asyncData({ params, $api, $auth }) {
|
||||
const item = (
|
||||
@ -413,63 +333,14 @@ export default Vue.extend({
|
||||
}
|
||||
|
||||
let currentSource: MediaSourceInfo = {};
|
||||
let videoTracks: MediaStream[] = [];
|
||||
let currentVideoTrack: MediaStream = {};
|
||||
let audioTracks: MediaStream[] = [];
|
||||
let currentAudioTrack: MediaStream = {};
|
||||
let subtitleTracks: MediaStream[] = [];
|
||||
let currentSubtitleTrack: MediaStream = {};
|
||||
if (item.MediaSources && item.MediaSources.length > 0) {
|
||||
|
||||
if (item.MediaSources && item.MediaSources.length > 0)
|
||||
currentSource = item.MediaSources[0];
|
||||
|
||||
// Filter the streams to get each type of track
|
||||
if (currentSource.MediaStreams) {
|
||||
videoTracks = currentSource.MediaStreams.filter(
|
||||
(stream: MediaStream) => {
|
||||
return stream.Type === 'Video';
|
||||
}
|
||||
);
|
||||
audioTracks = currentSource.MediaStreams.filter(
|
||||
(stream: MediaStream) => {
|
||||
return stream.Type === 'Audio';
|
||||
}
|
||||
);
|
||||
subtitleTracks = currentSource.MediaStreams.filter(
|
||||
(stream: MediaStream) => {
|
||||
return stream.Type === 'Subtitle';
|
||||
}
|
||||
);
|
||||
|
||||
// Set default tracks
|
||||
if (videoTracks.length > 0) {
|
||||
currentVideoTrack = videoTracks[0];
|
||||
}
|
||||
if (audioTracks.length > 0 && currentSource.DefaultAudioStreamIndex) {
|
||||
currentAudioTrack =
|
||||
audioTracks[currentSource.DefaultAudioStreamIndex - 1];
|
||||
} else if (audioTracks.length > 0) {
|
||||
currentAudioTrack = audioTracks[0];
|
||||
}
|
||||
if (
|
||||
subtitleTracks.length > 0 &&
|
||||
currentSource.DefaultSubtitleStreamIndex
|
||||
) {
|
||||
currentSubtitleTrack =
|
||||
subtitleTracks[currentSource.DefaultSubtitleStreamIndex - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
item,
|
||||
crew,
|
||||
currentSource,
|
||||
videoTracks,
|
||||
currentVideoTrack,
|
||||
audioTracks,
|
||||
currentAudioTrack,
|
||||
subtitleTracks,
|
||||
currentSubtitleTrack
|
||||
currentSource
|
||||
};
|
||||
},
|
||||
data() {
|
||||
@ -479,12 +350,9 @@ export default Vue.extend({
|
||||
parentItem: {} as BaseItemDto,
|
||||
backdropImageSource: '',
|
||||
currentSource: {} as MediaSourceInfo,
|
||||
videoTracks: [] as MediaStream[],
|
||||
currentVideoTrack: {} as MediaStream,
|
||||
audioTracks: [] as MediaStream[],
|
||||
currentAudioTrack: {} as MediaStream,
|
||||
subtitleTracks: [] as MediaStream[],
|
||||
currentSubtitleTrack: {} as MediaStream
|
||||
currentVideoTrack: undefined as number | undefined,
|
||||
currentAudioTrack: undefined as number | undefined,
|
||||
currentSubtitleTrack: undefined as number | undefined
|
||||
};
|
||||
},
|
||||
head() {
|
||||
@ -493,6 +361,13 @@ export default Vue.extend({
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
currentSourceIndex: {
|
||||
get(): number | undefined {
|
||||
return this.item.MediaSources?.findIndex(
|
||||
(source) => source === this.currentSource
|
||||
);
|
||||
}
|
||||
},
|
||||
isPlayable: {
|
||||
get(): boolean {
|
||||
// TODO: Move this to a mixin
|
||||
@ -545,27 +420,7 @@ export default Vue.extend({
|
||||
methods: {
|
||||
...mapActions('playbackManager', ['play']),
|
||||
...mapActions('page', ['setPageTitle', 'setAppBarOpacity']),
|
||||
...mapActions('backdrop', ['setBackdrop', 'clearBackdrop']),
|
||||
getLanguageName(code?: string): string {
|
||||
if (!code) {
|
||||
return this.$t('undefined');
|
||||
}
|
||||
return langs.where('2B', code).name;
|
||||
},
|
||||
getSurroundIcon(layout: string): string {
|
||||
switch (layout) {
|
||||
case '2.0':
|
||||
return 'mdi-surround-sound-2-0';
|
||||
case '3.1':
|
||||
return 'mdi-surround-sound-3-1';
|
||||
case '5.1':
|
||||
return 'mdi-surround-sound-5-1';
|
||||
case '7.1':
|
||||
return 'mdi-surround-sound-7-1';
|
||||
default:
|
||||
return 'mdi-surround-sound';
|
||||
}
|
||||
}
|
||||
...mapActions('backdrop', ['setBackdrop', 'clearBackdrop'])
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
Loading…
x
Reference in New Issue
Block a user