mirror of
https://github.com/Radarr/Radarr.git
synced 2025-04-24 06:27:08 -04:00
New: Imdb Ratings
This commit is contained in:
parent
ec9a7f5c8e
commit
599f4907f4
29 changed files with 573 additions and 70 deletions
|
@ -183,7 +183,7 @@ class AddNewMovieSearchResult extends Component {
|
|||
<div>
|
||||
<Label size={sizes.LARGE}>
|
||||
<HeartRating
|
||||
rating={ratings.value}
|
||||
ratings={ratings}
|
||||
iconSize={13}
|
||||
/>
|
||||
</Label>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
.heart {
|
||||
.image {
|
||||
align-content: center;
|
||||
margin-right: 5px;
|
||||
color: $themeRed;
|
||||
vertical-align: -0.125em;
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
5
frontend/src/Components/ImdbRating.css
Normal file
5
frontend/src/Components/ImdbRating.css
Normal file
|
@ -0,0 +1,5 @@
|
|||
.imdb {
|
||||
align-content: center;
|
||||
margin-right: 5px;
|
||||
vertical-align: -0.125em;
|
||||
}
|
57
frontend/src/Components/ImdbRating.js
Normal file
57
frontend/src/Components/ImdbRating.js
Normal file
File diff suppressed because one or more lines are too long
5
frontend/src/Components/RottenTomatoRating.css
Normal file
5
frontend/src/Components/RottenTomatoRating.css
Normal file
|
@ -0,0 +1,5 @@
|
|||
.image {
|
||||
align-content: center;
|
||||
margin-right: 5px;
|
||||
vertical-align: -0.125em;
|
||||
}
|
58
frontend/src/Components/RottenTomatoRating.js
Normal file
58
frontend/src/Components/RottenTomatoRating.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
import styles from './RottenTomatoRating.css';
|
||||
|
||||
class RottenTomatoRating extends PureComponent {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
|
||||
const {
|
||||
ratings,
|
||||
hideIcon,
|
||||
iconSize
|
||||
} = this.props;
|
||||
|
||||
const rtRotten = 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTYwIDU2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNDQ1LjE4NSA0NDQuNjg0Yy03OS4zNjkgNC4xNjctOTUuNTg3LTg2LjY1Mi0xMjYuNzI2LTg2LjAwNi0xMy4yNjguMjc5LTIzLjcyNiAxNC4xNTEtMTkuMTMzIDMwLjMyIDIuNTI1IDguODg4IDkuNTMgMjEuOTIzIDEzLjk0NCAzMC4wMTEgMTUuNTcgMjguNTQ0LTcuNDQ3IDYwLjg0NS0zNC4zODMgNjMuNTc3LTQ0Ljc2IDQuNTQtNjMuNDMzLTIxLjQyNi02Mi4yNzgtNDguMDA3IDEuMy0yOS44NCAyNi42LTYwLjMzMS42NS03My4zMDUtMjcuMTk0LTEzLjU5Ny00OS4zMDEgMzkuNTcyLTc1LjMyNSA1MS40MzktMjMuNTUzIDEwLjc0MS01Ni4yNDggMi40MTMtNjcuODcyLTIzLjc0MS04LjE2NC0xOC4zNzktNi42OC01My43NjggMjkuNjctNjcuMjcgMjIuNzA2LTguNDMzIDczLjMwNSAxMS4wMjkgNzUuOS0xMy42MjMgMi45OTItMjguNDE2LTUzLjE1NS0zMC44MTItNzAuMDYtMzcuNjI2LTI5LjkxMi0xMi4wNTUtNDcuNTY3LTM3Ljg1LTMzLjczNC02NS41MjIgMTAuMzc4LTIwLjc1NyA0MC45MTUtMjkuMjAzIDY0LjIyMy0yMC4xMSAyNy45MjIgMTAuODkyIDMyLjQwNCAzOS44NTMgNDYuNzEgNTEuODk3IDEyLjMyNCAxMC4zOCAyOS4xOSAxMS42OCA0MC4yMiA0LjU0MyA4LjEzNS01LjI2NSAxMC44NDMtMTYuODI4IDcuNzc0LTI3LjM5LTQuMDctMTQuMDIzLTE0Ljg3NS0yMi43NzMtMjUuNDE1LTMxLjM0Ni0xOC43NTgtMTUuMjQ5LTQ1LjI0LTI4LjM2LTI5LjIyMi02OS45ODMgMTMuMTMtMzQuMTEgNTEuNjQyLTM1LjM0IDUxLjY0Mi0zNS4zNCAxNS4zLTEuNzIgMjkuMDAyIDIuOSA0MC4xNjcgMTIuODc1IDE0LjkyNyAxMy4zMzUgMTcuODM0IDMxLjE2IDE1LjMzNiA1MC4xNzYtMi4yODMgMTcuMzU4LTguNDI2IDMyLjU2LTExLjYzIDQ5Ljc1OS0zLjcxNyAxOS45NjYgNi45NTQgNDAuMDg2IDI3LjI0OSA0MC44NjkgMjYuNjk0IDEuMDMxIDM0LjY5OC0xOS40ODYgMzcuOTY0LTMyLjQ5MiA0Ljc4Mi0xOS4wMjggMTEuMDU4LTM2LjY5NCAyOC43MTgtNDcuODIgMjUuMzQ2LTE1Ljk3IDYwLjU1Mi0xMi40NyA3Ni44ODYgMTguMjIyIDEyLjkyIDI0LjI4NCA4Ljc3MiA1Ny43MTUtMTEuMDQ3IDc1Ljk3LTguODkyIDguMTg4LTE5LjU4NCAxMS4wNzUtMzEuMTQ4IDExLjE1Ni0xNi41ODUuMTE3LTMzLjE2Mi0uMjktNDguNTU2IDcuNDcxLTEwLjQ4IDUuMjgxLTE1LjA0NyAxMy44ODgtMTUuMDQ1IDI1LjQyMyAwIDExLjI0MiA1Ljg1MyAxOC41ODUgMTUuMzM2IDIzLjM2MyAxNy44NiA5LjAwMyAzNy41NzcgMTAuODQzIDU2Ljg3MSAxNC4yMjIgMjcuOTggNC45IDUyLjU4MSAxNC43NTUgNjguMzc1IDQwLjcyLjE0Mi4yMjguMjguNDU4LjQxNS42OSAxOC4xMzkgMzAuNzQxLS44MzEgNzUuMDA1LTM2LjQ3NiA3Ni44NzgiIGZpbGw9IiMwQUM4NTUiLz48L3N2Zz4=';
|
||||
const rtFresh = 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTYwIDU2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNDc4LjI5IDI5Ni45OGMtMy45OS02My45NjYtMzYuNTItMTExLjgyLTg1LjQ2OC0xMzguNTggMC4yNzggMS41Ni0xLjEwOSAzLjUwOC0yLjY4OCAyLjgxOC0zMi4wMTYtMTQuMDA2LTg2LjMyOCAzMS4zMi0xMjQuMjggNy41ODQgMC4yODUgOC41MTktMS4zNzggNTAuMDcyLTU5LjkxNCA1Mi40ODMtMS4zODIgMC4wNTYtMi4xNDItMS4zNTUtMS4yNjgtMi4zNTQgNy44MjgtOC45MjkgMTUuNzMyLTMxLjUzNSA0LjM2Ny00My41ODYtMjQuMzM4IDIxLjgxLTM4LjQ3MiAzMC4wMTctODUuMTM4IDE5LjE4Ni0yOS44NzggMzEuMjQxLTQ2LjgwOSA3NC00My40ODUgMTI3LjI2IDYuNzggMTA4Ljc0IDEwOC42MyAxNzAuODkgMjExLjE5IDE2NC40OSAxMDIuNTYtNi4zOTUgMTkzLjQ3LTgwLjU3MiAxODYuNjgtMTg5LjMxIiBmaWxsPSIjRkEzMjBBIi8+PHBhdGggZD0iTTI5MS4zNzUgMTMyLjI5M2MyMS4wNzUtNS4wMjMgODEuNjkzLS40OSAxMDEuMTE0IDI1LjI3NCAxLjE2NiAxLjU0NS0uNDc1IDQuNDY4LTIuMzU1IDMuNjQ4LTMyLjAxNi0xNC4wMDYtODYuMzI4IDMxLjMyLTEyNC4yODIgNy41ODQuMjg1IDguNTE5LTEuMzc4IDUwLjA3Mi01OS45MTQgNTIuNDgzLTEuMzgyLjA1Ni0yLjE0Mi0xLjM1NS0xLjI2OC0yLjM1NCA3LjgyOC04LjkyOSAxNS43My0zMS41MzUgNC4zNjctNDMuNTg2LTI2LjUxMiAyMy43NTgtNDAuODg0IDMxLjM5Mi05OC40MjYgMTUuODM4LTEuODgzLS41MDgtMS4yNDEtMy41MzUuNzYyLTQuMjk4IDEwLjg3Ni00LjE1NyAzNS41MTUtMjIuMzYxIDU4LjgyNC0zMC4zODUgNC40MzgtMS41MjYgOC44NjItMi43MSAxMy4xOC0zLjQtMjUuNjY1LTIuMjkzLTM3LjIzNS01Ljg2Mi01My41NTktMy40LTEuNzg5LjI3LTMuMDA0LTEuODEzLTEuODk1LTMuMjQxIDIxLjk5NS0yOC4zMzIgNjIuNTEzLTM2Ljg4OCA4Ny41MTItMjEuODM3LTE1LjQxLTE5LjA5NC0yNy40OC0zNC4zMjEtMjcuNDgtMzQuMzIxbDI4LjYwMS0xNi4yNDZzMTEuODE3IDI2LjQgMjAuNDE0IDQ1LjYxNGMyMS4yNzUtMzEuNDM1IDYwLjg2LTM0LjMzNiA3Ny41ODUtMTIuMDMzLjk5MiAxLjMyNi0uMDQ1IDMuMjEtMS43MDIgMy4xNzEtMTMuNjEyLS4zMzEtMjEuMTA3IDEyLjA1LTIxLjY3NSAyMS40NjZsLjE5Ny4wMjMiIGZpbGw9IiMwMDkxMkQiLz48L3N2Zz4=';
|
||||
|
||||
const rating = ratings.rottenTomatoes;
|
||||
|
||||
let ratingString = '0%';
|
||||
|
||||
if (rating) {
|
||||
ratingString = `${rating.value}%`;
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
{
|
||||
!hideIcon &&
|
||||
<img
|
||||
className={styles.image}
|
||||
src={rating.value > 50 ? rtFresh : rtRotten}
|
||||
style={{
|
||||
height: `${iconSize}px`
|
||||
}}
|
||||
/>
|
||||
}
|
||||
|
||||
{ratingString}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RottenTomatoRating.propTypes = {
|
||||
ratings: PropTypes.object.isRequired,
|
||||
iconSize: PropTypes.number.isRequired,
|
||||
hideIcon: PropTypes.bool
|
||||
};
|
||||
|
||||
RottenTomatoRating.defaultProps = {
|
||||
iconSize: 14
|
||||
};
|
||||
|
||||
export default RottenTomatoRating;
|
5
frontend/src/Components/TmdbRating.css
Normal file
5
frontend/src/Components/TmdbRating.css
Normal file
|
@ -0,0 +1,5 @@
|
|||
.tmdb {
|
||||
align-content: center;
|
||||
margin-right: 5px;
|
||||
vertical-align: -0.125em;
|
||||
}
|
57
frontend/src/Components/TmdbRating.js
Normal file
57
frontend/src/Components/TmdbRating.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
import styles from './TmdbRating.css';
|
||||
|
||||
class TmdbRating extends PureComponent {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
|
||||
const {
|
||||
ratings,
|
||||
hideIcon,
|
||||
iconSize
|
||||
} = this.props;
|
||||
|
||||
const tmdbImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOTAuMjQgODEuNTIiPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeTE9IjQwLjc2IiB4Mj0iMTkwLjI0IiB5Mj0iNDAuNzYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM5MGNlYTEiLz48c3RvcCBvZmZzZXQ9Ii41NiIgc3RvcC1jb2xvcj0iIzNjYmVjOSIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwYjNlNSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxwYXRoIGQ9Ik0xMDUuNjcgMzYuMDZoNjYuOWExNy42NyAxNy42NyAwIDAwMTcuNjctMTcuNjZBMTcuNjcgMTcuNjcgMCAwMDE3Mi41Ny43M2gtNjYuOUExNy42NyAxNy42NyAwIDAwODggMTguNGExNy42NyAxNy42NyAwIDAwMTcuNjcgMTcuNjZ6bS04OCA0NWg3Ni45YTE3LjY3IDE3LjY3IDAgMDAxNy42Ny0xNy42NiAxNy42NyAxNy42NyAwIDAwLTE3LjY3LTE3LjY3aC03Ni45QTE3LjY3IDE3LjY3IDAgMDAwIDYzLjRhMTcuNjcgMTcuNjcgMCAwMDE3LjY3IDE3LjY2em0tNy4yNi00NS42NGg3LjhWNi45MmgxMC4xVjBoLTI4djYuOWgxMC4xem0yOC4xIDBoNy44VjguMjVoLjFsOSAyNy4xNWg2bDkuMy0yNy4xNWguMVYzNS40aDcuOFYwSDY2Ljc2bC04LjIgMjMuMWgtLjFMNTAuMzEgMGgtMTEuOHptMTEzLjkyIDIwLjI1YTE1LjA3IDE1LjA3IDAgMDAtNC41Mi01LjUyIDE4LjU3IDE4LjU3IDAgMDAtNi42OC0zLjA4IDMzLjU0IDMzLjU0IDAgMDAtOC4wNy0xaC0xMS43djM1LjRoMTIuNzVhMjQuNTggMjQuNTggMCAwMDcuNTUtMS4xNSAxOS4zNCAxOS4zNCAwIDAwNi4zNS0zLjMyIDE2LjI3IDE2LjI3IDAgMDA0LjM3LTUuNSAxNi45MSAxNi45MSAwIDAwMS42My03LjU4IDE4LjUgMTguNSAwIDAwLTEuNjgtOC4yNXpNMTQ1IDY4LjZhOC44IDguOCAwIDAxLTIuNjQgMy40IDEwLjcgMTAuNyAwIDAxLTQgMS44MiAyMS41NyAyMS41NyAwIDAxLTUgLjU1aC00LjA1di0yMWg0LjZhMTcgMTcgMCAwMTQuNjcuNjMgMTEuNjYgMTEuNjYgMCAwMTMuODggMS44N0E5LjE0IDkuMTQgMCAwMTE0NSA1OWE5Ljg3IDkuODcgMCAwMTEgNC41MiAxMS44OSAxMS44OSAwIDAxLTEgNS4wOHptNDQuNjMtLjEzYTggOCAwIDAwLTEuNTgtMi42MiA4LjM4IDguMzggMCAwMC0yLjQyLTEuODUgMTAuMzEgMTAuMzEgMCAwMC0zLjE3LTF2LS4xYTkuMjIgOS4yMiAwIDAwNC40Mi0yLjgyIDcuNDMgNy40MyAwIDAwMS42OC01IDguNDIgOC40MiAwIDAwLTEuMTUtNC42NSA4LjA5IDguMDkgMCAwMC0zLTIuNzIgMTIuNTYgMTIuNTYgMCAwMC00LjE4LTEuMyAzMi44NCAzMi44NCAwIDAwLTQuNjItLjMzaC0xMy4ydjM1LjRoMTQuNWEyMi40MSAyMi40MSAwIDAwNC43Mi0uNSAxMy41MyAxMy41MyAwIDAwNC4yOC0xLjY1IDkuNDIgOS40MiAwIDAwMy4xLTMgOC41MiA4LjUyIDAgMDAxLjItNC42OCA5LjM5IDkuMzkgMCAwMC0uNTUtMy4xOHptLTE5LjQyLTE1Ljc1aDUuM2ExMCAxMCAwIDAxMS44NS4xOCA2LjE4IDYuMTggMCAwMTEuNy41NyAzLjM5IDMuMzkgMCAwMTEuMjIgMS4xMyAzLjIyIDMuMjIgMCAwMS40OCAxLjgyIDMuNjMgMy42MyAwIDAxLS40MyAxLjggMy40IDMuNCAwIDAxLTEuMTIgMS4yIDQuOTIgNC45MiAwIDAxLTEuNTguNjUgNy41MSA3LjUxIDAgMDEtMS43Ny4yaC01LjY1em0xMS43MiAyMGEzLjkgMy45IDAgMDEtMS4yMiAxLjMgNC42NCA0LjY0IDAgMDEtMS42OC43IDguMTggOC4xOCAwIDAxLTEuODIuMmgtN3YtOGg1LjlhMTUuMzUgMTUuMzUgMCAwMTIgLjE1IDguNDcgOC40NyAwIDAxMi4wNS41NSA0IDQgMCAwMTEuNTcgMS4xOCAzLjExIDMuMTEgMCAwMS42MyAyIDMuNzEgMy43MSAwIDAxLS40MyAxLjkyeiIgZmlsbD0idXJsKCNhKSIvPjwvc3ZnPg==';
|
||||
|
||||
const rating = ratings.tmdb;
|
||||
|
||||
let ratingString = '0%';
|
||||
|
||||
if (rating) {
|
||||
ratingString = `${rating.value * 10}%`;
|
||||
}
|
||||
|
||||
return (
|
||||
<span title={`${rating.votes} votes`}>
|
||||
{
|
||||
!hideIcon &&
|
||||
<img
|
||||
className={styles.image}
|
||||
src={tmdbImage}
|
||||
style={{
|
||||
height: `${iconSize}px`
|
||||
}}
|
||||
/>
|
||||
}
|
||||
|
||||
{ratingString}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TmdbRating.propTypes = {
|
||||
ratings: PropTypes.object.isRequired,
|
||||
iconSize: PropTypes.number.isRequired,
|
||||
hideIcon: PropTypes.bool
|
||||
};
|
||||
|
||||
TmdbRating.defaultProps = {
|
||||
iconSize: 14
|
||||
};
|
||||
|
||||
export default TmdbRating;
|
|
@ -73,7 +73,7 @@ function getInfoRowProps(row, props) {
|
|||
return {
|
||||
title: translate('Ratings'),
|
||||
iconName: icons.HEART,
|
||||
label: `${props.ratings.value * 10}%`
|
||||
label: `${props.ratings.tmdb.value * 10}%`
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ function DiscoverMoviePosterInfo(props) {
|
|||
return (
|
||||
<div className={styles.info}>
|
||||
<HeartRating
|
||||
rating={ratings.value}
|
||||
ratings={ratings}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -129,7 +129,7 @@ DiscoverMoviePosterInfo.propTypes = {
|
|||
digitalRelease: PropTypes.string,
|
||||
physicalRelease: PropTypes.string,
|
||||
runtime: PropTypes.number,
|
||||
ratings: PropTypes.object,
|
||||
ratings: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
sortKey: PropTypes.string.isRequired,
|
||||
showRelativeDates: PropTypes.bool.isRequired,
|
||||
shortDateFormat: PropTypes.string.isRequired,
|
||||
|
|
|
@ -246,7 +246,7 @@ class DiscoverMovieRow extends Component {
|
|||
className={styles[name]}
|
||||
>
|
||||
<HeartRating
|
||||
rating={ratings.value}
|
||||
ratings={ratings}
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
);
|
||||
|
@ -373,7 +373,7 @@ DiscoverMovieRow.propTypes = {
|
|||
digitalRelease: PropTypes.string,
|
||||
runtime: PropTypes.number,
|
||||
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
ratings: PropTypes.object.isRequired,
|
||||
ratings: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
certification: PropTypes.string,
|
||||
collection: PropTypes.object,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
.header {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 350px;
|
||||
height: 375px;
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
|
@ -41,8 +41,8 @@
|
|||
.poster {
|
||||
flex-shrink: 0;
|
||||
margin-right: 35px;
|
||||
width: 200px;
|
||||
height: 294px;
|
||||
width: 217px;
|
||||
height: 319px;
|
||||
}
|
||||
|
||||
.info {
|
||||
|
|
|
@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
|
|||
import React, { Component } from 'react';
|
||||
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
|
||||
import TextTruncate from 'react-text-truncate';
|
||||
import HeartRating from 'Components/HeartRating';
|
||||
import Icon from 'Components/Icon';
|
||||
import ImdbRating from 'Components/ImdbRating';
|
||||
import InfoLabel from 'Components/InfoLabel';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import Marquee from 'Components/Marquee';
|
||||
|
@ -16,6 +16,8 @@ import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
|||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||
import RottenTomatoRating from 'Components/RottenTomatoRating';
|
||||
import TmdbRating from 'Components/TmdbRating';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import Tooltip from 'Components/Tooltip/Tooltip';
|
||||
import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
|
||||
|
@ -449,17 +451,6 @@ class MovieDetails extends Component {
|
|||
</span>
|
||||
}
|
||||
|
||||
{
|
||||
!!ratings &&
|
||||
<span className={styles.rating}>
|
||||
<HeartRating
|
||||
rating={ratings.value}
|
||||
iconSize={20}
|
||||
hideHeart={isSmallScreen}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
|
||||
{
|
||||
<span className={styles.links}>
|
||||
<Tooltip
|
||||
|
@ -501,6 +492,36 @@ class MovieDetails extends Component {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.details}>
|
||||
{
|
||||
!!ratings.tmdb &&
|
||||
<span className={styles.rating}>
|
||||
<TmdbRating
|
||||
ratings={ratings}
|
||||
iconSize={20}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
{
|
||||
!!ratings.imdb &&
|
||||
<span className={styles.rating}>
|
||||
<ImdbRating
|
||||
ratings={ratings}
|
||||
iconSize={20}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
{
|
||||
!!ratings.rottenTomatoes &&
|
||||
<span className={styles.rating}>
|
||||
<RottenTomatoRating
|
||||
ratings={ratings}
|
||||
iconSize={20}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className={styles.detailsLabels}>
|
||||
<InfoLabel
|
||||
className={styles.detailsInfoLabel}
|
||||
|
|
|
@ -332,7 +332,7 @@ class MovieIndexRow extends Component {
|
|||
className={styles[name]}
|
||||
>
|
||||
<HeartRating
|
||||
rating={ratings.value}
|
||||
ratings={ratings}
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
);
|
||||
|
|
|
@ -200,7 +200,7 @@ export const defaultState = {
|
|||
ratings: function(item) {
|
||||
const { ratings = {} } = item;
|
||||
|
||||
return ratings.value;
|
||||
return ratings.tmdb? ratings.tmdb.value : 0;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -330,8 +330,23 @@ export const defaultState = {
|
|||
valueType: filterBuilderValueTypes.MINIMUM_AVAILABILITY
|
||||
},
|
||||
{
|
||||
name: 'ratings',
|
||||
label: 'Rating',
|
||||
name: 'tmdbRating',
|
||||
label: translate('TmdbRating'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'tmdbVotes',
|
||||
label: translate('TmdbVotes'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'imdbRating',
|
||||
label: translate('ImdbRating'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'imdbVotes',
|
||||
label: translate('ImdbVotes'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
|
|
|
@ -131,10 +131,38 @@ export const filterPredicates = {
|
|||
return dateFilterPredicate(item.digitalRelease, filterValue, type);
|
||||
},
|
||||
|
||||
ratings: function(item, filterValue, type) {
|
||||
tmdbRating: function(item, filterValue, type) {
|
||||
const predicate = filterTypePredicates[type];
|
||||
|
||||
return predicate(item.ratings.value * 10, filterValue);
|
||||
const rating = item.ratings.tmdb ? item.ratings.tmdb.value : 0;
|
||||
|
||||
return predicate(rating * 10, filterValue);
|
||||
},
|
||||
|
||||
tmdbVotes: function(item, filterValue, type) {
|
||||
const predicate = filterTypePredicates[type];
|
||||
|
||||
const rating = item.ratings.tmdb ? item.ratings.tmdb.votes : 0;
|
||||
|
||||
return predicate(rating, filterValue);
|
||||
},
|
||||
|
||||
imdbRating: function(item, filterValue, type) {
|
||||
const predicate = filterTypePredicates[type];
|
||||
|
||||
console.log(item.ratings);
|
||||
|
||||
const rating = item.ratings.imdb ? item.ratings.imdb.value : 0;
|
||||
|
||||
return predicate(rating, filterValue);
|
||||
},
|
||||
|
||||
imdbVotes: function(item, filterValue, type) {
|
||||
const predicate = filterTypePredicates[type];
|
||||
|
||||
const rating = item.ratings.imdb ? item.ratings.imdb.votes : 0;
|
||||
|
||||
return predicate(rating, filterValue);
|
||||
},
|
||||
|
||||
qualityCutoffNotMet: function(item) {
|
||||
|
|
|
@ -209,7 +209,7 @@ export const defaultState = {
|
|||
ratings: function(item) {
|
||||
const { ratings = {} } = item;
|
||||
|
||||
return ratings.value;
|
||||
return ratings.tmdb? ratings.tmdb.value : 0;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -357,8 +357,23 @@ export const defaultState = {
|
|||
}
|
||||
},
|
||||
{
|
||||
name: 'ratings',
|
||||
label: translate('Ratings'),
|
||||
name: 'tmdbRating',
|
||||
label: translate('TmdbRating'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'tmdbVotes',
|
||||
label: translate('TmdbVotes'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'imdbRating',
|
||||
label: translate('ImdbRating'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'imdbVotes',
|
||||
label: translate('ImdbVotes'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Dapper;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(206)]
|
||||
public class multiple_ratings_support : NzbDroneMigrationBase
|
||||
{
|
||||
private readonly JsonSerializerOptions _serializerSettings;
|
||||
|
||||
public multiple_ratings_support()
|
||||
{
|
||||
_serializerSettings = new JsonSerializerOptions
|
||||
{
|
||||
AllowTrailingCommas = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
||||
PropertyNameCaseInsensitive = true,
|
||||
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = true
|
||||
};
|
||||
}
|
||||
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Execute.Sql("UPDATE CustomFilters SET Filters = Replace(Filters, 'ratings', 'tmdbRating') WHERE Type = 'discoverMovie';");
|
||||
Execute.Sql("UPDATE CustomFilters SET Filters = Replace(Filters, 'ratings', 'tmdbRating') WHERE Type = 'movieIndex';");
|
||||
|
||||
Execute.WithConnection((conn, tran) => FixRatings(conn, tran, "Movies"));
|
||||
Execute.WithConnection((conn, tran) => FixRatings(conn, tran, "ImportListMovies"));
|
||||
}
|
||||
|
||||
private void FixRatings(IDbConnection conn, IDbTransaction tran, string table)
|
||||
{
|
||||
var rows = conn.Query<Movie205>($"SELECT Id, Ratings FROM {table}");
|
||||
|
||||
var corrected = new List<Movie206>();
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var oldRatings = JsonSerializer.Deserialize<Ratings205>(row.Ratings, _serializerSettings);
|
||||
|
||||
var newRatings = new Ratings206
|
||||
{
|
||||
Tmdb = new RatingChild206
|
||||
{
|
||||
Votes = oldRatings.Votes,
|
||||
Value = oldRatings.Value,
|
||||
Type = RatingType206.User
|
||||
}
|
||||
};
|
||||
|
||||
corrected.Add(new Movie206
|
||||
{
|
||||
Id = row.Id,
|
||||
Ratings = JsonSerializer.Serialize(newRatings, _serializerSettings)
|
||||
});
|
||||
}
|
||||
|
||||
var updateSql = $"UPDATE {table} SET Ratings = @Ratings WHERE Id = @Id";
|
||||
conn.Execute(updateSql, corrected, transaction: tran);
|
||||
}
|
||||
|
||||
private class Movie205
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Ratings { get; set; }
|
||||
}
|
||||
|
||||
private class Ratings205
|
||||
{
|
||||
public int Votes { get; set; }
|
||||
public decimal Value { get; set; }
|
||||
}
|
||||
|
||||
private class Movie206
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Ratings { get; set; }
|
||||
}
|
||||
|
||||
private class Ratings206
|
||||
{
|
||||
public RatingChild206 Tmdb { get; set; }
|
||||
public RatingChild206 Imdb { get; set; }
|
||||
public RatingChild206 Metacritic { get; set; }
|
||||
public RatingChild206 RottenTomatoes { get; set; }
|
||||
}
|
||||
|
||||
private class RatingChild206
|
||||
{
|
||||
public int Votes { get; set; }
|
||||
public decimal Value { get; set; }
|
||||
public RatingType206 Type { get; set; }
|
||||
}
|
||||
|
||||
private enum RatingType206
|
||||
{
|
||||
User
|
||||
}
|
||||
}
|
||||
}
|
|
@ -179,6 +179,7 @@ namespace NzbDrone.Core.Datastore
|
|||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<string>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<ParsedMovieInfo>(new QualityIntConverter(), new LanguageIntConverter()));
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<ReleaseInfo>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<Ratings>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<MovieTranslation>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<HashSet<int>>());
|
||||
SqlMapper.AddTypeHandler(new OsPathConverter());
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
|
|||
movieElement.Add(new XElement("Overview", movie.Overview));
|
||||
movieElement.Add(new XElement("LocalTitle", movie.Title));
|
||||
|
||||
movieElement.Add(new XElement("Rating", movie.Ratings.Value));
|
||||
movieElement.Add(new XElement("Rating", movie.Ratings.Tmdb?.Value ?? 0));
|
||||
movieElement.Add(new XElement("ProductionYear", movie.Year));
|
||||
movieElement.Add(new XElement("RunningTime", movie.Runtime));
|
||||
movieElement.Add(new XElement("IMDB", movie.ImdbId));
|
||||
|
|
|
@ -154,19 +154,32 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
|||
|
||||
details.Add(new XElement("sorttitle", movie.SortTitle));
|
||||
|
||||
if (movie.Ratings != null && movie.Ratings.Votes > 0)
|
||||
if (movie.Ratings.Tmdb?.Votes > 0 || movie.Ratings.Imdb?.Votes > 0)
|
||||
{
|
||||
var setRating = new XElement("ratings");
|
||||
var setRatethemoviedb = new XElement("rating", new XAttribute("name", "themoviedb"), new XAttribute("max", "10"), new XAttribute("default", "true"));
|
||||
setRatethemoviedb.Add(new XElement("value", movie.Ratings.Value));
|
||||
setRatethemoviedb.Add(new XElement("votes", movie.Ratings.Votes));
|
||||
setRating.Add(setRatethemoviedb);
|
||||
|
||||
if (movie.Ratings.Tmdb?.Votes > 0)
|
||||
{
|
||||
var setRatethemoviedb = new XElement("rating", new XAttribute("name", "themoviedb"), new XAttribute("max", "10"), new XAttribute("default", "true"));
|
||||
setRatethemoviedb.Add(new XElement("value", movie.Ratings.Tmdb.Value));
|
||||
setRatethemoviedb.Add(new XElement("votes", movie.Ratings.Tmdb.Votes));
|
||||
setRating.Add(setRatethemoviedb);
|
||||
}
|
||||
|
||||
if (movie.Ratings.Imdb?.Votes > 0)
|
||||
{
|
||||
var setRateImdb = new XElement("rating", new XAttribute("name", "imdb"), new XAttribute("max", "10"));
|
||||
setRateImdb.Add(new XElement("value", movie.Ratings.Imdb.Value));
|
||||
setRateImdb.Add(new XElement("votes", movie.Ratings.Imdb.Votes));
|
||||
setRating.Add(setRateImdb);
|
||||
}
|
||||
|
||||
details.Add(setRating);
|
||||
}
|
||||
|
||||
if (movie.Ratings != null && movie.Ratings.Votes > 0)
|
||||
if (movie.Ratings?.Tmdb?.Votes > 0)
|
||||
{
|
||||
details.Add(new XElement("rating", movie.Ratings.Value));
|
||||
details.Add(new XElement("rating", movie.Ratings.Tmdb.Value));
|
||||
}
|
||||
|
||||
details.Add(new XElement("userrating"));
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace NzbDrone.Core.ImportLists.ImportListMovies
|
|||
Images = new List<MediaCover.MediaCover>();
|
||||
Genres = new List<string>();
|
||||
Translations = new List<MovieTranslation>();
|
||||
Ratings = new Ratings();
|
||||
}
|
||||
|
||||
public int TmdbId { get; set; }
|
||||
|
|
|
@ -226,6 +226,10 @@
|
|||
"DetailedProgressBar": "Detailed Progress Bar",
|
||||
"DetailedProgressBarHelpText": "Show text on progress bar",
|
||||
"Details": "Details",
|
||||
"TmdbRating": "TMDb Rating",
|
||||
"TmdbVotes": "TMDb Votes",
|
||||
"ImdbRating": "IMDb Rating",
|
||||
"ImdbVotes": "IMDb Votes",
|
||||
"DigitalRelease": "Digital Release",
|
||||
"Disabled": "Disabled",
|
||||
"Discord": "Discord",
|
||||
|
|
|
@ -11,7 +11,10 @@ namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
|
|||
public string Title { get; set; }
|
||||
public string OriginalTitle { get; set; }
|
||||
public string TitleSlug { get; set; }
|
||||
public List<RatingResource> Ratings { get; set; }
|
||||
|
||||
//Depricated but left in place until cache fills new object (MovieRatings)
|
||||
public List<RatingItem> Ratings { get; set; }
|
||||
public RatingResource MovieRatings { get; set; }
|
||||
public int? Runtime { get; set; }
|
||||
public List<ImageResource> Images { get; set; }
|
||||
public List<string> Genres { get; set; }
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
|
||||
{
|
||||
public class RatingResource
|
||||
{
|
||||
public RatingItem Tmdb { get; set; }
|
||||
public RatingItem Imdb { get; set; }
|
||||
public RatingItem Metacritic { get; set; }
|
||||
public RatingItem RottenTomatoes { get; set; }
|
||||
}
|
||||
|
||||
public class RatingItem
|
||||
{
|
||||
public int Count { get; set; }
|
||||
public decimal Value { get; set; }
|
||||
|
|
|
@ -202,10 +202,21 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
var certificationCountry = _configService.CertificationCountry.ToString();
|
||||
|
||||
movie.Certification = resource.Certifications.FirstOrDefault(m => m.Country == certificationCountry)?.Certification;
|
||||
movie.Ratings = resource.Ratings.Select(MapRatings).FirstOrDefault() ?? new Ratings();
|
||||
movie.Ratings = MapRatings(resource.MovieRatings) ?? new Ratings();
|
||||
movie.Genres = resource.Genres;
|
||||
movie.Recommendations = resource.Recommendations?.Select(r => r.TmdbId).ToList() ?? new List<int>();
|
||||
|
||||
//Workaround due to metadata change until cache cleans up
|
||||
if (movie.Ratings.Tmdb == null)
|
||||
{
|
||||
var tmdbRating = resource.Ratings.FirstOrDefault();
|
||||
movie.Ratings.Tmdb = new RatingChild
|
||||
{
|
||||
Votes = tmdbRating.Count,
|
||||
Value = tmdbRating.Value
|
||||
};
|
||||
}
|
||||
|
||||
var now = DateTime.Now;
|
||||
|
||||
movie.Status = MovieStatusType.Announced;
|
||||
|
@ -512,18 +523,56 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
return newAlternativeTitle;
|
||||
}
|
||||
|
||||
private static Ratings MapRatings(RatingResource rating)
|
||||
private static Ratings MapRatings(RatingResource ratings)
|
||||
{
|
||||
if (rating == null)
|
||||
if (ratings == null)
|
||||
{
|
||||
return new Ratings();
|
||||
}
|
||||
|
||||
return new Ratings
|
||||
var mappedRatings = new Ratings();
|
||||
|
||||
if (ratings.Tmdb != null)
|
||||
{
|
||||
Votes = rating.Count,
|
||||
Value = rating.Value
|
||||
};
|
||||
mappedRatings.Tmdb = new RatingChild
|
||||
{
|
||||
Type = (RatingType)Enum.Parse(typeof(RatingType), ratings.Tmdb.Type),
|
||||
Value = ratings.Tmdb.Value,
|
||||
Votes = ratings.Tmdb.Count
|
||||
};
|
||||
}
|
||||
|
||||
if (ratings.Imdb != null)
|
||||
{
|
||||
mappedRatings.Imdb = new RatingChild
|
||||
{
|
||||
Type = (RatingType)Enum.Parse(typeof(RatingType), ratings.Imdb.Type),
|
||||
Value = ratings.Imdb.Value,
|
||||
Votes = ratings.Imdb.Count
|
||||
};
|
||||
}
|
||||
|
||||
if (ratings.Metacritic != null)
|
||||
{
|
||||
mappedRatings.Metacritic = new RatingChild
|
||||
{
|
||||
Type = (RatingType)Enum.Parse(typeof(RatingType), ratings.Metacritic.Type),
|
||||
Value = ratings.Metacritic.Value,
|
||||
Votes = ratings.Metacritic.Count
|
||||
};
|
||||
}
|
||||
|
||||
if (ratings.RottenTomatoes != null)
|
||||
{
|
||||
mappedRatings.RottenTomatoes = new RatingChild
|
||||
{
|
||||
Type = (RatingType)Enum.Parse(typeof(RatingType), ratings.RottenTomatoes.Type),
|
||||
Value = ratings.RottenTomatoes.Value,
|
||||
Votes = ratings.RottenTomatoes.Count
|
||||
};
|
||||
}
|
||||
|
||||
return mappedRatings;
|
||||
}
|
||||
|
||||
private static MediaCover.MediaCover MapImage(ImageResource arg)
|
||||
|
|
|
@ -1,10 +1,25 @@
|
|||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.Movies
|
||||
{
|
||||
public class Ratings : IEmbeddedDocument
|
||||
{
|
||||
public RatingChild Imdb { get; set; }
|
||||
public RatingChild Tmdb { get; set; }
|
||||
public RatingChild Metacritic { get; set; }
|
||||
public RatingChild RottenTomatoes { get; set; }
|
||||
}
|
||||
|
||||
public class RatingChild
|
||||
{
|
||||
public int Votes { get; set; }
|
||||
public decimal Value { get; set; }
|
||||
public RatingType Type { get; set; }
|
||||
}
|
||||
|
||||
public enum RatingType
|
||||
{
|
||||
User,
|
||||
Critic
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace NzbDrone.Core.Notifications.Discord
|
|||
break;
|
||||
case DiscordGrabFieldType.Rating:
|
||||
discordField.Name = "Rating";
|
||||
discordField.Value = message.Movie.Ratings.Value.ToString();
|
||||
discordField.Value = message.Movie.Ratings.Tmdb?.Value.ToString() ?? string.Empty;
|
||||
break;
|
||||
case DiscordGrabFieldType.Genres:
|
||||
discordField.Name = "Genres";
|
||||
|
@ -157,7 +157,7 @@ namespace NzbDrone.Core.Notifications.Discord
|
|||
break;
|
||||
case DiscordImportFieldType.Rating:
|
||||
discordField.Name = "Rating";
|
||||
discordField.Value = message.Movie.Ratings.Value.ToString();
|
||||
discordField.Value = message.Movie.Ratings.Tmdb?.Value.ToString() ?? string.Empty;
|
||||
break;
|
||||
case DiscordImportFieldType.Genres:
|
||||
discordField.Name = "Genres";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue