(cherry picked from commit 4e4bf3507f20c0f8581c66804f8ef406c41952d8) Closes #10753pull/10799/head
parent
5efefd804b
commit
c81b2e80ee
@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import MediaInfoProps from 'typings/MediaInfo';
|
||||
import getEntries from 'Utilities/Object/getEntries';
|
||||
|
||||
function MediaInfo(props: MediaInfoProps) {
|
||||
return (
|
||||
<DescriptionList>
|
||||
{getEntries(props).map(([key, value]) => {
|
||||
const title = key
|
||||
.replace(/([A-Z])/g, ' $1')
|
||||
.replace(/^./, (str) => str.toUpperCase());
|
||||
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<DescriptionListItem key={key} title={title} data={props[key]} />
|
||||
);
|
||||
})}
|
||||
</DescriptionList>
|
||||
);
|
||||
}
|
||||
|
||||
export default MediaInfo;
|
@ -1,33 +0,0 @@
|
||||
import React from 'react';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
|
||||
function MediaInfoPopover(props) {
|
||||
return (
|
||||
<DescriptionList>
|
||||
{
|
||||
Object.keys(props).map((key) => {
|
||||
const title = key
|
||||
.replace(/([A-Z])/g, ' $1')
|
||||
.replace(/^./, (str) => str.toUpperCase());
|
||||
|
||||
const value = props[key];
|
||||
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<DescriptionListItem
|
||||
key={key}
|
||||
title={title}
|
||||
data={props[key]}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</DescriptionList>
|
||||
);
|
||||
}
|
||||
|
||||
export default MediaInfoPopover;
|
@ -1,104 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import getLanguageName from 'Utilities/String/getLanguageName';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import * as mediaInfoTypes from './mediaInfoTypes';
|
||||
|
||||
function formatLanguages(languages) {
|
||||
if (!languages) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const splitLanguages = _.uniq(languages.split('/')).map((l) => {
|
||||
const simpleLanguage = l.split('_')[0];
|
||||
|
||||
if (simpleLanguage === 'und') {
|
||||
return translate('Unknown');
|
||||
}
|
||||
|
||||
return getLanguageName(simpleLanguage);
|
||||
});
|
||||
|
||||
if (splitLanguages.length > 3) {
|
||||
return (
|
||||
<span title={splitLanguages.join(', ')}>
|
||||
{splitLanguages.slice(0, 2).join(', ')}, {splitLanguages.length - 2} more
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
{splitLanguages.join(', ')}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function MediaInfo(props) {
|
||||
const {
|
||||
type,
|
||||
audioChannels,
|
||||
audioCodec,
|
||||
audioLanguages,
|
||||
subtitles,
|
||||
videoCodec,
|
||||
videoDynamicRangeType
|
||||
} = props;
|
||||
|
||||
if (type === mediaInfoTypes.AUDIO) {
|
||||
return (
|
||||
<span>
|
||||
{
|
||||
audioCodec ? audioCodec : ''
|
||||
}
|
||||
|
||||
{
|
||||
audioCodec && audioChannels ? ' - ' : ''
|
||||
}
|
||||
|
||||
{
|
||||
audioChannels ? audioChannels.toFixed(1) : ''
|
||||
}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === mediaInfoTypes.AUDIO_LANGUAGES) {
|
||||
return formatLanguages(audioLanguages);
|
||||
}
|
||||
|
||||
if (type === mediaInfoTypes.SUBTITLES) {
|
||||
return formatLanguages(subtitles);
|
||||
}
|
||||
|
||||
if (type === mediaInfoTypes.VIDEO) {
|
||||
return (
|
||||
<span>
|
||||
{videoCodec}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === mediaInfoTypes.VIDEO_DYNAMIC_RANGE_TYPE) {
|
||||
return (
|
||||
<span>
|
||||
{videoDynamicRangeType}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
MediaInfo.propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
audioChannels: PropTypes.number,
|
||||
audioCodec: PropTypes.string,
|
||||
audioLanguages: PropTypes.string,
|
||||
subtitles: PropTypes.string,
|
||||
videoCodec: PropTypes.string,
|
||||
videoDynamicRangeType: PropTypes.string
|
||||
};
|
||||
|
||||
export default MediaInfo;
|
@ -0,0 +1,92 @@
|
||||
import React from 'react';
|
||||
import getLanguageName from 'Utilities/String/getLanguageName';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import useMovieFile from './useMovieFile';
|
||||
|
||||
function formatLanguages(languages: string | undefined) {
|
||||
if (!languages) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const splitLanguages = [...new Set(languages.split('/'))].map((l) => {
|
||||
const simpleLanguage = l.split('_')[0];
|
||||
|
||||
if (simpleLanguage === 'und') {
|
||||
return translate('Unknown');
|
||||
}
|
||||
|
||||
return getLanguageName(simpleLanguage);
|
||||
});
|
||||
|
||||
if (splitLanguages.length > 3) {
|
||||
return (
|
||||
<span title={splitLanguages.join(', ')}>
|
||||
{splitLanguages.slice(0, 2).join(', ')}, {splitLanguages.length - 2}{' '}
|
||||
more
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return <span>{splitLanguages.join(', ')}</span>;
|
||||
}
|
||||
|
||||
export type MediaInfoType =
|
||||
| 'audio'
|
||||
| 'audioLanguages'
|
||||
| 'subtitles'
|
||||
| 'video'
|
||||
| 'videoDynamicRangeType';
|
||||
|
||||
interface MediaInfoProps {
|
||||
movieFileId?: number;
|
||||
type: MediaInfoType;
|
||||
}
|
||||
|
||||
function MediaInfo({ movieFileId, type }: MediaInfoProps) {
|
||||
const movieFile = useMovieFile(movieFileId);
|
||||
|
||||
if (!movieFile?.mediaInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
audioChannels,
|
||||
audioCodec,
|
||||
audioLanguages,
|
||||
subtitles,
|
||||
videoCodec,
|
||||
videoDynamicRangeType,
|
||||
} = movieFile.mediaInfo;
|
||||
|
||||
if (type === 'audio') {
|
||||
return (
|
||||
<span>
|
||||
{audioCodec ? audioCodec : ''}
|
||||
|
||||
{audioCodec && audioChannels ? ' - ' : ''}
|
||||
|
||||
{audioChannels ? audioChannels.toFixed(1) : ''}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === 'audioLanguages') {
|
||||
return formatLanguages(audioLanguages);
|
||||
}
|
||||
|
||||
if (type === 'subtitles') {
|
||||
return formatLanguages(subtitles);
|
||||
}
|
||||
|
||||
if (type === 'video') {
|
||||
return <span>{videoCodec}</span>;
|
||||
}
|
||||
|
||||
if (type === 'videoDynamicRangeType') {
|
||||
return <span>{videoDynamicRangeType}</span>;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default MediaInfo;
|
@ -1,21 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createMovieFileSelector from 'Store/Selectors/createMovieFileSelector';
|
||||
import MediaInfo from './MediaInfo';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createMovieFileSelector(),
|
||||
(movieFile) => {
|
||||
if (movieFile) {
|
||||
return {
|
||||
...movieFile.mediaInfo
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps)(MediaInfo);
|
@ -1,17 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import MovieLanguages from 'Movie/MovieLanguages';
|
||||
import createMovieFileSelector from 'Store/Selectors/createMovieFileSelector';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createMovieFileSelector(),
|
||||
(movieFile) => {
|
||||
return {
|
||||
languages: movieFile ? movieFile.languages : undefined
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps)(MovieLanguages);
|
@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import MovieLanguages from 'Movie/MovieLanguages';
|
||||
import useMovieFile from './useMovieFile';
|
||||
|
||||
interface MovieFileLanguagesProps {
|
||||
movieFileId: number;
|
||||
}
|
||||
|
||||
function MovieFileLanguages({ movieFileId }: MovieFileLanguagesProps) {
|
||||
const movieFile = useMovieFile(movieFileId);
|
||||
|
||||
return <MovieLanguages languages={movieFile?.languages ?? []} />;
|
||||
}
|
||||
|
||||
export default MovieFileLanguages;
|
@ -0,0 +1,18 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import AppState from 'App/State/AppState';
|
||||
|
||||
function createMovieFileSelector(movieFileId?: number) {
|
||||
return createSelector(
|
||||
(state: AppState) => state.movieFiles.items,
|
||||
(movieFiles) => {
|
||||
return movieFiles.find(({ id }) => id === movieFileId);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function useMovieFile(movieFileId: number | undefined) {
|
||||
return useSelector(createMovieFileSelector(movieFileId));
|
||||
}
|
||||
|
||||
export default useMovieFile;
|
@ -0,0 +1,9 @@
|
||||
export type Entries<T> = {
|
||||
[K in keyof T]: [K, T[K]];
|
||||
}[keyof T][];
|
||||
|
||||
function getEntries<T extends object>(obj: T): Entries<T> {
|
||||
return Object.entries(obj) as Entries<T>;
|
||||
}
|
||||
|
||||
export default getEntries;
|
Loading…
Reference in new issue