mirror of
https://github.com/mmahdium/TBW.git
synced 2026-08-14 16:22:48 +03:30
Added more maps to MediaType
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { MovieDetailsType } from '@/types/Movie'
|
import type { MovieDetailsType } from '@/types/Movie'
|
||||||
import type { TvSeriesDetailsType } from '@/types/TvSeries'
|
import type { TvSeriesDetailsType } from '@/types/TvSeries'
|
||||||
import { computed , ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useMediaStore } from '@/stores/movies'
|
import { useMediaStore } from '@/stores/movies'
|
||||||
import type { MediaType } from '@/types/Media'
|
import type { MediaType } from '@/types/Media'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
type: 'movie' | 'tv'
|
type: 'movie' | 'tv'
|
||||||
|
media?: MediaType
|
||||||
movie?: MovieDetailsType | null
|
movie?: MovieDetailsType | null
|
||||||
tvSeries?: TvSeriesDetailsType | null
|
tvSeries?: TvSeriesDetailsType | null
|
||||||
}>()
|
}>()
|
||||||
@@ -103,24 +104,23 @@ const alreadyAdded = computed(() =>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<!-- TODO: Fix this -->
|
|
||||||
<div class="card-actions" v-auto-animate>
|
<div class="card-actions" v-auto-animate>
|
||||||
<!-- <template v-if="props.type === 'movie' && props.movie">
|
<template v-if="(props.movie && props.media) || (props.tvSeries && props.media)">
|
||||||
<button
|
<button
|
||||||
v-if="!alreadyAdded"
|
v-if="!alreadyAdded"
|
||||||
class="btn px-6 bg-gradient-to-r from-gray-100 to-gray-200 border border-gray-300 text-gray-700 hover:from-gray-200 hover:to-gray-300"
|
class="btn px-6 bg-gradient-to-r from-gray-100 to-gray-200 border border-gray-300 text-gray-700 hover:from-gray-200 hover:to-gray-300"
|
||||||
@click="store.addMedia(props.movie)"
|
@click="store.addMedia(props.media)"
|
||||||
>
|
>
|
||||||
Add to list
|
Add to list
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn px-6 bg-gradient-to-r from-red-50 to-red-100 border border-red-200 text-red-600 hover:from-red-100 hover:to-red-200"
|
class="btn px-6 bg-gradient-to-r from-red-50 to-red-100 border border-red-200 text-red-600 hover:from-red-100 hover:to-red-200"
|
||||||
@click="store.removeMedia(props.movie.ImdbId)"
|
@click="store.removeMedia(props.media.Id)"
|
||||||
>
|
>
|
||||||
Remove from library
|
Remove from library
|
||||||
</button>
|
</button>
|
||||||
</template> -->
|
</template>
|
||||||
|
|
||||||
<RouterLink
|
<RouterLink
|
||||||
:to="{
|
:to="{
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ export type MediaType = {
|
|||||||
Overview: string
|
Overview: string
|
||||||
PosterPath: string
|
PosterPath: string
|
||||||
Popularity: number
|
Popularity: number
|
||||||
ReleaseDate: string // For movies
|
ReleaseDate: string // For movies
|
||||||
FirstAirDate: string // For TV series
|
FirstAirDate: string // For TV series
|
||||||
VoteAverage: number
|
VoteAverage: number
|
||||||
VoteCount: number
|
VoteCount: number
|
||||||
|
|||||||
+42
-2
@@ -1,4 +1,6 @@
|
|||||||
import type { MediaType } from "./Media"
|
import type { MediaType } from './Media'
|
||||||
|
import type { MovieDetailsType } from './Movie'
|
||||||
|
import type { TvSeriesDetailsType } from './TvSeries'
|
||||||
|
|
||||||
type TMDBMedia = {
|
type TMDBMedia = {
|
||||||
adult: boolean
|
adult: boolean
|
||||||
@@ -34,4 +36,42 @@ export const mapMedia = (m: TMDBMedia): MediaType => ({
|
|||||||
FirstAirDate: m.first_air_date ?? '',
|
FirstAirDate: m.first_air_date ?? '',
|
||||||
VoteAverage: m.vote_average,
|
VoteAverage: m.vote_average,
|
||||||
VoteCount: m.vote_count,
|
VoteCount: m.vote_count,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const mapMovieDetailsToMedia = (movie: MovieDetailsType): MediaType => {
|
||||||
|
return {
|
||||||
|
Adult: movie.Adult,
|
||||||
|
BackdropPath: movie.BackdropPath,
|
||||||
|
Id: movie.Id,
|
||||||
|
Title: movie.Title,
|
||||||
|
OriginalTitle: movie.OriginalTitle,
|
||||||
|
OriginalLanguage: movie.OriginalLanguage,
|
||||||
|
MediaType: 'movie', // since this mapper is for MovieDetailsType
|
||||||
|
Overview: movie.Overview,
|
||||||
|
PosterPath: movie.PosterPath,
|
||||||
|
Popularity: movie.Popularity,
|
||||||
|
ReleaseDate: movie.ReleaseDate,
|
||||||
|
FirstAirDate: '', // not applicable for movies
|
||||||
|
VoteAverage: movie.VoteAverage,
|
||||||
|
VoteCount: movie.VoteCount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapTvSeriesDetailsToMedia = (tv: TvSeriesDetailsType): MediaType => {
|
||||||
|
return {
|
||||||
|
Adult: tv.Adult,
|
||||||
|
BackdropPath: tv.BackdropPath,
|
||||||
|
Id: tv.Id,
|
||||||
|
Title: tv.Name, // TV shows use "Name"
|
||||||
|
OriginalTitle: tv.OriginalName,
|
||||||
|
OriginalLanguage: tv.OriginalLanguage,
|
||||||
|
MediaType: 'tv',
|
||||||
|
Overview: tv.Overview,
|
||||||
|
PosterPath: tv.PosterPath,
|
||||||
|
Popularity: tv.Popularity,
|
||||||
|
ReleaseDate: '', // not applicable for TV
|
||||||
|
FirstAirDate: tv.FirstAirDate,
|
||||||
|
VoteAverage: tv.VoteAverage,
|
||||||
|
VoteCount: tv.VoteCount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { MovieDetailsType } from "./Movie"
|
import type { MovieDetailsType } from './Movie'
|
||||||
|
|
||||||
type TMDBMovieDetails = {
|
type TMDBMovieDetails = {
|
||||||
adult: boolean
|
adult: boolean
|
||||||
@@ -43,9 +43,9 @@ export const mapMovieDetails = (m: TMDBMovieDetails): MovieDetailsType => ({
|
|||||||
Adult: m.adult,
|
Adult: m.adult,
|
||||||
BackdropPath: m.backdrop_path ?? '',
|
BackdropPath: m.backdrop_path ?? '',
|
||||||
Budget: m.budget,
|
Budget: m.budget,
|
||||||
Genres: m.genres.map(genre => ({
|
Genres: m.genres.map((genre) => ({
|
||||||
id: genre.id,
|
id: genre.id,
|
||||||
name: genre.name
|
name: genre.name,
|
||||||
})),
|
})),
|
||||||
Homepage: m.homepage,
|
Homepage: m.homepage,
|
||||||
Id: m.id,
|
Id: m.id,
|
||||||
@@ -55,23 +55,23 @@ export const mapMovieDetails = (m: TMDBMovieDetails): MovieDetailsType => ({
|
|||||||
Overview: m.overview,
|
Overview: m.overview,
|
||||||
Popularity: m.popularity,
|
Popularity: m.popularity,
|
||||||
PosterPath: m.poster_path ?? '',
|
PosterPath: m.poster_path ?? '',
|
||||||
ProductionCompanies: m.production_companies.map(company => ({
|
ProductionCompanies: m.production_companies.map((company) => ({
|
||||||
id: company.id,
|
id: company.id,
|
||||||
logoPath: company.logo_path,
|
logoPath: company.logo_path,
|
||||||
name: company.name,
|
name: company.name,
|
||||||
originCountry: company.origin_country
|
originCountry: company.origin_country,
|
||||||
})),
|
})),
|
||||||
ProductionCountries: m.production_countries.map(country => ({
|
ProductionCountries: m.production_countries.map((country) => ({
|
||||||
iso31661: country.iso_3166_1,
|
iso31661: country.iso_3166_1,
|
||||||
name: country.name
|
name: country.name,
|
||||||
})),
|
})),
|
||||||
ReleaseDate: m.release_date,
|
ReleaseDate: m.release_date,
|
||||||
Revenue: m.revenue,
|
Revenue: m.revenue,
|
||||||
Runtime: m.runtime ?? 0,
|
Runtime: m.runtime ?? 0,
|
||||||
SpokenLanguages: m.spoken_languages.map(lang => ({
|
SpokenLanguages: m.spoken_languages.map((lang) => ({
|
||||||
englishName: lang.english_name,
|
englishName: lang.english_name,
|
||||||
iso6391: lang.iso_639_1,
|
iso6391: lang.iso_639_1,
|
||||||
name: lang.name
|
name: lang.name,
|
||||||
})),
|
})),
|
||||||
Status: m.status,
|
Status: m.status,
|
||||||
Tagline: m.tagline ?? '',
|
Tagline: m.tagline ?? '',
|
||||||
|
|||||||
+31
-29
@@ -1,4 +1,4 @@
|
|||||||
import type { TvSeriesDetailsType } from "./TvSeries"
|
import type { TvSeriesDetailsType } from './TvSeries'
|
||||||
|
|
||||||
type TMDBTvSeriesDetails = {
|
type TMDBTvSeriesDetails = {
|
||||||
adult: boolean
|
adult: boolean
|
||||||
@@ -82,44 +82,46 @@ type TMDBTvSeriesDetails = {
|
|||||||
export const mapTvSeriesDetails = (tv: TMDBTvSeriesDetails): TvSeriesDetailsType => ({
|
export const mapTvSeriesDetails = (tv: TMDBTvSeriesDetails): TvSeriesDetailsType => ({
|
||||||
Adult: tv.adult,
|
Adult: tv.adult,
|
||||||
BackdropPath: tv.backdrop_path ?? '',
|
BackdropPath: tv.backdrop_path ?? '',
|
||||||
CreatedBy: tv.created_by.map(creator => ({
|
CreatedBy: tv.created_by.map((creator) => ({
|
||||||
id: creator.id,
|
id: creator.id,
|
||||||
creditId: creator.credit_id,
|
creditId: creator.credit_id,
|
||||||
name: creator.name,
|
name: creator.name,
|
||||||
gender: creator.gender,
|
gender: creator.gender,
|
||||||
profilePath: creator.profile_path
|
profilePath: creator.profile_path,
|
||||||
})),
|
})),
|
||||||
EpisodeRunTime: tv.episode_run_time,
|
EpisodeRunTime: tv.episode_run_time,
|
||||||
FirstAirDate: tv.first_air_date ?? '',
|
FirstAirDate: tv.first_air_date ?? '',
|
||||||
Genres: tv.genres.map(genre => ({
|
Genres: tv.genres.map((genre) => ({
|
||||||
id: genre.id,
|
id: genre.id,
|
||||||
name: genre.name
|
name: genre.name,
|
||||||
})),
|
})),
|
||||||
Homepage: tv.homepage,
|
Homepage: tv.homepage,
|
||||||
Id: tv.id,
|
Id: tv.id,
|
||||||
InProduction: tv.in_production,
|
InProduction: tv.in_production,
|
||||||
Languages: tv.languages,
|
Languages: tv.languages,
|
||||||
LastAirDate: tv.last_air_date ?? '',
|
LastAirDate: tv.last_air_date ?? '',
|
||||||
LastEpisodeToAir: tv.last_episode_to_air ? {
|
LastEpisodeToAir: tv.last_episode_to_air
|
||||||
id: tv.last_episode_to_air.id,
|
? {
|
||||||
name: tv.last_episode_to_air.name,
|
id: tv.last_episode_to_air.id,
|
||||||
overview: tv.last_episode_to_air.overview,
|
name: tv.last_episode_to_air.name,
|
||||||
voteAverage: tv.last_episode_to_air.vote_average,
|
overview: tv.last_episode_to_air.overview,
|
||||||
voteCount: tv.last_episode_to_air.vote_count,
|
voteAverage: tv.last_episode_to_air.vote_average,
|
||||||
airDate: tv.last_episode_to_air.air_date ?? '',
|
voteCount: tv.last_episode_to_air.vote_count,
|
||||||
episodeNumber: tv.last_episode_to_air.episode_number,
|
airDate: tv.last_episode_to_air.air_date ?? '',
|
||||||
productionCode: tv.last_episode_to_air.production_code,
|
episodeNumber: tv.last_episode_to_air.episode_number,
|
||||||
runtime: tv.last_episode_to_air.runtime ?? 0,
|
productionCode: tv.last_episode_to_air.production_code,
|
||||||
seasonNumber: tv.last_episode_to_air.season_number,
|
runtime: tv.last_episode_to_air.runtime ?? 0,
|
||||||
showId: tv.last_episode_to_air.show_id,
|
seasonNumber: tv.last_episode_to_air.season_number,
|
||||||
stillPath: tv.last_episode_to_air.still_path
|
showId: tv.last_episode_to_air.show_id,
|
||||||
} : null,
|
stillPath: tv.last_episode_to_air.still_path,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
Name: tv.name,
|
Name: tv.name,
|
||||||
Networks: tv.networks.map(network => ({
|
Networks: tv.networks.map((network) => ({
|
||||||
id: network.id,
|
id: network.id,
|
||||||
logoPath: network.logo_path,
|
logoPath: network.logo_path,
|
||||||
name: network.name,
|
name: network.name,
|
||||||
originCountry: network.origin_country
|
originCountry: network.origin_country,
|
||||||
})),
|
})),
|
||||||
NumberOfEpisodes: tv.number_of_episodes,
|
NumberOfEpisodes: tv.number_of_episodes,
|
||||||
NumberOfSeasons: tv.number_of_seasons,
|
NumberOfSeasons: tv.number_of_seasons,
|
||||||
@@ -129,17 +131,17 @@ export const mapTvSeriesDetails = (tv: TMDBTvSeriesDetails): TvSeriesDetailsType
|
|||||||
Overview: tv.overview,
|
Overview: tv.overview,
|
||||||
Popularity: tv.popularity,
|
Popularity: tv.popularity,
|
||||||
PosterPath: tv.poster_path ?? '',
|
PosterPath: tv.poster_path ?? '',
|
||||||
ProductionCompanies: tv.production_companies.map(company => ({
|
ProductionCompanies: tv.production_companies.map((company) => ({
|
||||||
id: company.id,
|
id: company.id,
|
||||||
logoPath: company.logo_path,
|
logoPath: company.logo_path,
|
||||||
name: company.name,
|
name: company.name,
|
||||||
originCountry: company.origin_country
|
originCountry: company.origin_country,
|
||||||
})),
|
})),
|
||||||
ProductionCountries: tv.production_countries.map(country => ({
|
ProductionCountries: tv.production_countries.map((country) => ({
|
||||||
iso31661: country.iso_3166_1,
|
iso31661: country.iso_3166_1,
|
||||||
name: country.name
|
name: country.name,
|
||||||
})),
|
})),
|
||||||
Seasons: tv.seasons.map(season => ({
|
Seasons: tv.seasons.map((season) => ({
|
||||||
airDate: season.air_date,
|
airDate: season.air_date,
|
||||||
episodeCount: season.episode_count,
|
episodeCount: season.episode_count,
|
||||||
id: season.id,
|
id: season.id,
|
||||||
@@ -147,12 +149,12 @@ export const mapTvSeriesDetails = (tv: TMDBTvSeriesDetails): TvSeriesDetailsType
|
|||||||
overview: season.overview,
|
overview: season.overview,
|
||||||
posterPath: season.poster_path,
|
posterPath: season.poster_path,
|
||||||
seasonNumber: season.season_number,
|
seasonNumber: season.season_number,
|
||||||
voteAverage: season.vote_average
|
voteAverage: season.vote_average,
|
||||||
})),
|
})),
|
||||||
SpokenLanguages: tv.spoken_languages.map(lang => ({
|
SpokenLanguages: tv.spoken_languages.map((lang) => ({
|
||||||
englishName: lang.english_name,
|
englishName: lang.english_name,
|
||||||
iso6391: lang.iso_639_1,
|
iso6391: lang.iso_639_1,
|
||||||
name: lang.name
|
name: lang.name,
|
||||||
})),
|
})),
|
||||||
Status: tv.status,
|
Status: tv.status,
|
||||||
Tagline: tv.tagline,
|
Tagline: tv.tagline,
|
||||||
|
|||||||
+50
-19
@@ -1,46 +1,77 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import ErrorAlert from '@/components/alerts/ErrorAlert.vue'
|
||||||
import MediaDetails from '@/components/MediaDetails.vue'
|
import MediaDetails from '@/components/MediaDetails.vue'
|
||||||
import { getMovieDetails, getSeriesDetails } from '@/lib/api'
|
import { getMovieDetails, getSeriesDetails } from '@/lib/api'
|
||||||
|
import { mapMovieDetailsToMedia, mapTvSeriesDetailsToMedia } from '@/types/MediaMap'
|
||||||
import type { MovieDetailsType } from '@/types/Movie'
|
import type { MovieDetailsType } from '@/types/Movie'
|
||||||
import type { TvSeriesDetailsType } from '@/types/TvSeries'
|
import type { TvSeriesDetailsType } from '@/types/TvSeries'
|
||||||
import { onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const movie = ref<MovieDetailsType | null>()
|
const movieDetails = ref<MovieDetailsType | null>(null)
|
||||||
const tvSeries = ref<TvSeriesDetailsType | null>()
|
const tvSeriesDetails = ref<TvSeriesDetailsType | null>(null)
|
||||||
|
const isLoading = ref(false)
|
||||||
|
const errorMessage = ref<string | null>(null)
|
||||||
|
|
||||||
|
const media = computed(() => {
|
||||||
|
if (movieDetails.value) {
|
||||||
|
return mapMovieDetailsToMedia(movieDetails.value)
|
||||||
|
} else if (tvSeriesDetails.value) {
|
||||||
|
return mapTvSeriesDetailsToMedia(tvSeriesDetails.value)
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
if (!route.params.id || !route.params.type) {
|
||||||
|
errorMessage.value = 'Invalid route parameters'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading.value = true
|
||||||
|
errorMessage.value = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (route.params.id && route.params.type === 'movie') {
|
if (route.params.type === 'movie') {
|
||||||
movie.value = await getMovieDetails(route.params.id as string)
|
movieDetails.value = await getMovieDetails(route.params.id as string)
|
||||||
} else if (route.params.id && route.params.type === 'tv') {
|
} else if (route.params.type === 'tv') {
|
||||||
tvSeries.value = await getSeriesDetails(route.params.id as string)
|
tvSeriesDetails.value = await getSeriesDetails(route.params.id as string)
|
||||||
} else {
|
} else {
|
||||||
|
errorMessage.value = 'Unsupported media type'
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err: unknown) {
|
||||||
console.error(error)
|
console.error(err)
|
||||||
|
errorMessage.value = 'Failed to load media details'
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="container mx-auto px-4 py-8">
|
<div class="container mx-auto px-4 py-8">
|
||||||
<div
|
<!-- Error -->
|
||||||
v-if="(route.params.type === 'movie' && !movie) || (route.params.type === 'tv' && !tvSeries)"
|
<ErrorAlert v-if="errorMessage" :message="errorMessage" />
|
||||||
class="flex justify-center items-center"
|
|
||||||
>
|
<!-- Loading -->
|
||||||
|
<div v-else-if="isLoading" class="flex justify-center items-center">
|
||||||
<span class="loading loading-ring loading-lg text-primary"></span>
|
<span class="loading loading-ring loading-lg text-primary"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Details -->
|
||||||
<MediaDetails
|
<MediaDetails
|
||||||
v-if="movie || tvSeries"
|
v-else-if="movieDetails || tvSeriesDetails"
|
||||||
:type="(route.params.type as 'movie' | 'tv') || undefined"
|
:type="(route.params.type as 'movie' | 'tv')"
|
||||||
:movie="movie"
|
:media="media"
|
||||||
:tv-series="tvSeries"
|
:movie="movieDetails"
|
||||||
|
:tv-series="tvSeriesDetails"
|
||||||
v-motion-fade-visible-once
|
v-motion-fade-visible-once
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Fallback if nothing found -->
|
||||||
|
<ErrorAlert v-else message="Could not find media" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const isLoaded = ref(false)
|
|||||||
<!-- Title with Experimental badge -->
|
<!-- Title with Experimental badge -->
|
||||||
<div class="flex items-center gap-3 mb-6">
|
<div class="flex items-center gap-3 mb-6">
|
||||||
<h1 class="text-3xl font-bold text-gray-700">
|
<h1 class="text-3xl font-bold text-gray-700">
|
||||||
Watch
|
Watch <br />
|
||||||
<span class="bg-gradient-to-r from-indigo-500 to-cyan-400 bg-clip-text text-transparent">
|
<span class="bg-gradient-to-r from-indigo-500 to-cyan-400 bg-clip-text text-transparent">
|
||||||
{{ movieName }}
|
{{ movieName }}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user