A music player that connects to your cloud/distributed storage.
1//
2// Processing
3// ♪(´ε` )
4//
5// Audio processing, getting metadata, etc.
6
7
8import * as musicMetadata from "music-metadata-browser"
9import { makeTokenizer } from "@tokenizer/http"
10
11import { mimeType } from "./common"
12import { transformUrl } from "./urls"
13
14
15// Contexts
16// --------
17
18export function processContext(context, app) {
19 const initialPromise = Promise.resolve([])
20
21 return context.urlsForTags.reduce((accumulator, urls, idx) => {
22 return accumulator.then(col => {
23 const filename = context
24 .receivedFilePaths[ idx ]
25 .split("/")
26 .reverse()[ 0 ]
27
28 return Promise.all([
29 transformUrl(urls.headUrl, app),
30 transformUrl(urls.getUrl, app)
31
32 ]).then(([ headUrl, getUrl ]) => {
33 return getTags(headUrl, getUrl, filename, { skipCovers: true })
34
35 }).then(r => {
36 return col.concat(r)
37
38 }).catch(e => {
39 console.warn(e)
40 return col.concat(null)
41
42 })
43 })
44
45 }, initialPromise).then(col => {
46 context.receivedTags = col
47 return context
48
49 })
50}
51
52
53
54// Tags
55// ----
56
57
58const parserConfiguration = Object.assign(
59 {}, musicMetadata.parsingOptions,
60 { duration: false, skipPostHeaders: true }
61)
62
63
64export function getTags(headUrl, getUrl, filename, options) {
65 const fileExtMatch = filename.match(/\.(\w+)$/)
66 const fileExt = fileExtMatch && fileExtMatch[ 1 ]
67
68 const overrideContentType = (
69 getUrl.includes("googleapis.com") ||
70 getUrl.includes("googleusercontent.com")
71 )
72
73 return makeTokenizer(headUrl)
74 .then(tokenizer => {
75 const fileMime = overrideContentType
76 ? mimeType(fileExt)
77 : tokenizer.fileInfo.mimeType
78
79 tokenizer.fileInfo.mimeType = fileMime
80 tokenizer.fileInfo.url = getUrl
81 tokenizer.rangeRequestClient.url = getUrl
82 tokenizer.rangeRequestClient.resolvedUrl = undefined
83
84 return musicMetadata.parseFromTokenizer(
85 tokenizer,
86 Object.assign({}, parserConfiguration, options || {})
87 )
88 })
89 .then(result => {
90 return pickTags(filename, result)
91 })
92 .catch(err => {
93 console.error(err)
94 return fallbackTags(filename)
95 })
96}
97
98
99function pickTags(filename, result) {
100 const tags = result && result.common
101 if (!tags) return null
102
103 const artist = tags.artist && tags.artist.length ? tags.artist : null
104 const title = tags.title && tags.title.length ? tags.title : null
105
106 return {
107 disc: tags.disk.no || 1,
108 nr: tags.track.no || 1,
109 album: tags.album && tags.album.length ? tags.album : "Unknown",
110 artist: artist || "Unknown",
111 title: title ? title : (artist ? "Unknown" : filename.replace(/\.\w+$/, "")),
112 genre: (tags.genre && tags.genre[ 0 ]) || null,
113 year: tags.year || null,
114 picture: tags.picture ? tags.picture[ 0 ] : null
115 }
116}
117
118
119function fallbackTags(filename) {
120 const filenameWithoutExt = filename.replace(/\.\w+$/, "")
121
122 return {
123 disc: 1,
124 nr: 1,
125 album: "Unknown",
126 artist: "Unknown",
127 title: filenameWithoutExt,
128 genre: null,
129 year: null,
130 picture: null
131 }
132}