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