From a4b2e8f51c00c5387638220dd5de07ae2cfd8ef8 Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 19 Aug 2022 10:08:34 +0200 Subject: [PATCH 1/9] Instead of having a list of emojis, generate from code point --- src/webserver/controllers/misc/emoji.js | 837 +----------------------- 1 file changed, 13 insertions(+), 824 deletions(-) diff --git a/src/webserver/controllers/misc/emoji.js b/src/webserver/controllers/misc/emoji.js index 5e866a6..fbc7086 100644 --- a/src/webserver/controllers/misc/emoji.js +++ b/src/webserver/controllers/misc/emoji.js @@ -1,3 +1,15 @@ +const emojiBlock = { + start: 127744, + end: 128512 +}; + +const randomEmoji = () => { + const seed = Math.floor(Math.random() * (emojiBlock.end - emojiBlock.start)); + const code = emojiBlock.start + seed; + const hex = `0x${code.toString(16)}`; + return String.fromCodePoint(hex); +}; + /** * Controller: Returns a random emoji โœจ * @param {Request} req http request variable @@ -5,832 +17,9 @@ * @returns {Callback} */ function emojiController(req, res) { - const emojis = [ - /* eslint-disable comma-spacing */ - "๐Ÿ˜„", - "๐Ÿ˜ƒ", - "๐Ÿ˜€", - "๐Ÿ˜Š", - "โ˜บ", - "๐Ÿ˜‰", - "๐Ÿ˜", - "๐Ÿ˜˜", - "๐Ÿ˜š", - "๐Ÿ˜—", - "๐Ÿ˜™", - "๐Ÿ˜œ", - "๐Ÿ˜", - "๐Ÿ˜›", - "๐Ÿ˜ณ", - "๐Ÿ˜", - "๐Ÿ˜”", - "๐Ÿ˜Œ", - "๐Ÿ˜’", - "๐Ÿ˜ž", - "๐Ÿ˜ฃ", - "๐Ÿ˜ข", - "๐Ÿ˜‚", - "๐Ÿ˜ญ", - "๐Ÿ˜ช", - "๐Ÿ˜ฅ", - "๐Ÿ˜ฐ", - "๐Ÿ˜…", - "๐Ÿ˜“", - "๐Ÿ˜ฉ", - "๐Ÿ˜ซ", - "๐Ÿ˜จ", - "๐Ÿ˜ฑ", - "๐Ÿ˜ ", - "๐Ÿ˜ก", - "๐Ÿ˜ค", - "๐Ÿ˜–", - "๐Ÿ˜†", - "๐Ÿ˜‹", - "๐Ÿ˜ท", - "๐Ÿ˜Ž", - "๐Ÿ˜ด", - "๐Ÿ˜ต", - "๐Ÿ˜ฒ", - "๐Ÿ˜Ÿ", - "๐Ÿ˜ฆ", - "๐Ÿ˜ง", - "๐Ÿ˜ˆ", - "๐Ÿ‘ฟ", - "๐Ÿ˜ฎ", - "๐Ÿ˜ฌ", - "๐Ÿ˜", - "๐Ÿ˜•", - "๐Ÿ˜ฏ", - "๐Ÿ˜ถ", - "๐Ÿ˜‡", - "๐Ÿ˜", - "๐Ÿ˜‘", - "๐Ÿ‘ฒ", - "๐Ÿ‘ณ", - "๐Ÿ‘ฎ", - "๐Ÿ‘ท", - "๐Ÿ’‚", - "๐Ÿ‘ถ", - "๐Ÿ‘ฆ", - "๐Ÿ‘ง", - "๐Ÿ‘จ", - "๐Ÿ‘ฉ", - "๐Ÿ‘ด", - "๐Ÿ‘ต", - "๐Ÿ‘ฑ", - "๐Ÿ‘ผ", - "๐Ÿ‘ธ", - "๐Ÿ˜บ", - "๐Ÿ˜ธ", - "๐Ÿ˜ป", - "๐Ÿ˜ฝ", - "๐Ÿ˜ผ", - "๐Ÿ™€", - "๐Ÿ˜ฟ", - "๐Ÿ˜น", - "๐Ÿ˜พ", - "๐Ÿ‘น", - "๐Ÿ‘บ", - "๐Ÿ™ˆ", - "๐Ÿ™‰", - "๐Ÿ™Š", - "๐Ÿ’€", - "๐Ÿ‘ฝ", - "๐Ÿ’ฉ", - "๐Ÿ”ฅ", - "โœจ", - "๐ŸŒŸ", - "๐Ÿ’ซ", - "๐Ÿ’ฅ", - "๐Ÿ’ข", - "๐Ÿ’ฆ", - "๐Ÿ’ง", - "๐Ÿ’ค", - "๐Ÿ’จ", - "๐Ÿ‘‚", - "๐Ÿ‘€", - "๐Ÿ‘ƒ", - "๐Ÿ‘…", - "๐Ÿ‘„", - "๐Ÿ‘", - "๐Ÿ‘Ž", - "๐Ÿ‘Œ", - "๐Ÿ‘Š", - "โœŠ", - "โœŒ", - "๐Ÿ‘‹", - "โœ‹", - "๐Ÿ‘", - "๐Ÿ‘†", - "๐Ÿ‘‡", - "๐Ÿ‘‰", - "๐Ÿ‘ˆ", - "๐Ÿ™Œ", - "๐Ÿ™", - "โ˜", - "๐Ÿ‘", - "๐Ÿ’ช", - "๐Ÿšถ", - "๐Ÿƒ", - "๐Ÿ’ƒ", - "๐Ÿ‘ซ", - "๐Ÿ‘ช", - "๐Ÿ‘ฌ", - "๐Ÿ‘ญ", - "๐Ÿ’", - "๐Ÿ’‘", - "๐Ÿ‘ฏ", - "๐Ÿ™†", - "๐Ÿ™…", - "๐Ÿ’", - "๐Ÿ™‹", - "๐Ÿ’†", - "๐Ÿ’‡", - "๐Ÿ’…", - "๐Ÿ‘ฐ", - "๐Ÿ™Ž", - "๐Ÿ™", - "๐Ÿ™‡", - "๐ŸŽฉ", - "๐Ÿ‘‘", - "๐Ÿ‘’", - "๐Ÿ‘Ÿ", - "๐Ÿ‘ž", - "๐Ÿ‘ก", - "๐Ÿ‘ ", - "๐Ÿ‘ข", - "๐Ÿ‘•", - "๐Ÿ‘”", - "๐Ÿ‘š", - "๐Ÿ‘—", - "๐ŸŽฝ", - "๐Ÿ‘–", - "๐Ÿ‘˜", - "๐Ÿ‘™", - "๐Ÿ’ผ", - "๐Ÿ‘œ", - "๐Ÿ‘", - "๐Ÿ‘›", - "๐Ÿ‘“", - "๐ŸŽ€", - "๐ŸŒ‚", - "๐Ÿ’„", - "๐Ÿ’›", - "๐Ÿ’™", - "๐Ÿ’œ", - "๐Ÿ’š", - "โค", - "๐Ÿ’”", - "๐Ÿ’—", - "๐Ÿ’“", - "๐Ÿ’•", - "๐Ÿ’–", - "๐Ÿ’ž", - "๐Ÿ’˜", - "๐Ÿ’Œ", - "๐Ÿ’‹", - "๐Ÿ’", - "๐Ÿ’Ž", - "๐Ÿ‘ค", - "๐Ÿ‘ฅ", - "๐Ÿ’ฌ", - "๐Ÿ‘ฃ", - "๐Ÿ’ญ", - "๐Ÿถ", - "๐Ÿบ", - "๐Ÿฑ", - "๐Ÿญ", - "๐Ÿน", - "๐Ÿฐ", - "๐Ÿธ", - "๐Ÿฏ", - "๐Ÿจ", - "๐Ÿป", - "๐Ÿท", - "๐Ÿฝ", - "๐Ÿฎ", - "๐Ÿ—", - "๐Ÿต", - "๐Ÿ’", - "๐Ÿด", - "๐Ÿ‘", - "๐Ÿ˜", - "๐Ÿผ", - "๐Ÿง", - "๐Ÿฆ", - "๐Ÿค", - "๐Ÿฅ", - "๐Ÿฃ", - "๐Ÿ”", - "๐Ÿ", - "๐Ÿข", - "๐Ÿ›", - "๐Ÿ", - "๐Ÿœ", - "๐Ÿž", - "๐ŸŒ", - "๐Ÿ™", - "๐Ÿš", - "๐Ÿ ", - "๐ŸŸ", - "๐Ÿฌ", - "๐Ÿณ", - "๐Ÿ‹", - "๐Ÿ„", - "๐Ÿ", - "๐Ÿ€", - "๐Ÿƒ", - "๐Ÿ…", - "๐Ÿ‡", - "๐Ÿ‰", - "๐ŸŽ", - "๐Ÿ", - "๐Ÿ“", - "๐Ÿ•", - "๐Ÿ–", - "๐Ÿ", - "๐Ÿ‚", - "๐Ÿฒ", - "๐Ÿก", - "๐ŸŠ", - "๐Ÿซ", - "๐Ÿช", - "๐Ÿ†", - "๐Ÿˆ", - "๐Ÿฉ", - "๐Ÿพ", - "๐Ÿ’", - "๐ŸŒธ", - "๐ŸŒท", - "๐Ÿ€", - "๐ŸŒน", - "๐ŸŒป", - "๐ŸŒบ", - "๐Ÿ", - "๐Ÿƒ", - "๐Ÿ‚", - "๐ŸŒฟ", - "๐ŸŒพ", - "๐Ÿ„", - "๐ŸŒต", - "๐ŸŒด", - "๐ŸŒฒ", - "๐ŸŒณ", - "๐ŸŒฐ", - "๐ŸŒฑ", - "๐ŸŒผ", - "๐ŸŒ", - "๐ŸŒž", - "๐ŸŒ", - "๐ŸŒš", - "๐ŸŒ‘", - "๐ŸŒ’", - "๐ŸŒ“", - "๐ŸŒ”", - "๐ŸŒ•", - "๐ŸŒ–", - "๐ŸŒ—", - "๐ŸŒ˜", - "๐ŸŒœ", - "๐ŸŒ›", - "๐ŸŒ™", - "๐ŸŒ", - "๐ŸŒŽ", - "๐ŸŒ", - "๐ŸŒ‹", - "๐ŸŒŒ", - "๐ŸŒ ", - "โญ", - "โ˜€", - "โ›…", - "โ˜", - "โšก", - "โ˜”", - "โ„", - "โ›„", - "๐ŸŒ€", - "๐ŸŒ", - "๐ŸŒˆ", - "๐ŸŒŠ", - "๐ŸŽ", - "๐Ÿ’", - "๐ŸŽŽ", - "๐ŸŽ’", - "๐ŸŽ“", - "๐ŸŽ", - "๐ŸŽ†", - "๐ŸŽ‡", - "๐ŸŽ", - "๐ŸŽ‘", - "๐ŸŽƒ", - "๐Ÿ‘ป", - "๐ŸŽ…", - "๐ŸŽ„", - "๐ŸŽ", - "๐ŸŽ‹", - "๐ŸŽ‰", - "๐ŸŽŠ", - "๐ŸŽˆ", - "๐ŸŽŒ", - "๐Ÿ”ฎ", - "๐ŸŽฅ", - "๐Ÿ“ท", - "๐Ÿ“น", - "๐Ÿ“ผ", - "๐Ÿ’ฟ", - "๐Ÿ“€", - "๐Ÿ’ฝ", - "๐Ÿ’พ", - "๐Ÿ’ป", - "๐Ÿ“ฑ", - "โ˜Ž", - "๐Ÿ“ž", - "๐Ÿ“Ÿ", - "๐Ÿ“ ", - "๐Ÿ“ก", - "๐Ÿ“บ", - "๐Ÿ“ป", - "๐Ÿ”Š", - "๐Ÿ”‰", - "๐Ÿ”ˆ", - "๐Ÿ”‡", - "๐Ÿ””", - "๐Ÿ”•", - "๐Ÿ“ข", - "๐Ÿ“ฃ", - "โณ", - "โŒ›", - "โฐ", - "โŒš", - "๐Ÿ”“", - "๐Ÿ”’", - "๐Ÿ”", - "๐Ÿ”", - "๐Ÿ”‘", - "๐Ÿ”Ž", - "๐Ÿ’ก", - "๐Ÿ”ฆ", - "๐Ÿ”†", - "๐Ÿ”…", - "๐Ÿ”Œ", - "๐Ÿ”‹", - "๐Ÿ”", - "๐Ÿ›", - "๐Ÿ›€", - "๐Ÿšฟ", - "๐Ÿšฝ", - "๐Ÿ”ง", - "๐Ÿ”ฉ", - "๐Ÿ”จ", - "๐Ÿšช", - "๐Ÿšฌ", - "๐Ÿ’ฃ", - "๐Ÿ”ซ", - "๐Ÿ”ช", - "๐Ÿ’Š", - "๐Ÿ’‰", - "๐Ÿ’ฐ", - "๐Ÿ’ด", - "๐Ÿ’ต", - "๐Ÿ’ท", - "๐Ÿ’ถ", - "๐Ÿ’ณ", - "๐Ÿ’ธ", - "๐Ÿ“ฒ", - "๐Ÿ“ง", - "๐Ÿ“ฅ", - "๐Ÿ“ค", - "โœ‰", - "๐Ÿ“ฉ", - "๐Ÿ“จ", - "๐Ÿ“ฏ", - "๐Ÿ“ซ", - "๐Ÿ“ช", - "๐Ÿ“ฌ", - "๐Ÿ“ญ", - "๐Ÿ“ฎ", - "๐Ÿ“ฆ", - "๐Ÿ“", - "๐Ÿ“„", - "๐Ÿ“ƒ", - "๐Ÿ“‘", - "๐Ÿ“Š", - "๐Ÿ“ˆ", - "๐Ÿ“‰", - "๐Ÿ“œ", - "๐Ÿ“‹", - "๐Ÿ“…", - "๐Ÿ“†", - "๐Ÿ“‡", - "๐Ÿ“", - "๐Ÿ“‚", - "โœ‚", - "๐Ÿ“Œ", - "๐Ÿ“Ž", - "โœ’", - "โœ", - "๐Ÿ“", - "๐Ÿ“", - "๐Ÿ“•", - "๐Ÿ“—", - "๐Ÿ“˜", - "๐Ÿ“™", - "๐Ÿ““", - "๐Ÿ“”", - "๐Ÿ“’", - "๐Ÿ“š", - "๐Ÿ“–", - "๐Ÿ”–", - "๐Ÿ“›", - "๐Ÿ”ฌ", - "๐Ÿ”ญ", - "๐Ÿ“ฐ", - "๐ŸŽจ", - "๐ŸŽฌ", - "๐ŸŽค", - "๐ŸŽง", - "๐ŸŽผ", - "๐ŸŽต", - "๐ŸŽถ", - "๐ŸŽน", - "๐ŸŽป", - "๐ŸŽบ", - "๐ŸŽท", - "๐ŸŽธ", - "๐Ÿ‘พ", - "๐ŸŽฎ", - "๐Ÿƒ", - "๐ŸŽด", - "๐Ÿ€„", - "๐ŸŽฒ", - "๐ŸŽฏ", - "๐Ÿˆ", - "๐Ÿ€", - "โšฝ", - "โšพ", - "๐ŸŽพ", - "๐ŸŽฑ", - "๐Ÿ‰", - "๐ŸŽณ", - "โ›ณ", - "๐Ÿšต", - "๐Ÿšด", - "๐Ÿ", - "๐Ÿ‡", - "๐Ÿ†", - "๐ŸŽฟ", - "๐Ÿ‚", - "๐ŸŠ", - "๐Ÿ„", - "๐ŸŽฃ", - "โ˜•", - "๐Ÿต", - "๐Ÿถ", - "๐Ÿผ", - "๐Ÿบ", - "๐Ÿป", - "๐Ÿธ", - "๐Ÿน", - "๐Ÿท", - "๐Ÿด", - "๐Ÿ•", - "๐Ÿ”", - "๐ŸŸ", - "๐Ÿ—", - "๐Ÿ–", - "๐Ÿ", - "๐Ÿ›", - "๐Ÿค", - "๐Ÿฑ", - "๐Ÿฃ", - "๐Ÿฅ", - "๐Ÿ™", - "๐Ÿ˜", - "๐Ÿš", - "๐Ÿœ", - "๐Ÿฒ", - "๐Ÿข", - "๐Ÿก", - "๐Ÿณ", - "๐Ÿž", - "๐Ÿฉ", - "๐Ÿฎ", - "๐Ÿฆ", - "๐Ÿจ", - "๐Ÿง", - "๐ŸŽ‚", - "๐Ÿฐ", - "๐Ÿช", - "๐Ÿซ", - "๐Ÿฌ", - "๐Ÿญ", - "๐Ÿฏ", - "๐ŸŽ", - "๐Ÿ", - "๐ŸŠ", - "๐Ÿ‹", - "๐Ÿ’", - "๐Ÿ‡", - "๐Ÿ‰", - "๐Ÿ“", - "๐Ÿ‘", - "๐Ÿˆ", - "๐ŸŒ", - "๐Ÿ", - "๐Ÿ", - "๐Ÿ ", - "๐Ÿ†", - "๐Ÿ…", - "๐ŸŒฝ", - "๐Ÿ ", - "๐Ÿก", - "๐Ÿซ", - "๐Ÿข", - "๐Ÿฃ", - "๐Ÿฅ", - "๐Ÿฆ", - "๐Ÿช", - "๐Ÿฉ", - "๐Ÿจ", - "๐Ÿ’’", - "โ›ช", - "๐Ÿฌ", - "๐Ÿค", - "๐ŸŒ‡", - "๐ŸŒ†", - "๐Ÿฏ", - "๐Ÿฐ", - "โ›บ", - "๐Ÿญ", - "๐Ÿ—ผ", - "๐Ÿ—พ", - "๐Ÿ—ป", - "๐ŸŒ„", - "๐ŸŒ…", - "๐ŸŒƒ", - "๐Ÿ—ฝ", - "๐ŸŒ‰", - "๐ŸŽ ", - "๐ŸŽก", - "โ›ฒ", - "๐ŸŽข", - "๐Ÿšข", - "โ›ต", - "๐Ÿšค", - "๐Ÿšฃ", - "โš“", - "๐Ÿš€", - "โœˆ", - "๐Ÿ’บ", - "๐Ÿš", - "๐Ÿš‚", - "๐ŸšŠ", - "๐Ÿš‰", - "๐Ÿšž", - "๐Ÿš†", - "๐Ÿš„", - "๐Ÿš…", - "๐Ÿšˆ", - "๐Ÿš‡", - "๐Ÿš", - "๐Ÿš‹", - "๐Ÿšƒ", - "๐ŸšŽ", - "๐ŸšŒ", - "๐Ÿš", - "๐Ÿš™", - "๐Ÿš˜", - "๐Ÿš—", - "๐Ÿš•", - "๐Ÿš–", - "๐Ÿš›", - "๐Ÿšš", - "๐Ÿšจ", - "๐Ÿš“", - "๐Ÿš”", - "๐Ÿš’", - "๐Ÿš‘", - "๐Ÿš", - "๐Ÿšฒ", - "๐Ÿšก", - "๐ŸšŸ", - "๐Ÿš ", - "๐Ÿšœ", - "๐Ÿ’ˆ", - "๐Ÿš", - "๐ŸŽซ", - "๐Ÿšฆ", - "๐Ÿšฅ", - "โš ", - "๐Ÿšง", - "๐Ÿ”ฐ", - "โ›ฝ", - "๐Ÿฎ", - "๐ŸŽฐ", - "โ™จ", - "๐Ÿ—ฟ", - "๐ŸŽช", - "๐ŸŽญ", - "๐Ÿ“", - "๐Ÿšฉ", - "โฌ†", - "โฌ‡", - "โฌ…", - "โžก", - "๐Ÿ” ", - "๐Ÿ”ก", - "๐Ÿ”ค", - "โ†—", - "โ†–", - "โ†˜", - "โ†™", - "โ†”", - "โ†•", - "๐Ÿ”„", - "โ—€", - "โ–ถ", - "๐Ÿ”ผ", - "๐Ÿ”ฝ", - "โ†ฉ", - "โ†ช", - "โ„น", - "โช", - "โฉ", - "โซ", - "โฌ", - "โคต", - "โคด", - "๐Ÿ†—", - "๐Ÿ”€", - "๐Ÿ”", - "๐Ÿ”‚", - "๐Ÿ†•", - "๐Ÿ†™", - "๐Ÿ†’", - "๐Ÿ†“", - "๐Ÿ†–", - "๐Ÿ“ถ", - "๐ŸŽฆ", - "๐Ÿˆ", - "๐Ÿˆฏ", - "๐Ÿˆณ", - "๐Ÿˆต", - "๐Ÿˆด", - "๐Ÿˆฒ", - "๐Ÿ‰", - "๐Ÿˆน", - "๐Ÿˆบ", - "๐Ÿˆถ", - "๐Ÿˆš", - "๐Ÿšป", - "๐Ÿšน", - "๐Ÿšบ", - "๐Ÿšผ", - "๐Ÿšพ", - "๐Ÿšฐ", - "๐Ÿšฎ", - "๐Ÿ…ฟ", - "โ™ฟ", - "๐Ÿšญ", - "๐Ÿˆท", - "๐Ÿˆธ", - "๐Ÿˆ‚", - "โ“‚", - "๐Ÿ›‚", - "๐Ÿ›„", - "๐Ÿ›…", - "๐Ÿ›ƒ", - "๐Ÿ‰‘", - "ใŠ™", - "ใŠ—", - "๐Ÿ†‘", - "๐Ÿ†˜", - "๐Ÿ†”", - "๐Ÿšซ", - "๐Ÿ”ž", - "๐Ÿ“ต", - "๐Ÿšฏ", - "๐Ÿšฑ", - "๐Ÿšณ", - "๐Ÿšท", - "๐Ÿšธ", - "โ›”", - "โœณ", - "โ‡", - "โŽ", - "โœ…", - "โœด", - "๐Ÿ’Ÿ", - "๐Ÿ†š", - "๐Ÿ“ณ", - "๐Ÿ“ด", - "๐Ÿ…ฐ", - "๐Ÿ…ฑ", - "๐Ÿ†Ž", - "๐Ÿ…พ", - "๐Ÿ’ ", - "โžฟ", - "โ™ป", - "โ™ˆ", - "โ™‰", - "โ™Š", - "โ™‹", - "โ™Œ", - "โ™", - "โ™Ž", - "โ™", - "โ™", - "โ™‘", - "โ™’", - "โ™“", - "โ›Ž", - "๐Ÿ”ฏ", - "๐Ÿง", - "๐Ÿ’น", - "๐Ÿ’ฒ", - "๐Ÿ’ฑ", - "ยฉ", - "ยฎ", - "โ„ข", - "ใ€ฝ", - "ใ€ฐ", - "๐Ÿ”", - "๐Ÿ”š", - "๐Ÿ”™", - "๐Ÿ”›", - "๐Ÿ”œ", - "โŒ", - "โญ•", - "โ—", - "โ“", - "โ•", - "โ”", - "๐Ÿ”ƒ", - "๐Ÿ•›", - "๐Ÿ•ง", - "๐Ÿ•", - "๐Ÿ•œ", - "๐Ÿ•‘", - "๐Ÿ•", - "๐Ÿ•’", - "๐Ÿ•ž", - "๐Ÿ•“", - "๐Ÿ•Ÿ", - "๐Ÿ•”", - "๐Ÿ• ", - "๐Ÿ••", - "๐Ÿ•–", - "๐Ÿ•—", - "๐Ÿ•˜", - "๐Ÿ•™", - "๐Ÿ•š", - "๐Ÿ•ก", - "๐Ÿ•ข", - "๐Ÿ•ฃ", - "๐Ÿ•ค", - "๐Ÿ•ฅ", - "๐Ÿ•ฆ", - "โœ–", - "โž•", - "โž–", - "โž—", - "โ™ ", - "โ™ฅ", - "โ™ฃ", - "โ™ฆ", - "๐Ÿ’ฎ", - "๐Ÿ’ฏ", - "โœ”", - "โ˜‘", - "๐Ÿ”˜", - "๐Ÿ”—", - "โžฐ", - "๐Ÿ”ฑ", - "๐Ÿ”ฒ", - "๐Ÿ”ณ", - "โ—ผ", - "โ—ป", - "โ—พ", - "โ—ฝ", - "โ–ช", - "โ–ซ", - "๐Ÿ”บ", - "โฌœ", - "โฌ›", - "โšซ", - "โšช", - "๐Ÿ”ด", - "๐Ÿ”ต", - "๐Ÿ”ป", - "๐Ÿ”ถ", - "๐Ÿ”ท", - "๐Ÿ”ธ", - "๐Ÿ”น" - ]; - res.send({ success: true, - emoji: emojis[Math.floor(Math.random() * emojis.length)], + emoji: randomEmoji(), message: "Happy emoji-ing! ๐ŸŒ" }); } -- 2.34.1 From 31c4b8b7df75764bd9086e9aab7aa03713764799 Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 19 Aug 2022 10:18:16 +0200 Subject: [PATCH 2/9] Replaced travis CI badge with Drone CI --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fefe130..b1667a1 100644 --- a/README.md +++ b/README.md @@ -6,16 +6,19 @@

Season your media library with the shows and movies that you and your friends want.

