mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat: add production countries to movie/TV detail pages (#2170)
* feat: add production countries to movie/TV detail pages * feat: add country flags to production countries
This commit is contained in:
@@ -909,6 +909,15 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/ProductionCompany'
|
$ref: '#/components/schemas/ProductionCompany'
|
||||||
|
productionCountries:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
iso_3166_1:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
spokenLanguages:
|
spokenLanguages:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
@@ -251,6 +251,10 @@ export interface TmdbTvDetails {
|
|||||||
name: string;
|
name: string;
|
||||||
origin_country: string;
|
origin_country: string;
|
||||||
}[];
|
}[];
|
||||||
|
production_countries: {
|
||||||
|
iso_3166_1: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
spoken_languages: {
|
spoken_languages: {
|
||||||
english_name: string;
|
english_name: string;
|
||||||
iso_639_1: string;
|
iso_639_1: string;
|
||||||
|
@@ -90,6 +90,10 @@ export interface TvDetails {
|
|||||||
overview: string;
|
overview: string;
|
||||||
popularity: number;
|
popularity: number;
|
||||||
productionCompanies: ProductionCompany[];
|
productionCompanies: ProductionCompany[];
|
||||||
|
productionCountries: {
|
||||||
|
iso_3166_1: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
spokenLanguages: SpokenLanguage[];
|
spokenLanguages: SpokenLanguage[];
|
||||||
seasons: Season[];
|
seasons: Season[];
|
||||||
status: string;
|
status: string;
|
||||||
@@ -187,6 +191,7 @@ export const mapTvDetails = (
|
|||||||
originCountry: company.origin_country,
|
originCountry: company.origin_country,
|
||||||
logoPath: company.logo_path,
|
logoPath: company.logo_path,
|
||||||
})),
|
})),
|
||||||
|
productionCountries: show.production_countries,
|
||||||
contentRatings: show.content_ratings,
|
contentRatings: show.content_ratings,
|
||||||
spokenLanguages: show.spoken_languages.map((language) => ({
|
spokenLanguages: show.spoken_languages.map((language) => ({
|
||||||
englishName: language.english_name,
|
englishName: language.english_name,
|
||||||
|
@@ -11,6 +11,8 @@ import {
|
|||||||
ChevronDoubleDownIcon,
|
ChevronDoubleDownIcon,
|
||||||
ChevronDoubleUpIcon,
|
ChevronDoubleUpIcon,
|
||||||
} from '@heroicons/react/solid';
|
} from '@heroicons/react/solid';
|
||||||
|
import { hasFlag } from 'country-flag-icons';
|
||||||
|
import 'country-flag-icons/3x2/flags.css';
|
||||||
import { uniqBy } from 'lodash';
|
import { uniqBy } from 'lodash';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
@@ -69,6 +71,8 @@ const messages = defineMessages({
|
|||||||
showmore: 'Show More',
|
showmore: 'Show More',
|
||||||
showless: 'Show Less',
|
showless: 'Show Less',
|
||||||
streamingproviders: 'Currently Streaming On',
|
streamingproviders: 'Currently Streaming On',
|
||||||
|
productioncountries:
|
||||||
|
'Production {countryCount, plural, one {Country} other {Countries}}',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface MovieDetailsProps {
|
interface MovieDetailsProps {
|
||||||
@@ -596,6 +600,37 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{data.productionCountries.length > 0 && (
|
||||||
|
<div className="media-fact">
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage(messages.productioncountries, {
|
||||||
|
countryCount: data.productionCountries.length,
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
<span className="media-fact-value">
|
||||||
|
{data.productionCountries.map((c) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className="flex items-center justify-end"
|
||||||
|
key={`prodcountry-${c.iso_3166_1}`}
|
||||||
|
>
|
||||||
|
{hasFlag(c.iso_3166_1) && (
|
||||||
|
<span
|
||||||
|
className={`mr-1.5 text-xs leading-5 flag:${c.iso_3166_1}`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<span>
|
||||||
|
{intl.formatDisplayName(c.iso_3166_1, {
|
||||||
|
type: 'region',
|
||||||
|
fallback: 'none',
|
||||||
|
}) ?? c.name}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{data.productionCompanies.length > 0 && (
|
{data.productionCompanies.length > 0 && (
|
||||||
<div className="media-fact">
|
<div className="media-fact">
|
||||||
<span>
|
<span>
|
||||||
|
@@ -5,6 +5,8 @@ import {
|
|||||||
FilmIcon,
|
FilmIcon,
|
||||||
PlayIcon,
|
PlayIcon,
|
||||||
} from '@heroicons/react/outline';
|
} from '@heroicons/react/outline';
|
||||||
|
import { hasFlag } from 'country-flag-icons';
|
||||||
|
import 'country-flag-icons/3x2/flags.css';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
@@ -63,6 +65,8 @@ const messages = defineMessages({
|
|||||||
episodeRuntime: 'Episode Runtime',
|
episodeRuntime: 'Episode Runtime',
|
||||||
episodeRuntimeMinutes: '{runtime} minutes',
|
episodeRuntimeMinutes: '{runtime} minutes',
|
||||||
streamingproviders: 'Currently Streaming On',
|
streamingproviders: 'Currently Streaming On',
|
||||||
|
productioncountries:
|
||||||
|
'Production {countryCount, plural, one {Country} other {Countries}}',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface TvDetailsProps {
|
interface TvDetailsProps {
|
||||||
@@ -533,6 +537,37 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{data.productionCountries.length > 0 && (
|
||||||
|
<div className="media-fact">
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage(messages.productioncountries, {
|
||||||
|
countryCount: data.productionCountries.length,
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
<span className="media-fact-value">
|
||||||
|
{data.productionCountries.map((c) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className="flex items-center justify-end"
|
||||||
|
key={`prodcountry-${c.iso_3166_1}`}
|
||||||
|
>
|
||||||
|
{hasFlag(c.iso_3166_1) && (
|
||||||
|
<span
|
||||||
|
className={`mr-1.5 text-xs leading-5 flag:${c.iso_3166_1}`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<span>
|
||||||
|
{intl.formatDisplayName(c.iso_3166_1, {
|
||||||
|
type: 'region',
|
||||||
|
fallback: 'none',
|
||||||
|
}) ?? c.name}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{data.networks.length > 0 && (
|
{data.networks.length > 0 && (
|
||||||
<div className="media-fact">
|
<div className="media-fact">
|
||||||
<span>
|
<span>
|
||||||
@@ -552,7 +587,10 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
|||||||
))
|
))
|
||||||
.reduce((prev, curr) => (
|
.reduce((prev, curr) => (
|
||||||
<>
|
<>
|
||||||
{prev}, {curr}
|
{intl.formatMessage(globalMessages.delimitedlist, {
|
||||||
|
a: prev,
|
||||||
|
b: curr,
|
||||||
|
})}
|
||||||
</>
|
</>
|
||||||
))}
|
))}
|
||||||
</span>
|
</span>
|
||||||
|
@@ -155,6 +155,7 @@
|
|||||||
"components.MovieDetails.overviewunavailable": "Overview unavailable.",
|
"components.MovieDetails.overviewunavailable": "Overview unavailable.",
|
||||||
"components.MovieDetails.play4konplex": "Play in 4K on Plex",
|
"components.MovieDetails.play4konplex": "Play in 4K on Plex",
|
||||||
"components.MovieDetails.playonplex": "Play on Plex",
|
"components.MovieDetails.playonplex": "Play on Plex",
|
||||||
|
"components.MovieDetails.productioncountries": "Production {countryCount, plural, one {Country} other {Countries}}",
|
||||||
"components.MovieDetails.recommendations": "Recommendations",
|
"components.MovieDetails.recommendations": "Recommendations",
|
||||||
"components.MovieDetails.releasedate": "{releaseCount, plural, one {Release Date} other {Release Dates}}",
|
"components.MovieDetails.releasedate": "{releaseCount, plural, one {Release Date} other {Release Dates}}",
|
||||||
"components.MovieDetails.revenue": "Revenue",
|
"components.MovieDetails.revenue": "Revenue",
|
||||||
@@ -793,6 +794,7 @@
|
|||||||
"components.TvDetails.overviewunavailable": "Overview unavailable.",
|
"components.TvDetails.overviewunavailable": "Overview unavailable.",
|
||||||
"components.TvDetails.play4konplex": "Play in 4K on Plex",
|
"components.TvDetails.play4konplex": "Play in 4K on Plex",
|
||||||
"components.TvDetails.playonplex": "Play on Plex",
|
"components.TvDetails.playonplex": "Play on Plex",
|
||||||
|
"components.TvDetails.productioncountries": "Production {countryCount, plural, one {Country} other {Countries}}",
|
||||||
"components.TvDetails.recommendations": "Recommendations",
|
"components.TvDetails.recommendations": "Recommendations",
|
||||||
"components.TvDetails.seasons": "{seasonCount, plural, one {# Season} other {# Seasons}}",
|
"components.TvDetails.seasons": "{seasonCount, plural, one {# Season} other {# Seasons}}",
|
||||||
"components.TvDetails.showtype": "Series Type",
|
"components.TvDetails.showtype": "Series Type",
|
||||||
|
Reference in New Issue
Block a user