From 0addc761261d24897ed2285dcc53f1e1a47a0f2c Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Tue, 9 Jan 2018 23:03:53 +0100 Subject: [PATCH 01/10] Changed the positioning of the type icon in the header and forgot the set the style of the movie info header to the correct css element, this is fixed now. --- client/app/components/admin/AdminRequestInfo.jsx | 2 +- client/app/components/styles/adminRequestInfo.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/app/components/admin/AdminRequestInfo.jsx b/client/app/components/admin/AdminRequestInfo.jsx index a67e7e1..4b10da4 100644 --- a/client/app/components/admin/AdminRequestInfo.jsx +++ b/client/app/components/admin/AdminRequestInfo.jsx @@ -195,7 +195,7 @@ class AdminRequestInfo extends Component {
-

Movie info

+

Movie info

{ this.generateSummary() }
diff --git a/client/app/components/styles/adminRequestInfo.jsx b/client/app/components/styles/adminRequestInfo.jsx index d3a525f..a03e83c 100644 --- a/client/app/components/styles/adminRequestInfo.jsx +++ b/client/app/components/styles/adminRequestInfo.jsx @@ -25,7 +25,7 @@ export default { }, type_icon: { - marginLeft: '-1.9em', + marginLeft: '-0.2em', marginRight: '0.7em', }, type_text: { -- 2.34.1 From 4f98f2fd235f4389f7f6dd15f583e7649082aa86 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Tue, 9 Jan 2018 23:08:59 +0100 Subject: [PATCH 02/10] Changed the distance between the search bar and the content to be a little less and added a shadow around the search bar to make it pop a bit more. --- client/app/components/styles/searchRequestStyle.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/app/components/styles/searchRequestStyle.jsx b/client/app/components/styles/searchRequestStyle.jsx index 0700a4e..0702afe 100644 --- a/client/app/components/styles/searchRequestStyle.jsx +++ b/client/app/components/styles/searchRequestStyle.jsx @@ -14,7 +14,7 @@ export default { backgroundColor: 'rgb(1, 28, 35)', // backgroundImage: 'radial-gradient(circle, #004c67 0, #005771 120%)', zIndex: 1, - marginBottom: '80px' + marginBottom: '70px' }, backgroundSmallHeader: { @@ -61,6 +61,7 @@ export default { width: '77%', paddingLeft: '23%', backgroundColor: 'white', + boxShadow: 'grey 0px 1px 2px', }, searchSmallContainer: { -- 2.34.1 From 0b42cf7f129d18d2a0b9393589337cb424919ebd Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Tue, 9 Jan 2018 23:12:27 +0100 Subject: [PATCH 03/10] Because the content on the landing page felt static I added a random function to pick between the four list types. --- client/app/components/SearchRequest.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/components/SearchRequest.jsx b/client/app/components/SearchRequest.jsx index bdb5098..50e93a4 100644 --- a/client/app/components/SearchRequest.jsx +++ b/client/app/components/SearchRequest.jsx @@ -47,7 +47,7 @@ class SearchRequest extends React.Component { // this.setState({responseMovieList: null}) this.resetPageNumber(); this.state.loadResults = true; - this.fetchTmdbList('discover'); + this.fetchTmdbList(this.allowedListTypes[Math.floor(Math.random()*this.allowedListTypes.length)]); } // Handles all errors of the response of a fetch call -- 2.34.1 From 3639105240bc51409a58d42c21fbd6a3bd2b2807 Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 9 Jan 2018 23:43:32 +0100 Subject: [PATCH 04/10] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0466557..9f50bc6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ [![Build Status](https://travis-ci.org/KevinMidboe/seasonedShows.svg?branch=master)](https://travis-ci.org/KevinMidboe/seasonedShows) [![DUB](https://img.shields.io/dub/l/vibe-d.svg)]() -Your customly *seasoned* movie and show requester, downloader and organizer. +Your customly *seasoned* movie and show requester, downloader and organizer. +Demo can be found [here](https://kevinmidboe.com/request) ## About The goal of this project is to create a full custom stack that can to everything surround downloading, organizing and notifiyng of new media. From the top down we have a website using [tmdb](https://www.themoviedb.com) api to search for from over 350k movies and 70k tv shows. Using [hjone72](https://github.com/hjone72/PlexAuth) great PHP reverse proxy we can have a secure way of allowing users to login with their plex credentials which limits request capabilites to only users that are authenticated to use your plex library. -- 2.34.1 From 6f6b38c23dc03c95d115d5f4745e18e76626e1ca Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 9 Jan 2018 23:43:44 +0100 Subject: [PATCH 05/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f50bc6..8a8d745 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/KevinMidboe/seasonedShows.svg?branch=master)](https://travis-ci.org/KevinMidboe/seasonedShows) [![DUB](https://img.shields.io/dub/l/vibe-d.svg)]() -Your customly *seasoned* movie and show requester, downloader and organizer. +Your customly *seasoned* movie and show requester, downloader and organizer. Demo can be found [here](https://kevinmidboe.com/request) ## About -- 2.34.1 From c0c958706673b37f9d0a8f8e85e9dc053c18a5f3 Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 9 Jan 2018 23:45:01 +0100 Subject: [PATCH 06/10] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 8a8d745..300c84b 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,7 @@ [![Build Status](https://travis-ci.org/KevinMidboe/seasonedShows.svg?branch=master)](https://travis-ci.org/KevinMidboe/seasonedShows) [![DUB](https://img.shields.io/dub/l/vibe-d.svg)]() -Your customly *seasoned* movie and show requester, downloader and organizer. -Demo can be found [here](https://kevinmidboe.com/request) +Your customly *seasoned* movie and show requester, downloader and organizer. Demo page can be viewed [here](https://kevinmidboe.com/request) ## About The goal of this project is to create a full custom stack that can to everything surround downloading, organizing and notifiyng of new media. From the top down we have a website using [tmdb](https://www.themoviedb.com) api to search for from over 350k movies and 70k tv shows. Using [hjone72](https://github.com/hjone72/PlexAuth) great PHP reverse proxy we can have a secure way of allowing users to login with their plex credentials which limits request capabilites to only users that are authenticated to use your plex library. -- 2.34.1 From 6f626d410d7f6ec246644ae819de5da9037bf469 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Mon, 5 Feb 2018 22:44:57 +0100 Subject: [PATCH 07/10] Rewrote most of this class. Now we have helper functions for getting info about items in plex. Used function is inPlex where we can input a tmdb item and it append if the item exsists in plex. --- seasoned_api/src/plex/plexRepository.js | 57 +++++++++++++++++++------ 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/seasoned_api/src/plex/plexRepository.js b/seasoned_api/src/plex/plexRepository.js index db3b752..2a3b975 100644 --- a/seasoned_api/src/plex/plexRepository.js +++ b/seasoned_api/src/plex/plexRepository.js @@ -3,9 +3,11 @@ const convertPlexToSeasoned = require('src/plex/convertPlexToSeasoned'); const convertPlexToStream = require('src/plex/convertPlexToStream'); var rp = require('request-promise'); +const PLEX_METHODS = ['lookup', 'playing'] + class PlexRepository { - searchMedia(query) { + search(query, callback) { var options = { uri: 'http://10.0.0.44:32400/search?query=' + query, headers: { @@ -15,18 +17,40 @@ class PlexRepository { } return rp(options) - .then((result) => { - var seasonedMediaObjects = result.MediaContainer.Metadata.reduce(function(match, media_item) { - if (media_item.type === 'movie' || media_item.type === 'show') { - match.push(convertPlexToSeasoned(media_item)); - } - return match; - }, []); - return seasonedMediaObjects; - }) - .catch((err) => { - throw new Error(err); - }) + .then((result) => this.mapResults(result)) + .then(([mappedResults, resultCount]) => { + return { 'results': mappedResults, 'total_results': resultCount } + }) + } + + compareTmdbToPlex(tmdb, plexResult) { + return Promise.resolve() + .then(() => { + plexResult.results.map((plexItem) => { + if (tmdb.title === plexItem.title && tmdb.year === plexItem.year) + tmdb.matchedInPlex = true; + }) + return tmdb + }) + } + + inPlex(tmdbResult) { + return Promise.resolve() + .then(() => this.search(tmdbResult.title)) + .then((plexResult) => this.compareTmdbToPlex(tmdbResult, plexResult)) + } + + mapResults(response) { + return Promise.resolve() + .then(() => { + if (! response.MediaContainer.hasOwnProperty('Metadata')) return [[], 0] + + const mappedResults = response.MediaContainer.Metadata.filter((element) => { + return (element.type === 'movie' || element.type === 'show') + }).map((element) => convertPlexToSeasoned(element)) + return [mappedResults, mappedResults.length] + }) + .catch((error) => {throw new Error(error)}) } nowPlaying() { @@ -51,6 +75,13 @@ class PlexRepository { throw new Error('Error handling plex playing. Error: ' + err); }) } + + // multipleInPlex(tmdbResults) { + // const results = tmdbResults.results.map(async (tmdb) => { + // return this.inPlex(tmdb) + // }) + // return Promise.all(results) + // } } module.exports = PlexRepository; -- 2.34.1 From d8b2cef18ff93644a9a581e2524d59d655aa228d Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Mon, 5 Feb 2018 22:46:10 +0100 Subject: [PATCH 08/10] Removed filtering of items when searching tmdb. Also added total_results object to all return statements. --- seasoned_api/src/tmdb/tmdb.js | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/seasoned_api/src/tmdb/tmdb.js b/seasoned_api/src/tmdb/tmdb.js index 3ef3716..76b6fd5 100644 --- a/seasoned_api/src/tmdb/tmdb.js +++ b/seasoned_api/src/tmdb/tmdb.js @@ -43,29 +43,11 @@ class TMDB { .catch(() => this.tmdb(methodTypes[type], query)) .catch(() => { throw new Error('Could not search for movies/shows at tmdb.'); }) .then((response) => this.cache.set(cacheKey, response)) - .then((response) => { - try { - let filteredTmdbItems = response.results.filter(function(tmdbResultItem) { - return ((tmdbResultItem.vote_count >= 10 || tmdbResultItem.popularity > 2) && (tmdbResultItem.release_date !== undefined || tmdbResultItem.first_air_date !== undefined)) - }) - - let seasonedItems = filteredTmdbItems.map((tmdbItem) => { - if (type === 'movie') - return convertTmdbToSeasoned(tmdbItem, 'movie'); - else if (type === 'show') - return convertTmdbToSeasoned(tmdbItem, 'show'); - else - return convertTmdbToSeasoned(tmdbItem); - }); - - // TODO add page number if results are larger than 20 - return { 'results': seasonedItems, 'number_of_items_on_page': seasonedItems.length, - 'page': 1, 'total_pages': 1 }; - - } catch (parseError) { - throw new Error('Could not parse result.'); - } - }); + .then((response) => this.mapResults(response)) + .catch((error) => { throw new Error(error); }) + .then(([mappedResults, pagenumber, totalpages, total_results]) => { + return {'results': mappedResults, 'page': pagenumber, 'total_results': total_results, 'total_pages': totalpages} + }) } @@ -140,7 +122,7 @@ class TMDB { const mappedResults = response.results.map((result) => { return convertTmdbToSeasoned(result, type) }) - return [mappedResults, response.page, response.total_pages] + return [mappedResults, response.page, response.total_pages, response.total_results] }) .catch((error) => { throw new Error(error)}) @@ -164,8 +146,8 @@ class TMDB { .then((response) => this.cache.set(cacheKey, response)) .then((response) => this.mapResults(response, media_type)) .catch((error) => { throw new Error(error); }) - .then(([mappedResults, pagenumber, totalpages]) => { - return {'results': mappedResults, 'page': pagenumber, 'total_pages': totalpages} + .then(([mappedResults, pagenumber, totalpages, total_results]) => { + return {'results': mappedResults, 'page': pagenumber, 'total_pages': totalpages, 'total_results': total_results} }) } -- 2.34.1 From 3c263a1ae788b8ebb6780f1358f034b71afd823c Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Mon, 5 Feb 2018 22:48:00 +0100 Subject: [PATCH 09/10] Now we have brand spanking new functions for lookup and searching. The idea here is to match tmdb items to plex counterparts. --- seasoned_api/src/plex/requestRepository.js | 103 ++------------------- 1 file changed, 8 insertions(+), 95 deletions(-) diff --git a/seasoned_api/src/plex/requestRepository.js b/seasoned_api/src/plex/requestRepository.js index 6ef1072..b24e7f8 100644 --- a/seasoned_api/src/plex/requestRepository.js +++ b/seasoned_api/src/plex/requestRepository.js @@ -29,108 +29,21 @@ class RequestRepository { } } - searchRequest(text, page, type) { - // STRIP METADATA THAT IS NOT ALLOWED - - // Do a search in the tmdb api and return the results of the object - let getTmdbResults = function() { - return tmdb.search(text, page, type) - .then((tmdbSearch) => { - return tmdbSearch.results; - }) - } - - // Take inputs and verify them with a list. Now we are for every item in tmdb result - // runnning through the entire plex loop. Many loops, but safe. - let checkIfMatchesPlexObjects = function(title, year, plexarray) { - // Iterate all elements in plexarray - console.log(plexArray) - for (let plexItem of plexarray) { - // If matches with our title and year return true - if (plexItem.title === title && plexItem.year === year) - return true; - } - // If no matches were found, return false - return false; - } - + search(query, type, page) { return Promise.resolve() - .then(() => plexRepository.searchMedia(text)) - // Get the list of plexItems matching the query passed. - .then((plexItem) => { - let tmdbSearchResult = getTmdbResults(); - - // When we get the result from tmdbSearchResult we pass it along and iterate over each - // element, and updates the matchedInPlex status of a item. - return tmdbSearchResult.then((tmdbResult) => { - for (var i = 0; i < tmdbResult.length; i++) { - let foundMatchInPlex = checkIfMatchesPlexObjects(tmdbResult[i].title, tmdbResult[i].year, plexItem); - tmdbResult[i].matchedInPlex = foundMatchInPlex; - } - return { 'results': tmdbResult, 'page': 1 }; - }) - // TODO log error - .catch((error) => { - console.log(error); - throw new Error('Search query did not give any results.'); - }) - }) - .catch(() => { - let tmdbSearchResult = getTmdbResults(); - - // Catch if empty, then 404 - return tmdbSearchResult.then((tmdbResult) => { - return {'results': tmdbResult, 'page': 1 }; - }) + .then(() => tmdb.search(query, type, page)) + // .then((tmdbResult) => plexRepository.multipleInPlex(tmdbResult)) + .then((result) => { + return result }) + .catch((error) => {return 'error in the house' + error}) } lookup(identifier, type = 'movie') { -// console.log('Lookup: ', identifier + ' : ' + type) -// if (type === 'movie') { type = 'movieInfo'} -// else if (type === 'tv') { type = 'tvInfo'} -// return Promise.resolve() -// .then(() => tmdb.lookup(identifier, type)) -// .then((tmdbMovie) => { -// return Promise.resolve(plexRepository.searchMedia(tmdbMovie.title)) -// .then((plexMovies) => { -// for (var i = 0; i < plexMovies.length; i++) { -// if (tmdbMovie.title === plexMovies[i].title && tmdbMovie.year === plexMovies[i].year) { -// tmdbMovie.matchedInPlex = true; -// return tmdbMovie; -// } -// } -// }) -// .catch((error) => { -// return error; -// }); -// return tmdbMovie; -// }); - let tmdbType = undefined; - if (type === 'movie') { tmdbType = 'movieInfo'} - else if (type === 'tv') { tmdbType = 'tvInfo'} return Promise.resolve() - .then(() => tmdb.lookup(identifier, tmdbType)) + .then(() => tmdb.lookup(identifier, type)) .then((tmdbMovie) => this.checkID(tmdbMovie)) - .then((tmdbMovie) => { - return Promise.resolve(plexRepository.searchMedia(tmdbMovie.title)) - .then((plexMovies) => { - console.log('plexMovies lookup: ', plexMovies) - for (var i = 0; i < plexMovies.length; i++) { - if (tmdbMovie.title === plexMovies[i].title && tmdbMovie.year === plexMovies[i].year) { - console.log('matched') - tmdbMovie.matchedInPlex = true; - return tmdbMovie; - } - } - return tmdbMovie; - }) - // Add it here - .catch((error) => { - console.log('there was a error:', error) - return tmdbMovie; - }) - }) + .then((tmdbMovie) => plexRepository.inPlex(tmdbMovie)) .catch((error) => { console.log(error) }) -- 2.34.1 From af64a4e28a301653e653820b60827ddc4c32857e Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Mon, 5 Feb 2018 22:48:41 +0100 Subject: [PATCH 10/10] Removed and clean up function and formatting. --- .../webserver/controllers/plex/searchRequest.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/seasoned_api/src/webserver/controllers/plex/searchRequest.js b/seasoned_api/src/webserver/controllers/plex/searchRequest.js index 020bb5e..8be256a 100644 --- a/seasoned_api/src/webserver/controllers/plex/searchRequest.js +++ b/seasoned_api/src/webserver/controllers/plex/searchRequest.js @@ -9,22 +9,12 @@ const searchHistory = new SearchHistory(); function searchRequestController(req, res) { const user = req.headers.loggedinuser; const { query, page, type } = req.query; - console.log('searchReq: ' + query, page, type); Promise.resolve() - .then(() => { - if (user !== 'false') { - searchHistory.create(user, query); - } - }) - .then(() => requestRepository.searchRequest(query, page, type)) + .then(() => searchHistory.create(user, query)) + .then(() => requestRepository.search(query, page, type)) .then((searchResult) => { - if (searchResult.results.length > 0) { - res.send(searchResult); - } - else { - res.status(404).send({success: false, error: 'Search query did not return any results.'}) - } + res.send(searchResult); }) .catch((error) => { res.status(500).send({success: false, error: error.message }); -- 2.34.1