parent
34ae65c087
commit
4e4bf3507f
@ -1,33 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
|
||||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
|
||||||
|
|
||||||
function MediaInfo(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 MediaInfo;
|
|
@ -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,17 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
|
||||||
import createEpisodeFileSelector from 'Store/Selectors/createEpisodeFileSelector';
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
createEpisodeFileSelector(),
|
|
||||||
(episodeFile) => {
|
|
||||||
return {
|
|
||||||
languages: episodeFile ? episodeFile.languages : undefined
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps)(EpisodeLanguages);
|
|
@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import EpisodeLanguages from 'Episode/EpisodeLanguages';
|
||||||
|
import useEpisodeFile from './useEpisodeFile';
|
||||||
|
|
||||||
|
interface EpisodeFileLanguagesProps {
|
||||||
|
episodeFileId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function EpisodeFileLanguages({ episodeFileId }: EpisodeFileLanguagesProps) {
|
||||||
|
const episodeFile = useEpisodeFile(episodeFileId);
|
||||||
|
|
||||||
|
return <EpisodeLanguages languages={episodeFile?.languages ?? []} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EpisodeFileLanguages;
|
@ -1,105 +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 useEpisodeFile from './useEpisodeFile';
|
||||||
|
|
||||||
|
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 {
|
||||||
|
episodeFileId?: number;
|
||||||
|
type: MediaInfoType;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MediaInfo({ episodeFileId, type }: MediaInfoProps) {
|
||||||
|
const episodeFile = useEpisodeFile(episodeFileId);
|
||||||
|
|
||||||
|
if (!episodeFile?.mediaInfo) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
audioChannels,
|
||||||
|
audioCodec,
|
||||||
|
audioLanguages,
|
||||||
|
subtitles,
|
||||||
|
videoCodec,
|
||||||
|
videoDynamicRangeType,
|
||||||
|
} = episodeFile.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 createEpisodeFileSelector from 'Store/Selectors/createEpisodeFileSelector';
|
|
||||||
import MediaInfo from './MediaInfo';
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
createEpisodeFileSelector(),
|
|
||||||
(episodeFile) => {
|
|
||||||
if (episodeFile) {
|
|
||||||
return {
|
|
||||||
...episodeFile.mediaInfo
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps)(MediaInfo);
|
|
@ -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