freesound-client
Version:
 [](http://badge.fury.io/js/freesound-client) [](https://
504 lines • 19.5 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* There are three kinds of tokens:
* 1. Auth tokens
* 2. Access tokens
* 3. Refresh tokens
*
* Auth tokens expire after 10 minutes. They can be used to get access tokens
* Access tokens expire after 24hrs
* Access token relates your application with the user that has logged in.
*/
const node_fetch_1 = __importDefault(require("node-fetch"));
const form_data_1 = __importDefault(require("form-data"));
const url_1 = require("url");
// A hack that prevents the 'TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation' issue
const fetch = node_fetch_1.default;
;
;
class FreeSound {
constructor() {
this.authHeader = '';
this.clientId = '';
this.clientSecret = '';
this.host = 'freesound.org';
this.uris = {
base: `https://${this.host}/apiv2`,
textSearch: '/search/text/',
contentSearch: '/search/content/',
combinedSearch: '/search/combined/',
sound: '/sounds/<sound_id>/',
soundAnalysis: '/sounds/<sound_id>/analysis/',
similarSounds: '/sounds/<sound_id>/similar/',
comments: '/sounds/<sound_id>/comments/',
download: '/sounds/<sound_id>/download/',
upload: '/sounds/upload/',
describe: '/sounds/<sound_id>/describe/',
pending: '/sounds/pending_uploads/',
bookmark: '/sounds/<sound_id>/bookmark/',
rate: '/sounds/<sound_id>/rate/',
comment: '/sounds/<sound_id>/comment/',
authorize: '/oauth2/authorize/',
logout: '/api-auth/logout/',
logoutAuthorize: '/oauth2/logout_and_authorize/',
me: '/me/',
user: '/users/<username>/',
userSounds: '/users/<username>/sounds/',
userPacks: '/users/<username>/packs/',
userBookmarkCategories: '/users/<username>/bookmark_categories/',
userBookmarkCategorySounds: '/users/<username>/bookmark_categories/<category_id>/sounds/',
pack: '/packs/<pack_id>/',
packSounds: '/packs/<pack_id>/sounds/',
packDownload: '/packs/<pack_id>/download/',
// @TODO
// edit: ''
};
}
checkOauth() {
// @TODO: Support node
if (typeof window !== 'object') {
throw new Error('OAuth is not supported in Node');
}
if (!this.authHeader.includes('Bearer')) {
throw new Error('Oauth authentication required');
}
}
makeFormData(obj, prevFormData) {
const formData = prevFormData ? prevFormData : new form_data_1.default();
for (const prop in obj) {
formData.append(prop, obj[prop]);
}
return formData;
}
search(options, uri) {
if (options.analysis_file) {
return this.makeRequest(this.makeUri(uri), 'POST', this.makeFormData(options));
}
return this.makeRequest(this.makeUri(uri), 'GET', options);
}
Collection(oldJsonObject) {
const nextOrPrev = (which) => this.makeRequest(which).then(this.Collection);
const nextPage = () => nextOrPrev(oldJsonObject.next);
const previousPage = () => nextOrPrev(oldJsonObject.previous);
const getItem = (idx) => oldJsonObject.results[idx];
return {
...oldJsonObject,
getItem,
nextOrPrev,
previousPage,
nextPage
};
}
SoundCollection(jsonObject) {
const collection = this.Collection(jsonObject);
return {
...collection,
getSound: idx => this.SoundObject(collection.results[idx])
};
}
PackCollection(jsonObject) {
const collection = this.Collection(jsonObject);
return {
...collection,
getPack: (idx) => this.PackObject(collection.results[idx])
};
}
SoundObject(oldJsonObject) {
const jsonObject = { ...oldJsonObject };
const getAnalysis = (filter) => this.makeRequest(this.makeUri(this.uris.soundAnalysis, [jsonObject.id, filter || '']));
const getSimilar = (params = {}) => this.makeRequest(this.makeUri(this.uris.similarSounds, [jsonObject.id]), 'GET', params).then(e => this.SoundCollection(e));
// @TODO
const getComments = () => this.makeRequest(this.makeUri(this.uris.comments, [jsonObject.id]), 'GET');
const download = () => {
// can be window, new, or iframe
this.checkOauth();
const uri = this.makeUri(this.uris.download, [jsonObject.id]);
return this.fetchWithAuthParams(uri);
};
// @TODO
// const comment = () => {
// this.checkOauth();
// const data = new FormData();
// data.append('comment', this.comment);
// const uri = this.makeUri(this.uris.comment, [jsonObject.id]);
// return this.makeRequest(uri, 'POST', data);
// };
const rate = (rating) => {
this.checkOauth();
const data = new form_data_1.default();
data.append('rating', rating);
const uri = this.makeUri(this.uris.rate, [jsonObject.id]);
return this.makeRequest(uri, 'POST', data);
};
const bookmark = (name, category) => {
this.checkOauth();
const data = new form_data_1.default();
data.append('name', name);
if (category) {
data.append('category', category);
}
const uri = this.makeUri(this.uris.bookmark, [jsonObject.id]);
return this.makeRequest(uri, 'POST', data);
};
// @TODO
// const edit = (description: { description: string }) => {
// this.checkOauth();
// const data = this.makeFormData(description);
// const uri = this.makeUri(this.uris.edit, [jsonObject.id]);
// return this.makeRequest(uri, 'POST', data);
// };
return {
...jsonObject,
getAnalysis,
getSimilar,
download,
rate,
getComments,
bookmark,
};
}
UserObject(oldJsonObject) {
const jsonObject = { ...oldJsonObject };
const sounds = (params = {}) => {
const uri = this.makeUri(this.uris.userSounds, [jsonObject.username]);
return this.makeRequest(uri, 'GET', params).then(e => this.SoundCollection(e));
};
const packs = () => {
const uri = this.makeUri(this.uris.userPacks, [jsonObject.username]);
return this.makeRequest(uri).then(e => this.PackCollection(e));
};
const bookmarkCategories = () => {
const uri = this.makeUri(this.uris.userBookmarkCategories, [
jsonObject.username
]);
return this.makeRequest(uri);
};
const bookmarkCategorySounds = (params = {}) => {
const uri = this.makeUri(this.uris.userBookmarkCategorySounds, [
jsonObject.username
]);
return this.makeRequest(uri, 'GET', params);
};
return {
...jsonObject,
sounds,
packs,
bookmarkCategories,
bookmarkCategorySounds
};
}
PackObject(oldJsonObject) {
const jsonObject = { ...oldJsonObject };
const sounds = (options = {}) => {
const uri = this.makeUri(this.uris.packSounds, [jsonObject.id]);
return this.makeRequest(uri, 'GET', options).then(e => this.SoundCollection(e));
};
const download = () => {
// can be current or new window, or iframe
this.checkOauth();
const uri = this.makeUri(this.uris.packDownload, [jsonObject.id]);
return this.fetchWithAuthParams(uri);
};
return {
...jsonObject,
sounds,
download
};
}
/**
*
* There are two ways of authenticating: OAuth and token method.
* The OAuth method is required for more privilidged actions such as
* downloading sounds.
*
* This method can set both kinds of tokens
*
* ```typescript
* await freeSound.setToken('your-api-key', 'oauth');
* ```
*/
setToken(token, type) {
this.authHeader = `${type === 'oauth' ? 'Bearer' : 'Token'} ${token}`;
return this.authHeader;
}
/**
* Set the credentials supplied by https://freesound.org/apiv2/apply for API
* call authentication. See
* https://freesound.org/docs/api/authentication.html?highlight=secret#token-authentication
* for more information.
*
* @param id your client ID, obtainable at https://freesound.org/apiv2/apply
* @param secret your client secret, obtainable at https://freesound.org/apiv2/apply
*
* ```typescript
* await freeSound.setClientSecrets(
* "your-client-id",
* "your-secret-key"
* );
* ```
*/
setClientSecrets(id, secret) {
this.clientId = id;
this.clientSecret = secret;
}
/**
* This method allows you to get a new token using a refresh token or an auth
* token
*
* ```typescript
* await freeSound.postAccessCode('your-temporary-code-from-login');
* ```
*/
postAccessCode(token, type = 'auth') {
const postUrl = `${this.uris.base}/oauth2/access_token/`;
const data = new form_data_1.default();
data.append('client_id', this.clientId);
data.append('client_secret', this.clientSecret);
const tokenType = type === 'auth'
? 'code'
: 'refresh_token';
data.append(tokenType, token);
const grantType = type === 'auth'
? 'authorization_code'
: 'refresh_token';
data.append('grant_type', grantType);
return this.makeRequest(postUrl, 'POST', data);
}
/**
* Search sounds in Freesound by matching their tags and other kinds of metadata. See
* https://freesound.org/docs/api/resources_apiv2.html#sound-text-search for more
* information.
*
* ```typescript
* await freeSound.textSearch('violoncello', {
* page: 1,
* filter: 'tag:tenuto duration:[1.0 TO 15.0]',
* sort: 'rating_desc',
* fields: 'id,name,url'
* });
* ```
*/
textSearch(query, opts = {}) {
const options = { ...opts };
options.query = query || ' ';
return this.search(options, this.uris.textSearch).then(e => this.SoundCollection(e));
}
/**
* Search sounds in Freesound based on their content descriptors. See
* https://freesound.org/docs/api/resources_apiv2.html#content-search
* for more information.
*
* ```typescript
* const result = await freeSound.contentSearch({
* target: 'lowlevel.pitch.mean:220',
* });
* ```
*/
contentSearch(options) {
if (!(options.target || options.analysis_file || options.descriptors_filter)) {
throw new Error('Missing target or analysis_file');
}
return this.search(options, this.uris.contentSearch).then(e => this.SoundCollection(e));
}
/**
* Search sounds in Freesound based on their tags, metadata and content-based descriptiors via
* a combination of text search and content search. See
* https://freesound.org/docs/api/resources_apiv2.html#combined-search for more information.
*
* ```typescript
* const soundCollectionResults = await freeSound.combinedSearch(
* filter: 'tag:scale',
* target: 'rhythm.bpm:120',
* );
* ```
*/
combinedSearch(options) {
if (!(options.target || options.query || options.descriptors_filter || options.target || options.filter)) {
throw new Error('Missing target, query, descriptors_filter, target, filter, or analysis_file');
}
return this.search(options, this.uris.combinedSearch);
}
/**
* Upload an audio file into Freesound and optionally describe it.
* If there is no file description, only the audio file will upload, and
* the user will need to add a description later using
* the describe(description: { description: string }) method. If the file description
* is present, the uploaded file will be ready for the processing and moderation stage.
* A list of uploaded files pending a description, processing or moderation is
* obtainable through the getPendingSounds() method. See
* https://freesound.org/docs/api/resources_apiv2.html#upload-sound-oauth2-required
* for more information. This method requires OAuth2 authentication.
*
* @param audiofile the audio file to upload
* @param filename the name of the audio file to upload
* @param description the description of the audio file to upload
*/
upload(audiofile, filename, description) {
this.checkOauth();
let formData = new form_data_1.default();
formData.append('audiofile', audiofile, filename);
if (description) {
formData = this.makeFormData(description, formData);
}
return this.makeRequest(this.makeUri(this.uris.upload), 'POST', formData);
}
/**
* Describe a previously uploaded file that does not have a description.
* Note: after a sound receives a description, the team of Freesound moderators
* still needs to process and moderate it, so it may not yet appear in Freesound.
* A list of sounds uploaded and described by the user, but still
* pending processing and moderation, is viewable with
* the getPendingSounds() method. This method requires OAuth2 authentication. See
* https://freesound.org/docs/api/resources_apiv2.html#describe-sound-oauth2-required
* for more information.
*
* @param description a description for an uploaded sound
*/
describe(description) {
this.checkOauth();
const formData = this.makeFormData(description);
return this.makeRequest(this.makeUri(this.uris.upload), 'POST', formData);
}
/**
* Retrieve a list of audio files uploaded by he Freesound user logged in using
* OAuth2 are not described, processed or moderated. In Freesound, sounds need
* descriptions after their upload. Then, sounds are automatically processed, and,
* finally, a team of human moderators either accepts or rejects the upload. This method
* keeps track of the status of these uploads and requires OAuth2 authentication. See
* https://freesound.org/docs/api/resources_apiv2.html#pending-uploads-oauth2-required
* for more information.
*
* ```typescript
* const result = await freeSound.getPendingSounds()
* ```
*/
getPendingSounds() {
this.checkOauth();
return this.makeRequest(this.makeUri(this.uris.pending));
}
/**
* Return basic information about the user that is logged in via OAuth2.
* This application can use it to identify which Freesound user has logged in.
*
* ```typescript
* const result = await freeSound.me();
* ```
*/
me() {
this.checkOauth();
return this.makeRequest(this.makeUri(this.uris.me));
}
/**
* Navigate to Freesound for user login.
*
* @returns a url where the user can login
*
* ```typescript
* const navigateToLogin = () => {
* window.location.replace(freeSound.getLoginURL());
* };
* ```
*/
getLoginURL() {
if (!this.clientId)
throw new Error('client_id was not set');
let loginUrl = this.makeUri(this.uris.authorize);
loginUrl += `?client_id=${this.clientId}&response_type=code`;
return loginUrl;
}
getLogoutURL() {
let logoutUrl = this.makeUri(this.uris.logoutAuthorize);
logoutUrl += `?client_id=${this.clientId}&response_type=code`;
return logoutUrl;
}
/**
* Retrieve information about a particular Freesound user. See
* https://freesound.org/docs/api/resources_apiv2.html#user-instance
* for more information.
*
* @param username the username of the Freesound user
* @returns information about a particular Freesound user
*
* ```typescript
* // Get information about the user https://freesound.org/people/MTG/.
* const user = await freeSound.getUser('MTG');
* ```
*/
getUser(username) {
return this.makeRequest(this.makeUri(this.uris.user, [username])).then(e => this.UserObject(e));
}
/**
* Retrieve the list of sounds included in a pack. See
* https://freesound.org/docs/api/resources_apiv2.html#pack-sounds for more information.
*
* @param packId the identification number of the pack to fetch
* @returns a list of sounds included in the pack that has packId as its identification number
*
* ```typescript
* // Fetch the pack
* // https://freesound.org/people/vroomvro0om/packs/21143/.
* const packObj = await freeSound.getPack(21143);
* ```
*/
async getPack(packId, options = {}) {
const pack = await this.makeRequest(this.makeUri(this.uris.pack, [packId]), 'GET', options);
return this.PackObject(pack);
}
/**
* Retrieve detailed information about a sound. See
* https://freesound.org/docs/api/resources_apiv2.html#sound-resources
* for more information.
*
* @param soundId the identification number of the sound
* @returns detailed information about a sound
*
* ```typescript
* // Fetch the sound
* // https://freesound.org/people/vroomvro0om/sounds/376626/.
* const fetchedSound = await freeSound.getSound(376626);
* ```
*/
async getSound(soundId) {
const sound = await this.makeRequest(this.makeUri(this.uris.sound, [soundId]));
return this.SoundObject(sound);
}
makeUri(uri, args) {
let newUri = String(uri);
if (args) {
args.forEach(element => {
newUri = newUri.replace(/<[\w_]+>/, String(element));
});
}
return this.uris.base + newUri;
}
async fetchWithAuthParams(uri, method = 'GET', params = {}) {
const IsoURLSearchParams = typeof window === 'object'
? URLSearchParams
: url_1.URLSearchParams;
return fetch(params ? `${uri}?${new IsoURLSearchParams(params).toString()}` : uri, {
method,
headers: {
Authorization: this.authHeader
}
});
}
async makeRequest(uri, method = 'GET', params = {}) {
return this.fetchWithAuthParams(uri, method, params)
.then(res => res.json())
.then(res => {
if (res.error) {
throw new Error(res.error);
}
if (res.detail === 'Authentication credentials were not provided') {
throw new Error(res.detail);
}
return res;
});
}
}
exports.default = FreeSound;
//# sourceMappingURL=index.js.map