require("dotenv").config()
const Logger = require("@ryanforever/logger").v2
const Axios = require("axios")
const fetch = require("node-fetch")
const convertXML = require('xml-js')
const MiniSearch = require('minisearch')
const fs = require("fs")
const fsp = require("fs").promises
const {Item, Library, Collection} = require("./schemas")
const qs = require("querystring")
const {humanizeTime} = require("./helpers.js")
let _ = require("underscore")
const getDecade = require('get-decade')
let m = {
success: "success ✅"
}
class Err extends Error {
name = "PLEX ERROR"
static errors = {
MISSING_LIBRARY_ID: "missing library id. i.e '4'",
MISSING_COLLECTION_ID: "missing collection id. i.e '65257'"
}
constructor(error) {
super(error)
if (Err.errors.hasOwnProperty(error)) this.message = Err.errors[error]
this.apiError = error?.response?.data
}
}
/**
* Plex
* @constructor
* @arg {object} config - plex config
* @arg {string} config.host - ip address of computer running plex server
* @arg {string} config.token - plex token
* @arg {boolean} [config.useCachedLibrary=true] - set to false to always get library from server
* @example
* const Plex = require("@ryanforever/plex")
* const plex = new Plex({
* token: process.env.PLEX_TOKEN,
* host: "192.168.1.128"
* })
*/
function Plex(config = {}) {
const logger = new Logger("plex", {debug: config.debug ?? false})
let token = config.token
let host = config.host
let useCachedLibrary = config.useCachedLibrary || false
let libraryCacheRefreshThreshold = 10 * 60 * 1000
let stopWords = new Set(["and", "it", "the", "a", "to", "in", "or"])
if (!token) throw new Error("please input your plex token")
let plexUrl = `http://${host}:32400/library/all?X-Plex-Token=${token}`
let plexHost = `http://${host}:32400/`
const axios = Axios.create({
baseURL: `http://${host}:32400`
})
axios.defaults.params = {}
axios.defaults.params["X-Plex-Token"] = token
const axios2 = Axios.create({
baseURL: `http://${host}:32400`
})
axios2.defaults.params = {}
axios2.defaults.params["X-Plex-Token"] = token
Item.plexHost = plexHost
Item.token = token
////////////////////////////////////////////////////////////
// API
////////////////////////////////////////////////////////////
this.request = async function(url, options = {}) {
let res = await axios2({
url,
...options
}).catch(err => {
let message = err.response?.data || err.response
logger.error(message)
throw new Error(err)
})
return res.data
}
////////////////////////////////////////////////////////////
// GET
////////////////////////////////////////////////////////////
/** find library by name or id */
this.findLibrary = async function(input) {
logger.debug(`findLibrary`)
if (!input) throw new Err(`please input a library ID or name`)
let libraries = await this.getLibraries()
return libraries.find(x => x.name == input || x.id == input)
}
/** get all libraries */
this.getLibraries = async function(raw) {
logger.debug(`getLibaries`)
let res = await axios.get("/library/sections")
let data = res?.data?.MediaContainer?.Directory
let mapped = data.map(x => new Library(x))
if (raw) return data
else return mapped
}
/** get collections from a single library, by libraryId */
this.getLibraryCollections = async function(libraryId, returnRaw) {
logger.debug(`getLibraryCollections`)
if (!libraryId) throw new Err(`MISSING_LIBRARY_ID`)
let library = await this.findLibrary(libraryId)
let res = await axios.get(`/library/sections/${libraryId}/collections`)
let raw = res?.data?.MediaContainer?.Metadata
if (!raw) return []
let mapped = raw.map(x => new Collection(x, library))
if (returnRaw) return raw
else return mapped
}
/** get all collections from all libraryies */
this.getCollections = async function(returnRaw) {
logger.debug(`getCollections`)
let libraries = await this.getLibraries()
let collector = []
for (let library of libraries) {
logger.debug(`getting "${library.name}" collections...`)
let collections = await this.getLibraryCollections(library.id, returnRaw)
logger.debug(`${collections.length} collections in "${library.name}"`)
collector.push(...collections)
}
return collector
}
/** get a collection by it's id */
this.getCollectionById = async function(id) {
logger.debug(`getCollectionById`)
if (!id) throw new Err(`MISSING_COLLECTION_ID`)
let res = await axios.get(`/library/collections/${id}`)
let raw = res.data?.MediaContainer.Metadata[0]
let collection = new Collection(raw)
return collection
}
this.getCollectionLibraryId = async function(collectionId) {
let collection = await this.getCollectionById(collectionId)
return collection.libraryId
}
/** find a collection by name or id */
this.findCollection = async function(input) {
logger.debug(`findCollection`)
let collections = await this.getCollections()
return collections.find(x => x.id == input || x.name == input)
}
/** search collections with given input. if an id is given, will return that collection */
this.searchCollections = async function(input) {
logger.debug(`searchCollections`)
input = input.toLowerCase().trim()
let collections = await this.getCollections()
return collections.filter(x => {
let name = x.name.toLowerCase().trim()
let id = x.id
return name.includes(input) || id == input
})
}
/** wrapper around plex's search function */
this.search = async function(input, params = {}) {
logger.debug(`search`)
if (!input) throw new Err(`missing search input`)
let returnRaw = params.returnRaw
let res = await axios("/hubs/search", {
params: {
query: input,
limit: 100
}
})
let raw = res.data.MediaContainer.Hub
if (returnRaw) return raw
let output = {
collections: [],
movies: [],
shows: []
}
let foundCollections = raw.find(x => x.title == "Collections")
let foundMovies = raw.find(x => x.title == "Movies")
let foundShows = raw.find(x => x.title == "Shows")
// found collections
if (foundCollections && foundCollections.Directory) {
let mapped = foundCollections.Directory.map(x => {
return new Collection({
name: x.tag,
id: x.id,
libraryId: x.librarySectionID,
libraryName: x.librarySectionTitle,
guid: x.guid,
score: x.score,
raw: x
})
})
output.collections.push(...mapped)
}
// found movies
if (foundMovies && foundMovies.Metadata) {
let mapped = foundMovies.Metadata.map(x => new Item(x))
output.movies.push(...mapped)
}
// found shows
if (foundShows && foundShows.Metadata) {
let mapped = foundShows.Metadata.map(x => new Item(x))
output.shows.push(...mapped)
}
return output
}
this.getCollectionVisibility = async function(collectionId, libraryId) {
if (!collectionId) throw new Err("MISSING_COLLECTION_ID")
logger.debug(`getCollectionVisibility`)
if (!libraryId) libraryId = await this.getCollectionLibraryId(collectionId)
let res = await axios(`/hubs/sections/${libraryId}/manage`, {
method: "GET",
params: {
metadataItemId: collectionId
}
})
let raw = res.data?.MediaContainer?.Hub[0]
return {
promotedToRecommended: (raw.promotedToRecommended) ? 1 : 0,
promotedToOwnHome: (raw.promotedToOwnHome) ? 1 : 0,
promotedToSharedHome: (raw.promotedToSharedHome) ? 1 : 0
}
}
////////////////////////////////////////////////////////////
// POST
////////////////////////////////////////////////////////////
/** update collection */
this.updateCollection = async function(collectionId, data = {}) {
logger.debug(`updateCollection`)
if (!collectionId) throw new Err("MISSING_COLLECTION_ID")
let collectionProps = new Map([
["name", "title.value"],
["sortName", "titleSort.value"],
["summary", "summary.value"]
])
let inputKeys = Object.keys(data)
let collectionKeys = Array.from(collectionProps.keys())
let collection = await this.getCollectionById(collectionId)
let libraryId = collection.libraryId
let params = {
type: 18,
id: collectionId,
"title.value": data.title || data.name,
"titleSort.value": data.sortTitle || data.sortName,
"summary.value": data.summary
}
let promises = []
if (data.hasOwnProperty("visibility") && !_.isEmpty(data.visibility)) {
let p = this.setCollectionVisibility(collectionId, data.visibility)
promises.push(p)
}
if (inputKeys.some(key => collectionProps.has(key))) {
logger.debug(`input has collection props`)
let params = {
type: 18,
id: collectionId
}
for (let key of collectionKeys) {
if (!data.hasOwnProperty(key)) continue
let plexKey = collectionProps.get(key)
params[plexKey] = data[key]
}
logger.debug(params)
let p = axios(`/library/sections/${libraryId}/all`, {
method: "PUT",
params
})
promises.push(p)
}
let res = await Promise.all(promises).catch(err => {
throw new Err(err)
})
logger.log(`success ✅`)
return res
}
/** set visibility of collection by id */
this.setCollectionVisibility = async function(collectionId, options = {}) {
logger.debug(`setCollectionVisibility`)
if (!collectionId) throw new Err("MISSING_COLLECTION_ID")
if (_.isEmpty(options)) throw new Err(`no visibility options provided`)
let collection = await this.getCollectionById(collectionId)
let libraryId = collection.libraryId
// have to get current states of visibility, or else it will revert to true for some stupid reason
let currentVisibility = await this.getCollectionVisibility(collectionId, libraryId)
let keys = new Map([
["library", "promotedToRecommended"],
["recommended", "promotedToRecommended"],
["promotedToRecommended", "promotedToRecommended"],
["visibleOnLibrary", "promotedToRecommended"],
["home", "promotedToOwnHome"],
["promotedToOwnHome", "promotedToOwnHome"],
["visibleOnHome", "promotedToOwnHome"],
["friendsHome", "promotedToSharedHome"],
["friends", "promotedToSharedHome"],
["promotedToSharedHome", "promotedToSharedHome"],
["visibleOnFriendsHome", "promotedToSharedHome"]
])
let params = {
metadataItemId: collectionId,
...currentVisibility
}
for (let [key, val] of Object.entries(options)) {
if (!keys.has(key)) continue
let plexKey = keys.get(key)
let plexVal
if (val == true) plexVal = 1
else if (val == false) plexVal = 0
params[plexKey] = plexVal
}
logger.debug(params)
// return
let res = await axios(`/hubs/sections/${libraryId}/manage`, {
method: "POST",
params
}).catch(err => {
throw new Err(err)
})
logger.log(m.success)
// return res
}
this.test = async function() {
let res = await axios.get("/library/sections/8/all")
// console.log(res)
let data = res?.data?.MediaContainer?.Metadata
// data = data.map(x => new Library(x))
return data[0].Media[0]
}
/** search all movies
* @arg {string} query - your search query
* @returns {array} array of movies
* @example
* plex.searchMovies("adaptation").then(console.log)
*/
this.searchMovies = async function(query) {
let movies = await this.getMovies()
let minisearch = new MiniSearch({
fields: ["title"],
// processTerm: (term, _fieldName) => stopWords.has(term) ? null : term.toLowerCase(),
searchOptions: {
// boost: { title: 10 },
fuzzy: .01
}
})
minisearch.addAll(movies)
let res = minisearch.search(query)
// res = res.filter(item => item.score > 5)
let matches = []
res.forEach(item => {
let match = movies.find(x => x.id == item.id)
match.searchMeta = item
if (match) matches.push(match)
})
return matches
}
/** search directors of movies
* @arg {string} query - your search query
* @returns {array} movies with queried director
* @example
* plex.searchDirectors("stanley kubrick").then(console.log)
*/
this.searchDirectors = async function(query) {
let movies = await this.getMovies()
let minisearch = new MiniSearch({
fields: ["director"],
processTerm: (term, _fieldName) => stopWords.has(term) ? null : term.toLowerCase(),
searchOptions: {
// boost: { title: 10 },
fuzzy: .01
}
})
minisearch.addAll(movies)
let res = minisearch.search(query)
res = res.filter(item => item.score > 5)
let matches = []
res.forEach(item => {
let match = movies.find(x => x.id == item.id)
match.searchMeta = item
if (match) matches.push(match)
})
return matches
}
/** search writers of movies
* @arg {string} query - your search query
* @returns {array} movies with queried writer
* @example
* plex.searchWriters("charlie kauffman").then(console.log)
*/
this.searchWriters = async function(query, simple) {
let movies = await this.getMovies()
let matches = movies.filter(x => {
if (x.hasOwnProperty("writer") && x.writer.length) {
let writers = x.writer.map(x => x.toLowerCase())
return writers.includes(query)
}
})
if (simple) {
matches = matches.map(x => {
return {
title: x.title,
year: x.year
}
})
matches = _.sortBy(matches, "year")
}
let output = {
writer: query,
matches
}
return output
}
/** search arctors in movies
* @arg {string} query - your search query
* @returns {array} movies with queried actor
* @example
* plex.searchActors("denzel washington").then(console.log)
*/
this.searchActors = async function(query) {
let movies = await this.getMovies()
let minisearch = new MiniSearch({
fields: ["role"],
processTerm: (term, _fieldName) => stopWords.has(term) ? null : term.toLowerCase(),
searchOptions: {
// boost: { title: 10 },
fuzzy: .01
}
})
minisearch.addAll(movies)
let res = minisearch.search(query)
res = res.filter(item => item.score > 5)
let matches = []
res.forEach(item => {
let match = movies.find(x => x.id == item.id)
match.searchMeta = item
if (match) matches.push(match)
})
return matches
}
// SEARCH ERAS //
// this.searchEras = async function(query) {
// }
/** list all directors
* @returns {array} directors
*/
this.listDirectors = async function() {
return await this.list("director")
}
/** list all writers
* @returns {array} writers
*/
this.listWriters = async function() {
return await this.list("writer")
}
/** list all actors
* @returns {array} actors
*/
this.listActors = async function() {
return await this.list("role")
}
/** list all countries
* @returns {array} countries
*/
this.listCountries = async function() {
return await this.list("country")
}
/** list all genres
* @returns {array} genres
*/
this.listGenres = async function() {
return await this.list("genre")
}
this.listStudios = async function() {
let movies = await this.getLibrary()
let studiosMap = new Set(movies.map(x => x.studio))
let studios = Array.from(studiosMap).filter(x => x).sort()
return studios
}
/** list movies with a given property
* @arg {string} prop - property i.e. "director" "writer" "genre" etc
* @returns {array} writers
*/
this.list = async function(prop) {
let movies = await this.getMovies()
let items = []
movies.forEach(movie => {
if (movie.hasOwnProperty(prop)) {
movie[prop].forEach(item => items.push(item))
}
})
items.sort()
items = new Set(items)
items = Array.from(items)
return items
}
/** get the full plex library
* @returns {array} plex items
*/
this.getLibrary = async function() {
logger.debug("getting library...")
let data
let cachedLibrary = {}
if (fs.existsSync("./cache/library.json")) cachedLibrary = require("../cache/library.json")
else await this.cacheLibrary()
if (useCachedLibrary) {
if (!cachedLibrary) await this.cacheLibrary()
else if (this.shouldRefreshCache()) await this.cacheLibrary()
return cachedLibrary.data
} else {
let res = await axios.get(plexUrl).catch(console.error)
let data = res?.data?.MediaContainer?.Metadata
return data
}
}
/** get only movies
* @returns {array} movies
*/
this.getMovies = async function(simple) {
let library = await this.getLibrary()
// console.log(library)
library = library.filter(item => item.type == "movie")
if (simple) {
library = library.map(x => new Item(x, plexHost, token))
}
// if (simple) library = library.map(x => {
// let keys = ["title", "year", "studio", "summary", "rating", "duration", "director", "writer", "role", "genre", "country", "contentRating" ]
// let obj = {}
// keys.forEach(key => {
// obj[key] = x[key]
// })
// return obj
// })
return library
}
/** get library from server and save locally
*/
this.cacheLibrary = async function() {
logger.debug("caching library...")
let res = await axios.get(plexUrl).catch(console.error)
let data = res?.data?.MediaContainer?.Metadata
let obj = {
cacheDate: new Date(Date.now()),
numItems: data.length,
data: data
}
obj = convertLibrary(obj)
let json = JSON.stringify(obj, null, 2)
logger.debug("saving...")
if (!fs.existsSync("./cache")) fs.mkdirSync("./cache")
await fsp.writeFile("./cache/library.json", json).catch(console.error)
logger.debug("done!")
return
}
this.convertLibrary = convertLibrary
// SHOULD REFRESH CACHE // returns true if last cached date is longer than threshold
this.shouldRefreshCache = function() {
logger.debug("checking cache...")
// const cachedLibrary = require("../cache/library.json")
let cachedLibrary = {}
if (fs.existsSync("./cache/library.json")) {
cachedLibrary = require("../cache/library.json")
}
let now = new Date(Date.now())
let diff = now - new Date(cachedLibrary.cacheDate)
let secsSinceLastCache = humanizeTime(diff)
console.log(`${secsSinceLastCache} since last cache`)
if (diff > libraryCacheRefreshThreshold) return true
else if(!diff) return true
else return false
}
/** analyze your plex library
* @param {object} config
* @param {object} config.max=25 - max amount of items to list
* @returns {object} an analysis of your plex library
*/
this.analyzeMovies = async function(config = {}) {
let max = config.max || 25
let movies = await this.getMovies()
let props = ["director", "role", "genre", "writer", "country"]
let schema = {
numMovies: movies.length,
director: [],
writer: [],
role: [],
genre: [],
studios: [],
country: [],
genders: [],
races: [],
years: [],
eras: [],
ratings: [],
reviews: [],
insights: []
}
// calculate num movies and percentages for each prop
props.forEach(prop => {
let list = _.chain(movies).pluck(prop).flatten().uniq().sort().value()
list.forEach(item => {
let matches = movies.filter(movie => {
if (movie.hasOwnProperty(prop)) {
if (movie[prop].includes(item)) return true
}
})
let numMovies = _.size(matches)
schema[prop].push({
name: item,
numMovies,
percent: ((numMovies / schema.numMovies) * 100).toFixed(2)
})
})
schema[prop] = _.chain(schema[prop]).sortBy("numMovies").reverse().value()
})
let years = _.chain(movies).pluck("year").flatten().uniq().compact().sort().value()
years.forEach(year => {
let matches = movies.filter(movie => movie.year == year)
let numMovies = _.size(matches)
schema.years.push({
year,
numMovies
})
})
schema.years = _.chain(schema.years).sortBy("numMovies").reverse().value()
// schema.eras.push(generateEras())
schema.years.forEach(item => {
let year = item.year
})
// GET STUDIOS
schema.studios = getStudios()
// GET RATINGS
schema.ratings = getRatings()
// get eras
schema.eras = parseEras()
// get insightes
// trim to max
for (let [key, val] of Object.entries(schema)) {
if (Array.isArray(val)) schema[key] = val.slice(0, max)
}
getReviews()
generateInsights()
// console.log(schema)
function generateEras() {
let eras = []
let minYear = 1900
let maxYear = new Date(Date.now()).getFullYear()
for (let i = minYear; i <= maxYear; i += 10) {
let century
let string
if (i >= 1900 && i <= 1999) century = "20th"
else century = "21st"
if (century == "20th") string = (i - 1900).toString() + "s"
else string = (i - 2000).toString() + "s"
schema.eras.push({
century,
era: i,
string,
numMovies: 0
})
}
return eras
}
// GET STUDIOS //
function getStudios() {
let studiosMap = new Set(movies.map(x => x.studio))
let studios = Array.from(studiosMap)
let studiosFinal = []
studios.forEach(studio => {
let numMovies = movies.filter(x => x.hasOwnProperty("studio") && x.studio.includes(studio)).length
studiosFinal.push({
name: studio,
numMovies,
percent: ((numMovies / schema.numMovies) * 100).toFixed(2)
})
})
studiosFinal = _.sortBy(studiosFinal, "numMovies").reverse()
return studiosFinal
}
// GET RATINGS //
function getRatings() {
let ratingsSet = new Set(movies.map(x => x.contentRating))
let ratings = Array.from(ratingsSet)
let ratingsFinal = []
ratings.forEach(rating => {
let numMovies = movies.filter(x => x.hasOwnProperty("contentRating") && x.contentRating.includes(rating)).length
ratingsFinal.push({
rating: rating,
numMovies,
percent: ((numMovies / schema.numMovies) * 100).toFixed(2)
})
})
ratingsFinal = _.sortBy(ratingsFinal, "numMovies").reverse()
return ratingsFinal
}
function getReviews() {
let ratingType = "rating"
let reviewSet = new Set(movies.map(x => x[ratingType]))
reviews = Array.from(reviewSet).map(num => {
if (typeof num == "number") percent = num * 10
else percent = "None"
return {
rating: percent,
numMovies: movies.filter(x => x[ratingType] == num).length
}
})
reviews = _.sortBy(reviews, "numMovies").reverse()
schema.reviews = reviews
}
function parseEras() {
let eras = {}
let output = []
movies.forEach(m => {
let y = m.year
let inc
let era
// 1900s
if (y >= 1900 && y <= 1909) era = "1900"
else if (y >= 1910 && y <= 1919) era = "1910"
else if (y >= 1920 && y <= 1929) era = "1920"
else if (y >= 1930 && y <= 1939) era = "1930"
else if (y >= 1940 && y <= 1949) era = "1940"
else if (y >= 1950 && y <= 1959) era = "1950"
else if (y >= 1960 && y <= 1969) era = "1960"
else if (y >= 1970 && y <= 1979) era = "1970"
else if (y >= 1980 && y <= 1989) era = "1980"
else if (y >= 1990 && y <= 1999) era = "1990"
// 2000s
else if (y >= 2000 && y <= 2009) era = "2000"
else if (y >= 2010 && y <= 2019) era = "2010"
else if (y >= 2020 && y <= 2029) era = "2020"
else if (y >= 2030 && y <= 2039) era = "2030"
else if (y >= 2040 && y <= 2049) era = "2040"
else if (y >= 2050 && y <= 2059) era = "2050"
else if (y >= 2060 && y <= 2069) era = "2060"
if (era) {
if (!eras[era]) eras[era] = 0
eras[era] ++
}
})
for (let [key, val] of Object.entries(eras)) {
output.push({decade: `${key}s`, numMovies: val})
}
return output
}
function generateInsights() {
// get countries
let countries = schema.country
let countryString = `${parseInt(countries[0].percent)}% of your movies are from ${countries[0].name}. You seem to also like movies from ${countries[1].name}, ${countries[2].name}, ${countries[3].name}, ${countries[4].name}, and ${countries[5].name}.`
schema.insights.push({type: "country", summary: countryString})
// get directors
let directors = schema.director
let directorString = `The top director in your library is ${directors[0].name}. You have ${directors[0].numMovies} movies by them.\nYou also seem to like ${directors[1].name}, ${directors[2].name}, ${directors[3].name}, ${directors[4].name}, and ${directors[5].name}.`
schema.insights.push({type: "director", summary: directorString})
// get actors
let actors = schema.role
let actorString = `Out of all your movies, ${actors[0].name} has starred in ${actors[0].numMovies} of them. The other top actors in your library are ${actors[1].name}, ${actors[2].name}, ${actors[3].name}, ${actors[4].name}, and ${actors[5].name}.`
schema.insights.push({type: "actor", summary: actorString})
// get writers
let writers = schema.writer
let writerString = `${writers[0].name} has written the most (${writers[0].numMovies} movies) out of all everyone in your library, followed by ${writers[1].name}, ${writers[2].name}, ${writers[3].name}, ${writers[4].name}, and ${writers[5].name}.`
schema.insights.push({type: "writer", summary: writerString})
// get eras
let eras = schema.eras
eras = _.sortBy(eras, "numMovies").reverse()
let years = schema.years
let eraString = `Most of your movies are from the ${eras[0].decade}, followed by the ${eras[1].decade}, the ${eras[2].decade}, and then the ${eras[3].decade}. ${years[0].year} has the most movies of any given year in your library.`
schema.insights.push({type: "era", summary: eraString})
// get genres
let genres = schema.genre
let genreString = `Your favorite genre seems to be ${genres[0].name}, which makes up about ${parseInt(genres[0].percent)}% of your library. You also like ${genres[1].name}, ${genres[2].name}, ${genres[3].name}, ${genres[4].name}, and ${genres[5].name}s.`
schema.insights.push({type: "genre", summary: genreString})
// get studios
let studios = schema.studios
let studioString = `Most of your movies come from ${studios[0].name} studios. They produced ${studios[0].numMovies} movies in your library. They are followed by ${studios[1].name}, ${studios[2].name}, ${studios[3].name}, ${studios[4].name}, and ${studios[5].name}.`
schema.insights.push({type: "studio", summary: studioString})
// get ratings
let ratings = schema.ratings
let g = ratings.find(x => x.rating == "G")
let nc17 = ratings.find(x => x.rating == "NC-17")
let ratingString = `${parseInt(ratings[0].percent)}% of your movies are rated ${ratings[0].rating}. You have ${g.numMovies} movies rated G, and ${nc17.numMovies} movies rated NC-17. Naughty!`
schema.insights.push({type: "rating", summary: ratingString})
// get reviews
let reviews = schema.reviews
// console.log(reviews)
let eighty = reviews.filter(x => x.rating >= 80).map(x => x.numMovies).reduce((a, b) => a + b, 0)
// console.log(eighty)
// schema.insights = schema.insights.map(x => `${x.type.toUpperCase()}\n${x.summary}`).join("\n\n")
}
return schema
}
function convertLibrary(library) {
libraryData = library.data
let newLibrary = []
let selectedKeys = ["Genre", "Director", "Country", "Role", "Writer"]
libraryData.forEach((item, i) => {
let newItem = {}
for (let [key, val] of Object.entries(item)) {
if (selectedKeys.includes(key)) {
let tags = []
val.forEach(x => tags.push(x.tag))
newItem[key.toLowerCase()] = tags
} else newItem[key] = val
}
newItem.id = i
// selectedKeys.forEach(x => {
// if (!newItem.hasOwnProperty(x.toLowerCase()) && newItem.type == "movie") newItem[x.toLowerCase()] = []
// })
newLibrary.push(newItem)
})
library.data = newLibrary
return library
}
}
module.exports = Plex
Source