From 2e5c16d9e86a1ee429153cdf0a945d5b7a9a796a Mon Sep 17 00:00:00 2001 From: Zach Bruggeman Date: Sun, 16 Apr 2017 18:56:53 -0700 Subject: [PATCH] Add MyAnimeList integration --- server/index.js | 115 ++------ server/io.js | 64 +++++ server/package.json | 10 +- server/{ => routes}/autocomplete.js | 9 +- server/{ => routes}/bif.js | 8 +- server/routes/mal.js | 84 ++++++ server/{ => routes}/opening.js | 16 +- server/yarn.lock | 392 +++++++++++++++++++++++++++- src/components/Header.vue | 93 ++++++- src/components/Search.vue | 3 +- src/components/Video.vue | 1 + src/pages/Login.vue | 2 +- src/pages/Media.vue | 51 +++- src/pages/Series.vue | 3 +- src/pages/Settings.vue | 69 +++++ src/router/index.js | 7 + src/store/index.js | 37 ++- 17 files changed, 837 insertions(+), 127 deletions(-) create mode 100644 server/io.js rename server/{ => routes}/autocomplete.js (73%) rename server/{ => routes}/bif.js (63%) create mode 100644 server/routes/mal.js rename server/{ => routes}/opening.js (51%) create mode 100644 src/pages/Settings.vue diff --git a/server/index.js b/server/index.js index 823b644..db11113 100644 --- a/server/index.js +++ b/server/index.js @@ -1,97 +1,40 @@ -const http = require('http') -const compress = require('compression')() -const autocompleteHandler = require('./autocomplete') -const openingHandler = require('./opening') -const bifHandler = require('./bif') - -const srv = http.createServer((req, res) => { - compress(req, res, () => { - if (req.url.indexOf('/autocomplete') === 0) { - autocompleteHandler(req, res) - } else if (req.url.indexOf('/opening') === 0) { - openingHandler(req, res) - } else if (req.url.indexOf('/bif') === 0) { - bifHandler(req, res) - } else if (req.url.indexOf('/update') === 0) { - updateHandler(req, res) - } else { - res.end('love arrow shoot!') - } - }) -}) +const express = require('express') +const compression = require('compression') +const cors = require('cors') + +const setupIo = require('./io') +const autocomplete = require('./routes/autocomplete') +const bif = require('./routes/bif') +const opening = require('./routes/opening') +const mal = require('./routes/mal') + +// create app +const app = express() +const srv = require('http').Server(app) +app.use(compression()) +app.use(cors()) + +// setup socket.io const io = require('socket.io')(srv) io.origins('*:*') +setupIo(io) -function findRoom (rooms) { - return Object.keys(rooms).find((k) => k.startsWith('umi//')) -} - -function updateHandler (req, res) { - const token = req.url.split('/update/')[1] +// setup routes +app.get('/', (req, res) => res.send({status: 'ok'})) +app.post('/update/:token', (req, res) => { + const token = req.params.token if (token !== process.env.UPDATE_TOKEN) { - return res.end('not ok') + return res.end({status: 'not ok'}) } io.emit('app-update') - res.end('ok') -} - -io.on('connection', (socket) => { - socket.on('join-room', (room) => { - const currentRoom = findRoom(socket.rooms) - if (currentRoom) return - - socket.join(room) - socket.broadcast.to(room).emit('user-joined') - const ioRoom = io.sockets.adapter.rooms[room] - if (ioRoom) { - socket.broadcast.to(room).emit('room-count', ioRoom.length) - socket.emit('room-count', ioRoom.length) - } - }) - - socket.on('leave-room', () => { - const room = findRoom(socket.rooms) - socket.leave(room) - socket.broadcast.to(room).emit('user-left') - const ioRoom = io.sockets.adapter.rooms[room] - if (ioRoom) { - socket.broadcast.to(room).emit('room-count', ioRoom.length) - } - }) - - socket.once('disconnecting', () => { - const room = findRoom(socket.rooms) - if (!room) return - - socket.leave(room) - socket.broadcast.to(room).emit('user-left') - const ioRoom = io.sockets.adapter.rooms[room] - if (ioRoom) { - socket.broadcast.to(room).emit('room-count', ioRoom.length) - } - }) - - socket.on('update-status', (obj) => { - const room = findRoom(socket.rooms) - socket.broadcast.to(room).emit('update-status', obj) - }) - - socket.on('player-event', (obj) => { - const room = findRoom(socket.rooms) - socket.broadcast.to(room).emit('player-event', obj) - }) - - socket.on('change', (mediaId) => { - const room = findRoom(socket.rooms) - socket.broadcast.to(room).emit('change', mediaId) - }) - - socket.on('emoji', (name) => { - const room = findRoom(socket.rooms) - socket.broadcast.to(room).emit('emoji', name) - }) + res.send({status: 'ok'}) }) +app.get('/autocomplete/:country', autocomplete) +app.get('/bif', bif) +app.get('/opening', opening) +app.use('/mal', mal) +// listen srv.listen(3001, () => { console.log('listening on 3001') }) diff --git a/server/io.js b/server/io.js new file mode 100644 index 0000000..5df42c5 --- /dev/null +++ b/server/io.js @@ -0,0 +1,64 @@ +function findRoom (rooms) { + return Object.keys(rooms).find((k) => k.startsWith('umi//')) +} + +function setupIo (io) { + io.on('connection', (socket) => { + socket.on('join-room', (room) => { + const currentRoom = findRoom(socket.rooms) + if (currentRoom) return + + socket.join(room) + socket.broadcast.to(room).emit('user-joined') + const ioRoom = io.sockets.adapter.rooms[room] + if (ioRoom) { + socket.broadcast.to(room).emit('room-count', ioRoom.length) + socket.emit('room-count', ioRoom.length) + } + }) + + socket.on('leave-room', () => { + const room = findRoom(socket.rooms) + socket.leave(room) + socket.broadcast.to(room).emit('user-left') + const ioRoom = io.sockets.adapter.rooms[room] + if (ioRoom) { + socket.broadcast.to(room).emit('room-count', ioRoom.length) + } + }) + + socket.once('disconnecting', () => { + const room = findRoom(socket.rooms) + if (!room) return + + socket.leave(room) + socket.broadcast.to(room).emit('user-left') + const ioRoom = io.sockets.adapter.rooms[room] + if (ioRoom) { + socket.broadcast.to(room).emit('room-count', ioRoom.length) + } + }) + + socket.on('update-status', (obj) => { + const room = findRoom(socket.rooms) + socket.broadcast.to(room).emit('update-status', obj) + }) + + socket.on('player-event', (obj) => { + const room = findRoom(socket.rooms) + socket.broadcast.to(room).emit('player-event', obj) + }) + + socket.on('change', (mediaId) => { + const room = findRoom(socket.rooms) + socket.broadcast.to(room).emit('change', mediaId) + }) + + socket.on('emoji', (name) => { + const room = findRoom(socket.rooms) + socket.broadcast.to(room).emit('emoji', name) + }) + }) +} + +module.exports = setupIo diff --git a/server/package.json b/server/package.json index e691d98..57b7127 100644 --- a/server/package.json +++ b/server/package.json @@ -7,18 +7,24 @@ "license": "MIT", "dependencies": { "axios": "^0.15.3", + "body-parser": "^1.17.1", "cheerio": "^0.22.0", "compression": "^1.6.2", + "cors": "^2.8.3", + "express": "^4.15.2", + "iron": "^4.0.4", + "popura": "^1.2.5", "socket.io": "^1.7.2" }, "scripts": { "start": "node index.js", - "dev": "cross-env UPDATE_TOKEN=example nodemon index.js" + "dev": "cross-env UPDATE_TOKEN=example IRON_TOKEN=EXAMPLE_TOKEN_PLEASE_DONT_USE_IN_PRODUCTION nodemon index.js" }, "now": { "alias": "umi-watch-api", "env": { - "UPDATE_TOKEN": "@update-token" + "UPDATE_TOKEN": "@update-token", + "IRON_TOKEN": "@iron-token" } } } diff --git a/server/autocomplete.js b/server/routes/autocomplete.js similarity index 73% rename from server/autocomplete.js rename to server/routes/autocomplete.js index 75ceae1..f7eea9c 100644 --- a/server/autocomplete.js +++ b/server/routes/autocomplete.js @@ -1,7 +1,7 @@ const axios = require('axios') function autocompleteHandler (req, res) { - const country = req.url.replace('/autocomplete/', '') + const {country} = req.params axios.all([ axios.get(`http://because.moe/json/${country}`), axios.get('http://www.crunchyroll.com/ajax/?req=RpcApiSearch_GetSearchCandidates') @@ -17,13 +17,10 @@ function autocompleteHandler (req, res) { image: c.img })) - res.setHeader('Access-Control-Allow-Origin', '*') - res.setHeader('Content-Type', 'application/json') - res.end(JSON.stringify(filtered)) + res.send(filtered) })).catch((err) => { console.error(err.message) - res.statusCode = 500 - res.end('something went wrong') + res.status(500).send('something went wrong') }) } diff --git a/server/bif.js b/server/routes/bif.js similarity index 63% rename from server/bif.js rename to server/routes/bif.js index e673433..3d758c5 100644 --- a/server/bif.js +++ b/server/routes/bif.js @@ -1,17 +1,13 @@ const axios = require('axios') const url = require('url') -const qs = require('querystring') function bifHandler (req, res) { - res.setHeader('Access-Control-Allow-Origin', '*') - - const {query} = url.parse(req.url) - const {bif} = qs.parse(query) + const {bif} = req.query if (!bif) return res.end() const {hostname} = url.parse(bif) if (!hostname.endsWith('crunchyroll.com')) return res.end() - res.setHeader('Content-Type', 'application/octet-stream') + res.type('application/octet-stream') axios.get(bif, { responseType: 'stream' }) diff --git a/server/routes/mal.js b/server/routes/mal.js new file mode 100644 index 0000000..21818e2 --- /dev/null +++ b/server/routes/mal.js @@ -0,0 +1,84 @@ +const express = require('express') +const axios = require('axios') +const {json} = require('body-parser') +const popura = require('popura') +const Iron = require('iron') + +const {IRON_TOKEN} = process.env + +const router = express.Router() +router.use(json()) + +router.post('/login', function malLogin (req, res) { + const {username, password} = req.body + if (!username || !password) return res.status(400).send({status: 'not ok', error: 'Invalid login'}) + + const client = popura(username, password) + + client.verifyAuth() + .then((obj) => { + Iron.seal(password, IRON_TOKEN, Iron.defaults, (err, sealed) => { + if (err) return res.status(500).send({status: 'not ok', error: 'Internal error'}) + + res.send({ + status: 'ok', + username: obj.username, + password: sealed + }) + }) + }) + .catch((err) => { + res.status(err.statusCode).send({ + status: 'not ok', + error: err.message + }) + }) +}) + +router.get('/series', function malSeries (req, res) { + const {name} = req.query + if (!name) return res.status(400).send({status: 'not ok', error: 'Invalid payload'}) + + axios({ + method: 'GET', + url: 'https://myanimelist.net/search/prefix.json', + params: { + type: 'anime', + keyword: name, + v: 1 + } + }) + .then(({data}) => { + const {items} = data.categories[0] + + let item = items.find((i) => i.name.toLowerCase() === name.toLowerCase()) || items[0] + if (name === 'My Hero Academia Season 2') { + item = items.find((i) => i.name === 'Boku no Hero Academia 2nd Season') || item + } + if (!item) return res.status(404).send({status: 'not ok', error: `Couldn't find anime for "${name}"`}) + + res.send({status: 'ok', item}) + }) +}) + +router.post('/update', function malUpdate (req, res) { + const {username, password, id, episode, status} = req.body + if (!username || !password) return res.status(400).send({status: 'not ok', error: 'Invalid login'}) + if (!id || !episode || !status) return res.status(400).send({status: 'not ok', error: 'Invalid payload'}) + + Iron.unseal(password, IRON_TOKEN, Iron.defaults, (err, unsealed) => { + if (err) return res.status(500).send({status: 'not ok', error: 'Internal error'}) + + const client = popura(username, unsealed) + client.updateAnime(id, {episode, status}) + .then(() => { + res.send({status: 'ok'}) + }) + .catch((err) => { + console.error(err) + res.status(500).send({status: 'not ok', error: 'Internal error'}) + }) + }) +}) + +module.exports = router diff --git a/server/opening.js b/server/routes/opening.js similarity index 51% rename from server/opening.js rename to server/routes/opening.js index 6745a24..12d9fae 100644 --- a/server/opening.js +++ b/server/routes/opening.js @@ -1,25 +1,19 @@ -const url = require('url') -const qs = require('querystring') const axios = require('axios') const cheerio = require('cheerio') function openingHandler (req, res) { - res.setHeader('Access-Control-Allow-Origin', '*') - res.setHeader('Content-Type', 'application/json') - - const {query} = url.parse(req.url) - const {search} = qs.parse(query) - if (!search) return res.end(JSON.stringify({result: null})) + const {search} = req.query + if (!search) return res.send({result: null}) axios.post('https://themes.moe/includes/anime_search.php', `search=-1&name=${search}`).then(({data}) => { const [html, id] = data - if (!id) return res.end(JSON.stringify({result: null})) + if (!id) return res.send({result: null}) const $ = cheerio.load(html) - const openings = $('a.vid-popup[data-type^="OP"]').toArray().map((el) => $(el).attr('href')) + const openings = $('a.vid-popup[data-type^="OP"]').toArray().map((el) => el.attribs.href) const result = openings[Math.floor(Math.random() * openings.length)] - res.end(JSON.stringify({result})) + res.send({result}) }) } diff --git a/server/yarn.lock b/server/yarn.lock index 473b15b..546dfb1 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -13,6 +13,10 @@ after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + arraybuffer.slice@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" @@ -45,10 +49,31 @@ blob@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" +body-parser@^1.17.1: + version "1.17.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" + dependencies: + bytes "2.4.0" + content-type "~1.0.2" + debug "2.6.1" + depd "~1.1.0" + http-errors "~1.6.1" + iconv-lite "0.4.15" + on-finished "~2.3.0" + qs "6.4.0" + raw-body "~2.2.0" + type-is "~1.6.14" + boolbase@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + buffer-shims@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" @@ -57,10 +82,18 @@ bytes@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" +bytes@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + callsite@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" +capture-stack-trace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" + cheerio@^0.22.0: version "0.22.0" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" @@ -115,6 +148,18 @@ compression@^1.6.2: on-headers "~1.0.1" vary "~1.1.0" +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" @@ -123,6 +168,25 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +cors@^2.8.3: + version "2.8.3" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.3.tgz#4cf78e1d23329a7496b2fc2225b77ca5bb5eb802" + dependencies: + object-assign "^4" + vary "^1" + +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + dependencies: + capture-stack-trace "^1.0.0" + +cryptiles@3.x.x: + version "3.1.1" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.1.tgz#86a9203f7367a0e9324bc7555ff0fcf5f81979ee" + dependencies: + boom "4.x.x" + css-select@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" @@ -142,12 +206,32 @@ debug@2.2.0, debug@~2.2.0: dependencies: ms "0.7.1" -debug@2.3.3, debug@^2.2.0: +debug@2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" dependencies: ms "0.7.2" +debug@2.6.1, debug@^2.2.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" + dependencies: + ms "0.7.2" + +debug@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" + dependencies: + ms "0.7.2" + +depd@1.1.0, depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + dom-serializer@0, dom-serializer@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" @@ -176,6 +260,18 @@ domutils@1.5.1, domutils@^1.5.1: dom-serializer "0" domelementtype "1" +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + engine.io-client@1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.3.tgz#1798ed93451246453d4c6f635d7a201fe940d5ab" @@ -219,12 +315,93 @@ entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +etag@~1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" + +express@^4.15.2: + version "4.15.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.2" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.1" + depd "~1.1.0" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.0" + finalhandler "~1.0.0" + fresh "0.5.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.3" + qs "6.4.0" + range-parser "~1.2.0" + send "0.15.1" + serve-static "1.12.1" + setprototypeof "1.0.3" + statuses "~1.3.1" + type-is "~1.6.14" + utils-merge "1.0.0" + vary "~1.1.0" + +finalhandler@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8" + dependencies: + debug "2.6.3" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.1" + statuses "~1.3.1" + unpipe "~1.0.0" + follow-redirects@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.0.0.tgz#8e34298cbd2e176f254effec75a1c78cc849fd37" dependencies: debug "^2.2.0" +forwarded@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + +fresh@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +got@^6.3.0: + version "6.7.1" + resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + has-binary@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" @@ -235,6 +412,10 @@ has-cors@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" +hoek@4.x.x: + version "4.1.1" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.1.1.tgz#9cc573ffba2b7b408fb5e9c2a13796be94cddce9" + htmlparser2@^3.9.1: version "3.9.2" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" @@ -246,14 +427,51 @@ htmlparser2@^3.9.1: inherits "^2.0.1" readable-stream "^2.0.2" +http-errors@~1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" + dependencies: + depd "1.1.0" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + +iconv-lite@0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" -inherits@^2.0.1, inherits@~2.0.1: +inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" +ipaddr.js@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" + +iron@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/iron/-/iron-4.0.4.tgz#c1f8cc4c91454194ab8920d9247ba882e528061a" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + +is-retry-allowed@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + +is-stream@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -314,7 +532,27 @@ lodash.some@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" -"mime-db@>= 1.27.0 < 2": +lodash@^4.0.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +lowercase-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +"mime-db@>= 1.27.0 < 2", mime-db@~1.27.0: version "1.27.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" @@ -328,6 +566,16 @@ mime-types@~2.1.11: dependencies: mime-db "~1.26.0" +mime-types@~2.1.15: + version "2.1.15" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" + dependencies: + mime-db "~1.27.0" + +mime@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + ms@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" @@ -346,7 +594,7 @@ nth-check@~1.0.1: dependencies: boolbase "~1.0.0" -object-assign@4.1.0: +object-assign@4.1.0, object-assign@^4: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" @@ -354,6 +602,12 @@ object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" @@ -380,10 +634,53 @@ parseuri@0.0.5: dependencies: better-assert "~1.0.0" +parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +popura@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/popura/-/popura-1.2.5.tgz#a92cd25fb940c2d6a5854029b825798a95c1901a" + dependencies: + debug "^2.2.0" + got "^6.3.0" + xml2js "^0.4.17" + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" +proxy-addr@~1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.3.0" + +qs@6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" + dependencies: + bytes "2.4.0" + iconv-lite "0.4.15" + unpipe "1.0.0" + readable-stream@^2.0.2: version "2.2.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.6.tgz#8b43aed76e71483938d12a8d46c6cf1a00b1f816" @@ -396,6 +693,45 @@ readable-stream@^2.0.2: string_decoder "~0.10.x" util-deprecate "~1.0.1" +safe-buffer@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" + +sax@>=0.6.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" + +send@0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" + dependencies: + debug "2.6.1" + depd "~1.1.0" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.0" + fresh "0.5.0" + http-errors "~1.6.1" + mime "1.3.4" + ms "0.7.2" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.1" + +serve-static@1.12.1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.15.1" + +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + socket.io-adapter@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" @@ -440,23 +776,56 @@ socket.io@^1.7.2: socket.io-client "1.7.3" socket.io-parser "2.3.1" +"statuses@>= 1.3.1 < 2", statuses@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" +timed-out@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" +type-is@~1.6.14: + version "1.6.15" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.15" + ultron@1.0.x: version "1.0.2" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -vary@~1.1.0: +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +vary@^1, vary@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" @@ -471,6 +840,19 @@ wtf-8@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" +xml2js@^0.4.17: + version "0.4.17" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + dependencies: + sax ">=0.6.0" + xmlbuilder "^4.1.0" + +xmlbuilder@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + dependencies: + lodash "^4.0.0" + xmlhttprequest-ssl@1.5.3: version "1.5.3" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" diff --git a/src/components/Header.vue b/src/components/Header.vue index 9bd896d..c5a0eb3 100644 --- a/src/components/Header.vue +++ b/src/components/Header.vue @@ -20,7 +20,29 @@ @@ -28,28 +50,73 @@ + + diff --git a/src/components/Search.vue b/src/components/Search.vue index d22b838..c3ed1c0 100644 --- a/src/components/Search.vue +++ b/src/components/Search.vue @@ -171,10 +171,11 @@ } .search-result.selected, .search-result:hover { - background: #f4f4f4; + background-color: #357edd; } .search-result.selected span, .search-result:hover span { + color: #fff; font-weight: 600; } diff --git a/src/components/Video.vue b/src/components/Video.vue index 15e05cd..f41bfe1 100644 --- a/src/components/Video.vue +++ b/src/components/Video.vue @@ -312,6 +312,7 @@ }, beforeDestroy () { this.logTime() + this.player.destroy() if (this.room !== '') { this.$socket.emit('player-event', { id: this.$socket.id, diff --git a/src/pages/Login.vue b/src/pages/Login.vue index ed7ba5e..2407f3b 100644 --- a/src/pages/Login.vue +++ b/src/pages/Login.vue @@ -17,7 +17,7 @@
- +
diff --git a/src/pages/Media.vue b/src/pages/Media.vue index 6b4e5fe..f5b6925 100644 --- a/src/pages/Media.vue +++ b/src/pages/Media.vue @@ -19,7 +19,7 @@ - +
@@ -34,7 +34,10 @@
- {{collectionLoaded ? collection.name : 'Loading...'}} +
+ {{collectionLoaded ? collection.name : 'Loading...'}} + +

