[feature] Next episode button #4
@ -1,15 +1,29 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Icon } from '@iconify/vue'
|
import { Icon } from '@iconify/vue'
|
||||||
|
import type { RouteLocationNormalized } from 'vue-router'
|
||||||
|
import { updateUrlParameter } from '~/components/util/route'
|
||||||
|
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
const route = useRoute()
|
||||||
|
const currentEpisode = computed(() => Number(route.query.episode as string))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
function changeEpisode(route: RouteLocationNormalized, props: Props, currentEpisode: number) {
|
||||||
|
let episodeOffset = 0
|
||||||
|
if (props.type == EpisodeChangeType.NEXT) {
|
||||||
|
episodeOffset = 1
|
||||||
|
}
|
||||||
|
if (props.type == EpisodeChangeType.PREVIOUS) {
|
||||||
|
episodeOffset = -1
|
||||||
|
}
|
||||||
|
updateUrlParameter(route, 'episode', String(currentEpisode + episodeOffset))
|
||||||
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type: EpisodeChangeType;
|
type: EpisodeChangeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
export enum EpisodeChangeType {
|
export enum EpisodeChangeType {
|
||||||
NEXT = "mage:next-fill",
|
NEXT = "mage:next-fill",
|
||||||
PREVIOUS = "mage:previous-fill",
|
PREVIOUS = "mage:previous-fill",
|
||||||
@ -17,7 +31,7 @@ export enum EpisodeChangeType {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UiButton variant="borderless" size="icon">
|
<UiButton v-on:click="changeEpisode(route, props, currentEpisode)" variant="borderless" size="icon">
|
||||||
<Icon :icon="props.type" class="size-5" />
|
<Icon :icon="props.type" class="size-5" />
|
||||||
</UiButton>
|
</UiButton>
|
||||||
</template>
|
</template>
|
||||||
|
@ -6,7 +6,7 @@ import { EpisodeChangeType } from "./ChangeEpisodeButton.vue";
|
|||||||
import { UiPlayerChangeEpisodeButton } from "#components";
|
import { UiPlayerChangeEpisodeButton } from "#components";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
urls: any;
|
urls: any[];
|
||||||
id: string;
|
id: string;
|
||||||
episodeButton: boolean;
|
episodeButton: boolean;
|
||||||
}
|
}
|
||||||
@ -17,36 +17,12 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
const emit = defineEmits(['get-instance'])
|
const emit = defineEmits(['get-instance'])
|
||||||
|
|
||||||
const options = computed(() => {
|
const options = computed(() => {
|
||||||
const controls = []
|
|
||||||
if (props.episodeButton) {
|
|
||||||
controls.push(
|
|
||||||
createVueControlSmart(UiPlayerChangeEpisodeButton, {
|
|
||||||
name: "next-episode",
|
|
||||||
index: 50,
|
|
||||||
tooltip: "Next episode",
|
|
||||||
type: EpisodeChangeType.NEXT
|
|
||||||
}, {
|
|
||||||
click: () => console.log("NEXT")
|
|
||||||
})
|
|
||||||
)
|
|
||||||
controls.push(
|
|
||||||
createVueControlSmart(UiPlayerChangeEpisodeButton, {
|
|
||||||
name: "previous-episode",
|
|
||||||
index: 50,
|
|
||||||
tooltip: "Previous episode",
|
|
||||||
type: EpisodeChangeType.PREVIOUS
|
|
||||||
}, {
|
|
||||||
click: () => console.log("Previous")
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
url: props.urls[0].url || '',
|
url: props.urls[0].url || '',
|
||||||
type: 'm3u8',
|
type: 'm3u8',
|
||||||
customType: {
|
customType: {
|
||||||
m3u8: playM3u8,
|
m3u8: playM3u8,
|
||||||
},
|
},
|
||||||
quality: props.urls,
|
|
||||||
autoSize: true,
|
autoSize: true,
|
||||||
autoMini: true,
|
autoMini: true,
|
||||||
playbackRate: true,
|
playbackRate: true,
|
||||||
@ -57,7 +33,6 @@ const options = computed(() => {
|
|||||||
autoOrientation: true,
|
autoOrientation: true,
|
||||||
autoPlayback: true,
|
autoPlayback: true,
|
||||||
id: props.id,
|
id: props.id,
|
||||||
controls: controls,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const artplayerRef = ref();
|
const artplayerRef = ref();
|
||||||
@ -83,6 +58,24 @@ onMounted(() => {
|
|||||||
container: artplayerRef.value,
|
container: artplayerRef.value,
|
||||||
...options.value,
|
...options.value,
|
||||||
})
|
})
|
||||||
|
if (props.episodeButton) {
|
||||||
|
instance.value.controls.add(
|
||||||
|
createVueControlSmart(UiPlayerChangeEpisodeButton, {
|
||||||
|
name: "next-episode",
|
||||||
|
index: 50,
|
||||||
|
tooltip: "Next episode",
|
||||||
|
type: EpisodeChangeType.NEXT,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
instance.value.controls.add(
|
||||||
|
createVueControlSmart(UiPlayerChangeEpisodeButton, {
|
||||||
|
name: "previous-episode",
|
||||||
|
index: 50,
|
||||||
|
tooltip: "Previous episode",
|
||||||
|
type: EpisodeChangeType.PREVIOUS,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
emit('get-instance')
|
emit('get-instance')
|
||||||
})
|
})
|
||||||
@ -93,6 +86,13 @@ onBeforeUnmount(() => {
|
|||||||
instance.value.destroy(false)
|
instance.value.destroy(false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch([instance, () => props.urls], async ([artplayer, urls]) => {
|
||||||
|
if (!artplayer) return;
|
||||||
|
artplayer.quality = urls;
|
||||||
|
artplayer.switch = urls[0].url;
|
||||||
|
instance.value = artplayer;
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -14,8 +14,6 @@ export function createVueControlSmart(component, props = {}, events = {}) {
|
|||||||
const container = $control.querySelector('.vue-control-wrapper')
|
const container = $control.querySelector('.vue-control-wrapper')
|
||||||
|
|
||||||
if (container && !vueApp) {
|
if (container && !vueApp) {
|
||||||
|
|
||||||
console.log("111")
|
|
||||||
vueApp = createApp({
|
vueApp = createApp({
|
||||||
render() {
|
render() {
|
||||||
return h(component, {
|
return h(component, {
|
||||||
|
9
app/components/util/route.js
Normal file
9
app/components/util/route.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export const updateUrlParameter = async (route, paramName, newValue) => {
|
||||||
|
await navigateTo({
|
||||||
|
path: route.path,
|
||||||
|
query: {
|
||||||
|
...route.query,
|
||||||
|
[paramName]: newValue
|
||||||
|
}
|
||||||
|
}, { replace: true })
|
||||||
|
}
|
@ -28,10 +28,10 @@ import { Player } from '~/components/ui/player'
|
|||||||
import { video, type KodikVideoLinks } from '~/openapi/extractor'
|
import { video, type KodikVideoLinks } from '~/openapi/extractor'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const mediaType = route.query.mediaType
|
const mediaType = computed(() => route.query.mediaType as string)
|
||||||
const mediaId = route.query.mediaId
|
const mediaId = computed(() => route.query.mediaId as string)
|
||||||
const mediaHash = route.query.mediaHash
|
const mediaHash = computed(() => route.query.mediaHash as string)
|
||||||
const episode = route.query.episode
|
const episode = computed(() => Number(route.query.episode as string))
|
||||||
|
|
||||||
const results = ref<KodikVideoLinks | null>(null)
|
const results = ref<KodikVideoLinks | null>(null)
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
@ -39,17 +39,15 @@ const error = ref<unknown>(null)
|
|||||||
const hlsUrls = ref<any>(null)
|
const hlsUrls = ref<any>(null)
|
||||||
|
|
||||||
watchEffect(async () => {
|
watchEffect(async () => {
|
||||||
if (!mediaType || !mediaId || !mediaHash || !episode) return
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
error.value = null
|
error.value = null
|
||||||
|
|
||||||
const videoParams: any = {
|
const videoParams: any = {
|
||||||
mediaType: mediaType as string,
|
mediaType: mediaType.value,
|
||||||
mediaId: mediaId as string,
|
mediaId: mediaId.value,
|
||||||
mediaHash: mediaHash as string,
|
mediaHash: mediaHash.value,
|
||||||
episode: Number(episode as string),
|
episode: episode.value,
|
||||||
quality: '360',
|
quality: '360',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user