Reworked all server code and implemented logger in there

This commit is contained in:
Kylart 2017-11-23 16:43:50 +01:00
parent be313e00ee
commit 5a0ac99081
42 changed files with 750 additions and 595 deletions

View File

@ -33,7 +33,6 @@
</template>
<script>
import axios from 'axios'
import _ from 'lodash'
export default {
@ -95,12 +94,14 @@
if (term && term.length > 2) {
try {
const {data, status} = await axios.get(`searchTermOnMal`, {
const {data, status} = await this.$axios.get(`searchTermOnMal`, {
params: {term}
})
if (status === 200) {
this.results = data.categories[0].items
this.results = data
} else {
throw new Error('Error while searching.')
}
} catch (e) {
console.log((new Date()).toLocaleTimeString(), e.message)

View File

@ -151,10 +151,12 @@
"nightwatch.conf.js",
"**/*.test.js",
"**/node_modules/**",
"**/openExternal.js",
"assets/serverStart.js",
"server/mal/index.js",
"server/mal/official.js"
"server/mal/official.js",
"server/openExternal",
"server/utils",
"server/env"
],
"watermarks": {
"lines": [

27
server/config/config.js Normal file
View File

@ -0,0 +1,27 @@
const {join} = require('path')
const {writeFileSync, readFileSync} = require('fs')
const {dir, Logger} = require('../utils')
const logger = new Logger('Config')
const get = (req, res) => {
const configPath = join(dir, 'config.json')
const configFile = JSON.parse(readFileSync(configPath))
res.type('application/json')
res.send(configFile)
}
const save = (req, res) => [
req.on('data', (chunk) => {
const data = JSON.parse(chunk)
writeFileSync(join(dir, 'config.json'), JSON.stringify(data))
logger.info('Successfully saved config!')
res.status(200).send()
})
]
module.exports = {
save,
get
}

11
server/config/index.js Normal file
View File

@ -0,0 +1,11 @@
const {save, get} = require('./config.js')
const {setupAccount} = require('./setupAccount.js')
const routes = [
(app) => app.get('/getConfig.json', get),
(app) => app.post('/saveConfig', save),
(app) => app.post('/_setupAccount', setupAccount)
]
module.exports = routes

View File

@ -0,0 +1,26 @@
const {join} = require('path')
const {writeFileSync} = require('fs')
const vault = require('../vault')
const {dir} = require('../utils')
const setupAccount = (req, res) => {
req.on('data', (chunk) => {
const {service, credentials} = JSON.parse(chunk)
// Writting the username in the config file so no one forgets
const p = join(dir, 'config.json')
const conf = require(p)
conf.config.malUsername = credentials.username
writeFileSync(p, JSON.stringify(conf), 'utf-8')
vault.setupCreds(service, credentials)
.then(() => res.send())
.catch(/* istanbul ignore next */ () => res.status(204).send())
})
}
module.exports = {
setupAccount
}

8
server/env/env.js vendored Normal file
View File

@ -0,0 +1,8 @@
const get = (req, res) => {
res.status(200).send({
platform: process.platform,
NODE_ENV: process.env.NODE_ENV
})
}
module.exports = get

14
server/env/index.js vendored Normal file
View File

@ -0,0 +1,14 @@
const getEnv = require('./env.js')
const isOnline = require('./isOnline.js')
const {actOnWin} = require('./win.js')
const getNotes = require('./releaseNotes.js')
const routes = [
(app) => app.get('/_win', actOnWin),
(app) => app.get('/_env', getEnv),
(app) => app.get('/_isOnline', isOnline),
(app) => app.get('/releaseNotes', getNotes)
]
module.exports = routes

13
server/env/isOnline.js vendored Normal file
View File

@ -0,0 +1,13 @@
const axios = require('axios')
const isOnline = async (req, res) => {
try {
const {status} = await axios.get('https://myanimelist.net')
res.status(status === 200 ? 200 : 204).send()
} catch (e) {
res.status(204).send()
}
}
module.exports = isOnline

18
server/env/releaseNotes.js vendored Normal file
View File

@ -0,0 +1,18 @@
const {join} = require('path')
const _ = require('lodash')
const axios = require('axios')
const _VERSION_ = require(join(__dirname, '..', '..', 'package.json')).version
const get = async (req, res) => {
try {
const {data, status} = await axios.get('https://api.github.com/repos/Kylart/KawAnime/releases')
status === 200
? res.status(200).send(_.find(data, (e) => e.name === `v${_VERSION_}`).body)
: res.status(204).send()
} catch (e) {
res.status(204).send()
}
}
module.exports = get

19
server/env/win.js vendored Normal file
View File

@ -0,0 +1,19 @@
const actOnWin = ({query}, res) => {
const {action} = query
if (action === 'minimize') {
process.win.minimize()
} else if (action === 'maximize') {
process.win.isMaximized()
? process.win.unmaximize()
: process.win.maximize()
} else if (action === 'close') {
process.win.close()
}
res.status(200).send()
}
module.exports = {
actOnWin
}

122
server/generateEnv.js Normal file
View File

@ -0,0 +1,122 @@
const fs = require('fs')
const {join} = require('path')
const _ = require('lodash')
const randomString = require('randomstring')
const {dir, Logger} = require('./utils')
const logger = new Logger('Env')
const BASE_PATH = require('os').homedir()
// Initiating files and directory
// Create the .KawAnime directory
const createDir = () => {
/* istanbul ignore next */
if (!fs.existsSync(dir)) fs.mkdirSync(dir)
}
const createConfig = () => {
// Conf file
const confPath = join(dir, 'config.json')
const basicConf = {
config: {
fansub: 'HorribleSubs',
quality: '720p',
localPath: join(BASE_PATH, 'Downloads'),
sound: 'Nyanpasu',
inside: true,
magnets: true,
malUsername: '',
system: {
autoStart: false,
toTray: false
}
}
}
/* istanbul ignore next */
if (!fs.existsSync(confPath)) {
logger.info('No configuration file detected. Creating...')
fs.writeFileSync(confPath, JSON.stringify(basicConf), 'utf-8')
} else {
// Checking if no key is missing. Careful, works only up to 2 levels inside config
const currentConf = require(confPath)
let changed = false
_.each(basicConf.config, (elem, key) => {
if (typeof currentConf.config[key] === 'undefined') {
currentConf.config[key] = elem
changed = true
}
})
changed && fs.writeFileSync(confPath, JSON.stringify(currentConf), 'utf-8')
}
}
// Local file
const createLocal = () => {
const animeLocalPath = join(dir, 'locals.json')
/* istanbul ignore next */
if (!fs.existsSync(animeLocalPath)) {
logger.info('No anime local file detected. Creating...')
fs.writeFileSync(animeLocalPath, '{}', 'utf-8')
}
}
// List file
const createList = () => {
const listPath = join(dir, 'lists.json')
/* istanbul ignore next */
if (!fs.existsSync(listPath)) {
logger.info('No anime list file detected. Creating...')
const basicLists = {
watchList: [],
seen: [],
watching: [],
dropped: [],
onHold: []
}
fs.writeFileSync(listPath, JSON.stringify(basicLists), 'utf-8')
}
}
// History file
const createHistory = () => {
const historyPath = join(dir, 'history.json')
/* istanbul ignore next */
if (!fs.existsSync(historyPath)) {
logger.info('No watch history file detected. Creating...')
fs.writeFileSync(historyPath, '{}', 'utf-8')
}
}
const createToken = () => {
const tokenPath = join(dir, '_token')
/* istanbul ignore next */
if (!fs.existsSync(tokenPath)) {
logger.info('No token file detected. Creating...')
fs.writeFileSync(tokenPath, randomString.generate(40), 'utf-8')
}
}
module.exports = function generateEnv () {
createDir()
createConfig()
createLocal()
createHistory()
createList()
createToken()
}

View File

@ -4,16 +4,13 @@
const {join} = require('path')
const {writeFileSync} = require('fs')
const {userInfo} = require('os')
const dir = process.env.NODE_ENV !== 'KawAnime-test'
/* istanbul ignore next */
? join(userInfo().homedir, '.KawAnime')
: join(userInfo().homedir, '.KawAnime-test')
const {Logger, dir} = require('../utils')
const logger = new Logger('History')
const historyPath = join(dir, 'history.json')
exports.appendHistory = (req, res) => {
const appendHistory = (req, res) => {
// Date info
const today = new Date()
const day = today.toDateString()
@ -42,13 +39,13 @@ exports.appendHistory = (req, res) => {
// Writing file to history.json
writeFileSync(historyPath, JSON.stringify(historyFile), 'utf-8')
console.log(`[History]: New entry appended to history.`)
logger.info('New entry appended to history.')
})
res.status(200).send()
}
exports.getHistory = (res) => {
const getHistory = (req, res) => {
// Getting history
const historyFile = require(historyPath)
@ -56,15 +53,14 @@ exports.getHistory = (res) => {
res.status(200).send(JSON.stringify(historyFile))
}
exports.removeFromHistory = (req, res) => {
const removeFromHistory = (req, res) => {
req.on('data', (chunk) => {
chunk = JSON.parse(chunk)
// Getting history
const historyFile = require(historyPath)
const date = chunk.date
const info = chunk.info
const {date, info} = chunk
historyFile[date] = historyFile[date].filter((elem) => {
return elem.time !== info.time
@ -73,8 +69,14 @@ exports.removeFromHistory = (req, res) => {
// Writing file to history.json
writeFileSync(historyPath, JSON.stringify(historyFile), 'utf-8')
console.log(`[History]: Removed an entry from the ${date}:\n`, info)
logger.info(`Removed an entry from the ${date}:`, info)
})
res.status(200).send()
}
module.exports = {
appendHistory,
getHistory,
removeFromHistory
}

13
server/history/index.js Normal file
View File

@ -0,0 +1,13 @@
const {
appendHistory,
getHistory,
removeFromHistory
} = require('./history.js')
const routes = [
(app) => app.post('/appendHistory', appendHistory),
(app) => app.get('/getHistory', getHistory),
(app) => app.post('/removeFromHistory', removeFromHistory)
]
module.exports = routes

View File

@ -8,8 +8,12 @@
const horribleApi = require('horrible-api')
const malScraper = require('mal-scraper')
exports.getLatest = (query, res) => {
const quality = query.quality
const {Logger} = require('../utils')
const horribleLogger = new Logger('Horrible (Releases)')
const malLogger = new Logger('Mal-Scraper (Releases)')
exports.getLatest = ({query}, res) => {
const {quality} = query
let counter = 0
let toReturn = []
@ -38,18 +42,18 @@ exports.getLatest = (query, res) => {
++counter
/* istanbul ignore next */
if (counter === 18) {
console.log('[Horrible] (Releases): Sending Latest releases.')
horribleLogger.info('Sending latest releases.')
res.type('application/json')
res.status(200).send(JSON.stringify(toReturn))
}
})
.catch(/* istanbul ignore next */ (err) => {
console.log('[MalScraper] (Releases): An error occurred...\n', err)
malLogger.error('An error occurred.', err)
res.status(202).send()
})
}
}).catch((err) => {
console.log('[Horrible] (Releases): An error occurred...\n' + err)
horribleLogger.error('An error occurred.', err)
res.status(204).send()
})
}

7
server/horrible/index.js Normal file
View File

@ -0,0 +1,7 @@
const {getLatest} = require('./horrible.js')
const routes = [
(app) => app.get('/getLatest.json', getLatest)
]
module.exports = routes

View File

@ -1,326 +1,39 @@
/**
* Created by Kylart on 03/04/2017.
*/
'use strict'
const fs = require('fs')
const {join} = require('path')
const _ = require('lodash')
const randomString = require('randomstring')
const axios = require('axios')
const {homedir} = require('os')
const BASE_PATH = homedir()
/* istanbul ignore next */
const dir = process.env.NODE_ENV !== 'KawAnime-test'
? join(BASE_PATH, '.KawAnime')
: join(BASE_PATH, '.KawAnime-test')
const generateEnv = require('./generateEnv.js')
const _VERSION_ = require(join(__dirname, '..', 'package.json')).version
// Initiating files and directory
// Create the .KawAnime directory
const createDir = () => {
/* istanbul ignore next */
if (!fs.existsSync(dir)) fs.mkdirSync(dir)
const features = {
config: require('./config'),
env: require('./env'),
history: require('./history'),
horrible: require('./horrible'),
local: require('./local'),
mal: require('./mal'),
news: require('./news'),
nyaa: require('./nyaa'),
openExternal: require('./openExternal'),
seasons: require('./seasons'),
search: require('./search'),
wl: require('./watchList')
}
const createConfig = () => {
// Conf file
const confPath = join(dir, 'config.json')
const basicConf = {
config: {
fansub: 'HorribleSubs',
quality: '720p',
localPath: join(BASE_PATH, 'Downloads'),
sound: 'Nyanpasu',
inside: true,
magnets: true,
malUsername: '',
system: {
autoStart: false,
toTray: false
}
}
}
/* istanbul ignore next */
if (!fs.existsSync(confPath)) {
console.log('No configuration file detected. Creating...')
fs.writeFileSync(confPath, JSON.stringify(basicConf), 'utf-8')
} else {
// Checking if no key is missing. Careful, works only up to 2 levels inside config
const currentConf = require(confPath)
let changed = false
_.each(basicConf.config, (elem, key) => {
if (typeof currentConf.config[key] === 'undefined') {
currentConf.config[key] = elem
changed = true
}
})
changed && fs.writeFileSync(confPath, JSON.stringify(currentConf), 'utf-8')
}
}
// Local file
const createLocal = () => {
const animeLocalPath = join(dir, 'locals.json')
/* istanbul ignore next */
if (!fs.existsSync(animeLocalPath)) {
console.log('No anime local file detected. Creating...')
fs.writeFileSync(animeLocalPath, '{}', 'utf-8')
}
}
// List file
const createList = () => {
const listPath = join(dir, 'lists.json')
/* istanbul ignore next */
if (!fs.existsSync(listPath)) {
console.log('No anime list file detected. Creating...')
const basicLists = {
watchList: [],
seen: [],
watching: [],
dropped: [],
onHold: []
}
fs.writeFileSync(listPath, JSON.stringify(basicLists), 'utf-8')
}
}
// History file
const createHistory = () => {
const historyPath = join(dir, 'history.json')
/* istanbul ignore next */
if (!fs.existsSync(historyPath)) {
console.log('No watch history file detected. Creating...')
fs.writeFileSync(historyPath, '{}', 'utf-8')
}
}
const createToken = () => {
const tokenPath = join(dir, '_token')
/* istanbul ignore next */
if (!fs.existsSync(tokenPath)) {
console.log('No token file detected. Creating...')
fs.writeFileSync(tokenPath, randomString.generate(40), 'utf-8')
}
}
const vault = require('./vault')
const {openExternal, openInBrowser} = require('./openExternal.js')
const seasons = require('./seasons.js')
const news = require('./news.js')
const local = require('./local.js')
const wl = require('./watchList.js')
const mal = require('./mal')
const history = require('./history')
const horrible = require('./horrible.js')
const nyaa = require('./nyaa.js')
const search = require('./search.js')
let routes = [
(app) => {
app.get('/getConfig.json', (req, res) => {
const configPath = join(dir, 'config.json')
const configFile = JSON.parse(fs.readFileSync(configPath))
res.type('application/json')
res.send(configFile)
})
},
(app) => {
app.get('/getLatestNyaa', ({query}, res) => {
nyaa.getLatest(query, res)
})
},
(app) => {
app.get('/getLatest.json', ({query}, res) => {
horrible.getLatest(query, res)
})
},
/* istanbul ignore next */ (app) => {
app.get('/openThis', ({query}, res) => {
openExternal(query, res)
})
},
(app) => {
app.get('/seasons.json', ({query}, res) => {
seasons.getSeason(query, res)
})
},
(app) => {
app.post('/download', (req, res) => {
nyaa.download(req, res)
})
},
(app) => {
app.get('/news.json', (req, res) => {
news.getNews(res)
})
},
(app) => {
app.get('/local.json', ({query}, res) => {
local.searchLocalFiles(query, res)
})
},
(app) => {
app.get('/watchList.json', (req, res) => {
wl.getLists(res)
})
},
(app) => {
app.post('/saveWatchList', (req, res) => {
wl.saveWatchList(req, res)
})
},
(app) => {
app.get('/resetLocal', ({query}, res) => {
local.resetLocal(query, res)
})
},
(app) => {
app.post('/appendHistory', (req, res) => {
history.appendHistory(req, res)
})
},
(app) => {
app.get('/getHistory', (req, res) => {
history.getHistory(res)
})
},
(app) => {
app.post('/removeFromHistory', (req, res) => {
history.removeFromHistory(req, res)
})
},
(app) => {
app.post('/saveConfig', (req, res) => {
req.on('data', (chunk) => {
const data = JSON.parse(chunk)
fs.writeFileSync(join(dir, 'config.json'), JSON.stringify(data))
console.log('[Open-External]: Successfully saved config!')
})
res.status(200).send()
})
},
(app) => {
app.get('/searchTermOnMal', ({query}, res) => {
search.searchTerm(query, res)
})
},
(app) => {
app.get('/getInfoFromMal', ({query}, res) => {
query.url
? search.fromUrl(query, res)
: search.fromName(query, res)
})
},
/* istanbul ignore next */ (app) => {
app.get('/_openInBrowser', (req, res) => {
openInBrowser(res)
})
},
/* istanbul ignore next */ (app) => {
app.get('/_win', ({query}, res) => {
const action = query.action
if (action === 'minimize') {
process.win.minimize()
} else if (action === 'maximize') {
process.win.isMaximized()
? process.win.unmaximize()
: process.win.maximize()
} else if (action === 'close') {
process.win.close()
}
res.status(200).send()
})
},
(app) => {
app.get('/_env', (req, res) => {
res.status(200).send({
platform: process.platform,
NODE_ENV: process.env.NODE_ENV
})
})
},
(app) => {
app.post('/_setupAccount', (req, res) => {
req.on('data', (chunk) => {
const {service, credentials} = JSON.parse(chunk)
// Writting the username in the config file so no one forgets
const p = join(dir, 'config.json')
const conf = require(p)
conf.config.malUsername = credentials.username
fs.writeFileSync(p, JSON.stringify(conf), 'utf-8')
vault.setupCreds(service, credentials)
.then(() => res.send())
.catch(/* istanbul ignore next */ () => res.status(204).send())
})
})
},
/* istanbul ignore next */ (app) => {
app.get('/_isOnline', async (req, res) => {
try {
const {status} = await axios.get('https://myanimelist.net')
res.status(status === 200 ? 200 : 204).send()
} catch (e) {
res.status(204).send()
}
})
},
/* istanbul ignore next */ (app) => {
app.get('/releaseNotes', async (req, res) => {
try {
const {data, status} = await axios.get('https://api.github.com/repos/Kylart/KawAnime/releases')
status === 200
? res.status(200).send(_.find(data, (e) => e.name === `v${_VERSION_}`).body)
: res.status(204).send()
} catch (e) {
res.status(204).send()
}
})
}
]
let routes = []
const setup = (app) => {
createDir()
createConfig()
createLocal()
createHistory()
createList()
createToken()
generateEnv()
_.each(features, (feature) => {
_.each(feature, (route) => routes.push(route))
})
// auto update
/* istanbul ignore next */
if (!['KawAnime-test', 'development'].includes(process.env.NODE_ENV)) {
routes = require('./updater.js')(app, routes)
routes = require('./updater')(app, routes)
}
_.each(mal, (route) => routes.push(route))
_.each(routes, (route) => route(app))
}

8
server/local/index.js Normal file
View File

@ -0,0 +1,8 @@
const {resetLocal, searchLocalFiles} = require('./local.js')
const routes = [
(app) => app.get('/local.json', searchLocalFiles),
(app) => app.get('/resetLocal', resetLocal)
]
module.exports = routes

View File

@ -1,12 +1,8 @@
/**
* Created by Kylart on 12/04/2017.
*/
const malScraper = require('mal-scraper')
const fs = require('fs')
const {userInfo} = require('os')
const {join, extname} = require('path')
const {removeUnwanted} = require('./utils')
const {removeUnwanted, Logger, dir} = require('../utils')
const logger = new Logger('Local')
const extensions = ['.mkv', '.mp4']
@ -44,7 +40,7 @@ const getUniques = (files) => {
const sendFiles = (json, files, res) => {
const result = []
console.log('[Local]: Sending files.')
logger.info('Sending files.')
files.forEach((file) => {
const name = getName(file)
@ -60,15 +56,12 @@ const sendFiles = (json, files, res) => {
res.status(200).send(JSON.stringify(result))
}
const searchLocalFiles = (query, res) => {
/* istanbul ignore next */
const json = process.env.NODE_ENV !== 'KawAnime-test'
? require(join(userInfo().homedir, '.KawAnime', 'locals.json'))
: require(join(userInfo().homedir, '.KawAnime-test', 'locals.json'))
const searchLocalFiles = ({query}, res) => {
const json = require(join(dir, 'locals.json'))
const dir = query.dir
const DIR = query.dir
const files = fs.readdirSync(dir).filter((file) => { return extensions.includes(extname(file)) })
const files = fs.readdirSync(DIR).filter((file) => extensions.includes(extname(file)))
const uniqueNames = getUniques(files)
let counter = 0
@ -79,9 +72,9 @@ const searchLocalFiles = (query, res) => {
uniqueNames.forEach((elem) => {
// Search MAL for each name if not in json
if (!json[minifyName(elem)]) {
console.log(`[Local]: Looking for ${elem} on MAL.`)
logger.info(`Looking for ${elem} on MAL.`)
malScraper.getInfoFromName(elem).then((anime) => {
console.log('[Local]: Found!')
logger.info('Found!')
json[minifyName(elem)] = {
name: elem,
@ -98,17 +91,15 @@ const searchLocalFiles = (query, res) => {
++counter
/* istanbul ignore next */
if (counter === uniqueNames.length) {
/* istanbul ignore next */
// Saving new data
process.env.NODE_ENV !== 'KawAnime-test'
? fs.writeFileSync(join(userInfo().homedir, '.KawAnime', 'locals.json'), JSON.stringify(json), 'utf-8')
: fs.writeFileSync(join(userInfo().homedir, '.KawAnime-test', 'locals.json'), JSON.stringify(json), 'utf-8')
console.log('[Local]: Successfully saved data.')
fs.writeFileSync(join(dir, 'locals.json'), JSON.stringify(json), 'utf-8')
logger.info('Successfully saved data.')
sendFiles(json, files, res)
}
}).catch(/* istanbul ignore next */(err) => {
console.log('[Local]: ' + err)
logger.error('An error occurred.', err)
res.status(204).send()
})
} else {
@ -120,26 +111,22 @@ const searchLocalFiles = (query, res) => {
}
}
const resetLocal = (query, res) => {
/**
* Here we just erase stored data about files in directory.
*/
/* istanbul ignore next */
const json = process.env.NODE_ENV !== 'KawAnime-test'
? require(join(userInfo().homedir, '.KawAnime', 'locals.json'))
: require(join(userInfo().homedir, '.KawAnime-test', 'locals.json'))
/* istanbul ignore next */
const resetLocal = (req, res) => {
// Here we just erase stored data about files in directory.
const json = require(join(dir, 'locals.json'))
const dir = query.dir
const DIR = req.query.dir
console.log('[Local]: Received a request to reset local data for files in ' + dir)
logger.info('Received a request to reset local data for files in ' + DIR)
const files = fs.readdirSync(dir).filter((file) => { return extensions.includes(extname(file)) })
const files = fs.readdirSync(dir).filter((file) => extensions.includes(extname(file)))
files.forEach((file) => {
delete json[minifyName(getName(file))]
})
searchLocalFiles(query, res)
searchLocalFiles(req, res)
}
module.exports = {

View File

@ -2,9 +2,9 @@ const {getWatchList} = require('./scrap.js')
const {initOfficialApi, actOnList} = require('./official.js')
const routes = [
(app) => app.get('/getWatchList', ({query}, res) => getWatchList(query, res)),
(app) => app.post('/_initOfficalApi', (req, res) => initOfficialApi(req, res)),
(app) => app.post('/actOnMalList', (req, res) => actOnList(req, res))
(app) => app.get('/getWatchList', getWatchList),
(app) => app.post('/_initOfficalApi', initOfficialApi),
(app) => app.post('/actOnMalList', actOnList)
]
module.exports = routes

View File

@ -2,6 +2,9 @@ const vault = require('../vault')
const malScraper = require('mal-scraper')
const Api = malScraper.officialApi
const {Logger} = require('../utils')
const logger = new Logger('Mal-Scraper')
let api
const checkCreds = (res) => {
@ -11,7 +14,7 @@ const checkCreds = (res) => {
res.status(isOk ? 200 : 206).send()
})
.catch((err) => {
console.log('[Mal-Scraper]: (check): An error occurred...', err)
logger.error('An error occurred while checking credentials.', err)
res.status(204).send()
})
}
@ -37,11 +40,11 @@ const actOnList = (req, res) => {
api.actOnList(type, id, opts)
.then((data) => {
console.log('[Mal-Scraper]: (Act on List):', data)
logger.info('(Act on List):' + data)
res.status(typeof data === 'string' ? 200 : 204).send()
})
.catch((err) => {
console.log('[Mal-Scraper]: (Act on List): An error occurrred', err)
logger.error('(Act on List): An error occurred.', err)
res.status(204).send()
})
})

View File

@ -1,14 +1,16 @@
const malScraper = require('mal-scraper')
const {Logger} = require('../utils')
const logger = new Logger('Mal-Scraper')
const getWatchList = (query, res) => {
const getWatchList = ({query}, res) => {
const {user} = query
console.log('[Mal-Scraper]: Looking for the watch lists of', user + '...')
logger.info('Looking for the watch lists of ' + user + '...')
malScraper.getWatchListFromUser(user)
.then((data) => res.send(data.lists))
.catch(/* istanbul ignore next */ (err) => {
console.log('[Mal-Scraper]: An error occurred while gathring watchLIst from user...', err)
logger.error('An error occurred while gathring watchLIst from user.', err)
res.status(204).send()
})
}

7
server/news/index.js Normal file
View File

@ -0,0 +1,7 @@
const {getNews} = require('./news.js')
const routes = [
(app) => app.get('/news.json', getNews)
]
module.exports = routes

View File

@ -3,19 +3,24 @@
*/
const {getNewsNoDetails} = require('mal-scraper')
const {Logger} = require('../utils')
const logger = new Logger('Mal-Scraper (News)')
/* istanbul ignore next */
exports.getNews = (res) => {
const getNews = (req, res) => {
getNewsNoDetails().then((news) => {
console.log('[Mal-Scraper] (News): Finished gathering the news.')
logger.info('Finished gathering the news.')
res.type('application/json')
res.status(200).send(JSON.stringify(news))
}).catch((err) => {
console.log('[Mal-Scraper] (News): A problem occurred while gathering news.')
console.error(err.message)
logger.error('A problem occurred while gathering news.', err)
res.type('application/json')
res.status(204).send(JSON.stringify([]))
})
}
module.exports = {
getNews
}

View File

@ -1,137 +0,0 @@
/**
* Created by Kylart on 27/05/2017.
*/
const {si, pantsu} = require('nyaapi')
const malScraper = require('mal-scraper')
const _ = require('lodash')
const {removeUnwanted} = require('./utils')
const sendRes = (object, res) => {
res.status(200).send(JSON.stringify(object))
}
const formatMagnets = (data, searchData, choice, res) => {
const magnets = []
const eps = []
const isPantsu = choice === 'pantsu'
data.forEach((elem) => {
elem.name = removeUnwanted(elem.name)
const ep = elem.name.split(' ').splice(-2, 1)[0]
eps.push(ep)
if (ep <= searchData.untilEp && ep >= searchData.fromEp) {
magnets.push({
name: elem.name,
link: isPantsu ? elem.magnet : elem.links.magnet
})
}
})
sendRes({
minEp: _.min(eps),
maxEp: _.max(eps),
magnets
}, res)
}
const download = (req, res) => {
req.on('data', (chunk) => {
chunk = JSON.parse(chunk)
const choice = chunk.choice
console.log('[Nyaa] (Download): Received a download request. Choice is ' + choice)
const searchData = {
quality: chunk.quality,
name: chunk.name,
fansub: chunk.fansub,
fromEp: chunk.fromEp,
untilEp: chunk.untilEp
}
console.log(searchData)
const term = `[${searchData.fansub}] ${searchData.quality} ${searchData.name} ` + (choice === 'si' ? '-unofficial' : '')
if (choice === 'si') {
si.search(term).then((data) => {
formatMagnets(data, searchData, choice, res)
}).catch(/* istanbul ignore next */(err) => {
console.log('[Nyaa]: An error occurred...\n' + err)
res.status(204).send()
})
} else {
pantsu.search(term).then((data) => {
formatMagnets(data, searchData, choice, res)
}).catch(/* istanbul ignore next */(err) => {
console.log(err.message)
res.status(204).send()
})
}
})
}
const makeSearch = (data, res, isPantsu = false) => {
let counter = 0
const toReturn = []
for (let i = 0; i < 18; ++i) {
const realName = removeUnwanted(data[i].name)
const name = realName.split(' ').slice(1).join(' ')
const rawName = name.split(' ').slice(0, -3).join(' ')
const researchName = rawName.split(' ').join('').toLowerCase()
const ep = name.split(' ').splice(-2, 1)[0]
const link = !isPantsu ? data[i].links.magnet : data[i].magnet
malScraper.getInfoFromName(rawName)
.then((item) => {
item.rawName = rawName
item.researchName = researchName
item.magnetLink = link
item.ep = ep
toReturn[i] = item
++counter
if (counter === 18) {
console.log('[Nyaa] (Releases): Sending Latest releases.')
res.writeHead(200, {'Content-type': 'application/json'})
res.write(JSON.stringify(toReturn))
res.end()
}
}).catch(/* istanbul ignore next */(err) => {
console.log('[MalScraper] (Releases): An error occurred...\n' + err)
res.status(202).send()
})
}
}
const getLatest = (query, res) => {
const fansub = query.fansub
const choice = query.choice
const quality = query.quality
if (choice === 'si') {
si.search(`[${fansub}] ${quality} -unofficial`, 18).then((data) => {
makeSearch(data, res)
}).catch(/* istanbul ignore next */(err) => {
console.log('[Nyaa] (Releases): An error occurred...\n', err)
res.status(204).send()
})
} else {
pantsu.search(`[${fansub}] ${quality}`, 18).then((data) => {
makeSearch(data, res, true)
}).catch(/* istanbul ignore next */(err) => {
console.log('[Nyaa] (Releases): An error occurred...\n', err)
res.status(204).send()
})
}
}
module.exports = {
download,
getLatest
}

71
server/nyaa/download.js Normal file
View File

@ -0,0 +1,71 @@
const {si, pantsu} = require('nyaapi')
const _ = require('lodash')
const {removeUnwanted, Logger} = require('../utils')
const logger = new Logger('Nyaa (Download)')
const sendRes = (object, res) => {
res.status(200).send(JSON.stringify(object))
}
const formatMagnets = (data, searchData, choice, res) => {
const magnets = []
const eps = []
const isPantsu = choice === 'pantsu'
data.forEach((elem) => {
elem.name = removeUnwanted(elem.name)
const ep = elem.name.split(' ').splice(-2, 1)[0]
eps.push(ep)
if (ep <= searchData.untilEp && ep >= searchData.fromEp) {
magnets.push({
name: elem.name,
link: isPantsu ? elem.magnet : elem.links.magnet
})
}
})
sendRes({
minEp: _.min(eps),
maxEp: _.max(eps),
magnets
}, res)
}
const download = (req, res) => {
req.on('data', (chunk) => {
chunk = JSON.parse(chunk)
const {choice} = chunk
const searchData = {
quality: chunk.quality,
name: chunk.name,
fansub: chunk.fansub,
fromEp: chunk.fromEp,
untilEp: chunk.untilEp
}
logger.info('Received a download request. Choice is ' + choice, searchData)
const term = `[${searchData.fansub}] ${searchData.quality} ${searchData.name} ` + (choice === 'si' ? '-unofficial' : '')
if (choice === 'si') {
si.search(term).then((data) => {
formatMagnets(data, searchData, choice, res)
}).catch(/* istanbul ignore next */(err) => {
logger.error('An error occurred.', err)
res.status(204).send()
})
} else {
pantsu.search(term).then((data) => {
formatMagnets(data, searchData, choice, res)
}).catch(/* istanbul ignore next */(err) => {
logger.error('An error occurred.', err)
res.status(204).send()
})
}
})
}
module.exports = download

61
server/nyaa/getLatest.js Normal file
View File

@ -0,0 +1,61 @@
const {si, pantsu} = require('nyaapi')
const malScraper = require('mal-scraper')
const {removeUnwanted, Logger} = require('../utils')
const logger = new Logger('Nyaa (Releases)')
const makeSearch = (data, res, isPantsu = false) => {
let counter = 0
const toReturn = []
for (let i = 0; i < 18; ++i) {
const realName = removeUnwanted(data[i].name)
const name = realName.split(' ').slice(1).join(' ')
const rawName = name.split(' ').slice(0, -3).join(' ')
const researchName = rawName.split(' ').join('').toLowerCase()
const ep = name.split(' ').splice(-2, 1)[0]
const link = !isPantsu ? data[i].links.magnet : data[i].magnet
malScraper.getInfoFromName(rawName)
.then((item) => {
item.rawName = rawName
item.researchName = researchName
item.magnetLink = link
item.ep = ep
toReturn[i] = item
++counter
if (counter === 18) {
logger.info('Sending Latest releases.')
res.writeHead(200, {'Content-type': 'application/json'})
res.write(JSON.stringify(toReturn))
res.end()
}
}).catch(/* istanbul ignore next */(err) => {
logger.error('An error occurred.', err)
res.status(202).send()
})
}
}
const getLatest = ({query}, res) => {
const {fansub, choice, quality} = query
if (choice === 'si') {
si.search(`[${fansub}] ${quality} -unofficial`, 18).then((data) => {
makeSearch(data, res)
}).catch(/* istanbul ignore next */(err) => {
logger.error('An error occurred.', err)
res.status(204).send()
})
} else {
pantsu.search(`[${fansub}] ${quality}`, 18).then((data) => {
makeSearch(data, res, true)
}).catch(/* istanbul ignore next */(err) => {
logger.error('An error occurred.', err)
res.status(204).send()
})
}
}
module.exports = getLatest

9
server/nyaa/index.js Normal file
View File

@ -0,0 +1,9 @@
const getLatest = require('./getLatest.js')
const download = require('./download.js')
const routes = [
(app) => app.post('/download', download),
(app) => app.get('/getLatestNyaa', getLatest)
]
module.exports = routes

View File

@ -0,0 +1,8 @@
const {openExternal, openInBrowser} = require('./openExternal.js')
const routes = [
(app) => app.get('/openThis', openExternal),
(app) => app.get('/_openInBrowser', openInBrowser)
]
module.exports = routes

View File

@ -3,8 +3,9 @@
*/
const {join} = require('path')
const {dialog, BrowserWindow, shell} = require('electron')
const {Logger} = require('../utils')
const logger = new Logger('Open-External')
const sendEmptyRes = (res) => {
res.status(200).send()
@ -15,9 +16,9 @@ const sendRes = (res, data) => {
res.status(200).send(JSON.stringify(data))
}
exports.openExternal = (query, res) => {
const openExternal = ({query}, res) => {
const type = query.type
console.log('[Open-External] Got a request for external open: type is ' + type)
logger.info('Got a request for external open: type is ' + type)
switch (type) {
case 'video':
@ -68,7 +69,7 @@ exports.openExternal = (query, res) => {
}
}
exports.openInBrowser = (res) => {
const openInBrowser = (req, res) => {
shell.openExternal(process.appURL)
process.win && process.platform === 'darwin'
? process.win.hide()
@ -76,3 +77,8 @@ exports.openInBrowser = (res) => {
res.status(200).send()
}
module.exports = {
openInBrowser,
openExternal
}

12
server/search/index.js Normal file
View File

@ -0,0 +1,12 @@
const {searchTerm, fromName, fromUrl} = require('./search.js')
const routes = [
(app) => app.get('/searchTermOnMal', searchTerm),
(app) => app.get('/getInfoFromMal', ({query}, res) =>
query.url
? fromUrl(query, res)
: fromName(query, res)
)
]
module.exports = routes

View File

@ -2,24 +2,17 @@
* Created by Kylart on 27/06/2017.
*/
const axios = require('axios')
const malScraper = require('mal-scraper')
const {Logger} = require('../utils')
const logger = new Logger('Search')
const SEARCH_URI = 'https://myanimelist.net/search/prefix.json'
const searchTerm = (query, res) => {
axios.get(SEARCH_URI, {
params: {
type: 'anime',
keyword: query.term
}
}).then(({data}) => {
res.type('application/json')
res.status(200).send(JSON.stringify(data))
}).catch(/* istanbul ignore next */(e) => {
console.log('[Search] (Term):' + e.message)
res.status(204).send()
})
const searchTerm = ({query}, res) => {
malScraper.getResultsFromSearch(query.term)
.then((data) => res.send(data))
.catch(/* istanbul ignore next */(err) => {
logger.error('An error occurred', err)
res.status(204).send()
})
}
const fromName = (query, res) => {
@ -27,7 +20,7 @@ const fromName = (query, res) => {
res.type('application/json')
res.status(200).send(JSON.stringify(data))
}).catch(/* istanbul ignore next */(err) => {
console.log(err.message)
logger.error('An error occurred', err)
res.status(204).send()
})
}
@ -37,7 +30,7 @@ const fromUrl = (query, res) => {
res.type('application/json')
res.status(200).send(JSON.stringify(data))
}).catch(/* istanbul ignore next */(err) => {
console.log(err.message)
logger.error('An error occurred', err)
res.status(204).send()
})
}

7
server/seasons/index.js Normal file
View File

@ -0,0 +1,7 @@
const {getSeason} = require('./seasons.js')
const routes = [
(app) => app.get('/seasons.json', getSeason)
]
module.exports = routes

View File

@ -4,9 +4,12 @@
const {getSeason} = require('mal-scraper')
exports.getSeason = (query, res) => {
const {Logger} = require('../utils')
const logger = new Logger('Mal-Scraper (Seasons)')
exports.getSeason = ({query}, res) => {
getSeason(query.year, query.season).then((data) => {
console.log(`[Mal-Scraper] (Seasons): Now having ${query.season} ${query.year}.`)
logger.info(`Now having ${query.season} ${query.year}.`)
const keys = Object.keys(data)
@ -19,7 +22,7 @@ exports.getSeason = (query, res) => {
res.type('application/json')
res.status(200).send(JSON.stringify(data))
}).catch((err) => {
console.log('[MalScraper] (Seasons): ' + err.message)
logger.error('An error occurred.', err)
res.status(204).send()
})
}

10
server/utils/dir.js Normal file
View File

@ -0,0 +1,10 @@
const {homedir} = require('os')
const {join} = require('path')
const BASE_PATH = homedir()
const dir = process.env.NODE_ENV !== 'KawAnime-test'
? join(BASE_PATH, '.KawAnime')
: join(BASE_PATH, '.KawAnime-test')
module.exports = dir

View File

@ -3,7 +3,11 @@
*/
const removeUnwanted = require('./removeUnwanted')
const {Logger} = require('./logger.js')
const dir = require('./dir.js')
module.exports = {
removeUnwanted
removeUnwanted,
dir,
Logger
}

85
server/utils/logger.js Normal file
View File

@ -0,0 +1,85 @@
/**
* Very basic logger as we don't need much more.
*/
const {join} = require('path')
const {appendFileSync} = require('fs')
const chalk = require('chalk')
const dir = require('./dir.js')
const Logger = class {
constructor (label) {
this.setLabel(label)
}
setLabel (label) {
this.label = `[${label}]`
}
getDate () {
return `[${(new Date()).toLocaleDateString()}] ${(new Date()).toLocaleTimeString()}`
}
shouldLog () {
return !['production', 'KawAnime-test'].includes(process.env.NODE_ENV)
}
stringify (obj) {
return obj
? obj.stack
? '\n' + obj.stack
: '\n' + JSON.stringify(obj, null, 2)
: ''
}
toFile (type, msg, obj) {
const _msg = `${this.getDate()} ${type === 'error' ? 'ERROR' : 'INFO '} > ${this.label} ${msg} ${this.stringify(obj)}\n`
if (type === 'error') {
appendFileSync(join(dir, 'error.log'), _msg, 'utf-8')
}
appendFileSync(join(dir, 'logs.log'), _msg, 'utf-8')
}
/**
* Log an info from KawAnime's server
*
* @param {string} msg Log message
* @param {object} obj Optional object to log
*/
info (msg, obj) {
this.shouldLog() && console.log(
chalk.cyan(this.getDate()),
chalk.bold.green('- INFO >'),
chalk.bold.green(this.label + ':'),
msg,
this.stringify(obj)
)
this.toFile('info', msg, obj)
}
/**
* Log an error from KawAnime's server
*
* @param {string} msg Log message
* @param {error} err Optional error to log
*/
error (msg, err) {
this.shouldLog() && console.error(
chalk.magenta(this.getDate()),
chalk.bold.red('- ERROR >'),
chalk.bold.red(this.label + ':'),
msg,
this.stringify(err)
)
this.toFile('error', msg, err)
}
}
module.exports = {
Logger
}

View File

@ -1,26 +1,22 @@
const {homedir} = require('os')
const {join} = require('path')
const {writeFileSync, readFileSync, existsSync, mkdirSync} = require('fs')
const randomString = require('randomstring')
const buttercup = require('buttercup')
const {Archive, createCredentials, FileDatasource, EntryFinder} = buttercup
/* istanbul ignore next */
const dir = join(
homedir(),
process.env.NODE_ENV === 'KawAnime-test' ? '.KawAnime-test' : '.KawAnime',
'vault'
)
const {Logger, dir} = require('../utils')
const logger = new Logger('Vault')
const keyPath = join(dir, 'p')
const DIR = join(dir, 'vault')
const keyPath = join(DIR, 'p')
const setupCreds = (service, credentials) => {
return new Promise((resolve, reject) => {
/* istanbul ignore next */
if (!existsSync(dir)) {
if (!existsSync(DIR)) {
// Creating vault directory
mkdirSync(dir)
console.log('[Vault]: No vault detected. Creating...')
mkdirSync(DIR)
logger.info('No vault detected. Creating...')
// Setting up master key
writeFileSync(keyPath, randomString.generate(40), 'utf-8')
@ -36,16 +32,16 @@ const setupCreds = (service, credentials) => {
.setAttribute('username', credentials.username)
.setAttribute('password', credentials.password)
const ds = new FileDatasource(join(dir, service + '.bcup'))
const ds = new FileDatasource(join(DIR, service + '.bcup'))
const key = readFileSync(keyPath, 'utf-8')
ds.save(archive, createCredentials.fromPassword(key))
.then((data) => {
console.log('[Vault]: Saved new credentials.')
logger.info('Saved new credentials.')
resolve()
})
.catch(/* istanbul ignore next */ (err) => {
console.log('[Vault]: Error while saving file:', err)
logger.error('Error while saving file:', err)
reject(err)
})
})
@ -53,7 +49,7 @@ const setupCreds = (service, credentials) => {
const getCreds = (service) => {
return new Promise((resolve, reject) => {
const ds = new FileDatasource(join(dir, service + '.bcup'))
const ds = new FileDatasource(join(DIR, service + '.bcup'))
const key = readFileSync(keyPath, 'utf-8')
ds.load(createCredentials.fromPassword(key))
@ -66,7 +62,7 @@ const getCreds = (service) => {
})
})
.catch(/* istanbul ignore next */ (err) => {
console.log('[Vault]: Error while getting creds:', err)
logger.error('Error while getting creds:', err)
reject(err)
})
})

View File

@ -1,33 +0,0 @@
/**
* Created by Kylart on 20/04/2017.
*/
const fs = require('fs')
const {userInfo} = require('os')
const {join} = require('path')
/* istanbul ignore next */
const wlPath = process.env.NODE_ENV !== 'KawAnime-test'
/* istanbul ignore next */
? join(userInfo().homedir, '.KawAnime', 'lists.json')
: join(userInfo().homedir, '.KawAnime-test', 'lists.json')
exports.getLists = (res) => {
const wlFile = require(wlPath)
console.log(`[WatchList] Gathered lists from local.`)
res.type('application/json')
res.status(200).send(JSON.stringify(wlFile))
}
exports.saveWatchList = (req, res) => {
req.on('data', (chunk) => {
// Saving list
fs.writeFileSync(wlPath, chunk, 'utf-8')
console.log('[WatchList] Successfully saved lists.')
res.status(200).send()
})
}

View File

@ -0,0 +1,8 @@
const {get, save} = require('./watchList.js')
const routes = [
(app) => app.get('/watchList.json', get),
(app) => app.post('/saveWatchList', save)
]
module.exports = routes

View File

@ -0,0 +1,35 @@
/**
* Created by Kylart on 20/04/2017.
*/
const {writeFileSync} = require('fs')
const {join} = require('path')
const {Logger, dir} = require('../utils')
const logger = new Logger('WatchList')
const wlPath = join(dir, 'lists.json')
const get = (req, res) => {
const wlFile = require(wlPath)
logger.info(`Gathered lists from local.`)
res.type('application/json')
res.status(200).send(JSON.stringify(wlFile))
}
const save = (req, res) => {
req.on('data', (chunk) => {
// Saving list
writeFileSync(wlPath, chunk, 'utf-8')
logger.info('Successfully saved lists.')
res.status(200).send()
})
}
module.exports = {
get,
save
}

View File

@ -208,8 +208,7 @@ test('/download Mahou Shoujo Ikusei Keikaku with HorribleSubs at 720p from ep 3
})
test('/download Mahou Shoujo Ikusei Keikaku with HorribleSubs at 720p from ep 3 to 9 on nyaa.pantsu.cat' +
' exits and returns' +
' all magnets', async t => {
' exits and returns all magnets', async t => {
const { data, status } = await axios.post(`${uri}/download`, {
name: 'Mahou Shoujo Ikusei Keikaku',
quality: '720p',
@ -223,7 +222,8 @@ test('/download Mahou Shoujo Ikusei Keikaku with HorribleSubs at 720p from ep 3
t.is(data.magnets.length, 7)
t.not(data.magnets[0], '')
} else if (status === 204) {
t.is(data.magnets.length, 0)
console.info('An error occurred.'.yellow)
t.pass()
} else {
t.fail()
}
@ -407,10 +407,15 @@ test('/news.json route exits and returns 160 elements', async t => {
})
test('/searchTermOnMal route exits and return 10 elements', async t => {
const { data, status } = await axios.get(`${uri}/searchTermOnMal?term=sakura trick`)
try {
const { data, status } = await axios.get(`${uri}/searchTermOnMal?term=sakura trick`)
t.is(status, 200)
t.is(data.categories[0].items.length, 10)
t.is(status, 200)
t.is(data.length, 10)
} catch (e) {
console.error(e)
t.fail()
}
})
test('/getInfoFromMal route exits if given name and return an object with name', async t => {