- - Travis CI + + Drone CI + - - + + + + -- 2.34.1 From 2aace854188e5c0be78cc77050be7cb5aa7cca05 Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 19 Aug 2022 10:41:44 +0200 Subject: [PATCH 3/9] Automaticly fixable eslint issues, mostly 3 -> 2 space indentation --- src/cache/redis.js | 4 +- src/config/environmentVariables.js | 18 ++-- src/config/field.js | 86 ++++++++++--------- src/config/filters.js | 48 +++++------ src/git/gitRepository.js | 9 +- src/media_classes/media.js | 25 +++--- src/media_classes/mediaInfo.js | 22 ++--- src/media_classes/player.js | 16 ++-- src/media_classes/user.js | 8 +- src/notifications/sms.js | 2 +- src/pirate/pirateRepository.js | 4 +- src/plex/convertPlexToSeasoned.js | 8 +- src/plex/mailTemplate.js | 30 +++---- src/plex/plex.js | 40 ++++----- src/plex/plexRepository.js | 4 +- src/plex/requestRepository.js | 4 +- src/plex/stream/convertStreamToPlayback.js | 20 ++--- src/plex/types/episode.js | 6 +- src/plex/types/movie.js | 4 +- src/plex/types/show.js | 2 +- src/request/request.js | 11 +-- src/request/utils.js | 36 +++++--- src/seasoned/stray.js | 6 +- src/seasoned/strayRepository.js | 2 +- src/tmdb/tmdb.js | 18 ++-- src/tmdb/types.js | 12 +-- src/tmdb/types/credits.js | 10 ++- src/tmdb/types/movie.js | 76 +++++++++++++--- src/tmdb/types/releaseDates.js | 58 ++++++++----- src/tmdb/types/show.js | 59 ++++++++++--- src/user/token.js | 6 +- src/user/user.js | 8 +- src/webserver/app.js | 4 +- .../controllers/list/listController.js | 4 +- src/webserver/controllers/movie/credits.js | 9 +- .../controllers/movie/releaseDates.js | 9 +- src/webserver/controllers/person/credits.js | 1 + src/webserver/controllers/person/info.js | 3 +- src/webserver/controllers/pirate/addMagnet.js | 6 +- src/webserver/controllers/plex/hookDump.js | 12 +-- src/webserver/controllers/plex/readRequest.js | 2 +- src/webserver/controllers/plex/search.js | 11 ++- src/webserver/controllers/plex/searchMedia.js | 10 +-- .../controllers/plex/submitRequest.js | 3 +- .../controllers/plex/updateRequested.js | 4 +- .../controllers/plex/watchDirectLink.js | 1 + .../controllers/request/fetchAllRequests.js | 5 +- .../controllers/request/getRequest.js | 3 +- .../controllers/request/requestTmdbId.js | 3 +- .../controllers/search/movieSearch.js | 3 +- .../controllers/search/multiSearch.js | 5 +- .../controllers/search/personSearch.js | 3 +- .../controllers/search/showSearch.js | 3 +- src/webserver/controllers/show/credits.js | 9 +- src/webserver/controllers/show/info.js | 3 +- .../user/authenticatePlexAccount.js | 1 + src/webserver/controllers/user/login.js | 8 +- src/webserver/controllers/user/register.js | 2 +- src/webserver/controllers/user/settings.js | 1 + src/webserver/controllers/user/viewHistory.js | 10 +-- src/webserver/middleware/mustBeAdmin.js | 31 ++++--- .../middleware/mustHaveAccountLinkedToPlex.js | 42 +++++---- 62 files changed, 498 insertions(+), 375 deletions(-) diff --git a/src/cache/redis.js b/src/cache/redis.js index 75e098c..340d884 100644 --- a/src/cache/redis.js +++ b/src/cache/redis.js @@ -21,11 +21,11 @@ try { console.error("Unable to connect to redis, setting up redis-mock."); client = { - get: function () { + get() { console.log("redis-dummy get", arguments[0]); return Promise.resolve(); }, - set: function () { + set() { console.log("redis-dummy set", arguments[0]); return Promise.resolve(); } diff --git a/src/config/environmentVariables.js b/src/config/environmentVariables.js index b7fc3f2..22d467f 100644 --- a/src/config/environmentVariables.js +++ b/src/config/environmentVariables.js @@ -1,15 +1,15 @@ class EnvironmentVariables { - constructor(variables) { - this.variables = variables || process.env; - } + constructor(variables) { + this.variables = variables || process.env; + } - get(variable) { - return this.variables[variable]; - } + get(variable) { + return this.variables[variable]; + } - has(variable) { - return this.get(variable) !== undefined; - } + has(variable) { + return this.get(variable) !== undefined; + } } module.exports = EnvironmentVariables; diff --git a/src/config/field.js b/src/config/field.js index 42eb8cd..546513b 100644 --- a/src/config/field.js +++ b/src/config/field.js @@ -1,49 +1,53 @@ -const Filters = require('./filters.js'); -const EnvironmentVariables = require('./environmentVariables.js'); +const Filters = require("./filters.js"); +const EnvironmentVariables = require("./environmentVariables.js"); class Field { - constructor(rawValue, environmentVariables) { - this.rawValue = rawValue; - this.filters = new Filters(rawValue); - this.valueWithoutFilters = this.filters.removeFiltersFromValue(); - this.environmentVariables = new EnvironmentVariables(environmentVariables); - } - - get value() { - if (this.filters.isEmpty()) { - return this.valueWithoutFilters; - } - - if (this.filters.has('base64') && !this.filters.has('env')) { - return Field.base64Decode(this.valueWithoutFilters); - } - - if (this.environmentVariables.has(this.valueWithoutFilters) && - this.environmentVariables.get(this.valueWithoutFilters) === '') { - return undefined; - } - - if (!this.filters.has('base64') && this.filters.has('env')) { - if (this.environmentVariables.has(this.valueWithoutFilters)) { - return this.environmentVariables.get(this.valueWithoutFilters); - } - return undefined; - } - - if (this.filters.has('env') && this.filters.has('base64')) { - if (this.environmentVariables.has(this.valueWithoutFilters)) { - const encodedEnvironmentVariable = this.environmentVariables.get(this.valueWithoutFilters); - return Field.base64Decode(encodedEnvironmentVariable); - } - return undefined; - } + constructor(rawValue, environmentVariables) { + this.rawValue = rawValue; + this.filters = new Filters(rawValue); + this.valueWithoutFilters = this.filters.removeFiltersFromValue(); + this.environmentVariables = new EnvironmentVariables(environmentVariables); + } + get value() { + if (this.filters.isEmpty()) { return this.valueWithoutFilters; - } + } - static base64Decode(string) { - return new Buffer(string, 'base64').toString('utf-8'); - } + if (this.filters.has("base64") && !this.filters.has("env")) { + return Field.base64Decode(this.valueWithoutFilters); + } + + if ( + this.environmentVariables.has(this.valueWithoutFilters) && + this.environmentVariables.get(this.valueWithoutFilters) === "" + ) { + return undefined; + } + + if (!this.filters.has("base64") && this.filters.has("env")) { + if (this.environmentVariables.has(this.valueWithoutFilters)) { + return this.environmentVariables.get(this.valueWithoutFilters); + } + return undefined; + } + + if (this.filters.has("env") && this.filters.has("base64")) { + if (this.environmentVariables.has(this.valueWithoutFilters)) { + const encodedEnvironmentVariable = this.environmentVariables.get( + this.valueWithoutFilters + ); + return Field.base64Decode(encodedEnvironmentVariable); + } + return undefined; + } + + return this.valueWithoutFilters; + } + + static base64Decode(string) { + return new Buffer(string, "base64").toString("utf-8"); + } } module.exports = Field; diff --git a/src/config/filters.js b/src/config/filters.js index b4ec359..8d5fad1 100644 --- a/src/config/filters.js +++ b/src/config/filters.js @@ -1,34 +1,34 @@ class Filters { - constructor(value) { - this.value = value; - this.delimiter = '|'; - } + constructor(value) { + this.value = value; + this.delimiter = "|"; + } - get filters() { - return this.value.split(this.delimiter).slice(0, -1); - } + get filters() { + return this.value.split(this.delimiter).slice(0, -1); + } - isEmpty() { - return !this.hasValidType() || this.value.length === 0; - } + isEmpty() { + return !this.hasValidType() || this.value.length === 0; + } - has(filter) { - return this.filters.includes(filter); - } + has(filter) { + return this.filters.includes(filter); + } - hasValidType() { - return (typeof this.value === 'string'); - } + hasValidType() { + return typeof this.value === "string"; + } - removeFiltersFromValue() { - if (this.hasValidType() === false) { - return this.value; - } + removeFiltersFromValue() { + if (this.hasValidType() === false) { + return this.value; + } - let filtersCombined = this.filters.join(this.delimiter); - filtersCombined += this.filters.length >= 1 ? this.delimiter : ''; - return this.value.replace(filtersCombined, ''); - } + let filtersCombined = this.filters.join(this.delimiter); + filtersCombined += this.filters.length >= 1 ? this.delimiter : ""; + return this.value.replace(filtersCombined, ""); + } } module.exports = Filters; diff --git a/src/git/gitRepository.js b/src/git/gitRepository.js index 703ce2c..7659561 100644 --- a/src/git/gitRepository.js +++ b/src/git/gitRepository.js @@ -1,9 +1,8 @@ - class GitRepository { - static dumpHook(body) { - /* eslint-disable no-console */ - console.log(body); - } + static dumpHook(body) { + /* eslint-disable no-console */ + console.log(body); + } } module.exports = GitRepository; diff --git a/src/media_classes/media.js b/src/media_classes/media.js index 4ec1627..e68f670 100644 --- a/src/media_classes/media.js +++ b/src/media_classes/media.js @@ -1,19 +1,18 @@ - class Media { - constructor(title, year, type) { - this.title = title; - this.year = year; - this.type = type; - } + constructor(title, year, type) { + this.title = title; + this.year = year; + this.type = type; + } - toString() { - return `N: ${this.title} | Y: ${this.year} | T: ${this.type}`; - } + toString() { + return `N: ${this.title} | Y: ${this.year} | T: ${this.type}`; + } - print() { - /* eslint-disable no-console */ - console.log(this.toString()); - } + print() { + /* eslint-disable no-console */ + console.log(this.toString()); + } } module.exports = Media; diff --git a/src/media_classes/mediaInfo.js b/src/media_classes/mediaInfo.js index 3cbe69d..663bcb8 100644 --- a/src/media_classes/mediaInfo.js +++ b/src/media_classes/mediaInfo.js @@ -1,15 +1,15 @@ class MediaInfo { - constructor() { - this.duration = undefined; - this.height = undefined; - this.width = undefined; - this.bitrate = undefined; - this.resolution = undefined; - this.framerate = undefined; - this.protocol = undefined; - this.container = undefined; - this.audioCodec = undefined; - } + constructor() { + this.duration = undefined; + this.height = undefined; + this.width = undefined; + this.bitrate = undefined; + this.resolution = undefined; + this.framerate = undefined; + this.protocol = undefined; + this.container = undefined; + this.audioCodec = undefined; + } } module.exports = MediaInfo; diff --git a/src/media_classes/player.js b/src/media_classes/player.js index e675f85..6f9a22f 100644 --- a/src/media_classes/player.js +++ b/src/media_classes/player.js @@ -1,12 +1,12 @@ class Player { - constructor(device, address) { - this.device = device; - this.ip = address; - this.platform = undefined; - this.product = undefined; - this.title = undefined; - this.state = undefined; - } + constructor(device, address) { + this.device = device; + this.ip = address; + this.platform = undefined; + this.product = undefined; + this.title = undefined; + this.state = undefined; + } } module.exports = Player; diff --git a/src/media_classes/user.js b/src/media_classes/user.js index fc09d7d..62a5f3e 100644 --- a/src/media_classes/user.js +++ b/src/media_classes/user.js @@ -1,8 +1,8 @@ class User { - constructor(id, title) { - this.id = id; - this.title = title; - } + constructor(id, title) { + this.id = id; + this.title = title; + } } module.exports = User; diff --git a/src/notifications/sms.js b/src/notifications/sms.js index 7e78b05..a56587f 100644 --- a/src/notifications/sms.js +++ b/src/notifications/sms.js @@ -24,7 +24,7 @@ const sendSMS = message => { } }, function (err, r, body) { - console.log(err ? err : body); + console.log(err || body); console.log("sms provider response:", body); resolve(); } diff --git a/src/pirate/pirateRepository.js b/src/pirate/pirateRepository.js index ba01bfa..70a030c 100644 --- a/src/pirate/pirateRepository.js +++ b/src/pirate/pirateRepository.js @@ -92,8 +92,8 @@ async function AddMagnet(magnet, name, tmdb_id) { "INSERT INTO requested_torrent(magnet,torrent_name,tmdb_id) \ VALUES (?,?,?)"; - let response = database.run(insert_query, [magnet, name, tmdb_id]); - console.log("Response from requsted_torrent insert: " + response); + const response = database.run(insert_query, [magnet, name, tmdb_id]); + console.log(`Response from requsted_torrent insert: ${response}`); resolve({ success: true }); }) diff --git a/src/plex/convertPlexToSeasoned.js b/src/plex/convertPlexToSeasoned.js index 148fe7c..40f1dcc 100644 --- a/src/plex/convertPlexToSeasoned.js +++ b/src/plex/convertPlexToSeasoned.js @@ -5,10 +5,10 @@ function translateAdded(date_string) { } function convertPlexToSeasoned(plex) { - const title = plex.title; - const year = plex.year; - const type = plex.type; - const summary = plex.summary; + const { title } = plex; + const { year } = plex; + const { type } = plex; + const { summary } = plex; const poster_path = plex.thumb; const background_path = plex.art; const added = translateAdded(plex.addedAt); diff --git a/src/plex/mailTemplate.js b/src/plex/mailTemplate.js index 64d38a9..fa0a355 100644 --- a/src/plex/mailTemplate.js +++ b/src/plex/mailTemplate.js @@ -1,25 +1,25 @@ class mailTemplate { - constructor(mediaItem) { - this.mediaItem = mediaItem; - this.posterURL = 'https://image.tmdb.org/t/p/w600'; - } + constructor(mediaItem) { + this.mediaItem = mediaItem; + this.posterURL = "https://image.tmdb.org/t/p/w600"; + } - toText() { - return `${this.mediaItem.title} (${this.mediaItem.year})`; // plain text body - } + toText() { + return `${this.mediaItem.title} (${this.mediaItem.year})`; // plain text body + } - toHTML() { - const info = { - name: this.mediaItem.title, - year: `(${this.mediaItem.year})`, - poster: this.posterURL + this.mediaItem.poster, - }; + toHTML() { + const info = { + name: this.mediaItem.title, + year: `(${this.mediaItem.year})`, + poster: this.posterURL + this.mediaItem.poster + }; - return ` + return `

${info.name} ${info.year}

`; - } + } } module.exports = mailTemplate; diff --git a/src/plex/plex.js b/src/plex/plex.js index 159fd00..9108dcb 100644 --- a/src/plex/plex.js +++ b/src/plex/plex.js @@ -11,23 +11,22 @@ const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, ""); function fixedEncodeURIComponent(str) { return encodeURIComponent(str).replace(/[!'()*]/g, function (c) { - return "%" + c.charCodeAt(0).toString(16).toUpperCase(); + return `%${c.charCodeAt(0).toString(16).toUpperCase()}`; }); } const matchingTitleAndYear = (plex, tmdb) => { - let matchingTitle, matchingYear; + let matchingTitle; + let matchingYear; - if (plex["title"] != null && tmdb["title"] != null) { + if (plex.title != null && tmdb.title != null) { const plexTitle = sanitize(plex.title); const tmdbTitle = sanitize(tmdb.title); matchingTitle = plexTitle == tmdbTitle; - matchingTitle = matchingTitle - ? matchingTitle - : plexTitle.startsWith(tmdbTitle); + matchingTitle = matchingTitle || plexTitle.startsWith(tmdbTitle); } else matchingTitle = false; - if (plex["year"] != null && tmdb["year"] != null) + if (plex.year != null && tmdb.year != null) matchingYear = plex.year == tmdb.year; else matchingYear = false; @@ -35,12 +34,12 @@ const matchingTitleAndYear = (plex, tmdb) => { }; const successfullResponse = response => { - if (response && response["MediaContainer"]) return response; + if (response && response.MediaContainer) return response; if ( response == null || - response["status"] == null || - response["statusText"] == null + response.status == null || + response.statusText == null ) { throw Error("Unable to decode response"); } @@ -49,9 +48,8 @@ const successfullResponse = response => { if (status === 200) { return response.json(); - } else { - throw { message: statusText, status: status }; } + throw { message: statusText, status }; }; class Plex { @@ -77,13 +75,13 @@ class Plex { return new Promise((resolve, reject) => this.cache .get(cacheKey) - .then(machineInfo => resolve(machineInfo["machineIdentifier"])) + .then(machineInfo => resolve(machineInfo.machineIdentifier)) .catch(() => fetch(url, options)) .then(response => response.json()) .then(machineInfo => - this.cache.set(cacheKey, machineInfo["MediaContainer"], 2628000) + this.cache.set(cacheKey, machineInfo.MediaContainer, 2628000) ) - .then(machineInfo => resolve(machineInfo["machineIdentifier"])) + .then(machineInfo => resolve(machineInfo.machineIdentifier)) .catch(error => { if (error != undefined && error.type === "request-timeout") { reject({ @@ -104,7 +102,7 @@ class Plex { if (plex == null || tmdb == null) return false; if (plex instanceof Array) { - let possibleMatches = plex.map(plexItem => + const possibleMatches = plex.map(plexItem => matchingTitleAndYear(plexItem, tmdb) ); match = possibleMatches.includes(true); @@ -120,7 +118,7 @@ class Plex { tmdb.title, tmdb.year ); - return plexMatch ? true : false; + return !!plexMatch; } findPlexItemByTitleAndYear(title, year) { @@ -149,7 +147,7 @@ class Plex { if ( matchingObjectInPlex == false || matchingObjectInPlex == null || - matchingObjectInPlex["key"] == null || + matchingObjectInPlex.key == null || machineIdentifier == null ) return false; @@ -227,9 +225,11 @@ class Plex { .map(category => { if (category.type === "movie") { return category.Metadata; - } else if (category.type === "show") { + } + if (category.type === "show") { return category.Metadata.map(convertPlexToShow); - } else if (category.type === "episode") { + } + if (category.type === "episode") { return category.Metadata.map(convertPlexToEpisode); } }) diff --git a/src/plex/plexRepository.js b/src/plex/plexRepository.js index 4433fa2..3bc29ac 100644 --- a/src/plex/plexRepository.js +++ b/src/plex/plexRepository.js @@ -1,6 +1,6 @@ +const rp = require("request-promise"); const convertPlexToSeasoned = require("./convertPlexToSeasoned"); const convertPlexToStream = require("./convertPlexToStream"); -const rp = require("request-promise"); class PlexRepository { constructor(plexIP) { @@ -24,7 +24,7 @@ class PlexRepository { `http://${this.plexIP}:32400/search?query=${queryUri}` ); const options = { - uri: uri, + uri, headers: { Accept: "application/json" }, diff --git a/src/plex/requestRepository.js b/src/plex/requestRepository.js index 357ad40..fcf480e 100644 --- a/src/plex/requestRepository.js +++ b/src/plex/requestRepository.js @@ -56,7 +56,7 @@ class RequestRepository { if (error) { throw new Error(error); } - tmdbMovie.requested = result ? true : false; + tmdbMovie.requested = !!result; return tmdbMovie; }); } @@ -98,7 +98,7 @@ class RequestRepository { type, page ]); - else return this.database.all(this.queries.fetchRequestedItems, page); + return this.database.all(this.queries.fetchRequestedItems, page); }); } diff --git a/src/plex/stream/convertStreamToPlayback.js b/src/plex/stream/convertStreamToPlayback.js index cdabee4..c07d439 100644 --- a/src/plex/stream/convertStreamToPlayback.js +++ b/src/plex/stream/convertStreamToPlayback.js @@ -1,14 +1,14 @@ class convertStreamToPlayback { - constructor(plexStream) { - this.bitrate = plexStream.bitrate; - this.width = plexStream.width; - this.height = plexStream.height; - this.decision = plexStream.decision; - this.audioProfile = plexStream.audioProfile; - this.videoProfile = plexStream.videoProfile; - this.duration = plexStream.duration; - this.container = plexStream.container; - } + constructor(plexStream) { + this.bitrate = plexStream.bitrate; + this.width = plexStream.width; + this.height = plexStream.height; + this.decision = plexStream.decision; + this.audioProfile = plexStream.audioProfile; + this.videoProfile = plexStream.videoProfile; + this.duration = plexStream.duration; + this.container = plexStream.container; + } } module.exports = convertStreamToPlayback; diff --git a/src/plex/types/episode.js b/src/plex/types/episode.js index a99fa8f..69ce4fe 100644 --- a/src/plex/types/episode.js +++ b/src/plex/types/episode.js @@ -8,9 +8,9 @@ class Episode { this.summary = null; this.rating = null; this.views = null; - this.aired = null; - this.type = 'episode'; + this.aired = null; + this.type = "episode"; } } -module.exports = Episode; \ No newline at end of file +module.exports = Episode; diff --git a/src/plex/types/movie.js b/src/plex/types/movie.js index 8a2b6fa..aa62ca6 100644 --- a/src/plex/types/movie.js +++ b/src/plex/types/movie.js @@ -5,8 +5,8 @@ class Movie { this.summary = null; this.rating = null; this.tagline = null; - this.type = 'movie'; + this.type = "movie"; } } -module.exports = Movie; \ No newline at end of file +module.exports = Movie; diff --git a/src/plex/types/show.js b/src/plex/types/show.js index 86c1ef4..426fd7c 100644 --- a/src/plex/types/show.js +++ b/src/plex/types/show.js @@ -9,4 +9,4 @@ class Show { } } -module.exports = Show; \ No newline at end of file +module.exports = Show; diff --git a/src/request/request.js b/src/request/request.js index 97afb05..14ca0dc 100644 --- a/src/request/request.js +++ b/src/request/request.js @@ -1,6 +1,7 @@ const assert = require("assert"); const configuration = require("../config/configuration").getInstance(); const TMDB = require("../tmdb/tmdb"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const establishedDatabase = require("../database/database"); const utils = require("./utils"); @@ -33,7 +34,7 @@ class RequestRepository { } sortAndFilterToDbQuery(by, direction, filter, query) { - let dbQuery = undefined; + let dbQuery; if (query !== undefined) { const dbParams = [query, query]; @@ -87,7 +88,7 @@ class RequestRepository { mapToTmdbByType(rows) { return rows.map(row => { if (row.type === "movie") return tmdb.movieInfo(row.id); - else if (row.type === "show") return tmdb.showInfo(row.id); + if (row.type === "show") return tmdb.showInfo(row.id); }); } @@ -189,9 +190,9 @@ class RequestRepository { .then(async rows => { const sqliteResponse = await this.database.get( fetchTotalResults, - filter ? filter : undefined + filter || undefined ); - const totalRequests = sqliteResponse["totalRequests"]; + const { totalRequests } = sqliteResponse; const totalPages = Math.ceil(totalRequests / 26); return [ @@ -211,7 +212,7 @@ class RequestRepository { Promise.resolve({ results: result, total_results: totalRequests, - page: page, + page, total_pages: totalPages }) ) diff --git a/src/request/utils.js b/src/request/utils.js index 0f92156..6cbe37a 100644 --- a/src/request/utils.js +++ b/src/request/utils.js @@ -1,34 +1,48 @@ // TODO : test title and date are valid matches to columns in the database -const validSortParams = ['title', 'date'] -const validSortDirs = ['asc', 'desc'] -const validFilterParams = ['movie', 'show', 'seeding', 'downloading', 'paused', 'finished', 'downloaded'] +const validSortParams = ["title", "date"]; +const validSortDirs = ["asc", "desc"]; +const validFilterParams = [ + "movie", + "show", + "seeding", + "downloading", + "paused", + "finished", + "downloaded" +]; function validSort(by, direction) { return new Promise((resolve, reject) => { if (by === undefined) { - resolve() + resolve(); } if (validSortParams.includes(by) && validSortDirs.includes(direction)) { - resolve() + resolve(); } else { - reject(new Error(`invalid sort parameter, must be of: ${validSortParams} with optional sort directions: ${validSortDirs} appended with ':'`)) + reject( + new Error( + `invalid sort parameter, must be of: ${validSortParams} with optional sort directions: ${validSortDirs} appended with ':'` + ) + ); } }); } function validFilter(filter_param) { return new Promise((resolve, reject) => { - if (filter_param === undefined) { - resolve() + if (filter_param === undefined) { + resolve(); } if (filter_param && validFilterParams.includes(filter_param)) { - resolve() + resolve(); } else { - reject(new Error(`filter parameteres must be of type: ${validFilterParams}`)) + reject( + new Error(`filter parameteres must be of type: ${validFilterParams}`) + ); } }); } -module.exports = { validSort, validFilter } \ No newline at end of file +module.exports = { validSort, validFilter }; diff --git a/src/seasoned/stray.js b/src/seasoned/stray.js index f33e2ac..c2620fa 100644 --- a/src/seasoned/stray.js +++ b/src/seasoned/stray.js @@ -1,7 +1,7 @@ class Stray { - constructor(id) { - this.id = id; - } + constructor(id) { + this.id = id; + } } module.exports = Stray; diff --git a/src/seasoned/strayRepository.js b/src/seasoned/strayRepository.js index 8474295..9239736 100644 --- a/src/seasoned/strayRepository.js +++ b/src/seasoned/strayRepository.js @@ -1,7 +1,7 @@ const assert = require("assert"); +const pythonShell = require("python-shell"); const Stray = require("./stray"); const establishedDatabase = require("../database/database"); -const pythonShell = require("python-shell"); class StrayRepository { constructor(database) { diff --git a/src/tmdb/tmdb.js b/src/tmdb/tmdb.js index d549d0e..9110167 100644 --- a/src/tmdb/tmdb.js +++ b/src/tmdb/tmdb.js @@ -5,11 +5,11 @@ const { Movie, Show, Person, Credits, ReleaseDates } = require("./types"); const tmdbErrorResponse = (error, typeString = undefined) => { if (error.status === 404) { - let message = error.response.body.status_message; + const message = error.response.body.status_message; throw { status: 404, - message: message.slice(0, -1) + " in tmdb." + message: `${message.slice(0, -1)} in tmdb.` }; } else if (error.status === 401) { throw { @@ -221,7 +221,7 @@ class TMDB { } movieList(listname, page = 1) { - const query = { page: page }; + const query = { page }; const cacheKey = `tmdb/${this.cacheTags[listname]}:${page}`; return this.getFromCacheOrFetchFromTmdb(cacheKey, listname, query) @@ -230,7 +230,7 @@ class TMDB { } showList(listname, page = 1) { - const query = { page: page }; + const query = { page }; const cacheKey = `tmdb/${this.cacheTags[listname]}:${page}`; return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query) @@ -245,21 +245,23 @@ class TMDB { * @returns {Promise} dict with tmdb results, mapped as movie/show objects. */ mapResults(response, type = undefined) { - let results = response.results.map(result => { + const results = response.results.map(result => { if (type === "movie" || result.media_type === "movie") { const movie = Movie.convertFromTmdbResponse(result); return movie.createJsonResponse(); - } else if (type === "show" || result.media_type === "tv") { + } + if (type === "show" || result.media_type === "tv") { const show = Show.convertFromTmdbResponse(result); return show.createJsonResponse(); - } else if (type === "person" || result.media_type === "person") { + } + if (type === "person" || result.media_type === "person") { const person = Person.convertFromTmdbResponse(result); return person.createJsonResponse(); } }); return { - results: results, + results, page: response.page, total_results: response.total_results, total_pages: response.total_pages diff --git a/src/tmdb/types.js b/src/tmdb/types.js index 0c7ae23..f3a831a 100644 --- a/src/tmdb/types.js +++ b/src/tmdb/types.js @@ -1,7 +1,7 @@ -const Movie = require('./types/movie.js') -const Show = require('./types/show.js') -const Person = require('./types/person.js') -const Credits = require('./types/credits.js') -const ReleaseDates = require('./types/releaseDates.js') +const Movie = require("./types/movie.js"); +const Show = require("./types/show.js"); +const Person = require("./types/person.js"); +const Credits = require("./types/credits.js"); +const ReleaseDates = require("./types/releaseDates.js"); -module.exports = { Movie, Show, Person, Credits, ReleaseDates } +module.exports = { Movie, Show, Person, Credits, ReleaseDates }; diff --git a/src/tmdb/types/credits.js b/src/tmdb/types/credits.js index 0c47e51..b32a557 100644 --- a/src/tmdb/types/credits.js +++ b/src/tmdb/types/credits.js @@ -13,10 +13,11 @@ class Credits { const { id, cast, crew } = response; const allCast = cast.map(cast => { - if (cast["media_type"]) { + if (cast.media_type) { if (cast.media_type === "movie") { return CreditedMovie.convertFromTmdbResponse(cast); - } else if (cast.media_type === "tv") { + } + if (cast.media_type === "tv") { return CreditedShow.convertFromTmdbResponse(cast); } } @@ -31,10 +32,11 @@ class Credits { }); const allCrew = crew.map(crew => { - if (cast["media_type"]) { + if (cast.media_type) { if (cast.media_type === "movie") { return CreditedMovie.convertFromTmdbResponse(cast); - } else if (cast.media_type === "tv") { + } + if (cast.media_type === "tv") { return CreditedShow.convertFromTmdbResponse(cast); } } diff --git a/src/tmdb/types/movie.js b/src/tmdb/types/movie.js index 4663245..09b5816 100644 --- a/src/tmdb/types/movie.js +++ b/src/tmdb/types/movie.js @@ -1,7 +1,20 @@ class Movie { - constructor(id, title, year=undefined, overview=undefined, poster=undefined, backdrop=undefined, - releaseDate=undefined, rating=undefined, genres=undefined, productionStatus=undefined, - tagline=undefined, runtime=undefined, imdb_id=undefined, popularity=undefined) { + constructor( + id, + title, + year = undefined, + overview = undefined, + poster = undefined, + backdrop = undefined, + releaseDate = undefined, + rating = undefined, + genres = undefined, + productionStatus = undefined, + tagline = undefined, + runtime = undefined, + imdb_id = undefined, + popularity = undefined + ) { this.id = id; this.title = title; this.year = year; @@ -16,27 +29,66 @@ class Movie { this.runtime = runtime; this.imdb_id = imdb_id; this.popularity = popularity; - this.type = 'movie'; + this.type = "movie"; } static convertFromTmdbResponse(response) { - const { id, title, release_date, overview, poster_path, backdrop_path, vote_average, genres, status, - tagline, runtime, imdb_id, popularity } = response; + const { + id, + title, + release_date, + overview, + poster_path, + backdrop_path, + vote_average, + genres, + status, + tagline, + runtime, + imdb_id, + popularity + } = response; const releaseDate = new Date(release_date); const year = releaseDate.getFullYear(); - const genreNames = genres ? genres.map(g => g.name) : undefined + const genreNames = genres ? genres.map(g => g.name) : undefined; - return new Movie(id, title, year, overview, poster_path, backdrop_path, releaseDate, vote_average, genreNames, status, - tagline, runtime, imdb_id, popularity) + return new Movie( + id, + title, + year, + overview, + poster_path, + backdrop_path, + releaseDate, + vote_average, + genreNames, + status, + tagline, + runtime, + imdb_id, + popularity + ); } static convertFromPlexResponse(response) { // console.log('response', response) const { title, year, rating, tagline, summary } = response; - const _ = undefined + const _ = undefined; - return new Movie(null, title, year, summary, _, _, _, rating, _, _, tagline) + return new Movie( + null, + title, + year, + summary, + _, + _, + _, + rating, + _, + _, + tagline + ); } createJsonResponse() { @@ -55,7 +107,7 @@ class Movie { runtime: this.runtime, imdb_id: this.imdb_id, type: this.type - } + }; } } diff --git a/src/tmdb/types/releaseDates.js b/src/tmdb/types/releaseDates.js index 340479e..02b6a4a 100644 --- a/src/tmdb/types/releaseDates.js +++ b/src/tmdb/types/releaseDates.js @@ -1,4 +1,4 @@ -class ReleaseDates { +class ReleaseDates { constructor(id, releases) { this.id = id; this.releases = releases; @@ -7,24 +7,35 @@ class ReleaseDates { static convertFromTmdbResponse(response) { const { id, results } = response; - const releases = results.map(countryRelease => - new Release( - countryRelease.iso_3166_1, - countryRelease.release_dates.map(rd => new ReleaseDate(rd.certification, rd.iso_639_1, rd.release_date, rd.type, rd.note)) - )) + const releases = results.map( + countryRelease => + new Release( + countryRelease.iso_3166_1, + countryRelease.release_dates.map( + rd => + new ReleaseDate( + rd.certification, + rd.iso_639_1, + rd.release_date, + rd.type, + rd.note + ) + ) + ) + ); - return new ReleaseDates(id, releases) + return new ReleaseDates(id, releases); } createJsonResponse() { return { id: this.id, results: this.releases.map(release => release.createJsonResponse()) - } + }; } } -class Release { +class Release { constructor(country, releaseDates) { this.country = country; this.releaseDates = releaseDates; @@ -33,8 +44,10 @@ class Release { createJsonResponse() { return { country: this.country, - release_dates: this.releaseDates.map(releaseDate => releaseDate.createJsonResponse()) - } + release_dates: this.releaseDates.map(releaseDate => + releaseDate.createJsonResponse() + ) + }; } } @@ -49,19 +62,18 @@ class ReleaseDate { releaseTypeLookup(releaseTypeKey) { const releaseTypeEnum = { - 1: 'Premier', - 2: 'Limited theatrical', - 3: 'Theatrical', - 4: 'Digital', - 5: 'Physical', - 6: 'TV' - } + 1: "Premier", + 2: "Limited theatrical", + 3: "Theatrical", + 4: "Digital", + 5: "Physical", + 6: "TV" + }; if (releaseTypeKey <= Object.keys(releaseTypeEnum).length) { - return releaseTypeEnum[releaseTypeKey] - } else { - // TODO log | Release type not defined, does this need updating? - return null + return releaseTypeEnum[releaseTypeKey]; } + // TODO log | Release type not defined, does this need updating? + return null; } createJsonResponse() { @@ -71,7 +83,7 @@ class ReleaseDate { release_date: this.releaseDate, type: this.type, note: this.note - } + }; } } diff --git a/src/tmdb/types/show.js b/src/tmdb/types/show.js index 176c59a..995a4de 100644 --- a/src/tmdb/types/show.js +++ b/src/tmdb/types/show.js @@ -1,7 +1,18 @@ class Show { - constructor(id, title, year=undefined, overview=undefined, poster=undefined, backdrop=undefined, - seasons=undefined, episodes=undefined, rank=undefined, genres=undefined, status=undefined, - runtime=undefined) { + constructor( + id, + title, + year = undefined, + overview = undefined, + poster = undefined, + backdrop = undefined, + seasons = undefined, + episodes = undefined, + rank = undefined, + genres = undefined, + status = undefined, + runtime = undefined + ) { this.id = id; this.title = title; this.year = year; @@ -14,18 +25,44 @@ class Show { this.genres = genres; this.productionStatus = status; this.runtime = runtime; - this.type = 'show'; + this.type = "show"; } static convertFromTmdbResponse(response) { - const { id, name, first_air_date, overview, poster_path, backdrop_path, number_of_seasons, number_of_episodes, - rank, genres, status, episode_run_time, popularity } = response; + const { + id, + name, + first_air_date, + overview, + poster_path, + backdrop_path, + number_of_seasons, + number_of_episodes, + rank, + genres, + status, + episode_run_time, + popularity + } = response; - const year = new Date(first_air_date).getFullYear() - const genreNames = genres ? genres.map(g => g.name) : undefined + const year = new Date(first_air_date).getFullYear(); + const genreNames = genres ? genres.map(g => g.name) : undefined; - return new Show(id, name, year, overview, poster_path, backdrop_path, number_of_seasons, number_of_episodes, - rank, genreNames, status, episode_run_time, popularity) + return new Show( + id, + name, + year, + overview, + poster_path, + backdrop_path, + number_of_seasons, + number_of_episodes, + rank, + genreNames, + status, + episode_run_time, + popularity + ); } createJsonResponse() { @@ -43,7 +80,7 @@ class Show { production_status: this.productionStatus, runtime: this.runtime, type: this.type - } + }; } } diff --git a/src/user/token.js b/src/user/token.js index d99baac..3f80aad 100644 --- a/src/user/token.js +++ b/src/user/token.js @@ -1,5 +1,5 @@ -const User = require("./user"); const jwt = require("jsonwebtoken"); +const User = require("./user"); class Token { constructor(user, admin = false, settings = null) { @@ -16,8 +16,8 @@ class Token { toString(secret) { const { user, admin, settings } = this; - let data = { username: user.username, settings }; - if (admin) data["admin"] = admin; + const data = { username: user.username, settings }; + if (admin) data.admin = admin; return jwt.sign(data, secret, { expiresIn: "90d" }); } diff --git a/src/user/user.js b/src/user/user.js index bdf326a..0c24602 100644 --- a/src/user/user.js +++ b/src/user/user.js @@ -1,8 +1,8 @@ class User { - constructor(username, email=undefined) { - this.username = username; - this.email = email; - } + constructor(username, email = undefined) { + this.username = username; + this.email = email; + } } module.exports = User; diff --git a/src/webserver/app.js b/src/webserver/app.js index 270c9ff..e184f5c 100644 --- a/src/webserver/app.js +++ b/src/webserver/app.js @@ -59,7 +59,7 @@ router.get("/", (req, res) => { app.use(Raven.errorHandler()); app.use((err, req, res, next) => { res.statusCode = 500; - res.end(res.sentry + "\n"); + res.end(`${res.sentry}\n`); }); /** @@ -68,6 +68,7 @@ app.use((err, req, res, next) => { router.post("/v1/user", require("./controllers/user/register.js")); router.post("/v1/user/login", require("./controllers/user/login.js")); router.post("/v1/user/logout", require("./controllers/user/logout.js")); + router.get( "/v1/user/settings", mustBeAuthenticated, @@ -88,6 +89,7 @@ router.get( mustBeAuthenticated, require("./controllers/user/requests.js") ); + router.post( "/v1/user/link_plex", mustBeAuthenticated, diff --git a/src/webserver/controllers/list/listController.js b/src/webserver/controllers/list/listController.js index 9ec287e..9557099 100644 --- a/src/webserver/controllers/list/listController.js +++ b/src/webserver/controllers/list/listController.js @@ -1,5 +1,6 @@ const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); // there should be a translate function from query params to @@ -39,7 +40,8 @@ function fetchTmdbList(req, res, listname, type) { .movieList(listname, page) .then(listResponse => res.send(listResponse)) .catch(error => handleError(error, res)); - } else if (type === "show") { + } + if (type === "show") { return tmdb .showList(listname, page) .then(listResponse => res.send(listResponse)) diff --git a/src/webserver/controllers/movie/credits.js b/src/webserver/controllers/movie/credits.js index a33b2fa..f8ec6c1 100644 --- a/src/webserver/controllers/movie/credits.js +++ b/src/webserver/controllers/movie/credits.js @@ -17,12 +17,9 @@ const movieCreditsController = (req, res) => { } else { // TODO log unhandled errors console.log("caugth movie credits controller error", error); - res - .status(500) - .send({ - message: - "An unexpected error occured while requesting movie credits" - }); + res.status(500).send({ + message: "An unexpected error occured while requesting movie credits" + }); } }); }; diff --git a/src/webserver/controllers/movie/releaseDates.js b/src/webserver/controllers/movie/releaseDates.js index d8eb2e0..84bd43b 100644 --- a/src/webserver/controllers/movie/releaseDates.js +++ b/src/webserver/controllers/movie/releaseDates.js @@ -17,12 +17,9 @@ const movieReleaseDatesController = (req, res) => { } else { // TODO log unhandled errors : here our at tmdbReleaseError ? console.log("caugth release dates controller error", error); - res - .status(500) - .send({ - message: - "An unexpected error occured while requesting movie credits" - }); + res.status(500).send({ + message: "An unexpected error occured while requesting movie credits" + }); } }); }; diff --git a/src/webserver/controllers/person/credits.js b/src/webserver/controllers/person/credits.js index 91a79e5..19eb5c2 100644 --- a/src/webserver/controllers/person/credits.js +++ b/src/webserver/controllers/person/credits.js @@ -1,5 +1,6 @@ const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const personCreditsController = (req, res) => { diff --git a/src/webserver/controllers/person/info.js b/src/webserver/controllers/person/info.js index be1dad0..87c91ff 100644 --- a/src/webserver/controllers/person/info.js +++ b/src/webserver/controllers/person/info.js @@ -1,5 +1,6 @@ const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); function handleError(error, res) { @@ -31,7 +32,7 @@ async function personInfoController(req, res) { ? (credits = true) : (credits = false); - let tmdbQueue = [tmdb.personInfo(personId)]; + const tmdbQueue = [tmdb.personInfo(personId)]; if (credits) tmdbQueue.push(tmdb.personCredits(personId)); try { diff --git a/src/webserver/controllers/pirate/addMagnet.js b/src/webserver/controllers/pirate/addMagnet.js index 0ce38d0..7dfbbdd 100644 --- a/src/webserver/controllers/pirate/addMagnet.js +++ b/src/webserver/controllers/pirate/addMagnet.js @@ -8,9 +8,9 @@ const PirateRepository = require("../../../pirate/pirateRepository"); function addMagnet(req, res) { - const magnet = req.body.magnet; - const name = req.body.name; - const tmdb_id = req.body.tmdb_id; + const { magnet } = req.body; + const { name } = req.body; + const { tmdb_id } = req.body; PirateRepository.AddMagnet(magnet, name, tmdb_id) .then(result => { diff --git a/src/webserver/controllers/plex/hookDump.js b/src/webserver/controllers/plex/hookDump.js index 82d4e69..15682a0 100644 --- a/src/webserver/controllers/plex/hookDump.js +++ b/src/webserver/controllers/plex/hookDump.js @@ -1,12 +1,12 @@ /* -* @Author: KevinMidboe -* @Date: 2017-05-03 23:26:46 -* @Last Modified by: KevinMidboe -* @Last Modified time: 2018-02-06 20:54:22 -*/ + * @Author: KevinMidboe + * @Date: 2017-05-03 23:26:46 + * @Last Modified by: KevinMidboe + * @Last Modified time: 2018-02-06 20:54:22 + */ function hookDumpController(req, res) { - console.log(req); + console.log(req); } module.exports = hookDumpController; diff --git a/src/webserver/controllers/plex/readRequest.js b/src/webserver/controllers/plex/readRequest.js index db29647..04d8c98 100644 --- a/src/webserver/controllers/plex/readRequest.js +++ b/src/webserver/controllers/plex/readRequest.js @@ -9,7 +9,7 @@ const requestRepository = new RequestRepository(); * @returns {Callback} */ function readRequestController(req, res) { - const mediaId = req.params.mediaId; + const { mediaId } = req.params; const { type } = req.query; requestRepository .lookup(mediaId, type) diff --git a/src/webserver/controllers/plex/search.js b/src/webserver/controllers/plex/search.js index 0d7b577..50162e9 100644 --- a/src/webserver/controllers/plex/search.js +++ b/src/webserver/controllers/plex/search.js @@ -1,5 +1,6 @@ const configuration = require("../../../config/configuration").getInstance(); const Plex = require("../../../plex/plex"); + const plex = new Plex(configuration.get("plex", "ip")); /** @@ -16,12 +17,10 @@ function searchPlexController(req, res) { if (movies.length > 0) { res.send(movies); } else { - res - .status(404) - .send({ - success: false, - message: "Search query did not give any results from plex." - }); + res.status(404).send({ + success: false, + message: "Search query did not give any results from plex." + }); } }) .catch(error => { diff --git a/src/webserver/controllers/plex/searchMedia.js b/src/webserver/controllers/plex/searchMedia.js index c4d9698..d64cefe 100644 --- a/src/webserver/controllers/plex/searchMedia.js +++ b/src/webserver/controllers/plex/searchMedia.js @@ -19,12 +19,10 @@ function searchMediaController(req, res) { if (media !== undefined || media.length > 0) { res.send(media); } else { - res - .status(404) - .send({ - success: false, - message: "Search query did not return any results." - }); + res.status(404).send({ + success: false, + message: "Search query did not return any results." + }); } }) .catch(error => { diff --git a/src/webserver/controllers/plex/submitRequest.js b/src/webserver/controllers/plex/submitRequest.js index 2d78018..c06083a 100644 --- a/src/webserver/controllers/plex/submitRequest.js +++ b/src/webserver/controllers/plex/submitRequest.js @@ -1,6 +1,7 @@ const configuration = require("../../../config/configuration").getInstance(); const RequestRepository = require("../../../request/request"); const TMDB = require("../../../tmdb/tmdb"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const request = new RequestRepository(); @@ -26,7 +27,7 @@ function submitRequestController(req, res) { const user_agent = req.headers["user-agent"]; const username = req.loggedInUser ? req.loggedInUser.username : null; - let mediaFunction = undefined; + let mediaFunction; if (type === "movie") { console.log("movie"); diff --git a/src/webserver/controllers/plex/updateRequested.js b/src/webserver/controllers/plex/updateRequested.js index 3194a03..0fd4b18 100644 --- a/src/webserver/controllers/plex/updateRequested.js +++ b/src/webserver/controllers/plex/updateRequested.js @@ -10,8 +10,8 @@ const requestRepository = new RequestRepository(); */ function updateRequested(req, res) { const id = req.params.requestId; - const type = req.body.type; - const status = req.body.status; + const { type } = req.body; + const { status } = req.body; requestRepository .updateRequestedById(id, type, status) diff --git a/src/webserver/controllers/plex/watchDirectLink.js b/src/webserver/controllers/plex/watchDirectLink.js index a56f85d..13c4eb1 100644 --- a/src/webserver/controllers/plex/watchDirectLink.js +++ b/src/webserver/controllers/plex/watchDirectLink.js @@ -1,5 +1,6 @@ const configuration = require("../../../config/configuration").getInstance(); const Plex = require("../../../plex/plex"); + const plex = new Plex(configuration.get("plex", "ip")); /** diff --git a/src/webserver/controllers/request/fetchAllRequests.js b/src/webserver/controllers/request/fetchAllRequests.js index 7679169..c6f8ae2 100644 --- a/src/webserver/controllers/request/fetchAllRequests.js +++ b/src/webserver/controllers/request/fetchAllRequests.js @@ -1,4 +1,5 @@ const RequestRepository = require("../../../request/request"); + const request = new RequestRepository(); /** @@ -8,9 +9,9 @@ const request = new RequestRepository(); * @returns {Callback} */ function fetchAllRequests(req, res) { - let { page, filter, sort, query } = req.query; + const { page, filter, sort, query } = req.query; let sort_by = sort; - let sort_direction = undefined; + let sort_direction; if (sort !== undefined && sort.includes(":")) { [sort_by, sort_direction] = sort.split(":"); diff --git a/src/webserver/controllers/request/getRequest.js b/src/webserver/controllers/request/getRequest.js index 9167e95..ec79520 100644 --- a/src/webserver/controllers/request/getRequest.js +++ b/src/webserver/controllers/request/getRequest.js @@ -1,4 +1,5 @@ const RequestRepository = require("../../../request/request"); + const request = new RequestRepository(); /** @@ -8,7 +9,7 @@ const request = new RequestRepository(); * @returns {Callback} */ function fetchAllRequests(req, res) { - const id = req.params.id; + const { id } = req.params; const { type } = req.query; request diff --git a/src/webserver/controllers/request/requestTmdbId.js b/src/webserver/controllers/request/requestTmdbId.js index a4e6185..139e560 100644 --- a/src/webserver/controllers/request/requestTmdbId.js +++ b/src/webserver/controllers/request/requestTmdbId.js @@ -1,6 +1,7 @@ const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); const RequestRepository = require("../../../request/request"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const request = new RequestRepository(); // const { sendSMS } = require("src/notifications/sms"); @@ -26,7 +27,7 @@ function requestTmdbIdController(req, res) { const user_agent = req.headers["user-agent"]; const username = req.loggedInUser ? req.loggedInUser.username : null; - let mediaFunction = undefined; + let mediaFunction; if (id === undefined || type === undefined) { res.status(422).send({ diff --git a/src/webserver/controllers/search/movieSearch.js b/src/webserver/controllers/search/movieSearch.js index bfee6d1..3fa329d 100644 --- a/src/webserver/controllers/search/movieSearch.js +++ b/src/webserver/controllers/search/movieSearch.js @@ -1,6 +1,7 @@ const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); const SearchHistory = require("../../../searchHistory/searchHistory"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const searchHistory = new SearchHistory(); @@ -13,7 +14,7 @@ const searchHistory = new SearchHistory(); function movieSearchController(req, res) { const { query, page, adult } = req.query; const username = req.loggedInUser ? req.loggedInUser.username : null; - const includeAdult = adult == "true" ? true : false; + const includeAdult = adult == "true"; if (username) { searchHistory.create(username, query); diff --git a/src/webserver/controllers/search/multiSearch.js b/src/webserver/controllers/search/multiSearch.js index db977c7..5172612 100644 --- a/src/webserver/controllers/search/multiSearch.js +++ b/src/webserver/controllers/search/multiSearch.js @@ -1,11 +1,12 @@ -const configuration = require("../../..//config/configuration").getInstance(); +const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); const SearchHistory = require("../../../searchHistory/searchHistory"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const searchHistory = new SearchHistory(); function checkAndCreateJsonResponse(result) { - if (typeof result["createJsonResponse"] === "function") { + if (typeof result.createJsonResponse === "function") { return result.createJsonResponse(); } return result; diff --git a/src/webserver/controllers/search/personSearch.js b/src/webserver/controllers/search/personSearch.js index dbd11c1..4a3699f 100644 --- a/src/webserver/controllers/search/personSearch.js +++ b/src/webserver/controllers/search/personSearch.js @@ -1,6 +1,7 @@ const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); const SearchHistory = require("../../../searchHistory/searchHistory"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const searchHistory = new SearchHistory(); @@ -13,7 +14,7 @@ const searchHistory = new SearchHistory(); function personSearchController(req, res) { const { query, page, adult } = req.query; const username = req.loggedInUser ? req.loggedInUser.username : null; - const includeAdult = adult == "true" ? true : false; + const includeAdult = adult == "true"; if (username) { searchHistory.create(username, query); diff --git a/src/webserver/controllers/search/showSearch.js b/src/webserver/controllers/search/showSearch.js index cd420c4..2566010 100644 --- a/src/webserver/controllers/search/showSearch.js +++ b/src/webserver/controllers/search/showSearch.js @@ -1,6 +1,7 @@ const SearchHistory = require("../../../searchHistory/searchHistory"); const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const searchHistory = new SearchHistory(); @@ -13,7 +14,7 @@ const searchHistory = new SearchHistory(); function showSearchController(req, res) { const { query, page, adult } = req.query; const username = req.loggedInUser ? req.loggedInUser.username : null; - const includeAdult = adult == "true" ? true : false; + const includeAdult = adult == "true"; if (username) { searchHistory.create(username, query); diff --git a/src/webserver/controllers/show/credits.js b/src/webserver/controllers/show/credits.js index b7014a5..f381efd 100644 --- a/src/webserver/controllers/show/credits.js +++ b/src/webserver/controllers/show/credits.js @@ -1,5 +1,6 @@ const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const showCreditsController = (req, res) => { @@ -16,11 +17,9 @@ const showCreditsController = (req, res) => { } else { // TODO log unhandled errors console.log("caugth show credits controller error", error); - res - .status(500) - .send({ - message: "An unexpected error occured while requesting show credits" - }); + res.status(500).send({ + message: "An unexpected error occured while requesting show credits" + }); } }); }; diff --git a/src/webserver/controllers/show/info.js b/src/webserver/controllers/show/info.js index 322c381..9ae9e58 100644 --- a/src/webserver/controllers/show/info.js +++ b/src/webserver/controllers/show/info.js @@ -1,6 +1,7 @@ const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); const Plex = require("../../../plex/plex"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const plex = new Plex(configuration.get("plex", "ip")); @@ -35,7 +36,7 @@ async function showInfoController(req, res) { ? (check_existance = true) : (check_existance = false); - let tmdbQueue = [tmdb.showInfo(showId)]; + const tmdbQueue = [tmdb.showInfo(showId)]; if (credits) tmdbQueue.push(tmdb.showCredits(showId)); try { diff --git a/src/webserver/controllers/user/authenticatePlexAccount.js b/src/webserver/controllers/user/authenticatePlexAccount.js index 19a2749..4e5a09c 100644 --- a/src/webserver/controllers/user/authenticatePlexAccount.js +++ b/src/webserver/controllers/user/authenticatePlexAccount.js @@ -1,4 +1,5 @@ const UserRepository = require("../../../user/userRepository"); + const userRepository = new UserRepository(); const fetch = require("node-fetch"); const FormData = require("form-data"); diff --git a/src/webserver/controllers/user/login.js b/src/webserver/controllers/user/login.js index c0098ca..0438a89 100644 --- a/src/webserver/controllers/user/login.js +++ b/src/webserver/controllers/user/login.js @@ -27,7 +27,7 @@ const cookieOptions = { */ async function loginController(req, res) { const user = new User(req.body.username); - const password = req.body.password; + const { password } = req.body; try { const [loggedIn, isAdmin, settings] = await Promise.all([ @@ -43,11 +43,7 @@ async function loginController(req, res) { }); } - const token = new Token( - user, - isAdmin === 1 ? true : false, - settings - ).toString(secret); + const token = new Token(user, isAdmin === 1, settings).toString(secret); return res.cookie("authorization", token, cookieOptions).status(200).send({ success: true, diff --git a/src/webserver/controllers/user/register.js b/src/webserver/controllers/user/register.js index e3a5d71..2c36f4e 100644 --- a/src/webserver/controllers/user/register.js +++ b/src/webserver/controllers/user/register.js @@ -24,7 +24,7 @@ const cookieOptions = { */ function registerController(req, res) { const user = new User(req.body.username, req.body.email); - const password = req.body.password; + const { password } = req.body; userSecurity .createNewUser(user, password) diff --git a/src/webserver/controllers/user/settings.js b/src/webserver/controllers/user/settings.js index b69b322..caf55f8 100644 --- a/src/webserver/controllers/user/settings.js +++ b/src/webserver/controllers/user/settings.js @@ -1,4 +1,5 @@ const UserRepository = require("../../../user/userRepository"); + const userRepository = new UserRepository(); /** * Controller: Retrieves settings of a logged in user diff --git a/src/webserver/controllers/user/viewHistory.js b/src/webserver/controllers/user/viewHistory.js index 8a5334e..99725e5 100644 --- a/src/webserver/controllers/user/viewHistory.js +++ b/src/webserver/controllers/user/viewHistory.js @@ -1,5 +1,6 @@ const configuration = require("../../../config/configuration").getInstance(); const Tautulli = require("../../../tautulli/tautulli"); + const apiKey = configuration.get("tautulli", "apiKey"); const ip = configuration.get("tautulli", "ip"); const port = configuration.get("tautulli", "port"); @@ -10,12 +11,11 @@ function handleError(error, res) { if (status && message) { return res.status(status).send({ success: false, message }); - } else { - console.log("caught view history controller error", error); - return res.status(500).send({ - message: "An unexpected error occured while fetching view history" - }); } + console.log("caught view history controller error", error); + return res.status(500).send({ + message: "An unexpected error occured while fetching view history" + }); } function watchTimeStatsController(req, res) { diff --git a/src/webserver/middleware/mustBeAdmin.js b/src/webserver/middleware/mustBeAdmin.js index be516c6..4ee3bb6 100644 --- a/src/webserver/middleware/mustBeAdmin.js +++ b/src/webserver/middleware/mustBeAdmin.js @@ -1,29 +1,28 @@ const establishedDatabase = require("../../database/database"); const mustBeAdmin = (req, res, next) => { - let database = establishedDatabase; + const database = establishedDatabase; if (req.loggedInUser === undefined) { return res.status(401).send({ success: false, message: "You must be logged in." }); - } else { - database - .get( - `SELECT admin FROM user WHERE user_name IS ?`, - req.loggedInUser.username - ) - .then(isAdmin => { - console.log(isAdmin, req.loggedInUser); - if (isAdmin.admin == 0) { - return res.status(401).send({ - success: false, - message: "You must be logged in as a admin." - }); - } - }); } + database + .get( + `SELECT admin FROM user WHERE user_name IS ?`, + req.loggedInUser.username + ) + .then(isAdmin => { + console.log(isAdmin, req.loggedInUser); + if (isAdmin.admin == 0) { + return res.status(401).send({ + success: false, + message: "You must be logged in as a admin." + }); + } + }); return next(); }; diff --git a/src/webserver/middleware/mustHaveAccountLinkedToPlex.js b/src/webserver/middleware/mustHaveAccountLinkedToPlex.js index d3413d0..c1ce4a5 100644 --- a/src/webserver/middleware/mustHaveAccountLinkedToPlex.js +++ b/src/webserver/middleware/mustHaveAccountLinkedToPlex.js @@ -1,35 +1,33 @@ const establishedDatabase = require("../../database/database"); const mustHaveAccountLinkedToPlex = (req, res, next) => { - let database = establishedDatabase; - const loggedInUser = req.loggedInUser; + const database = establishedDatabase; + const { loggedInUser } = req; if (loggedInUser === undefined) { return res.status(401).send({ success: false, message: "You must have your account linked to a plex account." }); - } else { - database - .get( - `SELECT plex_userid FROM settings WHERE user_name IS ?`, - loggedInUser.username - ) - .then(row => { - const plex_userid = row.plex_userid; - - if (plex_userid === null || plex_userid === undefined) { - return res.status(403).send({ - success: false, - message: - "No plex account user id found for your user. Please authenticate your plex account at /user/authenticate." - }); - } else { - req.loggedInUser.plex_userid = plex_userid; - return next(); - } - }); } + database + .get( + `SELECT plex_userid FROM settings WHERE user_name IS ?`, + loggedInUser.username + ) + .then(row => { + const { plex_userid } = row; + + if (plex_userid === null || plex_userid === undefined) { + return res.status(403).send({ + success: false, + message: + "No plex account user id found for your user. Please authenticate your plex account at /user/authenticate." + }); + } + req.loggedInUser.plex_userid = plex_userid; + return next(); + }); }; module.exports = mustHaveAccountLinkedToPlex; -- 2.34.1 From e8ad9367c978a851ae888ec8b23c6983e8aa2b78 Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 19 Aug 2022 10:49:58 +0200 Subject: [PATCH 4/9] fix: updated plex_userid to camelcase --- src/tautulli/tautulli.js | 16 ++++++++-------- src/webserver/controllers/user/viewHistory.js | 8 ++++---- .../middleware/mustHaveAccountLinkedToPlex.js | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/tautulli/tautulli.js b/src/tautulli/tautulli.js index 3ac47bc..85adc6d 100644 --- a/src/tautulli/tautulli.js +++ b/src/tautulli/tautulli.js @@ -22,10 +22,10 @@ class Tautulli { throw error; } - getPlaysByDayOfWeek(plex_userid, days, y_axis) { + getPlaysByDayOfWeek(plexUserId, days, y_axis) { const url = this.buildUrlWithCmdAndUserid( "get_plays_by_dayofweek", - plex_userid + plexUserId ); url.searchParams.append("time_range", days); url.searchParams.append("y_axis", y_axis); @@ -35,8 +35,8 @@ class Tautulli { .catch(error => this.logTautulliError(error)); } - getPlaysByDays(plex_userid, days, y_axis) { - const url = this.buildUrlWithCmdAndUserid("get_plays_by_date", plex_userid); + getPlaysByDays(plexUserId, days, y_axis) { + const url = this.buildUrlWithCmdAndUserid("get_plays_by_date", plexUserId); url.searchParams.append("time_range", days); url.searchParams.append("y_axis", y_axis); @@ -45,10 +45,10 @@ class Tautulli { .catch(error => this.logTautulliError(error)); } - watchTimeStats(plex_userid) { + watchTimeStats(plexUserId) { const url = this.buildUrlWithCmdAndUserid( "get_user_watch_time_stats", - plex_userid + plexUserId ); url.searchParams.append("grouping", 0); @@ -57,8 +57,8 @@ class Tautulli { .catch(error => this.logTautulliError(error)); } - viewHistory(plex_userid) { - const url = this.buildUrlWithCmdAndUserid("get_history", plex_userid); + viewHistory(plexUserId) { + const url = this.buildUrlWithCmdAndUserid("get_history", plexUserId); url.searchParams.append("start", 0); url.searchParams.append("length", 50); diff --git a/src/webserver/controllers/user/viewHistory.js b/src/webserver/controllers/user/viewHistory.js index 99725e5..55b3077 100644 --- a/src/webserver/controllers/user/viewHistory.js +++ b/src/webserver/controllers/user/viewHistory.js @@ -22,7 +22,7 @@ function watchTimeStatsController(req, res) { const user = req.loggedInUser; return tautulli - .watchTimeStats(user.plex_userid) + .watchTimeStats(user.plexUserId) .then(data => { return res.send({ success: true, @@ -38,7 +38,7 @@ function getPlaysByDayOfWeekController(req, res) { const { days, y_axis } = req.query; return tautulli - .getPlaysByDayOfWeek(user.plex_userid, days, y_axis) + .getPlaysByDayOfWeek(user.plexUserId, days, y_axis) .then(data => res.send({ success: true, @@ -69,7 +69,7 @@ function getPlaysByDaysController(req, res) { } return tautulli - .getPlaysByDays(user.plex_userid, days, y_axis) + .getPlaysByDays(user.plexUserId, days, y_axis) .then(data => res.send({ success: true, @@ -86,7 +86,7 @@ function userViewHistoryController(req, res) { // and then return 501 Not implemented return tautulli - .viewHistory(user.plex_userid) + .viewHistory(user.plexUserId) .then(data => { return res.send({ success: true, diff --git a/src/webserver/middleware/mustHaveAccountLinkedToPlex.js b/src/webserver/middleware/mustHaveAccountLinkedToPlex.js index c1ce4a5..d7006d8 100644 --- a/src/webserver/middleware/mustHaveAccountLinkedToPlex.js +++ b/src/webserver/middleware/mustHaveAccountLinkedToPlex.js @@ -16,16 +16,16 @@ const mustHaveAccountLinkedToPlex = (req, res, next) => { loggedInUser.username ) .then(row => { - const { plex_userid } = row; + const plexUserId = row?.plex_userid; - if (plex_userid === null || plex_userid === undefined) { + if (plexUserId === null || plexUserId === undefined) { return res.status(403).send({ success: false, message: "No plex account user id found for your user. Please authenticate your plex account at /user/authenticate." }); } - req.loggedInUser.plex_userid = plex_userid; + req.loggedInUser.plexUserId = plexUserId; return next(); }); }; -- 2.34.1 From a98797088a05d66bcc5cf68cdae255da68c70549 Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 19 Aug 2022 11:22:29 +0200 Subject: [PATCH 5/9] Linted and some consistency refactor on middleware --- src/webserver/middleware/mustBeAdmin.js | 11 +++++---- .../middleware/mustBeAuthenticated.js | 4 +++- .../middleware/mustHaveAccountLinkedToPlex.js | 13 ++++++---- src/webserver/middleware/reqTokenToUser.js | 24 ++++++++----------- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/webserver/middleware/mustBeAdmin.js b/src/webserver/middleware/mustBeAdmin.js index 4ee3bb6..50e9c71 100644 --- a/src/webserver/middleware/mustBeAdmin.js +++ b/src/webserver/middleware/mustBeAdmin.js @@ -1,30 +1,31 @@ const establishedDatabase = require("../../database/database"); +// eslint-disable-next-line consistent-return const mustBeAdmin = (req, res, next) => { const database = establishedDatabase; if (req.loggedInUser === undefined) { - return res.status(401).send({ + res.status(401).send({ success: false, message: "You must be logged in." }); } + database .get( `SELECT admin FROM user WHERE user_name IS ?`, req.loggedInUser.username ) .then(isAdmin => { - console.log(isAdmin, req.loggedInUser); - if (isAdmin.admin == 0) { + if (isAdmin.admin === 0) { return res.status(401).send({ success: false, message: "You must be logged in as a admin." }); } - }); - return next(); + return next(); + }); }; module.exports = mustBeAdmin; diff --git a/src/webserver/middleware/mustBeAuthenticated.js b/src/webserver/middleware/mustBeAuthenticated.js index 6af925b..9a470db 100644 --- a/src/webserver/middleware/mustBeAuthenticated.js +++ b/src/webserver/middleware/mustBeAuthenticated.js @@ -1,3 +1,4 @@ +// eslint-disable-next-line consistent-return const mustBeAuthenticated = (req, res, next) => { if (req.loggedInUser === undefined) { return res.status(401).send({ @@ -5,7 +6,8 @@ const mustBeAuthenticated = (req, res, next) => { message: "You must be logged in." }); } - return next(); + + next(); }; module.exports = mustBeAuthenticated; diff --git a/src/webserver/middleware/mustHaveAccountLinkedToPlex.js b/src/webserver/middleware/mustHaveAccountLinkedToPlex.js index d7006d8..49e4849 100644 --- a/src/webserver/middleware/mustHaveAccountLinkedToPlex.js +++ b/src/webserver/middleware/mustHaveAccountLinkedToPlex.js @@ -1,33 +1,36 @@ const establishedDatabase = require("../../database/database"); +/* eslint-disable consistent-return */ const mustHaveAccountLinkedToPlex = (req, res, next) => { const database = establishedDatabase; const { loggedInUser } = req; - if (loggedInUser === undefined) { + if (loggedInUser === null) { return res.status(401).send({ success: false, message: "You must have your account linked to a plex account." }); } + database .get( `SELECT plex_userid FROM settings WHERE user_name IS ?`, loggedInUser.username ) .then(row => { - const plexUserId = row?.plex_userid; - - if (plexUserId === null || plexUserId === undefined) { + const plexUserId = row.plex_userid; + if (plexUserId === null) { return res.status(403).send({ success: false, message: "No plex account user id found for your user. Please authenticate your plex account at /user/authenticate." }); } + req.loggedInUser.plexUserId = plexUserId; - return next(); + next(); }); }; +/* eslint-enable consistent-return */ module.exports = mustHaveAccountLinkedToPlex; diff --git a/src/webserver/middleware/reqTokenToUser.js b/src/webserver/middleware/reqTokenToUser.js index 0b92cef..bde99f6 100644 --- a/src/webserver/middleware/reqTokenToUser.js +++ b/src/webserver/middleware/reqTokenToUser.js @@ -11,22 +11,18 @@ const reqTokenToUser = (req, res, next) => { const cookieAuthToken = req.cookies.authorization; const headerAuthToken = req.headers.authorization; - if (cookieAuthToken || headerAuthToken) { - try { - const token = Token.fromString( - cookieAuthToken || headerAuthToken, - secret - ); - req.loggedInUser = token.user; - } catch (error) { - req.loggedInUser = undefined; - } - } else { - // guest session - console.debug("No auth token in header or cookie."); + if (!(cookieAuthToken || headerAuthToken)) { + return next(); } - next(); + try { + const token = Token.fromString(cookieAuthToken || headerAuthToken, secret); + req.loggedInUser = token.user; + } catch (error) { + req.loggedInUser = null; + } + + return next(); }; module.exports = reqTokenToUser; -- 2.34.1 From 64dbec1f145c1d4bb11cf83aba8fa253508f2442 Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 19 Aug 2022 13:45:50 +0200 Subject: [PATCH 6/9] eslint uses ecmaversion 2020 & allow empty catch rule --- .eslintrc.json | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 9bbe884..e64f9ff 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,13 +1,17 @@ { "root": true, "parserOptions": { + "ecmaVersion": 2020, "sourceType": "module" }, - "extends": [ - "eslint-config-airbnb-base", - "plugin:prettier/recommended" - ], + "extends": ["eslint-config-airbnb-base", "plugin:prettier/recommended"], "rules": { + "no-empty": [ + 2, + { + "allowEmptyCatch": true + } + ], "no-underscore-dangle": "off", "no-shadow": "off" } -- 2.34.1 From b1d959389d77bdc24c42a507f377911f5db241f6 Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 19 Aug 2022 13:47:08 +0200 Subject: [PATCH 7/9] Started linting source files --- src/cache/redis.js | 11 +- src/config/configuration.js | 2 +- src/config/field.js | 4 +- src/database/sqliteDatabase.js | 5 +- src/media_classes/plex.js | 2 + src/media_classes/tmdb.js | 2 + src/notifications/sms.js | 13 +- src/pirate/pirateRepository.js | 14 +- src/plex/convertPlexToSeasoned.js | 3 +- src/plex/hookDump.js | 7 - src/plex/plex.js | 43 ++-- src/plex/requestRepository.js | 4 +- src/request/request.js | 99 ++------- src/request/utils.js | 6 +- src/searchHistory/searchHistory.js | 39 ++-- src/tautulli/tautulli.js | 29 ++- src/tmdb/tmdb.js | 95 ++++++--- src/tmdb/types.js | 10 +- src/tmdb/types.ts | 2 +- src/tmdb/types/credits.js | 103 +++++----- src/tmdb/types/movie.js | 2 + src/tmdb/types/person.js | 2 + src/tmdb/types/releaseDates.js | 106 +++++----- src/tmdb/types/show.js | 2 + src/user/userRepository.js | 48 ++--- src/user/userSecurity.js | 4 +- src/webserver/app.js | 86 ++++---- src/webserver/controllers/git/dumpHook.js | 8 +- .../controllers/list/listController.js | 7 +- src/webserver/controllers/movie/credits.js | 2 - src/webserver/controllers/movie/info.js | 40 ++-- .../controllers/movie/releaseDates.js | 2 - src/webserver/controllers/person/credits.js | 2 - src/webserver/controllers/person/info.js | 8 +- src/webserver/controllers/pirate/addMagnet.js | 11 +- .../controllers/plex/fetchRequested.js | 2 +- src/webserver/controllers/plex/hookDump.js | 12 +- .../controllers/plex/searchRequest.js | 6 +- .../controllers/plex/submitRequest.js | 6 +- .../controllers/plex/watchDirectLink.js | 2 +- .../controllers/request/fetchAllRequests.js | 12 +- .../controllers/request/requestTmdbId.js | 4 +- .../controllers/search/movieSearch.js | 4 +- .../controllers/search/multiSearch.js | 12 +- .../controllers/search/personSearch.js | 4 +- .../controllers/search/showSearch.js | 2 +- src/webserver/controllers/show/credits.js | 2 - src/webserver/controllers/show/info.js | 19 +- .../user/authenticatePlexAccount.js | 33 +-- src/webserver/controllers/user/register.js | 2 - src/webserver/controllers/user/requests.js | 2 +- src/webserver/controllers/user/settings.js | 7 +- src/webserver/controllers/user/viewHistory.js | 14 +- ...ade_runner_2049-info-success-response.json | 90 +++++++- ...rstellar-query-movie-success-response.json | 194 +++++++++++++++++- 55 files changed, 726 insertions(+), 526 deletions(-) delete mode 100644 src/plex/hookDump.js diff --git a/src/cache/redis.js b/src/cache/redis.js index 340d884..9318a31 100644 --- a/src/cache/redis.js +++ b/src/cache/redis.js @@ -1,4 +1,3 @@ -const { promisify } = require("util"); const configuration = require("../config/configuration").getInstance(); let client; @@ -16,7 +15,7 @@ try { client.on("connect", () => console.log("Redis connection established!")); - client.on("error", function (err) { + client.on("error", () => { client.quit(); console.error("Unable to connect to redis, setting up redis-mock."); @@ -38,7 +37,7 @@ function set(key, value, TTL = 10800) { const json = JSON.stringify(value); client.set(key, json, (error, reply) => { - if (reply == "OK") { + if (reply === "OK") { // successfully set value with key, now set TTL for key client.expire(key, TTL, e => { if (e) @@ -55,14 +54,14 @@ function set(key, value, TTL = 10800) { return value; } -function get() { +function get(key) { return new Promise((resolve, reject) => { client.get(key, (error, reply) => { - if (reply == null) { + if (reply === null) { return reject(); } - resolve(JSON.parse(reply)); + return resolve(JSON.parse(reply)); }); }); } diff --git a/src/config/configuration.js b/src/config/configuration.js index 0414dc4..9b9a192 100644 --- a/src/config/configuration.js +++ b/src/config/configuration.js @@ -1,5 +1,5 @@ const path = require("path"); -const Field = require("./field.js"); +const Field = require("./field"); let instance = null; diff --git a/src/config/field.js b/src/config/field.js index 546513b..4b86c80 100644 --- a/src/config/field.js +++ b/src/config/field.js @@ -1,5 +1,5 @@ -const Filters = require("./filters.js"); -const EnvironmentVariables = require("./environmentVariables.js"); +const Filters = require("./filters"); +const EnvironmentVariables = require("./environmentVariables"); class Field { constructor(rawValue, environmentVariables) { diff --git a/src/database/sqliteDatabase.js b/src/database/sqliteDatabase.js index a330487..a6f8e53 100644 --- a/src/database/sqliteDatabase.js +++ b/src/database/sqliteDatabase.js @@ -72,12 +72,11 @@ class SqliteDatabase { /** * Run a SQL query against the database and retrieve the status. * @param {String} sql SQL query - * @param {Array} parameters in the SQL query * @returns {Promise} */ execute(sql) { - return new Promise(resolve => { - this.connection.exec(sql, (err, database) => { + return new Promise((resolve, reject) => { + this.connection.exec(sql, err => { if (err) { console.log("ERROR: ", err); reject(err); diff --git a/src/media_classes/plex.js b/src/media_classes/plex.js index 2df0f77..2626e39 100644 --- a/src/media_classes/plex.js +++ b/src/media_classes/plex.js @@ -1,3 +1,5 @@ +/* eslint-disable camelcase */ + const Media = require("./media"); class Plex extends Media { diff --git a/src/media_classes/tmdb.js b/src/media_classes/tmdb.js index 724ac86..63a0c40 100644 --- a/src/media_classes/tmdb.js +++ b/src/media_classes/tmdb.js @@ -1,3 +1,5 @@ +/* eslint-disable camelcase */ + const Media = require("./media"); class TMDB extends Media { diff --git a/src/notifications/sms.js b/src/notifications/sms.js index a56587f..a8c80d7 100644 --- a/src/notifications/sms.js +++ b/src/notifications/sms.js @@ -1,6 +1,15 @@ const request = require("request"); const configuration = require("../config/configuration").getInstance(); +class SMSUnexpectedError extends Error { + constructor(errorMessage) { + const message = "Unexpected error from sms provider."; + super(message); + + this.errorMessage = errorMessage; + } +} + const sendSMS = message => { const apiKey = configuration.get("sms", "apikey"); @@ -24,8 +33,8 @@ const sendSMS = message => { } }, function (err, r, body) { - console.log(err || body); - console.log("sms provider response:", body); + const smsError = new SMSUnexpectedError(err || body); + console.error(smsError.message); resolve(); } ); diff --git a/src/pirate/pirateRepository.js b/src/pirate/pirateRepository.js index 70a030c..455ad0a 100644 --- a/src/pirate/pirateRepository.js +++ b/src/pirate/pirateRepository.js @@ -1,4 +1,3 @@ -const assert = require("assert"); const http = require("http"); const { URL } = require("url"); const PythonShell = require("python-shell"); @@ -8,12 +7,12 @@ const establishedDatabase = require("../database/database"); const cache = require("../cache/redis"); function getMagnetFromURL(url) { - return new Promise((resolve, reject) => { + return new Promise(resolve => { const options = new URL(url); if (options.protocol.includes("magnet")) resolve(url); http.get(options, res => { - if (res.statusCode == 301 || res.statusCode == 302) { + if (res.statusCode === 301 || res.statusCode === 302) { resolve(res.headers.location); } }); @@ -43,7 +42,6 @@ async function callPythonAddMagnet(url, callback) { PythonShell.run("deluge_cli.py", options, callback); }) .catch(err => { - console.log(err); throw new Error(err); }); } @@ -76,7 +74,7 @@ async function SearchPiratebay(query) { ); } -async function AddMagnet(magnet, name, tmdb_id) { +async function AddMagnet(magnet, name, tmdbId) { return await new Promise((resolve, reject) => callPythonAddMagnet(magnet, (err, results) => { if (err) { @@ -87,12 +85,12 @@ async function AddMagnet(magnet, name, tmdb_id) { /* eslint-disable no-console */ console.log("result/error:", err, results); - database = establishedDatabase; - insert_query = + const database = establishedDatabase; + const insert_query = "INSERT INTO requested_torrent(magnet,torrent_name,tmdb_id) \ VALUES (?,?,?)"; - const response = database.run(insert_query, [magnet, name, tmdb_id]); + const response = database.run(insert_query, [magnet, name, tmdbId]); console.log(`Response from requsted_torrent insert: ${response}`); resolve({ success: true }); diff --git a/src/plex/convertPlexToSeasoned.js b/src/plex/convertPlexToSeasoned.js index 40f1dcc..d216c23 100644 --- a/src/plex/convertPlexToSeasoned.js +++ b/src/plex/convertPlexToSeasoned.js @@ -1,3 +1,5 @@ +/* eslint-disable camelcase */ + const Plex = require("../media_classes/plex"); function translateAdded(date_string) { @@ -27,7 +29,6 @@ function convertPlexToSeasoned(plex) { seasons, episodes ); - // seasoned.print(); return seasoned; } diff --git a/src/plex/hookDump.js b/src/plex/hookDump.js deleted file mode 100644 index 5a34b2e..0000000 --- a/src/plex/hookDump.js +++ /dev/null @@ -1,7 +0,0 @@ -const configuration = require("../config/configuration").getInstance(); - -function hookDumpController(req, res) { - console.log(req); -} - -module.exports = hookDumpController; diff --git a/src/plex/plex.js b/src/plex/plex.js index 9108dcb..628c862 100644 --- a/src/plex/plex.js +++ b/src/plex/plex.js @@ -3,8 +3,6 @@ const convertPlexToMovie = require("./convertPlexToMovie"); const convertPlexToShow = require("./convertPlexToShow"); const convertPlexToEpisode = require("./convertPlexToEpisode"); -const { Movie, Show, Person } = require("../tmdb/types"); - const redisCache = require("../cache/redis"); const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, ""); @@ -19,15 +17,14 @@ const matchingTitleAndYear = (plex, tmdb) => { let matchingTitle; let matchingYear; - if (plex.title != null && tmdb.title != null) { + if (plex?.title && tmdb?.title) { const plexTitle = sanitize(plex.title); const tmdbTitle = sanitize(tmdb.title); - matchingTitle = plexTitle == tmdbTitle; + matchingTitle = plexTitle === tmdbTitle; matchingTitle = matchingTitle || plexTitle.startsWith(tmdbTitle); } else matchingTitle = false; - if (plex.year != null && tmdb.year != null) - matchingYear = plex.year == tmdb.year; + if (plex?.year && tmdb?.year) matchingYear = plex.year === tmdb.year; else matchingYear = false; return matchingTitle && matchingYear; @@ -37,9 +34,9 @@ const successfullResponse = response => { if (response && response.MediaContainer) return response; if ( - response == null || - response.status == null || - response.statusText == null + response === null || + response.status === null || + response.statusText === null ) { throw Error("Unable to decode response"); } @@ -83,7 +80,7 @@ class Plex { ) .then(machineInfo => resolve(machineInfo.machineIdentifier)) .catch(error => { - if (error != undefined && error.type === "request-timeout") { + if (error !== undefined && error.type === "request-timeout") { reject({ message: "Plex did not respond", status: 408, @@ -99,7 +96,7 @@ class Plex { matchTmdbAndPlexMedia(plex, tmdb) { let match; - if (plex == null || tmdb == null) return false; + if (plex === null || tmdb === null) return false; if (plex instanceof Array) { const possibleMatches = plex.map(plexItem => @@ -129,7 +126,7 @@ class Plex { this.matchTmdbAndPlexMedia(plex, query) ); const matchesIndex = matchesInPlex.findIndex(el => el === true); - return matchesInPlex != -1 ? plexResults[matchesIndex] : null; + return matchesInPlex !== -1 ? plexResults[matchesIndex] : null; }); } @@ -145,10 +142,10 @@ class Plex { matchingObjectInPlexPromise ]).then(([machineIdentifier, matchingObjectInPlex]) => { if ( - matchingObjectInPlex == false || - matchingObjectInPlex == null || - matchingObjectInPlex.key == null || - machineIdentifier == null + matchingObjectInPlex === false || + matchingObjectInPlex === null || + matchingObjectInPlex.key === null || + machineIdentifier === null ) return false; @@ -177,7 +174,7 @@ class Plex { .then(this.mapResults) .then(resolve) .catch(error => { - if (error != undefined && error.type === "request-timeout") { + if (error !== undefined && error.type === "request-timeout") { reject({ message: "Plex did not respond", status: 408, @@ -202,7 +199,7 @@ class Plex { cacheKey, (error, response => { - if (response == 1) return true; + if (response === 1) return true; // TODO improve cache key matching by lowercasing it on the backend. // what do we actually need to check for if the key was deleted or not @@ -213,11 +210,7 @@ class Plex { } mapResults(response) { - if ( - response == null || - response.MediaContainer == null || - response.MediaContainer.Hub == null - ) { + if (response?.MediaContainer?.Hub === null) { return []; } @@ -232,8 +225,10 @@ class Plex { if (category.type === "episode") { return category.Metadata.map(convertPlexToEpisode); } + + return null; }) - .filter(result => result !== undefined); + .filter(result => result !== null); } } diff --git a/src/plex/requestRepository.js b/src/plex/requestRepository.js index fcf480e..8a01d5f 100644 --- a/src/plex/requestRepository.js +++ b/src/plex/requestRepository.js @@ -66,7 +66,7 @@ class RequestRepository { * @param {identifier, type} the id of the media object and type of media must be defined * @returns {Promise} If nothing has gone wrong. */ - sendRequest(identifier, type, ip, user_agent, user) { + sendRequest(identifier, type, ip, userAgent, user) { return Promise.resolve() .then(() => tmdb.lookup(identifier, type)) .then(movie => { @@ -80,7 +80,7 @@ class RequestRepository { movie.background_path, username, ip, - user_agent, + userAgent, movie.type ]); }); diff --git a/src/request/request.js b/src/request/request.js index 14ca0dc..922e933 100644 --- a/src/request/request.js +++ b/src/request/request.js @@ -4,7 +4,6 @@ const TMDB = require("../tmdb/tmdb"); const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const establishedDatabase = require("../database/database"); -const utils = require("./utils"); class RequestRepository { constructor(database) { @@ -19,76 +18,23 @@ class RequestRepository { 'select count(*) as totalRequests from requests where status != "downloaded"', totalRequestsFilteredStatus: "select count(*) as totalRequests from requests where status = ?", - fetchAllSort: `select id, type from request order by ? ?`, - fetchAllFilter: `select id, type from request where ? is "?"`, - fetchAllQuery: `select id, type from request where title like "%?%" or year like "%?%"`, - fetchAllFilterAndSort: `select id, type from request where ? is "?" order by ? ?`, - downloaded: - "(select status from requests where id is request.id and type is request.type limit 1)", + // fetchAllSort: `select id, type from request order by ? ?`, + // fetchAllFilter: `select id, type from request where ? is "?"`, + // fetchAllQuery: `select id, type from request where title like "%?%" or year like "%?%"`, + // fetchAllFilterAndSort: `select id, type from request where ? is "?" order by ? ?`, + // downloaded: "(select status from requests where id is request.id and type is request.type limit 1)", // deluge: '(select status from deluge_torrent where id is request.id and type is request.type limit 1)', // fetchAllFilterStatus: 'select * from request where ' - readWithoutUserData: - "select id, title, year, type, status, date from requests where id is ? and type is ?", + // readWithoutUserData: "select id, title, year, type, status, date from requests where id is ? and type is ?", read: "select id, title, year, type, status, requested_by, ip, date, user_agent from requests where id is ? and type is ?" }; } - sortAndFilterToDbQuery(by, direction, filter, query) { - let dbQuery; - - if (query !== undefined) { - const dbParams = [query, query]; - const dbquery = this.queries.fetchAllQuery; - - dbQuery = dbquery - .split("") - .map(char => (char === "?" ? dbParams.shift() : char)) - .join(""); - } else if (by !== undefined && filter !== undefined) { - const paramToColumnAndValue = { - movie: ["type", "movie"], - show: ["type", "show"] - }; - const dbParams = paramToColumnAndValue[filter].concat([by, direction]); - const query = this.queries.fetchAllFilterAndSort; - - dbQuery = query - .split("") - .map(char => (char === "?" ? dbParams.shift() : char)) - .join(""); - } else if (by !== undefined) { - const dbParams = [by, direction]; - const query = this.queries.fetchAllSort; - - dbQuery = query - .split("") - .map(char => (char === "?" ? dbParams.shift() : char)) - .join(""); - } else if (filter !== undefined) { - const paramToColumnAndValue = { - movie: ["type", "movie"], - show: ["type", "show"], - downloaded: [this.queries.downloaded, "downloaded"] - // downloading: [this.database.delugeStatus, 'downloading'] - }; - const dbParams = paramToColumnAndValue[filter]; - const query = this.queries.fetchAllFilter; - - dbQuery = query - .split("") - .map(char => (char === "?" ? dbParams.shift() : char)) - .join(""); - } else { - dbQuery = this.queries.fetchAll; - } - - return dbQuery; - } - mapToTmdbByType(rows) { return rows.map(row => { if (row.type === "movie") return tmdb.movieInfo(row.id); if (row.type === "show") return tmdb.showInfo(row.id); + return null; }); } @@ -97,7 +43,7 @@ class RequestRepository { * @param {tmdb} tmdb class of movie|show to add * @returns {Promise} */ - requestFromTmdb(tmdb, ip, user_agent, username) { + requestFromTmdb(tmdb, ip, userAgent, username) { return Promise.resolve() .then(() => this.database.get(this.queries.read, [tmdb.id, tmdb.type])) .then(row => @@ -112,7 +58,7 @@ class RequestRepository { tmdb.backdrop, username, ip, - user_agent, + userAgent, tmdb.type ]) ) @@ -153,20 +99,12 @@ class RequestRepository { /** * Fetch all requests with optional sort and filter params * @param {String} what we are sorting by - * @param {String} direction that can be either 'asc' or 'desc', default 'asc'. * @param {String} params to filter by - * @param {String} query param to filter result on. Filters on title and year * @returns {Promise} */ - fetchAll( - page = 1, - sort_by = undefined, - sort_direction = "asc", - filter = undefined, - query = undefined - ) { + fetchAll(_page = 1, filter = null) { // TODO implemented sort and filter - page = parseInt(page); + const page = parseInt(_page); let fetchQuery = this.queries.fetchAll; let fetchTotalResults = this.queries.totalRequests; let fetchParams = [page]; @@ -177,26 +115,24 @@ class RequestRepository { filter === "downloaded" || filter === "requested") ) { - console.log("tes"); fetchQuery = this.queries.fetchAllFilteredStatus; fetchTotalResults = this.queries.totalRequestsFilteredStatus; fetchParams = [filter, page]; - } else { - filter = undefined; } - return Promise.resolve() - .then(dbQuery => this.database.all(fetchQuery, fetchParams)) + return this.database + .all(fetchQuery, fetchParams) .then(async rows => { const sqliteResponse = await this.database.get( fetchTotalResults, - filter || undefined + filter || null ); const { totalRequests } = sqliteResponse; const totalPages = Math.ceil(totalRequests / 26); return [ - rows.map(item => { + rows.map(_item => { + const item = _item; item.poster = item.poster_path; delete item.poster_path; item.backdrop = item.background_path; @@ -206,7 +142,8 @@ class RequestRepository { totalPages, totalRequests ]; - return Promise.all(this.mapToTmdbByType(rows)); + + return this.mapToTmdbByType(rows); }) .then(([result, totalPages, totalRequests]) => Promise.resolve({ diff --git a/src/request/utils.js b/src/request/utils.js index 6cbe37a..67756c0 100644 --- a/src/request/utils.js +++ b/src/request/utils.js @@ -29,13 +29,13 @@ function validSort(by, direction) { }); } -function validFilter(filter_param) { +function validFilter(filterParam) { return new Promise((resolve, reject) => { - if (filter_param === undefined) { + if (filterParam === undefined) { resolve(); } - if (filter_param && validFilterParams.includes(filter_param)) { + if (filterParam && validFilterParams.includes(filterParam)) { resolve(); } else { reject( diff --git a/src/searchHistory/searchHistory.js b/src/searchHistory/searchHistory.js index 15fdcb1..9c25380 100644 --- a/src/searchHistory/searchHistory.js +++ b/src/searchHistory/searchHistory.js @@ -1,5 +1,15 @@ const establishedDatabase = require("../database/database"); +class SearchHistoryCreateDatabaseError extends Error { + constructor(message = "an unexpected error occured", errorResponse = null) { + super(message); + + this.source = "database"; + this.statusCode = 500; + this.errorResponse = errorResponse; + } +} + class SearchHistory { constructor(database) { this.database = database || establishedDatabase; @@ -16,18 +26,12 @@ class SearchHistory { * @returns {Promise} */ read(user) { - return new Promise((resolve, reject) => - this.database - .all(this.queries.read, user) - .then((result, error) => { - if (error) throw new Error(error); - resolve(result.map(row => row.search_query)); - }) - .catch(error => { - console.log("Error when fetching history from database:", error); - reject("Unable to get history."); - }) - ); + return this.database + .all(this.queries.read, user) + .then(result => result.map(row => row.search_query)) + .catch(error => { + throw new Error("Unable to get history.", error); + }); } /** @@ -41,15 +45,12 @@ class SearchHistory { .run(this.queries.create, [searchQuery, username]) .catch(error => { if (error.message.includes("FOREIGN")) { - throw new Error("Could not create search history."); + throw new SearchHistoryCreateDatabaseError( + "Could not create search history." + ); } - throw { - success: false, - status: 500, - message: "An unexpected error occured", - source: "database" - }; + throw new SearchHistoryCreateDatabaseError(); }); } } diff --git a/src/tautulli/tautulli.js b/src/tautulli/tautulli.js index 85adc6d..cccd8a7 100644 --- a/src/tautulli/tautulli.js +++ b/src/tautulli/tautulli.js @@ -1,5 +1,15 @@ const fetch = require("node-fetch"); +class TautulliUnexpectedError extends Error { + constructor(errorMessage) { + const message = "Unexpected error fetching from tautulli."; + super(message); + + this.statusCode = 500; + this.errorMessage = errorMessage; + } +} + class Tautulli { constructor(apiKey, ip, port) { this.apiKey = apiKey; @@ -7,38 +17,37 @@ class Tautulli { this.port = port; } - buildUrlWithCmdAndUserid(cmd, user_id) { + buildUrlWithCmdAndUserid(cmd, userId) { const url = new URL("api/v2", `http://${this.ip}:${this.port}`); url.searchParams.append("apikey", this.apiKey); url.searchParams.append("cmd", cmd); - url.searchParams.append("user_id", user_id); + url.searchParams.append("user_id", userId); return url; } + /* eslint-disable-next-line class-methods-use-this */ logTautulliError(error) { - console.error("error fetching from tautulli"); - - throw error; + throw new TautulliUnexpectedError(error); } - getPlaysByDayOfWeek(plexUserId, days, y_axis) { + getPlaysByDayOfWeek(plexUserId, days, yAxis) { const url = this.buildUrlWithCmdAndUserid( "get_plays_by_dayofweek", plexUserId ); url.searchParams.append("time_range", days); - url.searchParams.append("y_axis", y_axis); + url.searchParams.append("y_axis", yAxis); return fetch(url.href) .then(resp => resp.json()) .catch(error => this.logTautulliError(error)); } - getPlaysByDays(plexUserId, days, y_axis) { + getPlaysByDays(plexUserId, days, yAxis) { const url = this.buildUrlWithCmdAndUserid("get_plays_by_date", plexUserId); url.searchParams.append("time_range", days); - url.searchParams.append("y_axis", y_axis); + url.searchParams.append("y_axis", yAxis); return fetch(url.href) .then(resp => resp.json()) @@ -63,8 +72,6 @@ class Tautulli { url.searchParams.append("start", 0); url.searchParams.append("length", 50); - console.log("fetching url", url.href); - return fetch(url.href) .then(resp => resp.json()) .catch(error => this.logTautulliError(error)); diff --git a/src/tmdb/tmdb.js b/src/tmdb/tmdb.js index 9110167..bddb86f 100644 --- a/src/tmdb/tmdb.js +++ b/src/tmdb/tmdb.js @@ -3,25 +3,41 @@ const redisCache = require("../cache/redis"); const { Movie, Show, Person, Credits, ReleaseDates } = require("./types"); -const tmdbErrorResponse = (error, typeString = undefined) => { +class TMDBNotFoundError extends Error { + constructor(message) { + super(message); + + this.statusCode = 404; + } +} + +class TMDBUnauthorizedError extends Error { + constructor(message = "TMDB returned access denied, requires api token.") { + super(message); + + this.statusCode = 401; + } +} + +class TMDBUnexpectedError extends Error { + constructor(type) { + const message = `An unexpected error occured while fetching ${type} from tmdb`; + super(message); + + this.statusCode = 500; + } +} + +const tmdbErrorResponse = (error, type = null) => { if (error.status === 404) { const message = error.response.body.status_message; - throw { - status: 404, - message: `${message.slice(0, -1)} in tmdb.` - }; + throw new TMDBNotFoundError(`${message.slice(0, -1)} in tmdb.`); } else if (error.status === 401) { - throw { - status: 401, - message: error.response.body.status_message - }; + throw new TMDBUnauthorizedError(error?.response?.body?.status_message); } - throw { - status: 500, - message: `An unexpected error occured while fetching ${typeString} from tmdb` - }; + throw new TMDBUnexpectedError(type); }; class TMDB { @@ -166,9 +182,9 @@ class TMDB { .then(credits => Credits.convertFromTmdbResponse(credits)); } - multiSearch(search_query, page = 1, include_adult = true) { - const query = { query: search_query, page, include_adult }; - const cacheKey = `tmdb/${this.cacheTags.multiSearch}:${page}:${search_query}:${include_adult}`; + multiSearch(searchQuery, page = 1, includeAdult = true) { + const query = { query: searchQuery, page, include_adult: includeAdult }; + const cacheKey = `tmdb/${this.cacheTags.multiSearch}:${page}:${searchQuery}:${includeAdult}`; return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMulti", query) .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) @@ -181,9 +197,13 @@ class TMDB { * @param {Number} page representing pagination of results * @returns {Promise} dict with query results, current page and total_pages */ - movieSearch(search_query, page = 1, include_adult = true) { - const tmdbquery = { query: search_query, page, include_adult }; - const cacheKey = `tmdb/${this.cacheTags.movieSearch}:${page}:${search_query}:${include_adult}`; + movieSearch(searchQuery, page = 1, includeAdult = true) { + const tmdbquery = { + query: searchQuery, + page, + include_adult: includeAdult + }; + const cacheKey = `tmdb/${this.cacheTags.movieSearch}:${page}:${searchQuery}:${includeAdult}`; return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMovie", tmdbquery) .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) @@ -196,9 +216,13 @@ class TMDB { * @param {Number} page representing pagination of results * @returns {Promise} dict with query results, current page and total_pages */ - showSearch(search_query, page = 1, include_adult = true) { - const tmdbquery = { query: search_query, page, include_adult }; - const cacheKey = `tmdb/${this.cacheTags.showSearch}:${page}:${search_query}:${include_adult}`; + showSearch(searchQuery, page = 1, includeAdult = true) { + const tmdbquery = { + query: searchQuery, + page, + include_adult: includeAdult + }; + const cacheKey = `tmdb/${this.cacheTags.showSearch}:${page}:${searchQuery}:${includeAdult}`; return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchTv", tmdbquery) .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) @@ -211,27 +235,31 @@ class TMDB { * @param {Number} page representing pagination of results * @returns {Promise} dict with query results, current page and total_pages */ - personSearch(search_query, page = 1, include_adult = true) { - const tmdbquery = { query: search_query, page, include_adult }; - const cacheKey = `tmdb/${this.cacheTags.personSearch}:${page}:${search_query}:${include_adult}`; + personSearch(searchQuery, page = 1, includeAdult = true) { + const tmdbquery = { + query: searchQuery, + page, + include_adult: includeAdult + }; + const cacheKey = `tmdb/${this.cacheTags.personSearch}:${page}:${searchQuery}:${includeAdult}`; return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchPerson", tmdbquery) .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) .then(response => this.mapResults(response, "person")); } - movieList(listname, page = 1) { + movieList(listName, page = 1) { const query = { page }; - const cacheKey = `tmdb/${this.cacheTags[listname]}:${page}`; + const cacheKey = `tmdb/${this.cacheTags[listName]}:${page}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, listname, query) + return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query) .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) .then(response => this.mapResults(response, "movie")); } - showList(listname, page = 1) { + showList(listName, page = 1) { const query = { page }; - const cacheKey = `tmdb/${this.cacheTags[listname]}:${page}`; + const cacheKey = `tmdb/${this.cacheTags[listName]}:${page}`; return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query) .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) @@ -244,8 +272,9 @@ class TMDB { * @param {String} The type declared in listSearch. * @returns {Promise} dict with tmdb results, mapped as movie/show objects. */ + // eslint-disable-next-line class-methods-use-this mapResults(response, type = undefined) { - const results = response.results.map(result => { + const results = response?.results?.map(result => { if (type === "movie" || result.media_type === "movie") { const movie = Movie.convertFromTmdbResponse(result); return movie.createJsonResponse(); @@ -258,6 +287,8 @@ class TMDB { const person = Person.convertFromTmdbResponse(result); return person.createJsonResponse(); } + + return {}; }); return { @@ -280,7 +311,7 @@ class TMDB { if (error) { return reject(error); } - resolve(reponse); + return resolve(reponse); }; if (!argument) { diff --git a/src/tmdb/types.js b/src/tmdb/types.js index f3a831a..cbf5cbc 100644 --- a/src/tmdb/types.js +++ b/src/tmdb/types.js @@ -1,7 +1,7 @@ -const Movie = require("./types/movie.js"); -const Show = require("./types/show.js"); -const Person = require("./types/person.js"); -const Credits = require("./types/credits.js"); -const ReleaseDates = require("./types/releaseDates.js"); +const Movie = require("./types/movie"); +const Show = require("./types/show"); +const Person = require("./types/person"); +const Credits = require("./types/credits"); +const ReleaseDates = require("./types/releaseDates"); module.exports = { Movie, Show, Person, Credits, ReleaseDates }; diff --git a/src/tmdb/types.ts b/src/tmdb/types.ts index 89e2f8a..e079157 100644 --- a/src/tmdb/types.ts +++ b/src/tmdb/types.ts @@ -61,4 +61,4 @@ interface Genre { name: string; } -export { Movie, Show, Person, Genre } +export { Movie, Show, Person, Genre }; diff --git a/src/tmdb/types/credits.js b/src/tmdb/types/credits.js index b32a557..8740b6d 100644 --- a/src/tmdb/types/credits.js +++ b/src/tmdb/types/credits.js @@ -1,5 +1,55 @@ -import Movie from "./movie"; -import Show from "./show"; +/* eslint-disable camelcase */ +const Movie = require("./movie"); +const Show = require("./show"); + +class CreditedMovie extends Movie {} +class CreditedShow extends Show {} + +class CastMember { + constructor(character, gender, id, name, profile_path) { + this.character = character; + this.gender = gender; + this.id = id; + this.name = name; + this.profile_path = profile_path; + this.type = "person"; + } + + createJsonResponse() { + return { + character: this.character, + gender: this.gender, + id: this.id, + name: this.name, + profile_path: this.profile_path, + type: this.type + }; + } +} + +class CrewMember { + constructor(department, gender, id, job, name, profile_path) { + this.department = department; + this.gender = gender; + this.id = id; + this.job = job; + this.name = name; + this.profile_path = profile_path; + this.type = "person"; + } + + createJsonResponse() { + return { + department: this.department, + gender: this.gender, + id: this.id, + job: this.job, + name: this.name, + profile_path: this.profile_path, + type: this.type + }; + } +} class Credits { constructor(id, cast = [], crew = []) { @@ -63,53 +113,4 @@ class Credits { } } -class CastMember { - constructor(character, gender, id, name, profile_path) { - this.character = character; - this.gender = gender; - this.id = id; - this.name = name; - this.profile_path = profile_path; - this.type = "person"; - } - - createJsonResponse() { - return { - character: this.character, - gender: this.gender, - id: this.id, - name: this.name, - profile_path: this.profile_path, - type: this.type - }; - } -} - -class CrewMember { - constructor(department, gender, id, job, name, profile_path) { - this.department = department; - this.gender = gender; - this.id = id; - this.job = job; - this.name = name; - this.profile_path = profile_path; - this.type = "person"; - } - - createJsonResponse() { - return { - department: this.department, - gender: this.gender, - id: this.id, - job: this.job, - name: this.name, - profile_path: this.profile_path, - type: this.type - }; - } -} - -class CreditedMovie extends Movie {} -class CreditedShow extends Show {} - module.exports = Credits; diff --git a/src/tmdb/types/movie.js b/src/tmdb/types/movie.js index 09b5816..db78856 100644 --- a/src/tmdb/types/movie.js +++ b/src/tmdb/types/movie.js @@ -1,3 +1,5 @@ +/* eslint-disable camelcase */ + class Movie { constructor( id, diff --git a/src/tmdb/types/person.js b/src/tmdb/types/person.js index 67ca569..2cd24d9 100644 --- a/src/tmdb/types/person.js +++ b/src/tmdb/types/person.js @@ -1,3 +1,5 @@ +/* eslint-disable camelcase */ + class Person { constructor( id, diff --git a/src/tmdb/types/releaseDates.js b/src/tmdb/types/releaseDates.js index 02b6a4a..94ffa31 100644 --- a/src/tmdb/types/releaseDates.js +++ b/src/tmdb/types/releaseDates.js @@ -1,3 +1,57 @@ +const releaseTypeEnum = { + 1: "Premier", + 2: "Limited theatrical", + 3: "Theatrical", + 4: "Digital", + 5: "Physical", + 6: "TV" +}; + +class Release { + constructor(country, releaseDates) { + this.country = country; + this.releaseDates = releaseDates; + } + + createJsonResponse() { + return { + country: this.country, + release_dates: this.releaseDates.map(releaseDate => + releaseDate.createJsonResponse() + ) + }; + } +} + +class ReleaseDate { + constructor(certification, language, releaseDate, type, note) { + this.certification = certification; + this.language = language; + this.releaseDate = releaseDate; + this.type = this.releaseTypeLookup(type); + this.note = note; + } + + static releaseTypeLookup(releaseTypeKey) { + if (releaseTypeKey <= Object.keys(releaseTypeEnum).length) { + return releaseTypeEnum[releaseTypeKey]; + } + + // TODO log | Release type not defined, does this need updating? + return null; + } + + createJsonResponse() { + return { + certification: this.certification, + language: this.language, + release_date: this.releaseDate, + type: this.type, + note: this.note + }; + } +} + class ReleaseDates { constructor(id, releases) { this.id = id; @@ -35,56 +89,4 @@ class ReleaseDates { } } -class Release { - constructor(country, releaseDates) { - this.country = country; - this.releaseDates = releaseDates; - } - - createJsonResponse() { - return { - country: this.country, - release_dates: this.releaseDates.map(releaseDate => - releaseDate.createJsonResponse() - ) - }; - } -} - -class ReleaseDate { - constructor(certification, language, releaseDate, type, note) { - this.certification = certification; - this.language = language; - this.releaseDate = releaseDate; - this.type = this.releaseTypeLookup(type); - this.note = note; - } - - releaseTypeLookup(releaseTypeKey) { - const releaseTypeEnum = { - 1: "Premier", - 2: "Limited theatrical", - 3: "Theatrical", - 4: "Digital", - 5: "Physical", - 6: "TV" - }; - if (releaseTypeKey <= Object.keys(releaseTypeEnum).length) { - return releaseTypeEnum[releaseTypeKey]; - } - // TODO log | Release type not defined, does this need updating? - return null; - } - - createJsonResponse() { - return { - certification: this.certification, - language: this.language, - release_date: this.releaseDate, - type: this.type, - note: this.note - }; - } -} - module.exports = ReleaseDates; diff --git a/src/tmdb/types/show.js b/src/tmdb/types/show.js index 995a4de..cbbf434 100644 --- a/src/tmdb/types/show.js +++ b/src/tmdb/types/show.js @@ -1,3 +1,5 @@ +/* eslint-disable camelcase */ + class Show { constructor( id, diff --git a/src/user/userRepository.js b/src/user/userRepository.js index 4f9683c..6022f48 100644 --- a/src/user/userRepository.js +++ b/src/user/userRepository.js @@ -51,8 +51,7 @@ class UserRepository { assert(row, "The user does not exist."); return row.password; }) - .catch(err => { - console.log(error); + .catch(() => { throw new Error("Unable to find your user."); }); } @@ -78,17 +77,14 @@ class UserRepository { this.database .run(this.queries.link, [plexUserID, username]) .then(row => resolve(row)) - .catch(error => { - // TODO log this unknown db error - console.error("db error", error); - + .catch(error => reject({ status: 500, message: "An unexpected error occured while linking plex and seasoned accounts", source: "seasoned database" - }); - }); + }) + ); }); } @@ -102,17 +98,14 @@ class UserRepository { this.database .run(this.queries.unlink, username) .then(row => resolve(row)) - .catch(error => { - // TODO log this unknown db error - console.log("db error", error); - + .catch(error => reject({ status: 500, message: "An unexpected error occured while unlinking plex and seasoned accounts", source: "seasoned database" - }); - }); + }) + ); }); } @@ -162,18 +155,14 @@ class UserRepository { resolve(row); }) - .catch(error => { - console.error( - "Unexpected error occured while fetching settings for your account. Error:", - error - ); + .catch(() => reject({ status: 500, message: "An unexpected error occured while fetching settings for your account", source: "seasoned database" - }); - }); + }) + ); }); } @@ -184,12 +173,12 @@ class UserRepository { * @param {String} emoji * @returns {Promsie} */ - updateSettings(username, dark_mode = undefined, emoji = undefined) { + updateSettings(username, darkMode = null, emoji = null) { const settings = this.getSettings(username); - dark_mode = dark_mode !== undefined ? dark_mode : settings.dark_mode; - emoji = emoji !== undefined ? emoji : settings.emoji; + darkMode = darkMode ? darkMode : settings.darkMode; + emoji = emoji ? emoji : settings.emoji; - return this.dbUpdateSettings(username, dark_mode, emoji).catch(error => { + return this.dbUpdateSettings(username, darkMode, emoji).catch(error => { if (error.status && error.message) { return error; } @@ -225,10 +214,10 @@ class UserRepository { * @param {String} username * @returns {Promsie} */ - dbUpdateSettings(username, dark_mode, emoji) { - return new Promise((resolve, reject) => + dbUpdateSettings(username, darkMode, emoji) { + return new Promise(resolve => this.database - .run(this.queries.updateSettings, [username, dark_mode, emoji]) + .run(this.queries.updateSettings, [username, darkMode, emoji]) .then(row => resolve(row)) ); } @@ -240,7 +229,6 @@ const rejectUnexpectedDatabaseError = ( error, reject = null ) => { - console.error(error); const body = { status, message, @@ -248,7 +236,7 @@ const rejectUnexpectedDatabaseError = ( }; if (reject == null) { - return new Promise((resolve, reject) => reject(body)); + return new Promise((_, reject) => reject(body)); } reject(body); }; diff --git a/src/user/userSecurity.js b/src/user/userSecurity.js index ea07bb8..5caef59 100644 --- a/src/user/userSecurity.js +++ b/src/user/userSecurity.js @@ -50,7 +50,7 @@ class UserSecurity { return new Promise((resolve, reject) => { bcrypt.compare(clearPassword, hash, (error, match) => { if (match) resolve(true); - reject(false); + reject(error); }); }); } @@ -61,7 +61,7 @@ class UserSecurity { * @returns {Promise} */ static hashPassword(clearPassword) { - return new Promise(resolve => { + return new Promise((resolve, reject) => { const saltRounds = 10; bcrypt.hash(clearPassword, saltRounds, (error, hash) => { if (error) reject(error); diff --git a/src/webserver/app.js b/src/webserver/app.js index e184f5c..859c4a4 100644 --- a/src/webserver/app.js +++ b/src/webserver/app.js @@ -11,7 +11,7 @@ const mustBeAdmin = require("./middleware/mustBeAdmin"); const mustHaveAccountLinkedToPlex = require("./middleware/mustHaveAccountLinkedToPlex"); const listController = require("./controllers/list/listController"); -const tautulli = require("./controllers/user/viewHistory.js"); +const tautulli = require("./controllers/user/viewHistory"); const SettingsController = require("./controllers/user/settings"); const AuthenticatePlexAccountController = require("./controllers/user/authenticatePlexAccount"); @@ -24,7 +24,7 @@ app.use(bodyParser.json()); app.use(cookieParser()); const router = express.Router(); -const allowedOrigins = configuration.get("webserver", "origins"); +// const allowedOrigins = configuration.get("webserver", "origins"); // TODO: All JSON handling in a single router // router.use(bodyParser.json()); @@ -57,7 +57,7 @@ router.get("/", (req, res) => { }); app.use(Raven.errorHandler()); -app.use((err, req, res, next) => { +app.use((err, req, res) => { res.statusCode = 500; res.end(`${res.sentry}\n`); }); @@ -65,9 +65,9 @@ app.use((err, req, res, next) => { /** * User */ -router.post("/v1/user", require("./controllers/user/register.js")); -router.post("/v1/user/login", require("./controllers/user/login.js")); -router.post("/v1/user/logout", require("./controllers/user/logout.js")); +router.post("/v1/user", require("./controllers/user/register")); +router.post("/v1/user/login", require("./controllers/user/login")); +router.post("/v1/user/logout", require("./controllers/user/logout")); router.get( "/v1/user/settings", @@ -82,12 +82,12 @@ router.put( router.get( "/v1/user/search_history", mustBeAuthenticated, - require("./controllers/user/searchHistory.js") + require("./controllers/user/searchHistory") ); router.get( "/v1/user/requests", mustBeAuthenticated, - require("./controllers/user/requests.js") + require("./controllers/user/requests") ); router.post( @@ -125,46 +125,40 @@ router.get( /** * Seasoned */ -router.get("/v1/seasoned/all", require("./controllers/seasoned/readStrays.js")); +router.get("/v1/seasoned/all", require("./controllers/seasoned/readStrays")); router.get( "/v1/seasoned/:strayId", - require("./controllers/seasoned/strayById.js") + require("./controllers/seasoned/strayById") ); router.post( "/v1/seasoned/verify/:strayId", - require("./controllers/seasoned/verifyStray.js") + require("./controllers/seasoned/verifyStray") ); -router.get("/v2/search/", require("./controllers/search/multiSearch.js")); -router.get("/v2/search/movie", require("./controllers/search/movieSearch.js")); -router.get("/v2/search/show", require("./controllers/search/showSearch.js")); -router.get( - "/v2/search/person", - require("./controllers/search/personSearch.js") -); +router.get("/v2/search/", require("./controllers/search/multiSearch")); +router.get("/v2/search/movie", require("./controllers/search/movieSearch")); +router.get("/v2/search/show", require("./controllers/search/showSearch")); +router.get("/v2/search/person", require("./controllers/search/personSearch")); router.get("/v2/movie/now_playing", listController.nowPlayingMovies); router.get("/v2/movie/popular", listController.popularMovies); router.get("/v2/movie/top_rated", listController.topRatedMovies); router.get("/v2/movie/upcoming", listController.upcomingMovies); -router.get("/v2/movie/:id/credits", require("./controllers/movie/credits.js")); +router.get("/v2/movie/:id/credits", require("./controllers/movie/credits")); router.get( "/v2/movie/:id/release_dates", - require("./controllers/movie/releaseDates.js") + require("./controllers/movie/releaseDates") ); -router.get("/v2/movie/:id", require("./controllers/movie/info.js")); +router.get("/v2/movie/:id", require("./controllers/movie/info")); router.get("/v2/show/now_playing", listController.nowPlayingShows); router.get("/v2/show/popular", listController.popularShows); router.get("/v2/show/top_rated", listController.topRatedShows); -router.get("/v2/show/:id/credits", require("./controllers/show/credits.js")); -router.get("/v2/show/:id", require("./controllers/show/info.js")); +router.get("/v2/show/:id/credits", require("./controllers/show/credits")); +router.get("/v2/show/:id", require("./controllers/show/info")); -router.get( - "/v2/person/:id/credits", - require("./controllers/person/credits.js") -); -router.get("/v2/person/:id", require("./controllers/person/info.js")); +router.get("/v2/person/:id/credits", require("./controllers/person/credits")); +router.get("/v2/person/:id", require("./controllers/person/info")); /** * Plex @@ -174,40 +168,40 @@ router.get("/v2/plex/search", require("./controllers/plex/search")); /** * List */ -router.get("/v1/plex/search", require("./controllers/plex/searchMedia.js")); -router.get("/v1/plex/playing", require("./controllers/plex/plexPlaying.js")); -router.get("/v1/plex/request", require("./controllers/plex/searchRequest.js")); +router.get("/v1/plex/search", require("./controllers/plex/searchMedia")); +router.get("/v1/plex/playing", require("./controllers/plex/plexPlaying")); +router.get("/v1/plex/request", require("./controllers/plex/searchRequest")); router.get( "/v1/plex/request/:mediaId", - require("./controllers/plex/readRequest.js") + require("./controllers/plex/readRequest") ); router.post( "/v1/plex/request/:mediaId", - require("./controllers/plex/submitRequest.js") + require("./controllers/plex/submitRequest") ); -router.post("/v1/plex/hook", require("./controllers/plex/hookDump.js")); +router.post("/v1/plex/hook", require("./controllers/plex/hookDump")); router.get( "/v1/plex/watch-link", mustBeAuthenticated, - require("./controllers/plex/watchDirectLink.js") + require("./controllers/plex/watchDirectLink") ); /** * Requests */ -router.get("/v2/request", require("./controllers/request/fetchAllRequests.js")); -router.get("/v2/request/:id", require("./controllers/request/getRequest.js")); -router.post("/v2/request", require("./controllers/request/requestTmdbId.js")); +router.get("/v2/request", require("./controllers/request/fetchAllRequests")); +router.get("/v2/request/:id", require("./controllers/request/getRequest")); +router.post("/v2/request", require("./controllers/request/requestTmdbId")); router.get( "/v1/plex/requests/all", - require("./controllers/plex/fetchRequested.js") + require("./controllers/plex/fetchRequested") ); router.put( "/v1/plex/request/:requestId", mustBeAuthenticated, - require("./controllers/plex/updateRequested.js") + require("./controllers/plex/updateRequested") ); /** @@ -215,24 +209,24 @@ router.put( */ router.get( "/v1/pirate/search", - mustBeAuthenticated, - require("./controllers/pirate/searchTheBay.js") + mustBeAdmin, + require("./controllers/pirate/searchTheBay") ); router.post( "/v1/pirate/add", - mustBeAuthenticated, - require("./controllers/pirate/addMagnet.js") + mustBeAdmin, + require("./controllers/pirate/addMagnet") ); /** * git */ -router.post("/v1/git/dump", require("./controllers/git/dumpHook.js")); +router.post("/v1/git/dump", require("./controllers/git/dumpHook")); /** * misc */ -router.get("/v1/emoji", require("./controllers/misc/emoji.js")); +router.get("/v1/emoji", require("./controllers/misc/emoji")); // REGISTER OUR ROUTES ------------------------------- // all of our routes will be prefixed with /api diff --git a/src/webserver/controllers/git/dumpHook.js b/src/webserver/controllers/git/dumpHook.js index bed04f5..5016893 100644 --- a/src/webserver/controllers/git/dumpHook.js +++ b/src/webserver/controllers/git/dumpHook.js @@ -5,12 +5,8 @@ const gitRepository = new GitRepository(); function dumpHookController(req, res) { gitRepository .dumpHook(req.body) - .then(() => { - res.status(200); - }) - .catch(error => { - res.status(500); - }); + .then(() => res.status(200)) + .catch(() => res.status(500)); } module.exports = dumpHookController; diff --git a/src/webserver/controllers/list/listController.js b/src/webserver/controllers/list/listController.js index 9557099..2b55c59 100644 --- a/src/webserver/controllers/list/listController.js +++ b/src/webserver/controllers/list/listController.js @@ -21,17 +21,12 @@ function handleError(error, res) { if (status && message) { res.status(status).send({ success: false, message }); } else { - console.log("caught list controller error", error); res .status(500) .send({ message: "An unexpected error occured while requesting list" }); } } -function handleListResponse(response, res) { - return res.send(response).catch(error => handleError(error, res)); -} - function fetchTmdbList(req, res, listname, type) { const { page } = req.query; @@ -48,7 +43,7 @@ function fetchTmdbList(req, res, listname, type) { .catch(error => handleError(error, res)); } - handleError( + return handleError( { status: 400, message: `'${type}' is not a valid list type.` diff --git a/src/webserver/controllers/movie/credits.js b/src/webserver/controllers/movie/credits.js index f8ec6c1..ce33c5f 100644 --- a/src/webserver/controllers/movie/credits.js +++ b/src/webserver/controllers/movie/credits.js @@ -15,8 +15,6 @@ const movieCreditsController = (req, res) => { if (status && message) { res.status(status).send({ success: false, message }); } else { - // TODO log unhandled errors - console.log("caugth movie credits controller error", error); res.status(500).send({ message: "An unexpected error occured while requesting movie credits" }); diff --git a/src/webserver/controllers/movie/info.js b/src/webserver/controllers/movie/info.js index 5d31b7e..f22889f 100644 --- a/src/webserver/controllers/movie/info.js +++ b/src/webserver/controllers/movie/info.js @@ -1,6 +1,7 @@ const configuration = require("../../../config/configuration").getInstance(); const TMDB = require("../../../tmdb/tmdb"); const Plex = require("../../../plex/plex"); + const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const plex = new Plex(configuration.get("plex", "ip")); @@ -10,9 +11,10 @@ function handleError(error, res) { if (status && message) { res.status(status).send({ success: false, message }); } else { - console.log("caught movieinfo controller error", error); res.status(500).send({ - message: "An unexpected error occured while requesting movie info" + success: false, + message: "An unexpected error occured while requesting movie info", + errorResponse: error?.message }); } } @@ -25,21 +27,18 @@ function handleError(error, res) { */ async function movieInfoController(req, res) { const movieId = req.params.id; - let { credits, release_dates, check_existance } = req.query; - credits && credits.toLowerCase() === "true" - ? (credits = true) - : (credits = false); - release_dates && release_dates.toLowerCase() === "true" - ? (release_dates = true) - : (release_dates = false); - check_existance && check_existance.toLowerCase() === "true" - ? (check_existance = true) - : (check_existance = false); + let credits = req.query?.credits; + let releaseDates = req.query?.release_dates; + let checkExistance = req.query?.check_existance; - let tmdbQueue = [tmdb.movieInfo(movieId)]; + credits = credits.toLowerCase() === "true"; + releaseDates = releaseDates.toLowerCase() === "true"; + checkExistance = checkExistance.toLowerCase() === "true"; + + const tmdbQueue = [tmdb.movieInfo(movieId)]; if (credits) tmdbQueue.push(tmdb.movieCredits(movieId)); - if (release_dates) tmdbQueue.push(tmdb.movieReleaseDates(movieId)); + if (releaseDates) tmdbQueue.push(tmdb.movieReleaseDates(movieId)); try { const [Movie, Credits, ReleaseDates] = await Promise.all(tmdbQueue); @@ -47,19 +46,12 @@ async function movieInfoController(req, res) { const movie = Movie.createJsonResponse(); if (Credits) movie.credits = Credits.createJsonResponse(); if (ReleaseDates) - movie.release_dates = ReleaseDates.createJsonResponse().results; + movie.releaseDates = ReleaseDates.createJsonResponse().results; - if (check_existance) { + if (checkExistance) { try { movie.exists_in_plex = await plex.existsInPlex(movie); - } catch (error) { - if (error.status === 401) { - console.log("Unathorized request, check plex server LAN settings"); - } else { - console.log("Unkown error from plex!"); - } - console.log(error?.message); - } + } catch {} } res.send(movie); diff --git a/src/webserver/controllers/movie/releaseDates.js b/src/webserver/controllers/movie/releaseDates.js index 84bd43b..8097002 100644 --- a/src/webserver/controllers/movie/releaseDates.js +++ b/src/webserver/controllers/movie/releaseDates.js @@ -15,8 +15,6 @@ const movieReleaseDatesController = (req, res) => { if (status && message) { res.status(status).send({ success: false, message }); } else { - // TODO log unhandled errors : here our at tmdbReleaseError ? - console.log("caugth release dates controller error", error); res.status(500).send({ message: "An unexpected error occured while requesting movie credits" }); diff --git a/src/webserver/controllers/person/credits.js b/src/webserver/controllers/person/credits.js index 19eb5c2..414936a 100644 --- a/src/webserver/controllers/person/credits.js +++ b/src/webserver/controllers/person/credits.js @@ -15,8 +15,6 @@ const personCreditsController = (req, res) => { if (status && message) { res.status(status).send({ success: false, message }); } else { - // TODO log unhandled errors - console.log("caugth show credits controller error", error); res.status(500).send({ message: "An unexpected error occured while requesting person credits" }); diff --git a/src/webserver/controllers/person/info.js b/src/webserver/controllers/person/info.js index 87c91ff..c57436f 100644 --- a/src/webserver/controllers/person/info.js +++ b/src/webserver/controllers/person/info.js @@ -9,7 +9,6 @@ function handleError(error, res) { if (status && message) { res.status(status).send({ success: false, message }); } else { - console.log("caught personinfo controller error", error); res.status(500).send({ message: "An unexpected error occured while requesting person info." }); @@ -26,11 +25,8 @@ function handleError(error, res) { async function personInfoController(req, res) { const personId = req.params.id; let { credits } = req.query; - arguments; - credits && credits.toLowerCase() === "true" - ? (credits = true) - : (credits = false); + credits = credits.toLowerCase() === "true"; const tmdbQueue = [tmdb.personInfo(personId)]; if (credits) tmdbQueue.push(tmdb.personCredits(personId)); @@ -43,7 +39,7 @@ async function personInfoController(req, res) { return res.send(person); } catch (error) { - handleError(error, res); + return handleError(error, res); } } diff --git a/src/webserver/controllers/pirate/addMagnet.js b/src/webserver/controllers/pirate/addMagnet.js index 7dfbbdd..2ff7599 100644 --- a/src/webserver/controllers/pirate/addMagnet.js +++ b/src/webserver/controllers/pirate/addMagnet.js @@ -8,14 +8,11 @@ const PirateRepository = require("../../../pirate/pirateRepository"); function addMagnet(req, res) { - const { magnet } = req.body; - const { name } = req.body; - const { tmdb_id } = req.body; + const { magnet, name } = req.body; + const tmdbId = req.body?.tmdb_id; - PirateRepository.AddMagnet(magnet, name, tmdb_id) - .then(result => { - res.send(result); - }) + PirateRepository.AddMagnet(magnet, name, tmdbId) + .then(result => res.send(result)) .catch(error => { res.status(500).send({ success: false, message: error.message }); }); diff --git a/src/webserver/controllers/plex/fetchRequested.js b/src/webserver/controllers/plex/fetchRequested.js index 56eeaaa..14ba536 100644 --- a/src/webserver/controllers/plex/fetchRequested.js +++ b/src/webserver/controllers/plex/fetchRequested.js @@ -1,4 +1,4 @@ -const RequestRepository = require("../../../plex/requestRepository.js"); +const RequestRepository = require("../../../plex/requestRepository"); const requestRepository = new RequestRepository(); diff --git a/src/webserver/controllers/plex/hookDump.js b/src/webserver/controllers/plex/hookDump.js index 15682a0..bd39fcb 100644 --- a/src/webserver/controllers/plex/hookDump.js +++ b/src/webserver/controllers/plex/hookDump.js @@ -1,12 +1,8 @@ -/* - * @Author: KevinMidboe - * @Date: 2017-05-03 23:26:46 - * @Last Modified by: KevinMidboe - * @Last Modified time: 2018-02-06 20:54:22 - */ - function hookDumpController(req, res) { - console.log(req); + // eslint-disable-next-line no-console + console.log("plex hook dump:", req); + + res.status(200); } module.exports = hookDumpController; diff --git a/src/webserver/controllers/plex/searchRequest.js b/src/webserver/controllers/plex/searchRequest.js index c040f48..b7ce101 100644 --- a/src/webserver/controllers/plex/searchRequest.js +++ b/src/webserver/controllers/plex/searchRequest.js @@ -1,6 +1,6 @@ const SearchHistory = require("../../../searchHistory/searchHistory"); const Cache = require("../../../tmdb/cache"); -const RequestRepository = require("../../../plex/requestRepository.js"); +const RequestRepository = require("../../../plex/requestRepository"); const cache = new Cache(); const requestRepository = new RequestRepository(cache); @@ -10,8 +10,8 @@ function searchRequestController(req, res) { const { query, page, type } = req.query; const username = req.loggedInUser ? req.loggedInUser.username : null; - Promise.resolve() - .then(() => searchHistory.create(username, query)) + searchHistory + .create(username, query) .then(() => requestRepository.search(query, page, type)) .then(searchResult => { res.send(searchResult); diff --git a/src/webserver/controllers/plex/submitRequest.js b/src/webserver/controllers/plex/submitRequest.js index c06083a..6039c47 100644 --- a/src/webserver/controllers/plex/submitRequest.js +++ b/src/webserver/controllers/plex/submitRequest.js @@ -24,16 +24,14 @@ function submitRequestController(req, res) { const id = req.params.mediaId; const type = req.query.type ? req.query.type.toLowerCase() : undefined; const ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress; - const user_agent = req.headers["user-agent"]; + const userAgent = req.headers["user-agent"]; const username = req.loggedInUser ? req.loggedInUser.username : null; let mediaFunction; if (type === "movie") { - console.log("movie"); mediaFunction = tmdbMovieInfo; } else if (type === "show") { - console.log("show"); mediaFunction = tmdbShowInfo; } else { res.status(422).send({ @@ -49,7 +47,7 @@ function submitRequestController(req, res) { mediaFunction(id) .then(tmdbMedia => - request.requestFromTmdb(tmdbMedia, ip, user_agent, username) + request.requestFromTmdb(tmdbMedia, ip, userAgent, username) ) .then(() => res.send({ success: true, message: "Media item successfully requested" }) diff --git a/src/webserver/controllers/plex/watchDirectLink.js b/src/webserver/controllers/plex/watchDirectLink.js index 13c4eb1..dabee21 100644 --- a/src/webserver/controllers/plex/watchDirectLink.js +++ b/src/webserver/controllers/plex/watchDirectLink.js @@ -16,7 +16,7 @@ function watchDirectLink(req, res) { plex .getDirectLinkByTitleAndYear(title, year) .then(plexDirectLink => { - if (plexDirectLink == false) + if (plexDirectLink === false) res.status(404).send({ success: true, link: null }); else res.status(200).send({ success: true, link: plexDirectLink }); }) diff --git a/src/webserver/controllers/request/fetchAllRequests.js b/src/webserver/controllers/request/fetchAllRequests.js index c6f8ae2..c20ea23 100644 --- a/src/webserver/controllers/request/fetchAllRequests.js +++ b/src/webserver/controllers/request/fetchAllRequests.js @@ -9,16 +9,10 @@ const request = new RequestRepository(); * @returns {Callback} */ function fetchAllRequests(req, res) { - const { page, filter, sort, query } = req.query; - let sort_by = sort; - let sort_direction; + const { page, filter } = req.query; - if (sort !== undefined && sort.includes(":")) { - [sort_by, sort_direction] = sort.split(":"); - } - - Promise.resolve() - .then(() => request.fetchAll(page, sort_by, sort_direction, filter, query)) + request + .fetchAll(page, filter) .then(result => res.send(result)) .catch(error => { res.status(404).send({ success: false, message: error.message }); diff --git a/src/webserver/controllers/request/requestTmdbId.js b/src/webserver/controllers/request/requestTmdbId.js index 139e560..01d5c1a 100644 --- a/src/webserver/controllers/request/requestTmdbId.js +++ b/src/webserver/controllers/request/requestTmdbId.js @@ -24,7 +24,7 @@ function requestTmdbIdController(req, res) { const { id, type } = req.body; const ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress; - const user_agent = req.headers["user-agent"]; + const userAgent = req.headers["user-agent"]; const username = req.loggedInUser ? req.loggedInUser.username : null; let mediaFunction; @@ -50,7 +50,7 @@ function requestTmdbIdController(req, res) { mediaFunction(id) // .catch((error) => { console.error(error); res.status(404).send({ success: false, error: 'Id not found' }) }) .then(tmdbMedia => { - request.requestFromTmdb(tmdbMedia, ip, user_agent, username); + request.requestFromTmdb(tmdbMedia, ip, userAgent, username); // TODO enable SMS // const url = `https://request.movie?${tmdbMedia.type}=${tmdbMedia.id}`; diff --git a/src/webserver/controllers/search/movieSearch.js b/src/webserver/controllers/search/movieSearch.js index 3fa329d..8d216c4 100644 --- a/src/webserver/controllers/search/movieSearch.js +++ b/src/webserver/controllers/search/movieSearch.js @@ -14,7 +14,7 @@ const searchHistory = new SearchHistory(); function movieSearchController(req, res) { const { query, page, adult } = req.query; const username = req.loggedInUser ? req.loggedInUser.username : null; - const includeAdult = adult == "true"; + const includeAdult = adult === "true"; if (username) { searchHistory.create(username, query); @@ -29,8 +29,6 @@ function movieSearchController(req, res) { if (status && message) { res.status(status).send({ success: false, message }); } else { - // TODO log unhandled errors - console.log("caugth movie search controller error", error); res.status(500).send({ message: `An unexpected error occured while searching movies with query: ${query}` }); diff --git a/src/webserver/controllers/search/multiSearch.js b/src/webserver/controllers/search/multiSearch.js index 5172612..b96a4f1 100644 --- a/src/webserver/controllers/search/multiSearch.js +++ b/src/webserver/controllers/search/multiSearch.js @@ -5,13 +5,6 @@ const SearchHistory = require("../../../searchHistory/searchHistory"); const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const searchHistory = new SearchHistory(); -function checkAndCreateJsonResponse(result) { - if (typeof result.createJsonResponse === "function") { - return result.createJsonResponse(); - } - return result; -} - /** * Controller: Search for multi (movies, shows and people by query and pagey * @param {Request} req http request variable @@ -21,13 +14,14 @@ function checkAndCreateJsonResponse(result) { function multiSearchController(req, res) { const { query, page, adult } = req.query; const username = req.loggedInUser ? req.loggedInUser.username : null; + const includeAdult = adult === "true"; if (username) { searchHistory.create(username, query); } return tmdb - .multiSearch(query, page, adult) + .multiSearch(query, page, includeAdult) .then(multiSearchResults => res.send(multiSearchResults)) .catch(error => { const { status, message } = error; @@ -35,8 +29,6 @@ function multiSearchController(req, res) { if (status && message) { res.status(status).send({ success: false, message }); } else { - // TODO log unhandled errors - console.log("caugth multi search controller error", error); res.status(500).send({ message: `An unexpected error occured while searching with query: ${query}` }); diff --git a/src/webserver/controllers/search/personSearch.js b/src/webserver/controllers/search/personSearch.js index 4a3699f..c908dea 100644 --- a/src/webserver/controllers/search/personSearch.js +++ b/src/webserver/controllers/search/personSearch.js @@ -14,7 +14,7 @@ const searchHistory = new SearchHistory(); function personSearchController(req, res) { const { query, page, adult } = req.query; const username = req.loggedInUser ? req.loggedInUser.username : null; - const includeAdult = adult == "true"; + const includeAdult = adult === "true"; if (username) { searchHistory.create(username, query); @@ -29,8 +29,6 @@ function personSearchController(req, res) { if (status && message) { res.status(status).send({ success: false, message }); } else { - // TODO log unhandled errors - console.log("caugth person search controller error", error); res.status(500).send({ message: `An unexpected error occured while searching people with query: ${query}` }); diff --git a/src/webserver/controllers/search/showSearch.js b/src/webserver/controllers/search/showSearch.js index 2566010..740f763 100644 --- a/src/webserver/controllers/search/showSearch.js +++ b/src/webserver/controllers/search/showSearch.js @@ -14,7 +14,7 @@ const searchHistory = new SearchHistory(); function showSearchController(req, res) { const { query, page, adult } = req.query; const username = req.loggedInUser ? req.loggedInUser.username : null; - const includeAdult = adult == "true"; + const includeAdult = adult === "true"; if (username) { searchHistory.create(username, query); diff --git a/src/webserver/controllers/show/credits.js b/src/webserver/controllers/show/credits.js index f381efd..bed66a9 100644 --- a/src/webserver/controllers/show/credits.js +++ b/src/webserver/controllers/show/credits.js @@ -15,8 +15,6 @@ const showCreditsController = (req, res) => { if (status && message) { res.status(status).send({ success: false, message }); } else { - // TODO log unhandled errors - console.log("caugth show credits controller error", error); res.status(500).send({ message: "An unexpected error occured while requesting show credits" }); diff --git a/src/webserver/controllers/show/info.js b/src/webserver/controllers/show/info.js index 9ae9e58..4eeba4a 100644 --- a/src/webserver/controllers/show/info.js +++ b/src/webserver/controllers/show/info.js @@ -11,7 +11,6 @@ function handleError(error, res) { if (status && message) { res.status(status).send({ success: false, message }); } else { - console.log("caught showinfo controller error", error); res.status(500).send({ message: "An unexpected error occured while requesting show info." }); @@ -27,14 +26,11 @@ function handleError(error, res) { async function showInfoController(req, res) { const showId = req.params.id; - let { credits, check_existance } = req.query; + let credits = req.query?.credits; + let checkExistance = req.query?.check_existance; - credits && credits.toLowerCase() === "true" - ? (credits = true) - : (credits = false); - check_existance && check_existance.toLowerCase() === "true" - ? (check_existance = true) - : (check_existance = false); + credits = credits?.toLowerCase() === "true"; + checkExistance = checkExistance?.toLowerCase() === "true"; const tmdbQueue = [tmdb.showInfo(showId)]; if (credits) tmdbQueue.push(tmdb.showCredits(showId)); @@ -45,7 +41,12 @@ async function showInfoController(req, res) { const show = Show.createJsonResponse(); if (credits) show.credits = Credits.createJsonResponse(); - if (check_existance) show.exists_in_plex = await plex.existsInPlex(show); + if (checkExistance) { + /* eslint no-empty: ["error", { "allowEmptyCatch": true }] */ + try { + show.exists_in_plex = await plex.existsInPlex(show); + } catch {} + } res.send(show); } catch (error) { diff --git a/src/webserver/controllers/user/authenticatePlexAccount.js b/src/webserver/controllers/user/authenticatePlexAccount.js index 4e5a09c..8ac5896 100644 --- a/src/webserver/controllers/user/authenticatePlexAccount.js +++ b/src/webserver/controllers/user/authenticatePlexAccount.js @@ -1,20 +1,33 @@ +const FormData = require("form-data"); const UserRepository = require("../../../user/userRepository"); const userRepository = new UserRepository(); -const fetch = require("node-fetch"); -const FormData = require("form-data"); + +class PlexAuthenticationError extends Error { + constructor(errorResponse, statusCode) { + const message = + "Unexptected error while authenticating to plex signin api. View error response."; + super(message); + + this.errorResponse = errorResponse; + this.statusCode = statusCode; + this.success = false; + } +} function handleError(error, res) { - let { status, message, source } = error; + const status = error?.status; + let { message, source } = error; if (status && message) { if (status === 401) { - (message = "Unauthorized. Please check plex credentials."), - (source = "plex"); + message = "Unauthorized. Please check plex credentials."; + source = "plex"; } res.status(status).send({ success: false, message, source }); } else { + // eslint-disable-next-line no-console console.log("caught authenticate plex account controller error", error); res.status(500).send({ message: @@ -26,11 +39,7 @@ function handleError(error, res) { function handleResponse(response) { if (!response.ok) { - throw { - success: false, - status: response.status, - message: response.statusText - }; + throw new PlexAuthenticationError(response.statusText, response.status); } return response.json(); @@ -64,7 +73,7 @@ function link(req, res) { return plexAuthenticate(username, password) .then(plexUser => userRepository.linkPlexUserId(user.username, plexUser.id)) - .then(response => + .then(() => res.send({ success: true, message: @@ -79,7 +88,7 @@ function unlink(req, res) { return userRepository .unlinkPlexUserId(username) - .then(response => + .then(() => res.send({ success: true, message: "Successfully unlinked plex account from seasoned request." diff --git a/src/webserver/controllers/user/register.js b/src/webserver/controllers/user/register.js index 2c36f4e..655f920 100644 --- a/src/webserver/controllers/user/register.js +++ b/src/webserver/controllers/user/register.js @@ -1,12 +1,10 @@ const User = require("../../../user/user"); const Token = require("../../../user/token"); const UserSecurity = require("../../../user/userSecurity"); -const UserRepository = require("../../../user/userRepository"); const configuration = require("../../../config/configuration").getInstance(); const secret = configuration.get("authentication", "secret"); const userSecurity = new UserSecurity(); -const userRepository = new UserRepository(); const isProduction = process.env.NODE_ENV === "production"; const cookieOptions = { diff --git a/src/webserver/controllers/user/requests.js b/src/webserver/controllers/user/requests.js index e412c64..5fe0f22 100644 --- a/src/webserver/controllers/user/requests.js +++ b/src/webserver/controllers/user/requests.js @@ -1,4 +1,4 @@ -const RequestRepository = require("../../../plex/requestRepository.js"); +const RequestRepository = require("../../../plex/requestRepository"); const requestRepository = new RequestRepository(); diff --git a/src/webserver/controllers/user/settings.js b/src/webserver/controllers/user/settings.js index caf55f8..adf0d8d 100644 --- a/src/webserver/controllers/user/settings.js +++ b/src/webserver/controllers/user/settings.js @@ -23,11 +23,12 @@ const getSettingsController = (req, res) => { const updateSettingsController = (req, res) => { const username = req.loggedInUser ? req.loggedInUser.username : null; - const idempotencyKey = req.headers("Idempotency-Key"); // TODO implement better transactions - const { dark_mode, emoji } = req.body; + // const idempotencyKey = req.headers("Idempotency-Key"); // TODO implement better transactions + const emoji = req.body?.emoji; + const darkMode = req.body?.dark_mode; userRepository - .updateSettings(username, dark_mode, emoji) + .updateSettings(username, darkMode, emoji) .then(settings => { res.send({ success: true, settings }); }) diff --git a/src/webserver/controllers/user/viewHistory.js b/src/webserver/controllers/user/viewHistory.js index 55b3077..865a3d7 100644 --- a/src/webserver/controllers/user/viewHistory.js +++ b/src/webserver/controllers/user/viewHistory.js @@ -12,7 +12,7 @@ function handleError(error, res) { if (status && message) { return res.status(status).send({ success: false, message }); } - console.log("caught view history controller error", error); + return res.status(500).send({ message: "An unexpected error occured while fetching view history" }); @@ -35,10 +35,11 @@ function watchTimeStatsController(req, res) { function getPlaysByDayOfWeekController(req, res) { const user = req.loggedInUser; - const { days, y_axis } = req.query; + const days = req.query?.days; + const yAxis = req.query?.y_axis; return tautulli - .getPlaysByDayOfWeek(user.plexUserId, days, y_axis) + .getPlaysByDayOfWeek(user.plexUserId, days, yAxis) .then(data => res.send({ success: true, @@ -51,7 +52,8 @@ function getPlaysByDayOfWeekController(req, res) { function getPlaysByDaysController(req, res) { const user = req.loggedInUser; - const { days, y_axis } = req.query; + const days = req.query?.days; + const yAxis = req.query?.y_axis; if (days === undefined) { return res.status(422).send({ @@ -61,7 +63,7 @@ function getPlaysByDaysController(req, res) { } const allowedYAxisDataType = ["plays", "duration"]; - if (!allowedYAxisDataType.includes(y_axis)) { + if (!allowedYAxisDataType.includes(yAxis)) { return res.status(422).send({ success: false, message: `Y axis parameter must be one of values: [${allowedYAxisDataType}]` @@ -69,7 +71,7 @@ function getPlaysByDaysController(req, res) { } return tautulli - .getPlaysByDays(user.plexUserId, days, y_axis) + .getPlaysByDays(user.plexUserId, days, yAxis) .then(data => res.send({ success: true, diff --git a/tests/fixtures/blade_runner_2049-info-success-response.json b/tests/fixtures/blade_runner_2049-info-success-response.json index 62eb96f..4c412e0 100644 --- a/tests/fixtures/blade_runner_2049-info-success-response.json +++ b/tests/fixtures/blade_runner_2049-info-success-response.json @@ -1 +1,89 @@ -[{"adult":false,"backdrop_path":"/mVr0UiqyltcfqxbAUcLl9zWL8ah.jpg","belongs_to_collection":{"id":422837,"name":"Blade Runner Collection","poster_path":"/cWESb1o9lW2i2Z3Xllv9u40aNIk.jpg","backdrop_path":"/bSHZIvLoPBWyGLeiAudN1mXdvQX.jpg"},"budget":150000000,"genres":[{"id":9648,"name":"Mystery"},{"id":878,"name":"Science Fiction"},{"id":53,"name":"Thriller"}],"homepage":"http://bladerunnermovie.com/","id":335984,"imdb_id":"tt1856101","original_language":"en","original_title":"Blade Runner 2049","overview":"Thirty years after the events of the first film, a new blade runner, LAPD Officer K, unearths a long-buried secret that has the potential to plunge what's left of society into chaos. K's discovery leads him on a quest to find Rick Deckard, a former LAPD blade runner who has been missing for 30 years.","popularity":30.03,"poster_path":"/gajva2L0rPYkEWjzgFlBXCAVBE5.jpg","production_companies":[{"id":79529,"logo_path":"/gVN3k8emmKy4iV4KREWcCtxusZK.png","name":"Torridon Films","origin_country":"US"},{"id":101829,"logo_path":"/8IOjCvgjq0zTrtP91cWD3kL2jMK.png","name":"16:14 Entertainment","origin_country":"US"},{"id":1645,"logo_path":"/6Ry6uNBaa0IbbSs1XYIgX5DkA9r.png","name":"Scott Free Productions","origin_country":""},{"id":5,"logo_path":"/71BqEFAF4V3qjjMPCpLuyJFB9A.png","name":"Columbia Pictures","origin_country":"US"},{"id":1088,"logo_path":"/9WOE5AQUXbOtLU6GTwfjS8OMF0v.png","name":"Alcon Entertainment","origin_country":"US"},{"id":78028,"logo_path":"/sTFcDFfJaSVT3sv3DoaZDE4SlGB.png","name":"Thunderbird Entertainment","origin_country":"CA"},{"id":174,"logo_path":"/ky0xOc5OrhzkZ1N6KyUxacfQsCk.png","name":"Warner Bros. Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"CA","name":"Canada"},{"iso_3166_1":"US","name":"United States of America"},{"iso_3166_1":"HU","name":"Hungary"},{"iso_3166_1":"GB","name":"United Kingdom"}],"release_date":"2017-10-04","revenue":259239658,"runtime":163,"spoken_languages":[{"iso_639_1":"en","name":"English"},{"iso_639_1":"fi","name":"suomi"}],"status":"Released","tagline":"There's still a page left.","title":"Blade Runner 2049","video":false,"vote_average":7.3,"vote_count":5478}] +[ + { + "adult": false, + "backdrop_path": "/mVr0UiqyltcfqxbAUcLl9zWL8ah.jpg", + "belongs_to_collection": { + "id": 422837, + "name": "Blade Runner Collection", + "poster_path": "/cWESb1o9lW2i2Z3Xllv9u40aNIk.jpg", + "backdrop_path": "/bSHZIvLoPBWyGLeiAudN1mXdvQX.jpg" + }, + "budget": 150000000, + "genres": [ + { "id": 9648, "name": "Mystery" }, + { "id": 878, "name": "Science Fiction" }, + { "id": 53, "name": "Thriller" } + ], + "homepage": "http://bladerunnermovie.com/", + "id": 335984, + "imdb_id": "tt1856101", + "original_language": "en", + "original_title": "Blade Runner 2049", + "overview": "Thirty years after the events of the first film, a new blade runner, LAPD Officer K, unearths a long-buried secret that has the potential to plunge what's left of society into chaos. K's discovery leads him on a quest to find Rick Deckard, a former LAPD blade runner who has been missing for 30 years.", + "popularity": 30.03, + "poster_path": "/gajva2L0rPYkEWjzgFlBXCAVBE5.jpg", + "production_companies": [ + { + "id": 79529, + "logo_path": "/gVN3k8emmKy4iV4KREWcCtxusZK.png", + "name": "Torridon Films", + "origin_country": "US" + }, + { + "id": 101829, + "logo_path": "/8IOjCvgjq0zTrtP91cWD3kL2jMK.png", + "name": "16:14 Entertainment", + "origin_country": "US" + }, + { + "id": 1645, + "logo_path": "/6Ry6uNBaa0IbbSs1XYIgX5DkA9r.png", + "name": "Scott Free Productions", + "origin_country": "" + }, + { + "id": 5, + "logo_path": "/71BqEFAF4V3qjjMPCpLuyJFB9A.png", + "name": "Columbia Pictures", + "origin_country": "US" + }, + { + "id": 1088, + "logo_path": "/9WOE5AQUXbOtLU6GTwfjS8OMF0v.png", + "name": "Alcon Entertainment", + "origin_country": "US" + }, + { + "id": 78028, + "logo_path": "/sTFcDFfJaSVT3sv3DoaZDE4SlGB.png", + "name": "Thunderbird Entertainment", + "origin_country": "CA" + }, + { + "id": 174, + "logo_path": "/ky0xOc5OrhzkZ1N6KyUxacfQsCk.png", + "name": "Warner Bros. Pictures", + "origin_country": "US" + } + ], + "production_countries": [ + { "iso_3166_1": "CA", "name": "Canada" }, + { "iso_3166_1": "US", "name": "United States of America" }, + { "iso_3166_1": "HU", "name": "Hungary" }, + { "iso_3166_1": "GB", "name": "United Kingdom" } + ], + "release_date": "2017-10-04", + "revenue": 259239658, + "runtime": 163, + "spoken_languages": [ + { "iso_639_1": "en", "name": "English" }, + { "iso_639_1": "fi", "name": "suomi" } + ], + "status": "Released", + "tagline": "There's still a page left.", + "title": "Blade Runner 2049", + "video": false, + "vote_average": 7.3, + "vote_count": 5478 + } +] diff --git a/tests/fixtures/interstellar-query-movie-success-response.json b/tests/fixtures/interstellar-query-movie-success-response.json index 19162ac..d511be2 100644 --- a/tests/fixtures/interstellar-query-movie-success-response.json +++ b/tests/fixtures/interstellar-query-movie-success-response.json @@ -1 +1,193 @@ -{"results":[{"id":157336,"title":"Interstellar","year":2014,"overview":"Interstellar chronicles the adventures of a group of explorers who make use of a newly discovered wormhole to surpass the limitations on human space travel and conquer the vast distances involved in an interstellar voyage.","poster":"/nBNZadXqJSdt05SHLqgT0HuC5Gm.jpg","backdrop":"/xu9zaAevzQ5nnrsXN6JcahLnG4i.jpg","rank":8.2,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","release_date":"2014-11-05T00:00:00.000Z"},{"id":301959,"title":"Interstellar: Nolan's Odyssey","year":2014,"overview":"Behind the scenes of Christopher Nolan's sci-fi drama, which stars Matthew McConaughey and Anne Hathaway","poster":"/xZwUIPqBHyJ2QIfMPANOZ1mAld6.jpg","backdrop":"/bT5jpIZE50MI0COE8pOeq0kMpQo.jpg","rank":7.9,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","credits":1,"release_date":"2014-11-05T00:00:00.000Z"},{"id":398188,"title":"Interstellar Wars","year":2016,"overview":"For Millennia the Aliien force has watched and waited, a brooding menace that has now at last decided to take over the Earth. Communications systems worldwide are sent into chaos by a strange atmospheric interference and this has turned into a global phenomenon. A massive spaceship headed towards Earth and smaller spaceships began to cover entire cities around the world. Suddenly, the wonder turns into horror as the spaceships destroy the cities with energy weapons. When the world counterattacks, the alien ships are invincible to military weapons. The survivors have to use their wits to kill the aliens, or die.","poster":"/cjvTebuqD8wmhchHE286ltVcbX6.jpg","backdrop":"/yTnHa6lgIv8rNneSNBDkBe8MnZe.jpg","rank":3.8,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","credits":2,"release_date":"2016-05-23T00:00:00.000Z"},{"id":287954,"title":"Lolita from Interstellar Space","year":2014,"overview":"An undeniably beautiful alien is sent to Earth to study the complex mating rituals of human beings, which leads to the young interstellar traveler experiencing the passion that surrounds the centuries-old ritual of the species.","poster":"/buoq7zYO4J3ttkEAqEMWelPDC0G.jpg","backdrop":"/mgb6tVEieDYLpQt666ACzGz5cyE.jpg","rank":7,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","credits":3,"release_date":"2014-03-08T00:00:00.000Z"},{"id":336592,"title":"The Science of Interstellar","year":2014,"overview":"The science of Christopher Nolan's sci-fi, Interstellar.","poster":"/6KBD7YSBjCfgBgHwpsQo3G3GGdx.jpg","backdrop":null,"rank":7.8,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","credits":4,"release_date":"2014-11-25T00:00:00.000Z"},{"id":529107,"title":"Inside Interstellar","year":2015,"overview":"Cast and crew of Christopher Nolan's 'Interstellar' discuss project origins, the film's imagery, ambitions, incorporating IMAX footage, the human element within the film, arm shooting locations outside of Calgary, the set construction and design, working with real corn, mechanical characters, including backstory, design, the blend of practical and digital effects in bringing them to life, the differences in the characters, the human performances behind the characters, the creative process behind the film's music, Icelandic locations, vehicle interiors, the processes of simulating the absence of gravity, the crucial end-film visuals and influence and inspiration for future generations","poster":"/vemBplPKQhVe5cRWL7kxtgp15Vq.jpg","backdrop":null,"rank":9,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","credits":5,"release_date":"2015-03-31T00:00:00.000Z"},{"id":552531,"title":"The Prom Goer's Interstellar Excursion","year":null,"overview":"High schooler Bennett lands the prom date of his dreams, Sophie, just days before the dance. Not long after, he witnesses Sophie being abducted by aliens in the middle of the New Mexico desert.","poster":null,"backdrop":null,"rank":0,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","credits":6,"release_date":null},{"id":460616,"title":"Interstellar Civil War: Shadows of the Empire","year":2018,"overview":"The Imperial Empire is attacked by an Alliance of rebels led by fanatical mystics. The ruler, Empress Nobu, the 8th generation of her family, wants to execute a bold plan to rescue a cyborg, Leah C6, trapped on the battle ravaged planet Endor. The Empress believes Leah C6 holds the secret to destroying the Alliance of Rebels before their insurgency can kill millions of citizens of the Empire. She recruits her heroic fleet commander, Lord General Luka Raan and asks him to gather a team from the Empire's elite soldiers, the Galactic Rangers. Raan assembles the team in the ruins of Endor which was attacked by depraved Rebels and outlaws led by, Kindo-Ker, a fanatical mystic in Dark Energy. The Galactic Rangers begin a desperate search to find and rescue Leah C6 before the Alliance Rebels can.","poster":"/1lDY7ZpEKOl3OaIQURjRbmFPfT8.jpg","backdrop":null,"rank":4,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","credits":7,"release_date":"2018-04-15T00:00:00.000Z"},{"id":47662,"title":"Trancers 4: Jack of Swords","year":1994,"overview":"Jack is now back in the future. He had since lost Lena, and finds out that he's lost his other wife Alice to none other than Harris. While heading out for another assignment, something goes awry with the TCL chamber. Jack finds himself in a whole new dimension. He also runs across a different version of trancers. These guys seem to be in control of this planet. Jack manages to assist a rebel group known as the \"Tunnel Rats\" crush the rule of the evil Lord Calaban.","poster":"/69yr3oxBpSgua26RJkFmsm7plTG.jpg","backdrop":"/5ism2HNUGuQi5a3ajYaN9ypMQMf.jpg","rank":5.2,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","credits":8,"release_date":"1994-02-02T00:00:00.000Z"},{"id":47663,"title":"Trancers 5: Sudden Deth","year":1994,"overview":"Jack Deth is back for one more round with the trancers. Jack must attempt to find his way home from the other-dimensional world of Orpheus, where magic works and the trancers were the ruling class (before Trancers IV, that is). Unfortunately, Jack's quest to find the mystical Tiamond in the Castle of Unrelenting Terror may be thwarted by the return of Caliban, king of the trancers who was thought dead.","poster":"/epMaTjPDMbgC8TbW1ZToh4RNv0i.jpg","backdrop":"/an0xpUEX1P1BI80sCpkU1pSoREx.jpg","rank":5,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","credits":9,"release_date":"1994-11-04T00:00:00.000Z"},{"id":261443,"title":"Angry Planet","year":2008,"overview":"A criminal sentenced to life on a prison planet reveals his true purpose: to extract revenge on the killers who murdered his family.","poster":"/ie5luS87ess1c5VgFhbGECJTQVK.jpg","backdrop":"/u4JBwlGZN8hGeLxwu7Q0WmibACp.jpg","rank":4.5,"genres":null,"status":null,"tagline":null,"runtime":null,"imdb_id":null,"type":"movie","credits":10,"release_date":"2008-01-01T00:00:00.000Z"}],"page":1,"total_results":11,"total_pages":1} \ No newline at end of file +{ + "results": [ + { + "id": 157336, + "title": "Interstellar", + "year": 2014, + "overview": "Interstellar chronicles the adventures of a group of explorers who make use of a newly discovered wormhole to surpass the limitations on human space travel and conquer the vast distances involved in an interstellar voyage.", + "poster": "/nBNZadXqJSdt05SHLqgT0HuC5Gm.jpg", + "backdrop": "/xu9zaAevzQ5nnrsXN6JcahLnG4i.jpg", + "rank": 8.2, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "release_date": "2014-11-05T00:00:00.000Z" + }, + { + "id": 301959, + "title": "Interstellar: Nolan's Odyssey", + "year": 2014, + "overview": "Behind the scenes of Christopher Nolan's sci-fi drama, which stars Matthew McConaughey and Anne Hathaway", + "poster": "/xZwUIPqBHyJ2QIfMPANOZ1mAld6.jpg", + "backdrop": "/bT5jpIZE50MI0COE8pOeq0kMpQo.jpg", + "rank": 7.9, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "credits": 1, + "release_date": "2014-11-05T00:00:00.000Z" + }, + { + "id": 398188, + "title": "Interstellar Wars", + "year": 2016, + "overview": "For Millennia the Aliien force has watched and waited, a brooding menace that has now at last decided to take over the Earth. Communications systems worldwide are sent into chaos by a strange atmospheric interference and this has turned into a global phenomenon. A massive spaceship headed towards Earth and smaller spaceships began to cover entire cities around the world. Suddenly, the wonder turns into horror as the spaceships destroy the cities with energy weapons. When the world counterattacks, the alien ships are invincible to military weapons. The survivors have to use their wits to kill the aliens, or die.", + "poster": "/cjvTebuqD8wmhchHE286ltVcbX6.jpg", + "backdrop": "/yTnHa6lgIv8rNneSNBDkBe8MnZe.jpg", + "rank": 3.8, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "credits": 2, + "release_date": "2016-05-23T00:00:00.000Z" + }, + { + "id": 287954, + "title": "Lolita from Interstellar Space", + "year": 2014, + "overview": "An undeniably beautiful alien is sent to Earth to study the complex mating rituals of human beings, which leads to the young interstellar traveler experiencing the passion that surrounds the centuries-old ritual of the species.", + "poster": "/buoq7zYO4J3ttkEAqEMWelPDC0G.jpg", + "backdrop": "/mgb6tVEieDYLpQt666ACzGz5cyE.jpg", + "rank": 7, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "credits": 3, + "release_date": "2014-03-08T00:00:00.000Z" + }, + { + "id": 336592, + "title": "The Science of Interstellar", + "year": 2014, + "overview": "The science of Christopher Nolan's sci-fi, Interstellar.", + "poster": "/6KBD7YSBjCfgBgHwpsQo3G3GGdx.jpg", + "backdrop": null, + "rank": 7.8, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "credits": 4, + "release_date": "2014-11-25T00:00:00.000Z" + }, + { + "id": 529107, + "title": "Inside Interstellar", + "year": 2015, + "overview": "Cast and crew of Christopher Nolan's 'Interstellar' discuss project origins, the film's imagery, ambitions, incorporating IMAX footage, the human element within the film, arm shooting locations outside of Calgary, the set construction and design, working with real corn, mechanical characters, including backstory, design, the blend of practical and digital effects in bringing them to life, the differences in the characters, the human performances behind the characters, the creative process behind the film's music, Icelandic locations, vehicle interiors, the processes of simulating the absence of gravity, the crucial end-film visuals and influence and inspiration for future generations", + "poster": "/vemBplPKQhVe5cRWL7kxtgp15Vq.jpg", + "backdrop": null, + "rank": 9, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "credits": 5, + "release_date": "2015-03-31T00:00:00.000Z" + }, + { + "id": 552531, + "title": "The Prom Goer's Interstellar Excursion", + "year": null, + "overview": "High schooler Bennett lands the prom date of his dreams, Sophie, just days before the dance. Not long after, he witnesses Sophie being abducted by aliens in the middle of the New Mexico desert.", + "poster": null, + "backdrop": null, + "rank": 0, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "credits": 6, + "release_date": null + }, + { + "id": 460616, + "title": "Interstellar Civil War: Shadows of the Empire", + "year": 2018, + "overview": "The Imperial Empire is attacked by an Alliance of rebels led by fanatical mystics. The ruler, Empress Nobu, the 8th generation of her family, wants to execute a bold plan to rescue a cyborg, Leah C6, trapped on the battle ravaged planet Endor. The Empress believes Leah C6 holds the secret to destroying the Alliance of Rebels before their insurgency can kill millions of citizens of the Empire. She recruits her heroic fleet commander, Lord General Luka Raan and asks him to gather a team from the Empire's elite soldiers, the Galactic Rangers. Raan assembles the team in the ruins of Endor which was attacked by depraved Rebels and outlaws led by, Kindo-Ker, a fanatical mystic in Dark Energy. The Galactic Rangers begin a desperate search to find and rescue Leah C6 before the Alliance Rebels can.", + "poster": "/1lDY7ZpEKOl3OaIQURjRbmFPfT8.jpg", + "backdrop": null, + "rank": 4, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "credits": 7, + "release_date": "2018-04-15T00:00:00.000Z" + }, + { + "id": 47662, + "title": "Trancers 4: Jack of Swords", + "year": 1994, + "overview": "Jack is now back in the future. He had since lost Lena, and finds out that he's lost his other wife Alice to none other than Harris. While heading out for another assignment, something goes awry with the TCL chamber. Jack finds himself in a whole new dimension. He also runs across a different version of trancers. These guys seem to be in control of this planet. Jack manages to assist a rebel group known as the \"Tunnel Rats\" crush the rule of the evil Lord Calaban.", + "poster": "/69yr3oxBpSgua26RJkFmsm7plTG.jpg", + "backdrop": "/5ism2HNUGuQi5a3ajYaN9ypMQMf.jpg", + "rank": 5.2, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "credits": 8, + "release_date": "1994-02-02T00:00:00.000Z" + }, + { + "id": 47663, + "title": "Trancers 5: Sudden Deth", + "year": 1994, + "overview": "Jack Deth is back for one more round with the trancers. Jack must attempt to find his way home from the other-dimensional world of Orpheus, where magic works and the trancers were the ruling class (before Trancers IV, that is). Unfortunately, Jack's quest to find the mystical Tiamond in the Castle of Unrelenting Terror may be thwarted by the return of Caliban, king of the trancers who was thought dead.", + "poster": "/epMaTjPDMbgC8TbW1ZToh4RNv0i.jpg", + "backdrop": "/an0xpUEX1P1BI80sCpkU1pSoREx.jpg", + "rank": 5, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "credits": 9, + "release_date": "1994-11-04T00:00:00.000Z" + }, + { + "id": 261443, + "title": "Angry Planet", + "year": 2008, + "overview": "A criminal sentenced to life on a prison planet reveals his true purpose: to extract revenge on the killers who murdered his family.", + "poster": "/ie5luS87ess1c5VgFhbGECJTQVK.jpg", + "backdrop": "/u4JBwlGZN8hGeLxwu7Q0WmibACp.jpg", + "rank": 4.5, + "genres": null, + "status": null, + "tagline": null, + "runtime": null, + "imdb_id": null, + "type": "movie", + "credits": 10, + "release_date": "2008-01-01T00:00:00.000Z" + } + ], + "page": 1, + "total_results": 11, + "total_pages": 1 +} -- 2.34.1 From c533d8868a5156eb80779bc824cf7c054309165d Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 19 Aug 2022 16:03:04 +0200 Subject: [PATCH 8/9] Fixed eslint errors & improved a lot of error handling --- src/cache/redis.js | 19 +- src/config/configuration.js | 1 + src/config/field.js | 2 +- src/notifications/sms.js | 11 +- src/pirate/pirateRepository.js | 19 +- src/plex/plex.js | 174 ++++++++-------- src/plex/plexRepository.js | 88 ++++----- src/plex/requestRepository.js | 96 +++++---- src/request/request.js | 30 ++- src/tautulli/tautulli.js | 17 +- src/tmdb/tmdb.js | 186 ++++++++++-------- src/user/userRepository.js | 120 ++++++----- src/webserver/app.js | 10 +- .../controllers/list/listController.js | 22 +-- src/webserver/controllers/movie/credits.js | 15 +- src/webserver/controllers/movie/info.js | 29 +-- .../controllers/movie/releaseDates.js | 15 +- src/webserver/controllers/person/credits.js | 15 +- src/webserver/controllers/person/info.js | 21 +- .../controllers/request/fetchAllRequests.js | 7 +- .../controllers/request/getRequest.js | 7 +- .../controllers/search/movieSearch.js | 15 +- .../controllers/search/multiSearch.js | 15 +- .../controllers/search/personSearch.js | 15 +- .../controllers/search/showSearch.js | 7 +- src/webserver/controllers/show/credits.js | 15 +- src/webserver/controllers/show/info.js | 21 +- 27 files changed, 496 insertions(+), 496 deletions(-) diff --git a/src/cache/redis.js b/src/cache/redis.js index 9318a31..fdee990 100644 --- a/src/cache/redis.js +++ b/src/cache/redis.js @@ -3,29 +3,29 @@ const configuration = require("../config/configuration").getInstance(); let client; try { - const redis = require("redis"); - console.log("Trying to connect with redis.."); + const redis = require("redis"); // eslint-disable-line global-require + console.log("Trying to connect with redis.."); // eslint-disable-line no-console const host = configuration.get("redis", "host"); const port = configuration.get("redis", "port"); - console.log(`redis://${host}:${port}`); + console.log(`redis://${host}:${port}`); // eslint-disable-line no-console client = redis.createClient({ url: `redis://${host}:${port}` }); - client.on("connect", () => console.log("Redis connection established!")); + client.on("connect", () => console.log("Redis connection established!")); // eslint-disable-line no-console client.on("error", () => { client.quit(); - console.error("Unable to connect to redis, setting up redis-mock."); + console.error("Unable to connect to redis, setting up redis-mock."); // eslint-disable-line no-console client = { - get() { - console.log("redis-dummy get", arguments[0]); + get(command) { + console.log(`redis-dummy get: ${command}`); // eslint-disable-line no-console return Promise.resolve(); }, - set() { - console.log("redis-dummy set", arguments[0]); + set(command) { + console.log(`redis-dummy set: ${command}`); // eslint-disable-line no-console return Promise.resolve(); } }; @@ -41,6 +41,7 @@ function set(key, value, TTL = 10800) { // successfully set value with key, now set TTL for key client.expire(key, TTL, e => { if (e) + // eslint-disable-next-line no-console console.error( "Unexpected error while setting expiration for key:", key, diff --git a/src/config/configuration.js b/src/config/configuration.js index 9b9a192..175a0a7 100644 --- a/src/config/configuration.js +++ b/src/config/configuration.js @@ -6,6 +6,7 @@ let instance = null; class Config { constructor() { this.location = Config.determineLocation(); + // eslint-disable-next-line import/no-dynamic-require, global-require this.fields = require(`${this.location}`); } diff --git a/src/config/field.js b/src/config/field.js index 4b86c80..ef4b3d1 100644 --- a/src/config/field.js +++ b/src/config/field.js @@ -46,7 +46,7 @@ class Field { } static base64Decode(string) { - return new Buffer(string, "base64").toString("utf-8"); + return Buffer.from(string, "base64").toString("utf-8"); } } diff --git a/src/notifications/sms.js b/src/notifications/sms.js index a8c80d7..b9e6f41 100644 --- a/src/notifications/sms.js +++ b/src/notifications/sms.js @@ -14,8 +14,8 @@ const sendSMS = message => { const apiKey = configuration.get("sms", "apikey"); if (!apiKey) { - console.warning("api key for sms not set, cannot send sms."); - return null; + console.warning("api key for sms not set, cannot send sms."); // eslint-disable-line no-console + return Promise.resolve(null); } const sender = configuration.get("sms", "sender"); @@ -32,10 +32,9 @@ const sendSMS = message => { recipients: [{ msisdn: `47${recipient}` }] } }, - function (err, r, body) { - const smsError = new SMSUnexpectedError(err || body); - console.error(smsError.message); - resolve(); + (err, r, body) => { + if (err) reject(new SMSUnexpectedError(err || body)); + resolve(body); } ); }); diff --git a/src/pirate/pirateRepository.js b/src/pirate/pirateRepository.js index 455ad0a..36849b2 100644 --- a/src/pirate/pirateRepository.js +++ b/src/pirate/pirateRepository.js @@ -46,8 +46,10 @@ async function callPythonAddMagnet(url, callback) { }); } -async function SearchPiratebay(query) { - if (query && query.includes("+")) { +async function SearchPiratebay(_query) { + let query = String(_query); + + if (query?.includes("+")) { query = query.replace("+", "%20"); } @@ -60,7 +62,7 @@ async function SearchPiratebay(query) { .catch(() => find(query, (err, results) => { if (err) { - console.log("THERE WAS A FUCKING ERROR!\n", err); + console.log("THERE WAS A FUCKING ERROR!\n", err); // eslint-disable-line no-console reject(Error("There was a error when searching for torrents")); } @@ -74,8 +76,8 @@ async function SearchPiratebay(query) { ); } -async function AddMagnet(magnet, name, tmdbId) { - return await new Promise((resolve, reject) => +function AddMagnet(magnet, name, tmdbId) { + return new Promise((resolve, reject) => callPythonAddMagnet(magnet, (err, results) => { if (err) { /* eslint-disable no-console */ @@ -86,11 +88,10 @@ async function AddMagnet(magnet, name, tmdbId) { console.log("result/error:", err, results); const database = establishedDatabase; - const insert_query = - "INSERT INTO requested_torrent(magnet,torrent_name,tmdb_id) \ - VALUES (?,?,?)"; + const insertQuery = + "INSERT INTO requested_torrent(magnet,torrent_name,tmdb_id) VALUES (?,?,?)"; - const response = database.run(insert_query, [magnet, name, tmdbId]); + const response = database.run(insertQuery, [magnet, name, tmdbId]); console.log(`Response from requsted_torrent insert: ${response}`); resolve({ success: true }); diff --git a/src/plex/plex.js b/src/plex/plex.js index 628c862..01b9cee 100644 --- a/src/plex/plex.js +++ b/src/plex/plex.js @@ -2,17 +2,28 @@ const fetch = require("node-fetch"); const convertPlexToMovie = require("./convertPlexToMovie"); const convertPlexToShow = require("./convertPlexToShow"); const convertPlexToEpisode = require("./convertPlexToEpisode"); - const redisCache = require("../cache/redis"); -const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, ""); +class PlexRequestTimeoutError extends Error { + constructor() { + const message = "Timeout: Plex did not respond."; -function fixedEncodeURIComponent(str) { - return encodeURIComponent(str).replace(/[!'()*]/g, function (c) { - return `%${c.charCodeAt(0).toString(16).toUpperCase()}`; - }); + super(message); + this.statusCode = 408; + } } +class PlexUnexpectedError extends Error { + constructor(plexError = null) { + const message = "Unexpected plex error occured."; + + super(message); + this.statusCode = 500; + this.plexError = plexError; + } +} + +const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, ""); const matchingTitleAndYear = (plex, tmdb) => { let matchingTitle; let matchingYear; @@ -30,25 +41,62 @@ const matchingTitleAndYear = (plex, tmdb) => { return matchingTitle && matchingYear; }; +function fixedEncodeURIComponent(str) { + return encodeURIComponent(str).replace(/[!'()*]/g, c => { + return `%${c.charCodeAt(0).toString(16).toUpperCase()}`; + }); +} + +function matchTmdbAndPlexMedia(plex, tmdb) { + let match; + + if (plex === null || tmdb === null) return false; + + if (plex instanceof Array) { + const possibleMatches = plex.map(plexItem => + matchingTitleAndYear(plexItem, tmdb) + ); + match = possibleMatches.includes(true); + } else { + match = matchingTitleAndYear(plex, tmdb); + } + + return match; +} + const successfullResponse = response => { - if (response && response.MediaContainer) return response; - - if ( - response === null || - response.status === null || - response.statusText === null - ) { - throw Error("Unable to decode response"); - } - const { status, statusText } = response; - - if (status === 200) { - return response.json(); + if (status !== 200) { + throw new PlexUnexpectedError(statusText); } - throw { message: statusText, status }; + + if (response?.MediaContainer) return response; + + return response.json(); }; +function mapResults(response) { + if (response?.MediaContainer?.Hub === null) { + return []; + } + + return response.MediaContainer.Hub.filter(category => category.size > 0) + .map(category => { + if (category.type === "movie") { + return category.Metadata.map(convertPlexToMovie); + } + if (category.type === "show") { + return category.Metadata.map(convertPlexToShow); + } + if (category.type === "episode") { + return category.Metadata.map(convertPlexToEpisode); + } + + return null; + }) + .filter(result => result !== null); +} + class Plex { constructor(ip, port = 32400, cache = null) { this.plexIP = ip; @@ -72,44 +120,23 @@ class Plex { return new Promise((resolve, reject) => this.cache .get(cacheKey) - .then(machineInfo => resolve(machineInfo.machineIdentifier)) + .then(machineInfo => resolve(machineInfo?.machineIdentifier)) .catch(() => fetch(url, options)) .then(response => response.json()) .then(machineInfo => this.cache.set(cacheKey, machineInfo.MediaContainer, 2628000) ) - .then(machineInfo => resolve(machineInfo.machineIdentifier)) + .then(machineInfo => resolve(machineInfo?.machineIdentifier)) .catch(error => { - if (error !== undefined && error.type === "request-timeout") { - reject({ - message: "Plex did not respond", - status: 408, - success: false - }); + if (error?.type === "request-timeout") { + reject(new PlexRequestTimeoutError()); } - reject(error); + reject(new PlexUnexpectedError()); }) ); } - matchTmdbAndPlexMedia(plex, tmdb) { - let match; - - if (plex === null || tmdb === null) return false; - - if (plex instanceof Array) { - const possibleMatches = plex.map(plexItem => - matchingTitleAndYear(plexItem, tmdb) - ); - match = possibleMatches.includes(true); - } else { - match = matchingTitleAndYear(plex, tmdb); - } - - return match; - } - async existsInPlex(tmdb) { const plexMatch = await this.findPlexItemByTitleAndYear( tmdb.title, @@ -123,7 +150,7 @@ class Plex { return this.search(title).then(plexResults => { const matchesInPlex = plexResults.map(plex => - this.matchTmdbAndPlexMedia(plex, query) + matchTmdbAndPlexMedia(plex, query) ); const matchesIndex = matchesInPlex.findIndex(el => el === true); return matchesInPlex !== -1 ? plexResults[matchesIndex] : null; @@ -171,18 +198,14 @@ class Plex { .catch(() => fetch(url, options)) // else fetch fresh data .then(successfullResponse) .then(results => this.cache.set(cacheKey, results, 21600)) // 6 hours - .then(this.mapResults) + .then(mapResults) .then(resolve) .catch(error => { - if (error !== undefined && error.type === "request-timeout") { - reject({ - message: "Plex did not respond", - status: 408, - success: false - }); + if (error?.type === "request-timeout") { + reject(new PlexRequestTimeoutError()); } - reject(error); + reject(new PlexUnexpectedError()); }) ); } @@ -195,40 +218,13 @@ class Plex { const query = title; const cacheKey = `${this.cacheTags.search}/${query}*`; - this.cache.del( - cacheKey, - (error, - response => { - if (response === 1) return true; - - // TODO improve cache key matching by lowercasing it on the backend. - // what do we actually need to check for if the key was deleted or not - // it might be an error or another response code. - console.log("Unable to delete, key might not exists"); - }) - ); - } - - mapResults(response) { - if (response?.MediaContainer?.Hub === null) { - return []; - } - - return response.MediaContainer.Hub.filter(category => category.size > 0) - .map(category => { - if (category.type === "movie") { - return category.Metadata; - } - if (category.type === "show") { - return category.Metadata.map(convertPlexToShow); - } - if (category.type === "episode") { - return category.Metadata.map(convertPlexToEpisode); - } - - return null; - }) - .filter(result => result !== null); + this.cache.del(cacheKey, (error, response) => { + // TODO improve cache key matching by lowercasing it on the backend. + // what do we actually need to check for if the key was deleted or not + // it might be an error or another response code. + console.log("Unable to delete, key might not exists"); + return response === 1; + }); } } diff --git a/src/plex/plexRepository.js b/src/plex/plexRepository.js index 3bc29ac..472111f 100644 --- a/src/plex/plexRepository.js +++ b/src/plex/plexRepository.js @@ -2,17 +2,54 @@ const rp = require("request-promise"); const convertPlexToSeasoned = require("./convertPlexToSeasoned"); const convertPlexToStream = require("./convertPlexToStream"); +// eslint-disable-next-line +function addAttributeIfTmdbInPlex(_tmdb, plexResult) { + const tmdb = { ..._tmdb }; + + if (plexResult?.results?.length > 0) { + plexResult.results.map(plexItem => { + tmdb.matchedInPlex = + tmdb.title === plexItem.title && tmdb.year === plexItem.year; + return tmdb; + }); + } else { + tmdb.matchedInPlex = false; + } + + return Promise.resolve(tmdb); +} + +function mapResults(response) { + return Promise.resolve() + .then(() => { + if (!response?.MediaContainer?.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); + }); +} + class PlexRepository { constructor(plexIP) { this.plexIP = plexIP; } - inPlex(tmdbResult) { - return Promise.resolve() - .then(() => this.search(tmdbResult.title)) - .then(plexResult => this.compareTmdbToPlex(tmdbResult, plexResult)) - .catch(error => { - console.log(error); + inPlex(_tmdbResult) { + const tmdbResult = { ..._tmdbResult }; + this.search(tmdbResult.title) + .then(plexResult => addAttributeIfTmdbInPlex(tmdbResult, plexResult)) + .catch(() => { + /** + * If something crashes with search from this function it probably + * fine to set the `matchedInPlex` attribute to false and return + * original tmdb object + * */ + tmdbResult.matchedInPlex = false; return tmdbResult; }); @@ -32,50 +69,13 @@ class PlexRepository { }; return rp(options) - .catch(error => { - console.log(error); - throw new Error("Unable to search plex."); - }) - .then(result => this.mapResults(result)) + .then(result => mapResults(result)) .then(([mappedResults, resultCount]) => ({ results: mappedResults, total_results: resultCount })); } - compareTmdbToPlex(tmdb, plexResult) { - return Promise.resolve().then(() => { - if (plexResult.results.length === 0) { - tmdb.matchedInPlex = false; - } else { - // console.log('plex and tmdb:', plexResult, '\n', tmdb) - plexResult.results.map(plexItem => { - if (tmdb.title === plexItem.title && tmdb.year === plexItem.year) - tmdb.matchedInPlex = true; - return tmdb; - }); - } - return tmdb; - }); - } - - 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() { const options = { uri: `http://${this.plexIP}:32400/status/sessions`, diff --git a/src/plex/requestRepository.js b/src/plex/requestRepository.js index 8a01d5f..85caaf1 100644 --- a/src/plex/requestRepository.js +++ b/src/plex/requestRepository.js @@ -28,15 +28,15 @@ class RequestRepository { }; } - search(query, type, page) { - return Promise.resolve() - .then(() => tmdb.search(query, type, page)) + static search(query, type, page) { + return tmdb + .search(query, type, page) .catch(error => Error(`error in the house${error}`)); } lookup(identifier, type = "movie") { - return Promise.resolve() - .then(() => tmdb.lookup(identifier, type)) + return tmdb + .lookup(identifier, type) .then(tmdbMovie => this.checkID(tmdbMovie)) .then(tmdbMovie => plexRepository.inPlex(tmdbMovie)) .catch(error => { @@ -44,18 +44,16 @@ class RequestRepository { }); } - checkID(tmdbMovie) { - return Promise.resolve() - .then(() => - this.database.get(this.queries.checkIfIdRequested, [ - tmdbMovie.id, - tmdbMovie.type - ]) - ) + checkID(_tmdbMovie) { + const tmdbMovie = _tmdbMovie; + + return this.database + .get(this.queries.checkIfIdRequested, [tmdbMovie.id, tmdbMovie.type]) .then((result, error) => { if (error) { throw new Error(error); } + tmdbMovie.requested = !!result; return tmdbMovie; }); @@ -67,44 +65,41 @@ class RequestRepository { * @returns {Promise} If nothing has gone wrong. */ sendRequest(identifier, type, ip, userAgent, user) { - return Promise.resolve() - .then(() => tmdb.lookup(identifier, type)) - .then(movie => { - const username = user === undefined ? undefined : user.username; - // Add request to database - return this.database.run(this.queries.insertRequest, [ - movie.id, - movie.title, - movie.year, - movie.poster_path, - movie.background_path, - username, - ip, - userAgent, - movie.type - ]); - }); - } - - fetchRequested(status, page = "1", type = "%") { - return Promise.resolve().then(() => { - if ( - status === "requested" || - status === "downloading" || - status === "downloaded" - ) - return this.database.all(this.queries.fetchRequestedItemsByStatus, [ - status, - type, - page - ]); - return this.database.all(this.queries.fetchRequestedItems, page); + return tmdb.lookup(identifier, type).then(movie => { + const username = user === undefined ? undefined : user.username; + // Add request to database + return this.database.run(this.queries.insertRequest, [ + movie.id, + movie.title, + movie.year, + movie.poster_path, + movie.background_path, + username, + ip, + userAgent, + movie.type + ]); }); } + fetchRequested(status, page = "1", type = "%") { + if ( + status === "requested" || + status === "downloading" || + status === "downloaded" + ) + return this.database.all(this.queries.fetchRequestedItemsByStatus, [ + status, + type, + page + ]); + + return this.database.all(this.queries.fetchRequestedItems, page); + } + userRequests(username) { - return Promise.resolve() - .then(() => this.database.all(this.queries.userRequests, username)) + return this.database + .all(this.queries.userRequests, username) .catch(error => { if (String(error).includes("no such column")) { throw new Error("Username not found"); @@ -113,8 +108,11 @@ class RequestRepository { }) .then(result => { // TODO do a correct mapping before sending, not just a dump of the database - result.map(item => (item.poster = item.poster_path)); - return result; + return result.map(_item => { + const item = { ..._item }; + item.poster = item.poster_path; + return item; + }); }); } diff --git a/src/request/request.js b/src/request/request.js index 922e933..3f3d91b 100644 --- a/src/request/request.js +++ b/src/request/request.js @@ -1,10 +1,18 @@ const assert = require("assert"); -const configuration = require("../config/configuration").getInstance(); -const TMDB = require("../tmdb/tmdb"); - -const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); +// const configuration = require("../config/configuration").getInstance(); +// const TMDB = require("../tmdb/tmdb"); const establishedDatabase = require("../database/database"); +// const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); + +// function mapToTmdbByType(rows) { +// return rows.map(row => { +// if (row.type === "movie") return tmdb.movieInfo(row.id); +// if (row.type === "show") return tmdb.showInfo(row.id); +// return null; +// }); +// } + class RequestRepository { constructor(database) { this.database = database || establishedDatabase; @@ -30,14 +38,6 @@ class RequestRepository { }; } - mapToTmdbByType(rows) { - return rows.map(row => { - if (row.type === "movie") return tmdb.movieInfo(row.id); - if (row.type === "show") return tmdb.showInfo(row.id); - return null; - }); - } - /** * Add tmdb movie|show to requests * @param {tmdb} tmdb class of movie|show to add @@ -69,7 +69,6 @@ class RequestRepository { ) { throw new Error("This id is already requested", error.message); } - console.log("Error @ request.addTmdb:", error); throw new Error("Could not add request"); }); } @@ -104,7 +103,7 @@ class RequestRepository { */ fetchAll(_page = 1, filter = null) { // TODO implemented sort and filter - const page = parseInt(_page); + const page = parseInt(_page, 10); let fetchQuery = this.queries.fetchAll; let fetchTotalResults = this.queries.totalRequests; let fetchParams = [page]; @@ -143,7 +142,7 @@ class RequestRepository { totalRequests ]; - return this.mapToTmdbByType(rows); + // return mapToTmdbByType(rows); }) .then(([result, totalPages, totalRequests]) => Promise.resolve({ @@ -154,7 +153,6 @@ class RequestRepository { }) ) .catch(error => { - console.log(error); throw error; }); } diff --git a/src/tautulli/tautulli.js b/src/tautulli/tautulli.js index cccd8a7..f5fdf3d 100644 --- a/src/tautulli/tautulli.js +++ b/src/tautulli/tautulli.js @@ -10,6 +10,10 @@ class TautulliUnexpectedError extends Error { } } +function logTautulliError(error) { + throw new TautulliUnexpectedError(error); +} + class Tautulli { constructor(apiKey, ip, port) { this.apiKey = apiKey; @@ -26,11 +30,6 @@ class Tautulli { return url; } - /* eslint-disable-next-line class-methods-use-this */ - logTautulliError(error) { - throw new TautulliUnexpectedError(error); - } - getPlaysByDayOfWeek(plexUserId, days, yAxis) { const url = this.buildUrlWithCmdAndUserid( "get_plays_by_dayofweek", @@ -41,7 +40,7 @@ class Tautulli { return fetch(url.href) .then(resp => resp.json()) - .catch(error => this.logTautulliError(error)); + .catch(error => logTautulliError(error)); } getPlaysByDays(plexUserId, days, yAxis) { @@ -51,7 +50,7 @@ class Tautulli { return fetch(url.href) .then(resp => resp.json()) - .catch(error => this.logTautulliError(error)); + .catch(error => logTautulliError(error)); } watchTimeStats(plexUserId) { @@ -63,7 +62,7 @@ class Tautulli { return fetch(url.href) .then(resp => resp.json()) - .catch(error => this.logTautulliError(error)); + .catch(error => logTautulliError(error)); } viewHistory(plexUserId) { @@ -74,7 +73,7 @@ class Tautulli { return fetch(url.href) .then(resp => resp.json()) - .catch(error => this.logTautulliError(error)); + .catch(error => logTautulliError(error)); } } diff --git a/src/tmdb/tmdb.js b/src/tmdb/tmdb.js index bddb86f..9adb346 100644 --- a/src/tmdb/tmdb.js +++ b/src/tmdb/tmdb.js @@ -20,14 +20,23 @@ class TMDBUnauthorizedError extends Error { } class TMDBUnexpectedError extends Error { - constructor(type) { + constructor(type, errorMessage) { const message = `An unexpected error occured while fetching ${type} from tmdb`; super(message); + this.errorMessage = errorMessage; this.statusCode = 500; } } +class TMDBNotReachableError extends Error { + constructor( + message = "TMDB api not reachable, check your internet connection" + ) { + super(message); + } +} + const tmdbErrorResponse = (error, type = null) => { if (error.status === 404) { const message = error.response.body.status_message; @@ -35,11 +44,45 @@ const tmdbErrorResponse = (error, type = null) => { throw new TMDBNotFoundError(`${message.slice(0, -1)} in tmdb.`); } else if (error.status === 401) { throw new TMDBUnauthorizedError(error?.response?.body?.status_message); + } else if (error?.code === "ENOTFOUND") { + throw new TMDBNotReachableError(); } - throw new TMDBUnexpectedError(type); + throw new TMDBUnexpectedError(type, error); }; +/** + * Maps our response from tmdb api to a movie/show object. + * @param {String} response from tmdb. + * @param {String} The type declared in listSearch. + * @returns {Promise} dict with tmdb results, mapped as movie/show objects. + */ +function mapResults(response, type = null) { + const results = response?.results?.map(result => { + if (type === "movie" || result.media_type === "movie") { + const movie = Movie.convertFromTmdbResponse(result); + return movie.createJsonResponse(); + } + if (type === "show" || result.media_type === "tv") { + const show = Show.convertFromTmdbResponse(result); + return show.createJsonResponse(); + } + if (type === "person" || result.media_type === "person") { + const person = Person.convertFromTmdbResponse(result); + return person.createJsonResponse(); + } + + return {}; + }); + + return { + results, + page: response?.page, + total_results: response?.total_results, + total_pages: response?.total_pages + }; +} + class TMDB { constructor(apiKey, cache, tmdbLibrary) { this.tmdbLibrary = tmdbLibrary || moviedb(apiKey); @@ -69,15 +112,17 @@ class TMDB { this.defaultTTL = 86400; } - getFromCacheOrFetchFromTmdb(cacheKey, tmdbMethod, query) { - return new Promise((resolve, reject) => - this.cache - .get(cacheKey) - .then(resolve) - .catch(() => this.tmdb(tmdbMethod, query)) - .then(resolve) - .catch(error => reject(tmdbErrorResponse(error, tmdbMethod))) - ); + async getFromCacheOrFetchFromTmdb(cacheKey, tmdbMethod, query) { + try { + const result = await this.cache.get(cacheKey); + if (!result) throw new Error(); + + return result; + } catch { + return this.tmdb(tmdbMethod, query) + .then(result => this.cache.set(cacheKey, result, this.defaultTTL)) + .catch(error => tmdbErrorResponse(error, tmdbMethod)); + } } /** @@ -91,9 +136,9 @@ class TMDB { const query = { id: identifier }; const cacheKey = `tmdb/${this.cacheTags.movieInfo}:${identifier}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, "movieInfo", query) - .then(movie => this.cache.set(cacheKey, movie, this.defaultTTL)) - .then(movie => Movie.convertFromTmdbResponse(movie)); + return this.getFromCacheOrFetchFromTmdb(cacheKey, "movieInfo", query).then( + movie => Movie.convertFromTmdbResponse(movie) + ); } /** @@ -105,9 +150,11 @@ class TMDB { const query = { id: identifier }; const cacheKey = `tmdb/${this.cacheTags.movieCredits}:${identifier}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, "movieCredits", query) - .then(credits => this.cache.set(cacheKey, credits, this.defaultTTL)) - .then(credits => Credits.convertFromTmdbResponse(credits)); + return this.getFromCacheOrFetchFromTmdb( + cacheKey, + "movieCredits", + query + ).then(credits => Credits.convertFromTmdbResponse(credits)); } /** @@ -123,11 +170,7 @@ class TMDB { cacheKey, "movieReleaseDates", query - ) - .then(releaseDates => - this.cache.set(cacheKey, releaseDates, this.defaultTTL) - ) - .then(releaseDates => ReleaseDates.convertFromTmdbResponse(releaseDates)); + ).then(releaseDates => ReleaseDates.convertFromTmdbResponse(releaseDates)); } /** @@ -140,18 +183,18 @@ class TMDB { const query = { id: identifier }; const cacheKey = `tmdb/${this.cacheTags.showInfo}:${identifier}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, "tvInfo", query) - .then(show => this.cache.set(cacheKey, show, this.defaultTTL)) - .then(show => Show.convertFromTmdbResponse(show)); + return this.getFromCacheOrFetchFromTmdb(cacheKey, "tvInfo", query).then( + show => Show.convertFromTmdbResponse(show) + ); } showCredits(identifier) { const query = { id: identifier }; const cacheKey = `tmdb/${this.cacheTags.showCredits}:${identifier}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, "tvCredits", query) - .then(credits => this.cache.set(cacheKey, credits, this.defaultTTL)) - .then(credits => Credits.convertFromTmdbResponse(credits)); + return this.getFromCacheOrFetchFromTmdb(cacheKey, "tvCredits", query).then( + credits => Credits.convertFromTmdbResponse(credits) + ); } /** @@ -164,9 +207,9 @@ class TMDB { const query = { id: identifier }; const cacheKey = `tmdb/${this.cacheTags.personInfo}:${identifier}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, "personInfo", query) - .then(person => this.cache.set(cacheKey, person, this.defaultTTL)) - .then(person => Person.convertFromTmdbResponse(person)); + return this.getFromCacheOrFetchFromTmdb(cacheKey, "personInfo", query).then( + person => Person.convertFromTmdbResponse(person) + ); } personCredits(identifier) { @@ -177,18 +220,18 @@ class TMDB { cacheKey, "personCombinedCredits", query - ) - .then(credits => this.cache.set(cacheKey, credits, this.defaultTTL)) - .then(credits => Credits.convertFromTmdbResponse(credits)); + ).then(credits => Credits.convertFromTmdbResponse(credits)); } multiSearch(searchQuery, page = 1, includeAdult = true) { const query = { query: searchQuery, page, include_adult: includeAdult }; const cacheKey = `tmdb/${this.cacheTags.multiSearch}:${page}:${searchQuery}:${includeAdult}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMulti", query) - .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) - .then(response => this.mapResults(response)); + return this.getFromCacheOrFetchFromTmdb( + cacheKey, + "searchMulti", + query + ).then(response => mapResults(response)); } /** @@ -205,9 +248,11 @@ class TMDB { }; const cacheKey = `tmdb/${this.cacheTags.movieSearch}:${page}:${searchQuery}:${includeAdult}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMovie", tmdbquery) - .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) - .then(response => this.mapResults(response, "movie")); + return this.getFromCacheOrFetchFromTmdb( + cacheKey, + "searchMovie", + tmdbquery + ).then(response => mapResults(response, "movie")); } /** @@ -224,9 +269,11 @@ class TMDB { }; const cacheKey = `tmdb/${this.cacheTags.showSearch}:${page}:${searchQuery}:${includeAdult}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchTv", tmdbquery) - .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) - .then(response => this.mapResults(response, "show")); + return this.getFromCacheOrFetchFromTmdb( + cacheKey, + "searchTv", + tmdbquery + ).then(response => mapResults(response, "show")); } /** @@ -243,60 +290,29 @@ class TMDB { }; const cacheKey = `tmdb/${this.cacheTags.personSearch}:${page}:${searchQuery}:${includeAdult}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchPerson", tmdbquery) - .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) - .then(response => this.mapResults(response, "person")); + return this.getFromCacheOrFetchFromTmdb( + cacheKey, + "searchPerson", + tmdbquery + ).then(response => mapResults(response, "person")); } movieList(listName, page = 1) { const query = { page }; const cacheKey = `tmdb/${this.cacheTags[listName]}:${page}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query) - .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) - .then(response => this.mapResults(response, "movie")); + return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query).then( + response => mapResults(response, "movie") + ); } showList(listName, page = 1) { const query = { page }; const cacheKey = `tmdb/${this.cacheTags[listName]}:${page}`; - return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query) - .then(response => this.cache.set(cacheKey, response, this.defaultTTL)) - .then(response => this.mapResults(response, "show")); - } - - /** - * Maps our response from tmdb api to a movie/show object. - * @param {String} response from tmdb. - * @param {String} The type declared in listSearch. - * @returns {Promise} dict with tmdb results, mapped as movie/show objects. - */ - // eslint-disable-next-line class-methods-use-this - mapResults(response, type = undefined) { - const results = response?.results?.map(result => { - if (type === "movie" || result.media_type === "movie") { - const movie = Movie.convertFromTmdbResponse(result); - return movie.createJsonResponse(); - } - if (type === "show" || result.media_type === "tv") { - const show = Show.convertFromTmdbResponse(result); - return show.createJsonResponse(); - } - if (type === "person" || result.media_type === "person") { - const person = Person.convertFromTmdbResponse(result); - return person.createJsonResponse(); - } - - return {}; - }); - - return { - results, - page: response.page, - total_results: response.total_results, - total_pages: response.total_pages - }; + return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query).then( + response => mapResults(response, "show") + ); } /** diff --git a/src/user/userRepository.js b/src/user/userRepository.js index 6022f48..d23f0d4 100644 --- a/src/user/userRepository.js +++ b/src/user/userRepository.js @@ -1,6 +1,69 @@ const assert = require("assert"); const establishedDatabase = require("../database/database"); +class LinkPlexUserError extends Error { + constructor(errorMessage = null) { + const message = + "An unexpected error occured while linking plex and seasoned accounts"; + super(message); + + this.statusCode = 500; + this.errorMessage = errorMessage; + this.source = "database"; + } +} + +class UnlinkPlexUserError extends Error { + constructor(errorMessage = null) { + const message = + "An unexpected error occured while unlinking plex and seasoned accounts"; + super(message); + + this.statusCode = 500; + this.errorMessage = errorMessage; + this.source = "database"; + } +} + +class UnexpectedUserSettingsError extends Error { + constructor(errorMessage = null) { + const message = + "An unexpected error occured while fetching settings for your account"; + super(message); + + this.statusCode = 500; + this.errorMessage = errorMessage; + this.source = "database"; + } +} + +class NoSettingsUserNotFoundError extends Error { + constructor() { + const message = "User not found, no settings to get"; + super(message); + + this.statusCode = 404; + } +} + +const rejectUnexpectedDatabaseError = ( + message, + status, + error, + reject = null +) => { + const body = { + status, + message, + source: "seasoned database" + }; + + if (reject == null) { + return new Promise((_, reject) => reject(body)); + } + return reject(body); +}; + class UserRepository { constructor(database) { this.database = database || establishedDatabase; @@ -77,14 +140,7 @@ class UserRepository { this.database .run(this.queries.link, [plexUserID, username]) .then(row => resolve(row)) - .catch(error => - reject({ - status: 500, - message: - "An unexpected error occured while linking plex and seasoned accounts", - source: "seasoned database" - }) - ); + .catch(error => reject(new LinkPlexUserError(error))); }); } @@ -98,14 +154,7 @@ class UserRepository { this.database .run(this.queries.unlink, username) .then(row => resolve(row)) - .catch(error => - reject({ - status: 500, - message: - "An unexpected error occured while unlinking plex and seasoned accounts", - source: "seasoned database" - }) - ); + .catch(error => reject(new UnlinkPlexUserError(error))); }); } @@ -131,6 +180,7 @@ class UserRepository { .get(this.queries.getSettings, username) .then(async row => { if (row == null) { + // eslint-disable-next-line no-console console.debug( `settings do not exist for user: ${username}. Creating settings entry.` ); @@ -146,23 +196,13 @@ class UserRepository { reject(error); } } else { - reject({ - status: 404, - message: "User not found, no settings to get" - }); + reject(new NoSettingsUserNotFoundError()); } } resolve(row); }) - .catch(() => - reject({ - status: 500, - message: - "An unexpected error occured while fetching settings for your account", - source: "seasoned database" - }) - ); + .catch(error => reject(new UnexpectedUserSettingsError(error))); }); } @@ -173,10 +213,10 @@ class UserRepository { * @param {String} emoji * @returns {Promsie} */ - updateSettings(username, darkMode = null, emoji = null) { + updateSettings(username, _darkMode = null, _emoji = null) { const settings = this.getSettings(username); - darkMode = darkMode ? darkMode : settings.darkMode; - emoji = emoji ? emoji : settings.emoji; + const darkMode = _darkMode || settings.darkMode; + const emoji = _emoji || settings.emoji; return this.dbUpdateSettings(username, darkMode, emoji).catch(error => { if (error.status && error.message) { @@ -223,22 +263,4 @@ class UserRepository { } } -const rejectUnexpectedDatabaseError = ( - message, - status, - error, - reject = null -) => { - const body = { - status, - message, - source: "seasoned database" - }; - - if (reject == null) { - return new Promise((_, reject) => reject(body)); - } - reject(body); -}; - module.exports = UserRepository; diff --git a/src/webserver/app.js b/src/webserver/app.js index 859c4a4..dcbe080 100644 --- a/src/webserver/app.js +++ b/src/webserver/app.js @@ -56,11 +56,11 @@ router.get("/", (req, res) => { res.send("welcome to seasoned api"); }); -app.use(Raven.errorHandler()); -app.use((err, req, res) => { - res.statusCode = 500; - res.end(`${res.sentry}\n`); -}); +// app.use(Raven.errorHandler()); +// app.use((err, req, res) => { +// res.statusCode = 500; +// res.end(`${res.sentry}\n`); +// }); /** * User diff --git a/src/webserver/controllers/list/listController.js b/src/webserver/controllers/list/listController.js index 2b55c59..298dccf 100644 --- a/src/webserver/controllers/list/listController.js +++ b/src/webserver/controllers/list/listController.js @@ -15,16 +15,13 @@ const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); // + newly created (tv/latest). // + movie/latest // -function handleError(error, res) { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res - .status(500) - .send({ message: "An unexpected error occured while requesting list" }); - } +function handleError(listname, error, res) { + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while requesting list with id: ${listname}` + }); } function fetchTmdbList(req, res, listname, type) { @@ -34,16 +31,17 @@ function fetchTmdbList(req, res, listname, type) { return tmdb .movieList(listname, page) .then(listResponse => res.send(listResponse)) - .catch(error => handleError(error, res)); + .catch(error => handleError(listname, error, res)); } if (type === "show") { return tmdb .showList(listname, page) .then(listResponse => res.send(listResponse)) - .catch(error => handleError(error, res)); + .catch(error => handleError(listname, error, res)); } return handleError( + listname, { status: 400, message: `'${type}' is not a valid list type.` diff --git a/src/webserver/controllers/movie/credits.js b/src/webserver/controllers/movie/credits.js index ce33c5f..ad467dd 100644 --- a/src/webserver/controllers/movie/credits.js +++ b/src/webserver/controllers/movie/credits.js @@ -10,15 +10,12 @@ const movieCreditsController = (req, res) => { .movieCredits(movieId) .then(credits => res.send(credits.createJsonResponse())) .catch(error => { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res.status(500).send({ - message: "An unexpected error occured while requesting movie credits" - }); - } + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while requesting credits for movie with id: ${movieId}` + }); }); }; diff --git a/src/webserver/controllers/movie/info.js b/src/webserver/controllers/movie/info.js index f22889f..6311b88 100644 --- a/src/webserver/controllers/movie/info.js +++ b/src/webserver/controllers/movie/info.js @@ -5,20 +5,6 @@ const Plex = require("../../../plex/plex"); const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const plex = new Plex(configuration.get("plex", "ip")); -function handleError(error, res) { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res.status(500).send({ - success: false, - message: "An unexpected error occured while requesting movie info", - errorResponse: error?.message - }); - } -} - /** * Controller: Retrieve information for a movie * @param {Request} req http request variable @@ -32,9 +18,9 @@ async function movieInfoController(req, res) { let releaseDates = req.query?.release_dates; let checkExistance = req.query?.check_existance; - credits = credits.toLowerCase() === "true"; - releaseDates = releaseDates.toLowerCase() === "true"; - checkExistance = checkExistance.toLowerCase() === "true"; + credits = credits?.toLowerCase() === "true"; + releaseDates = releaseDates?.toLowerCase() === "true"; + checkExistance = checkExistance?.toLowerCase() === "true"; const tmdbQueue = [tmdb.movieInfo(movieId)]; if (credits) tmdbQueue.push(tmdb.movieCredits(movieId)); @@ -54,9 +40,14 @@ async function movieInfoController(req, res) { } catch {} } - res.send(movie); + return res.send(movie); } catch (error) { - handleError(error, res); + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while requesting info for with id: ${movieId}` + }); } } diff --git a/src/webserver/controllers/movie/releaseDates.js b/src/webserver/controllers/movie/releaseDates.js index 8097002..74ad3d8 100644 --- a/src/webserver/controllers/movie/releaseDates.js +++ b/src/webserver/controllers/movie/releaseDates.js @@ -10,15 +10,12 @@ const movieReleaseDatesController = (req, res) => { .movieReleaseDates(movieId) .then(releaseDates => res.send(releaseDates.createJsonResponse())) .catch(error => { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res.status(500).send({ - message: "An unexpected error occured while requesting movie credits" - }); - } + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while requesting release dates for movie with id: ${movieId}` + }); }); }; diff --git a/src/webserver/controllers/person/credits.js b/src/webserver/controllers/person/credits.js index 414936a..72d9c5a 100644 --- a/src/webserver/controllers/person/credits.js +++ b/src/webserver/controllers/person/credits.js @@ -10,15 +10,12 @@ const personCreditsController = (req, res) => { .personCredits(personId) .then(credits => res.send(credits)) .catch(error => { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res.status(500).send({ - message: "An unexpected error occured while requesting person credits" - }); - } + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while requesting info for person with id ${personId}.` + }); }); }; diff --git a/src/webserver/controllers/person/info.js b/src/webserver/controllers/person/info.js index c57436f..5a00102 100644 --- a/src/webserver/controllers/person/info.js +++ b/src/webserver/controllers/person/info.js @@ -3,18 +3,6 @@ const TMDB = require("../../../tmdb/tmdb"); const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); -function handleError(error, res) { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res.status(500).send({ - message: "An unexpected error occured while requesting person info." - }); - } -} - /** * Controller: Retrieve information for a person * @param {Request} req http request variable @@ -26,7 +14,7 @@ async function personInfoController(req, res) { const personId = req.params.id; let { credits } = req.query; - credits = credits.toLowerCase() === "true"; + credits = credits?.toLowerCase() === "true"; const tmdbQueue = [tmdb.personInfo(personId)]; if (credits) tmdbQueue.push(tmdb.personCredits(personId)); @@ -39,7 +27,12 @@ async function personInfoController(req, res) { return res.send(person); } catch (error) { - return handleError(error, res); + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while requesting info for person with id: ${personId}` + }); } } diff --git a/src/webserver/controllers/request/fetchAllRequests.js b/src/webserver/controllers/request/fetchAllRequests.js index c20ea23..252d76f 100644 --- a/src/webserver/controllers/request/fetchAllRequests.js +++ b/src/webserver/controllers/request/fetchAllRequests.js @@ -15,7 +15,12 @@ function fetchAllRequests(req, res) { .fetchAll(page, filter) .then(result => res.send(result)) .catch(error => { - res.status(404).send({ success: false, message: error.message }); + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while requesting all requests` + }); }); } diff --git a/src/webserver/controllers/request/getRequest.js b/src/webserver/controllers/request/getRequest.js index ec79520..b4a491f 100644 --- a/src/webserver/controllers/request/getRequest.js +++ b/src/webserver/controllers/request/getRequest.js @@ -16,7 +16,12 @@ function fetchAllRequests(req, res) { .getRequestByIdAndType(id, type) .then(result => res.send(result)) .catch(error => { - res.status(404).send({ success: false, message: error.message }); + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while requesting request with id: ${id}` + }); }); } diff --git a/src/webserver/controllers/search/movieSearch.js b/src/webserver/controllers/search/movieSearch.js index 8d216c4..d863cc4 100644 --- a/src/webserver/controllers/search/movieSearch.js +++ b/src/webserver/controllers/search/movieSearch.js @@ -24,15 +24,12 @@ function movieSearchController(req, res) { .movieSearch(query, page, includeAdult) .then(movieSearchResults => res.send(movieSearchResults)) .catch(error => { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res.status(500).send({ - message: `An unexpected error occured while searching movies with query: ${query}` - }); - } + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while searching movies with query: ${query}` + }); }); } diff --git a/src/webserver/controllers/search/multiSearch.js b/src/webserver/controllers/search/multiSearch.js index b96a4f1..f16ce30 100644 --- a/src/webserver/controllers/search/multiSearch.js +++ b/src/webserver/controllers/search/multiSearch.js @@ -24,15 +24,12 @@ function multiSearchController(req, res) { .multiSearch(query, page, includeAdult) .then(multiSearchResults => res.send(multiSearchResults)) .catch(error => { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res.status(500).send({ - message: `An unexpected error occured while searching with query: ${query}` - }); - } + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while searching with query: ${query}` + }); }); } diff --git a/src/webserver/controllers/search/personSearch.js b/src/webserver/controllers/search/personSearch.js index c908dea..838bed0 100644 --- a/src/webserver/controllers/search/personSearch.js +++ b/src/webserver/controllers/search/personSearch.js @@ -24,15 +24,12 @@ function personSearchController(req, res) { .personSearch(query, page, includeAdult) .then(persons => res.send(persons)) .catch(error => { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res.status(500).send({ - message: `An unexpected error occured while searching people with query: ${query}` - }); - } + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while searching person with query: ${query}` + }); }); } diff --git a/src/webserver/controllers/search/showSearch.js b/src/webserver/controllers/search/showSearch.js index 740f763..534d1d0 100644 --- a/src/webserver/controllers/search/showSearch.js +++ b/src/webserver/controllers/search/showSearch.js @@ -26,7 +26,12 @@ function showSearchController(req, res) { res.send(shows); }) .catch(error => { - res.status(500).send({ success: false, message: error.message }); + res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while searching person with query: ${query}` + }); }); } diff --git a/src/webserver/controllers/show/credits.js b/src/webserver/controllers/show/credits.js index bed66a9..672f3e8 100644 --- a/src/webserver/controllers/show/credits.js +++ b/src/webserver/controllers/show/credits.js @@ -10,15 +10,12 @@ const showCreditsController = (req, res) => { .showCredits(showId) .then(credits => res.send(credits.createJsonResponse())) .catch(error => { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res.status(500).send({ - message: "An unexpected error occured while requesting show credits" - }); - } + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while requesting credits for show with id: ${showId}.` + }); }); }; diff --git a/src/webserver/controllers/show/info.js b/src/webserver/controllers/show/info.js index 4eeba4a..68f7301 100644 --- a/src/webserver/controllers/show/info.js +++ b/src/webserver/controllers/show/info.js @@ -5,18 +5,6 @@ const Plex = require("../../../plex/plex"); const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const plex = new Plex(configuration.get("plex", "ip")); -function handleError(error, res) { - const { status, message } = error; - - if (status && message) { - res.status(status).send({ success: false, message }); - } else { - res.status(500).send({ - message: "An unexpected error occured while requesting show info." - }); - } -} - /** * Controller: Retrieve information for a show * @param {Request} req http request variable @@ -48,9 +36,14 @@ async function showInfoController(req, res) { } catch {} } - res.send(show); + return res.send(show); } catch (error) { - handleError(error, res); + return res.status(error?.statusCode || 500).send({ + success: false, + message: + error?.message || + `An unexpected error occured while requesting info for show with id: ${showId}` + }); } } -- 2.34.1 From f1eaf3e019db055ca06e831df8b706b392d9dddc Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 19 Aug 2022 16:05:16 +0200 Subject: [PATCH 9/9] Set 2 eslint rules as warning temporarly --- .eslintrc.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index e64f9ff..157265e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -6,13 +6,15 @@ }, "extends": ["eslint-config-airbnb-base", "plugin:prettier/recommended"], "rules": { + "max-classes-per-file": 1, "no-empty": [ 2, { "allowEmptyCatch": true } ], - "no-underscore-dangle": "off", - "no-shadow": "off" + "no-promise-executor-return": 1, + "no-shadow": "off", + "no-underscore-dangle": "off" } } -- 2.34.1