Fetch image from MovieDB and set user_id in library update

This commit is contained in:
mjrode
2019-04-06 02:23:56 -05:00
parent 8ba5395421
commit acfb79e73d
19 changed files with 264 additions and 52 deletions

View File

@@ -37,7 +37,7 @@ class Hero extends Component {
</Typography>
<div className="center-align">
<Link
to="/plex-token"
to="/plex"
className="waves-effect waves-light btn-large"
>
<i className="material-icons left">live_tv</i>Get Started

View File

@@ -1,20 +1,70 @@
import React, {Component} from 'react';
import {BrowserRouter, Route} from 'react-router-dom';
import PropTypes from 'prop-types';
import CssBaseline from '@material-ui/core/CssBaseline';
import Typography from '@material-ui/core/Typography';
import {withStyles} from '@material-ui/core/styles';
import {connect} from 'react-redux';
import * as actions from '../actions';
import styles from './css';
import axios from 'axios';
class ImportLibrary extends Component {
importPlexLibrary = async params => {
const res = await axios.get('/api/plex/import/all');
console.log(res);
return res;
};
render() {
const {classes} = this.props;
return (
<div>
<p>Hello</p>
<React.Fragment>
<CssBaseline />
<main>
<div className={classes.heroUnit}>
<div className={classes.heroContent}>
<Typography
component="h1"
variant="h2"
align="center"
color="textPrimary"
gutterBottom
>
PlexRex
</Typography>
<Typography
variant="h6"
align="center"
color="textSecondary"
paragraph
>
Media recommendations based on your most watched Plex TV and
Movies.
</Typography>
<div className="center-align">
<button
onClick={this.importPlexLibrary}
className="waves-effect waves-light btn-large"
>
<i className="material-icons left">live_tv</i> Update/Import
Library
</button>
</div>
</div>
</div>
</main>
</React.Fragment>
</div>
);
}
}
ImportLibrary.propTypes = {
classes: PropTypes.object.isRequired,
};
function mapStateToProps({auth}) {
return {auth};
}
export default connect(mapStateToProps)(ImportLibrary);
export default connect(mapStateToProps)(withStyles(styles)(ImportLibrary));

View File

@@ -0,0 +1,46 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {withStyles} from '@material-ui/core/styles';
import {connect} from 'react-redux';
import styles from './css';
import axios from 'axios';
class MediaList extends Component {
componentDidMount() {
this.getMostWatched();
}
getMostWatched = async params => {
const res = await axios.get('/api/recommend/most-watched');
console.log(res);
return res;
};
render() {
const {classes} = this.props;
return (
<ul className="collection">
<li className="collection-item avatar">
<img src="images/yuna.jpg" alt="pic" className="circle" />
<span className="title">Title</span>
<p>
First Line <br />
Second Line
</p>
<a href="#!" className="secondary-content">
<i className="material-icons">grade</i>
</a>
</li>
</ul>
);
}
}
MediaList.propTypes = {
classes: PropTypes.object.isRequired,
};
function mapStateToProps({auth}) {
return {auth};
}
export default connect(mapStateToProps)(withStyles(styles)(MediaList));

View File

@@ -1,9 +1,8 @@
import React, {Component} from 'react';
import {BrowserRouter, Route} from 'react-router-dom';
import {connect} from 'react-redux';
import * as actions from '../actions';
import PlexTokenForm from './PlexTokenForm';
import ImportLibrary from './ImportLibrary';
import MediaList from './MediaList';
class Plex extends Component {
render() {
@@ -17,6 +16,7 @@ class Plex extends Component {
return (
<div>
<ImportLibrary />
<MediaList />
</div>
);
}

View File

@@ -22,12 +22,6 @@ class PlexTokenForm extends React.Component {
return res;
};
fetchSections = async params => {
const res = await axios.get('/plex/library/sections');
console.log(res);
this.setState({section_data: res.data});
};
render() {
const {classes} = this.props;
if (!this.props.auth) {

View File

@@ -4,6 +4,7 @@ const localConfig = {
googleClientID: process.env.GOOGLE_CLIENT_ID,
googleClientSecret: process.env.GOOGLE_CLIENT_SECRET,
cookieKey: process.env.COOKIE_KEY,
movieApiKey: process.env.MOVIE_API_KEY
};
export default localConfig;

View File

@@ -4,6 +4,7 @@ const prodConfig = {
cookieKey: process.env.COOKIE_KEY,
port: process.env.PORT,
cookieKey: process.env.COOKIE_KEY,
movieApiKey: process.env.MOVIE_API_KEY,
};
export default prodConfig;

View File

@@ -4,6 +4,7 @@ const testConfig = {
googleClientID: process.env.GOOGLE_CLIENT_ID,
googleClientSecret: process.env.GOOGLE_CLIENT_SECRET,
cookieKey: process.env.COOKIE_KEY,
movieApiKey: process.env.MOVIE_API_KEY,
};
export default testConfig;

74
package-lock.json generated
View File

@@ -599,12 +599,14 @@
"is-extglob": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
"optional": true
},
"is-glob": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
"optional": true,
"requires": {
"is-extglob": "^1.0.0"
}
@@ -643,6 +645,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
"optional": true,
"requires": {
"remove-trailing-separator": "^1.0.1"
}
@@ -1686,8 +1689,7 @@
"cookiejar": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz",
"integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==",
"dev": true
"integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA=="
},
"cookies": {
"version": "0.7.3",
@@ -2512,8 +2514,7 @@
"formidable": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz",
"integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==",
"dev": true
"integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg=="
},
"forwarded": {
"version": "0.1.2",
@@ -2570,7 +2571,8 @@
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true
"bundled": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@@ -2588,11 +2590,13 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -2605,15 +2609,18 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -2716,7 +2723,8 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true
"bundled": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@@ -2726,6 +2734,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -2738,17 +2747,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true
"bundled": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -2765,6 +2777,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -2837,7 +2850,8 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -2847,6 +2861,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -2922,7 +2937,8 @@
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true
"bundled": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -2952,6 +2968,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -2969,6 +2986,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -3007,11 +3025,13 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true
"bundled": true,
"optional": true
}
}
},
@@ -3110,12 +3130,14 @@
"is-extglob": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
"optional": true
},
"is-glob": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
"optional": true,
"requires": {
"is-extglob": "^1.0.0"
}
@@ -3920,6 +3942,11 @@
"invert-kv": "^2.0.0"
}
},
"limits.js": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/limits.js/-/limits.js-0.1.4.tgz",
"integrity": "sha1-2rIe8ioXDPoO8eoBpKe+yWRrXoI="
},
"lint-staged": {
"version": "8.1.3",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.3.tgz",
@@ -4457,6 +4484,15 @@
}
}
},
"moviedb-promise": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/moviedb-promise/-/moviedb-promise-1.3.2.tgz",
"integrity": "sha512-391/dwm9OI6ufHUC9w5B2JN+etPIFRG07Y9CWNHAYskmtGbGNR1n352DOTXQF9BYdsOFYL3H4Kh4M1N5e1PSoQ==",
"requires": {
"limits.js": "^0.1.4",
"superagent": "^3.8.3"
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
@@ -9408,7 +9444,8 @@
"is-extglob": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
"optional": true
},
"is-glob": {
"version": "2.0.1",
@@ -10690,7 +10727,6 @@
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz",
"integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==",
"dev": true,
"requires": {
"component-emitter": "^1.2.0",
"cookiejar": "^2.1.0",

View File

@@ -55,6 +55,7 @@
"http-proxy-middleware": "^0.19.1",
"lodash": "^4.17.11",
"morgan": "^1.9.1",
"moviedb-promise": "^1.3.2",
"onchange": "^5.2.0",
"passport": "^0.4.0",
"passport-google-oauth20": "^2.0.0",

View File

@@ -0,0 +1,8 @@
import {Router} from 'express';
import recommend from '../services/recommend';
const router = Router();
router.get('/most-watched', recommend.getMostWatched);
export default router;

View File

@@ -20,7 +20,7 @@ module.exports = {
rating_key: {
type: Sequelize.INTEGER,
},
metadata_path: {
poster_path: {
type: Sequelize.STRING,
},
summary: {

View File

@@ -6,7 +6,7 @@ module.exports = (sequelize, DataTypes) => {
type: DataTypes.STRING,
views: DataTypes.INTEGER,
rating_key: DataTypes.INTEGER,
metadata_path: DataTypes.STRING,
poster_path: DataTypes.STRING,
summary: DataTypes.TEXT,
rating: DataTypes.FLOAT,
year: DataTypes.INTEGER,

View File

@@ -8,6 +8,7 @@ import keys from '../config';
import plex from './routes/plex.route';
import tdaw from './routes/tdaw.route';
import auth from './routes/auth.route';
import recommend from './routes/recommend.route';
require('./services/auth/passport');
export default () => {
@@ -36,6 +37,7 @@ export default () => {
// Set up routes
server.use('/api/plex', plex);
server.use('/api/tdaw', tdaw);
server.use('/api/recommend', recommend);
server.use('/auth', auth);
server.use('/api/auth', auth);

View File

@@ -0,0 +1,9 @@
import recommendController from '../controllers/recommend.controller';
const express = require('express');
const router = express.Router();
router.use(recommendController);
export default router;

View File

@@ -1,20 +1,54 @@
import Promise from 'bluebird';
import plexApi from './plexApi';
import models from '../../db/models';
import config from '../../../config';
import MovieDb from 'moviedb-promise';
import {Op} from 'sequelize';
const mdb = new MovieDb(config.server.movieApiKey);
const importSections = async () => {
const importSections = async user => {
const sections = await plexApi.getSections();
const dbSections = await createSections(sections);
const dbSections = await createSections(sections, user);
return dbSections;
};
const createSections = sections => {
const getTvPosters = async user => {
try {
console.log('Called Get Posters');
const mostWatched = await models.PlexLibrary.findAll({
where: {UserId: user.id, type: 'show', views: {[Op.gt]: 0}},
});
console.log(mostWatched);
const imageUrls = await mostWatched.map(async show => {
console.log('title', show.title);
const res = await mdb.searchTv({query: show.title});
console.log('request-movie', res.results[0].poster_path);
return models.PlexLibrary.update(
{
poster_path: res.results[0].poster_path,
},
{
where: {title: show.title},
},
);
});
console.log('mike--', imageUrls);
} catch (error) {
console.log(error);
return error.message;
}
};
const createSections = (sections, user) => {
return Promise.map(sections, section => {
return models.PlexSection.upsert(
{
title: section.title,
type: section.type,
key: section.key,
UserId: user.id,
},
{
where: {
@@ -30,10 +64,10 @@ const createSections = sections => {
});
};
const importLibraries = async () => {
const importLibraries = async user => {
const sections = await plexApi.getSections();
return Promise.map(sections, section => {
return importLibrary(section.key);
return importLibrary(section.key, user);
});
};
@@ -41,7 +75,7 @@ const importMostWatched = async () => {
// const sectionKeys = await models.PlexSection.findAll().then(sections => {
// return sections.map(section => section.key.toString());
// });
const sectionKeys = [1, 2, 3];
const sectionKeys = [1, 2];
return Promise.map(sectionKeys, sectionKey => {
return importMostWatchedData(sectionKey);
}).catch(err => {
@@ -55,12 +89,12 @@ const importMostWatchedData = async sectionKey => {
return mostWatchedDbData;
};
const importLibrary = async sectionKey => {
console.log('section-key', sectionKey);
const importLibrary = async (sectionKey, user) => {
console.log('user--', user);
const libraryData = await plexApi.getLibraryDataBySection({
sectionKey,
});
const dbLibraryData = await createLibrary(libraryData);
const dbLibraryData = await createLibrary(libraryData, user);
return dbLibraryData;
};
@@ -72,7 +106,7 @@ const updateLibrary = libraryData => {
type: data.type,
views: data.globalViewCount,
rating_key: data.ratingKey,
metadata_path: data.key,
poster_path: data.key,
summary: data.summary,
rating: data.rating,
year: data.year,
@@ -89,11 +123,13 @@ const updateLibrary = libraryData => {
});
};
const createLibrary = libraryData => {
const createLibrary = (libraryData, user) => {
const userId = user.id;
return Promise.map(libraryData, sectionLibraryData => {
return models.PlexLibrary.upsert(
{
title: sectionLibraryData.title,
UserId: userId,
type: sectionLibraryData.type,
views: sectionLibraryData.views,
rating_key: sectionLibraryData.ratingKey,
@@ -112,4 +148,9 @@ const createLibrary = libraryData => {
}).catch(err => console.log(err));
};
export default {importSections, importLibraries, importMostWatched};
export default {
importSections,
importLibraries,
importMostWatched,
getTvPosters,
};

View File

@@ -73,10 +73,12 @@ const importMostWatched = async (req, res) => {
};
const importAll = async (req, res) => {
await importData.importSections();
await importData.importLibraries();
const data = await importData.importMostWatched();
res.json(data);
await importData.importSections(req.user);
await importData.importLibraries(req.user);
await importData.importMostWatched(req.user);
const images = await importData.getTvPosters(req.user);
res.json(images);
};
export default {

View File

@@ -0,0 +1,20 @@
import models from '../../db/models';
import helpers from '../helpers';
import {Op} from 'sequelize';
const getMostWatched = async (req, res) => {
try {
console.log('mike');
const mostWatched = await models.PlexLibrary.findAll({
where: {UserId: req.user.id, views: {[Op.gt]: 0}},
});
console.log('mostwatched', mostWatched);
res.json(mostWatched);
} catch (error) {
res.json(error.message);
}
};
export default {
getMostWatched,
};

View File

@@ -3,7 +3,7 @@ import nock from 'nock';
import app from '../../../../index';
import importData from '../../../../server/services/plex/importData';
import models from '../../../../server/db/models';
import { seed, truncate } from '../../../../server/db/scripts';
import {seed, truncate} from '../../../../server/db/scripts';
import * as nocks from '../../../nocks';
describe('ImportData', () => {
@@ -71,7 +71,7 @@ describe('ImportData', () => {
data => data.dataValues.title === 'New Girl',
);
newGirl[0].dataValues.views.should.eq(74);
newGirl[0].dataValues.metadata_path.should.eq(
newGirl[0].dataValues.poster_path.should.eq(
'/library/metadata/5485/children',
);
libraryMostWatched.should.be.length(56);