{{media.description}}

Episodes

@@ -52,7 +55,8 @@ + + diff --git a/src/router/index.js b/src/router/index.js index 0efd2f8..9f496c8 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -5,6 +5,7 @@ import Analytics from 'vue-analytics' import {authGuard, loginGuard} from 'lib/auth' import Home from 'pages/Home' +import Settings from 'pages/Settings' import History from 'pages/History' import Search from 'pages/Search' import Login from 'pages/Login' @@ -31,6 +32,12 @@ const router = new Router({ component: Home, beforeEnter: authGuard }, + { + path: '/settings', + name: 'settings', + component: Settings, + beforeEnter: authGuard + }, { path: '/history', name: 'history', diff --git a/src/store/index.js b/src/store/index.js index 880a57a..94608ca 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,8 +1,9 @@ import Vue from 'vue' import Vuex from 'vuex' import uuid from 'uuid/v4' +import axios from 'axios' -import api, {ACCESS_TOKEN, DEVICE_TYPE, LOCALE, VERSION} from 'lib/api' +import api, {ACCESS_TOKEN, DEVICE_TYPE, LOCALE, VERSION, UMI_SERVER} from 'lib/api' import {getUuid} from 'lib/auth' import WS from 'lib/websocket' @@ -18,6 +19,11 @@ const store = new Vuex.Store({ ) : ( {} ), + malAuth: localStorage.getItem('malAuth') ? ( + JSON.parse(localStorage.getItem('malAuth')) + ) : ( + {} + ), series: {}, seriesCollections: {}, collections: {}, @@ -94,7 +100,6 @@ const store = new Vuex.Store({ return new Promise(async (resolve, reject) => { try { commit('REMOVE_AUTH') - localStorage.removeItem('auth') await dispatch('startSession') resolve() } catch (err) { @@ -103,6 +108,22 @@ const store = new Vuex.Store({ }) }, + authenticateMal ({commit, state}, {username, password}) { + return new Promise(async (resolve, reject) => { + try { + const {data} = await axios.post(`${UMI_SERVER}/mal/login`, {username, password}) + if (data.status === 'ok') { + commit('UPDATE_MAL', data) + resolve() + } else { + reject(new Error(data.error)) + } + } catch (err) { + reject(err) + } + }) + }, + getQueueInfo ({commit, state}) { const params = { session_id: state.auth.session_id, @@ -363,9 +384,21 @@ const store = new Vuex.Store({ }, REMOVE_AUTH (state) { + localStorage.removeItem('auth') Vue.set(state, 'auth', {}) }, + UPDATE_MAL (state, obj) { + const updated = Object.assign({}, state.malAuth, obj) + localStorage.setItem('malAuth', JSON.stringify(updated)) + Vue.set(state, 'malAuth', updated) + }, + + REMOVE_MAL_AUTH (state) { + localStorage.removeItem('malAuth') + Vue.set(state, 'malAuth', {}) + }, + SET_SEARCH_IDS (state, arr) { state.searchIds = arr },