soundbirder/controllers/api.js

156 lines
4.6 KiB
JavaScript
Raw Normal View History

const debug = require('debug')('soundbirder:api');
const debugResponses = require('debug')('soundbirder:api:responses');
require('dotenv').config();
const axios = require('axios');
const eBird = require('@unclesamulus/ebird-api')(process.env.EBIRD_API_KEY);
const XenoCanto = require('@unclesamulus/xeno-canto-api');
const { choices, choice } = require('../utils/choices');
const OPENCAGE_API_KEY = process.env.OPENCAGE_API_KEY;
const OPENCAGE_API_URL = 'https://api.opencagedata.com/geocode/v1/json?q=<lat>+<lon>&key=<key>';
const QUIZZ_SIZE = process.env.QUIZZ_SIZE ? process.env.QUIZZ_SIZE : 5;
function check(req, res) {
}
function quizz(req, res) {
debug('Generating quizz');
const { lat, lng } = req.body;
generateQuizz({ lat, lng }, req.locale)
.then(({ species, correct, audio }) => {
req.session.correct = correct;
res.json({ species, audio });
debug("Quizz sent");
})
.catch(error => {
debug("Faced error while generating quizz");
res.json({ error });
throw error;
});
}
async function generateQuizz(coordinates, locale) {
const quizz = {}
try {
const speciesSelection = await getSpeciesSelection(coordinates);
const speciesSelectionLocalized = await getLocalizedNames(speciesSelection, locale);
quizz.species = await speciesSelectionLocalized;
debug("Got species selection", quizz.species);
const answer = await choice(speciesSelectionLocalized);
debug("Got answer", answer);
quizz.correct = answer.code;
quizz.audio = await getAudio(answer.sciName);
} catch (error) {
debug("Error raised while generating quizz");
console.error(error);
}
return quizz;
}
async function getSpeciesSelection(coordinates) {
const { lat, lng } = coordinates;
const region = await getRegion(lat, lng);
region.country_code = region.country_code.toUpperCase();
// const regionCode = await getRegionCode(region);
const regionCode = region.country_code;
const speciesList = await getSpeciesList(regionCode);
const speciesSelection = choices(speciesList, QUIZZ_SIZE);
debug("Species proposals:", speciesSelection)
return speciesSelection;
}
function getHome(req, res) {
res.render('api', {
title: "SoundBirder api",
version: 0
}
);
}
function getRegion(lat, lon) {
const url = OPENCAGE_API_URL
.replace('<lat>', lat)
.replace('<lon>', lon)
.replace('<key>', OPENCAGE_API_KEY);
return axios.get(url).then(response => {
const { results } = response.data;
const { country_code, country, state, county } = results[0].components;
return { country_code, country, state, county };
}).catch(error => {
throw error;
});
}
function getRegionCode({ country_code, country, state, county }) {
return eBird.ref.region.list('subnational1', country_code)()
.then(states => {
console.log(states);
const regionCode = states.find(region => region.name === state).code;
return regionCode;
}).catch(error => {
throw error;
});
}
async function getLocalizedNames(speciesCodes, locale) {
let names = [];
for (let i = 0; i < speciesCodes.length; i++) {
const code = speciesCodes[i];
const { sciName, comName } = await getLocalizedName(code, locale);
names.push({ code, sciName, comName });
}
return names;
}
function getLocalizedName(speciesCode, locale) {
return eBird.ref.taxonomy.ebird({
fmt: 'json',
locale: locale,
species: speciesCode
}).then(
response => {
const names = response[0];
debug("Got localized species names");
debugResponses(names);
return names;
}
).catch(error => {
throw error;
});
}
function getSpeciesList(regionCode) {
return eBird.product.spplist.in(regionCode)()
.then(species => {
return species;
})
.catch(error => {
throw error;
});
}
function getAudio(speciesScientificName) {
return XenoCanto.search({
name: speciesScientificName,
quality: 'A'
}).then(response => {
debugResponses(response);
const { recordings } = response;
const randomRecord = choice(recordings);
const audio = randomRecord.file;
return audio;
}).catch(error => {
throw error;
});
}
const game = {
check,
quizz
}
module.exports = {
getHome,
game
}