music-graph-ui/music_graph/src/MusicGraphApi.js
2019-06-14 22:36:42 -04:00

201 lines
6.3 KiB
JavaScript

import * as d3 from 'd3'
import {genres} from './genres'
const IGNORE_DATES_TAG = true
const ONLY_GENRE_TAGS = false
const nodeUtils = {
getNodeType: function (labels) {
if (labels.find(l => l === 'Tag')) {
return 'Tag'
} else if (labels.find(l => l === 'Group')) {
return 'Group'
} else if (labels.find(l => l === 'Artist')) {
return 'Artist'
} else if (labels.find(l => l === 'Album')) {
return 'Album'
} else if (labels.find(l => l === 'Single')) {
return 'Single'
} else if (labels.find(l => l === 'EP')) {
return 'EP'
}
return undefined
},
fromRawDict: function (data) {
const type = nodeUtils.getNodeType(data.labels)
if (type === 'Group' || type === 'Artist') {
return {
id: data.id,
mbid: data.mbid,
name: data.name,
listeners: data.listeners,
type: type,
sourceLinks: new Set(),
targetLinks: new Set(),
radius: nodeUtils.radius(type)
}
} else {
return {
id: data.id,
name: data.name,
mbid: data.mbid,
type: type,
sourceLinks: new Set(),
targetLinks: new Set(),
radius: nodeUtils.radius(type)
}
}
},
radius: function (type) {
return 35
}
}
export function MusicGraphApi() {
this.url = window.location.protocol + '//' + window.location.hostname + '/api'
this.resolveCoverUrl = function (mbid) {
return this.url + '/cover/' + mbid
}
this.getArtistDetails = function (mbid) {
return d3.json(this.url + '/artist/details/' + mbid)
}
this.getGroupMembers = function (mbid, originId) {
return d3.json(this.url + '/artist/members/' + mbid)
.then((r) => {
return {
newNodes: r.artists.map(nodeUtils.fromRawDict),
relations: r.artists.map(a => {
return {
source: a.id,
target: originId,
weight: 0.8
}
})
}
})
}
this.getArtistReleases = function (mbid, originId) {
return d3.json(this.url + '/artist/details/' + mbid)
.then((r) => {
const newNodes = r.releases
.map(nodeUtils.fromRawDict)
.filter(release => release.type === 'Album')
return {
newNodes: newNodes,
relations: newNodes.map(t => {
return {
source: originId,
target: t.id,
weight: 0.8
}
})
}
})
}
this._filterTags = function (tags) {
if (ONLY_GENRE_TAGS) {
return tags.filter(tag => genres.has(tag.name))
} else if (IGNORE_DATES_TAG) {
return tags.filter(tag => isNaN(tag.name) && isNaN(tag.name.slice(0, -1)))
}
return tags
}
this._addTagLabel = function (objects) {
return objects.map(tag => {
tag.labels = ['Tag']
return tag
})
}
this.getArtistTags = function (mbid, originId) {
return d3.json(this.url + '/artist/details/' + mbid)
.then((r) => {
const tags = this._filterTags(r.tags)
return {
newNodes: this._addTagLabel(tags).map(nodeUtils.fromRawDict),
relations: tags.map(t => {
return {
source: originId,
target: t.id,
weight: t.weight
}
})
}
})
}
this.getRelatedByMbid = function (mbid) {
return d3.json(this.url + '/artist/related/' + mbid)
.then((r) => {
let node = nodeUtils.fromRawDict(r.artists.find(a => a.mbid === mbid))
let directedRelations = r.relations.map(rel => {
// Make new nodes children of the expanded nodes, no matter the original direction
if (rel.source === node.id) {
return rel
} else {
return {
source: rel.target,
target: rel.source,
weight: rel.weight
}
}
})
return {
node: node,
newNodes: r.artists.map(nodeUtils.fromRawDict),
relations: directedRelations
}
})
}
this.getRelatedByTag = function (tagid) {
return d3.json(this.url + '/tag/related/' + tagid)
.then((r) => {
return {
node: nodeUtils.fromRawDict({
labels: ['Tag'],
id: r.tag.id,
name: r.tag.name
}),
newNodes: r.artists.map(nodeUtils.fromRawDict),
relations: r.relations
}
})
}
this.getReleaseDetails = function (mbid, originId) {
return d3.json(this.url + '/release/details/' + mbid)
.then((r) => {
const tags = this._filterTags(r.tags)
return {
newNodes: this._addTagLabel(tags).map(nodeUtils.fromRawDict),
relations: tags.map(t => {
return {
source: originId,
target: t.id,
weight: t.weight
}
})
}
})
}
this.autoComplete = function (prefix) {
prefix = prefix.replace(/[^\w.\-!?& ]/g, '_').toUpperCase()
prefix = prefix.replace(/ /g, '+')
return d3.json(this.url + '/artist/autocomplete/' + prefix)
}
}