|
@@ -47,15 +47,15 @@ export const downloadSong = (identity) => (dispatch, getState) => {
|
|
|
}, 1000)
|
|
|
fetch(`https://beatsaver.com/api/maps/by-hash/${hash}`)
|
|
|
.then(res => res.json())
|
|
|
- .then(results => {
|
|
|
+ .then(song => {
|
|
|
let utc = Date.now()
|
|
|
- if(results) {
|
|
|
+ if(song) {
|
|
|
dispatch({
|
|
|
type: ADD_TO_QUEUE,
|
|
|
- payload: { ...results, utc }
|
|
|
+ payload: { ...song, utc }
|
|
|
})
|
|
|
let req = request.get({
|
|
|
- url: `http://www.beatsaver.com${results.downloadURL}`,
|
|
|
+ url: `http://www.beatsaver.com${song.downloadURL}`,
|
|
|
encoding: null
|
|
|
}, (err, r, data) => {
|
|
|
try {
|
|
@@ -97,19 +97,33 @@ export const downloadSong = (identity) => (dispatch, getState) => {
|
|
|
dispatch({
|
|
|
type: DISPLAY_WARNING,
|
|
|
payload: {
|
|
|
- text: `There was an error unpacking the song "${results.name}." The song's files may be corrupt or use formatting other than UTF-8 (Why UTF-8? The IETF says so! https://tools.ietf.org/html/rfc8259#section-8.1). Please try again and contact the song's uploader, ${results.uploader.username}, if problem persists.`
|
|
|
+ text: `There was an error unpacking the song "${song.name}." The song's files may be corrupt or use formatting other than UTF-8 (Why UTF-8? The IETF says so! https://tools.ietf.org/html/rfc8259#section-8.1). Please try again and contact the song's uploader, ${song.uploader.username}, if problem persists.`
|
|
|
}
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
- infoObject.key = results.key
|
|
|
+ infoObject.key = song.key
|
|
|
infoObject.hash = hash
|
|
|
zip.updateFile(infoEntry.entryName, JSON.stringify(infoObject))
|
|
|
- let extractTo = (getState().settings.folderStructure === 'idKey' ? results.key : results.name.replace(/[\\/:*?"<>|.]/g, ''))
|
|
|
- zip.extractAllTo(path.join(getState().settings.installationDirectory, 'CustomSongs', extractTo))
|
|
|
+ let extractTo
|
|
|
+ switch(getState().settings.folderStructure) {
|
|
|
+ case 'keySongNameArtistName':
|
|
|
+ extractTo = `${ song.key } (${ song.metadata.songName.replace(/[\\/:*?"<>|.]/g, '') } - ${ song.metadata.songAuthorName })`
|
|
|
+ break
|
|
|
+ case 'key':
|
|
|
+ extractTo = song.key
|
|
|
+ break
|
|
|
+ case 'songName':
|
|
|
+ extractTo = song.name.replace(/[\\/:*?"<>|.]/g, '')
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ extractTo = `${ song.key } (${ song.name.replace(/[\\/:*?"<>|.]/g, '') } - ${ song.songAuthorName })`
|
|
|
+ break
|
|
|
+ }
|
|
|
+ zip.extractAllTo(path.join(getState().settings.installationDirectory, 'Beat Saber_Data', 'CustomLevels', extractTo))
|
|
|
dispatch({
|
|
|
type: SET_DOWNLOADED_SONGS,
|
|
|
- payload: [...getState().songs.downloadedSongs, { hash, file: path.join(getState().settings.installationDirectory, 'CustomSongs', extractTo, infoEntry.entryName) }]
|
|
|
+ payload: [...getState().songs.downloadedSongs, { hash, file: path.join(getState().settings.installationDirectory, 'Beat Saber_Data', 'CustomLevels', extractTo, infoEntry.entryName) }]
|
|
|
})
|
|
|
state = { ...getState() }
|
|
|
dispatch({
|
|
@@ -139,7 +153,7 @@ export const downloadSong = (identity) => (dispatch, getState) => {
|
|
|
type: UPDATE_PROGRESS,
|
|
|
payload: {
|
|
|
utc,
|
|
|
- hash: results.hash,
|
|
|
+ hash: song.hash,
|
|
|
progress: Math.trunc((chunks / len) * 100)
|
|
|
}
|
|
|
})
|
|
@@ -203,111 +217,116 @@ export const downloadSong = (identity) => (dispatch, getState) => {
|
|
|
}, 1000)
|
|
|
fetch(`https://beatsaver.com/api/maps/by-hash/${hash}`)
|
|
|
.then(res => res.json())
|
|
|
- .then(results => {
|
|
|
+ .then(song => {
|
|
|
let utc = Date.now()
|
|
|
- if(results.songs.length === 1) {
|
|
|
- dispatch({
|
|
|
- type: ADD_TO_QUEUE,
|
|
|
- payload: { ...results.songs[0], utc }
|
|
|
- })
|
|
|
- let req = request.get({
|
|
|
- url: results.downloadURL,
|
|
|
- encoding: null
|
|
|
- }, (err, r, data) => {
|
|
|
- try {
|
|
|
- // eslint-disable-next-line
|
|
|
- if(err || r ? r.statusCode !== 200 : false) throw 'Error downloading!'
|
|
|
- } catch(err) {
|
|
|
- state = { ...getState() }
|
|
|
- dispatch({
|
|
|
- type: SET_DOWNLOADING_COUNT,
|
|
|
- payload: --state.songs.downloadingCount
|
|
|
- })
|
|
|
- if(state.songs.waitingToDownload.length > 0) {
|
|
|
- let toDownload = state.songs.waitingToDownload.pop()
|
|
|
- dispatch({
|
|
|
- type: SET_WAIT_LIST,
|
|
|
- payload: state.songs.waitingToDownload
|
|
|
- })
|
|
|
- downloadSong(toDownload)(dispatch, getState)
|
|
|
- }
|
|
|
+ dispatch({
|
|
|
+ type: ADD_TO_QUEUE,
|
|
|
+ payload: { ...song, utc }
|
|
|
+ })
|
|
|
+ let req = request.get({
|
|
|
+ url: `https://beatsaver.com/${ song.downloadURL }`,
|
|
|
+ encoding: null
|
|
|
+ }, (err, r, data) => {
|
|
|
+ try {
|
|
|
+ // eslint-disable-next-line
|
|
|
+ if(err || r ? r.statusCode !== 200 : false) throw 'Error downloading!'
|
|
|
+ } catch(err) {
|
|
|
+ state = { ...getState() }
|
|
|
+ dispatch({
|
|
|
+ type: SET_DOWNLOADING_COUNT,
|
|
|
+ payload: --state.songs.downloadingCount
|
|
|
+ })
|
|
|
+ if(state.songs.waitingToDownload.length > 0) {
|
|
|
+ let toDownload = state.songs.waitingToDownload.pop()
|
|
|
dispatch({
|
|
|
- type: DISPLAY_WARNING,
|
|
|
- payload: {
|
|
|
- text: `There was an error downloading the song with hash ${hash}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.`
|
|
|
- }
|
|
|
+ type: SET_WAIT_LIST,
|
|
|
+ payload: state.songs.waitingToDownload
|
|
|
})
|
|
|
- return
|
|
|
- }
|
|
|
- let zip = new AdmZip(data)
|
|
|
- let zipEntries = zip.getEntries()
|
|
|
- let infoEntry, infoObject
|
|
|
- for(let i = 0; i < zipEntries.length; i++) {
|
|
|
- if(zipEntries[i].entryName.substr(zipEntries[i].entryName.length - 9, 9) === 'info.json') {
|
|
|
- infoEntry = zipEntries[i]
|
|
|
+ downloadSong(toDownload)(dispatch, getState)
|
|
|
}
|
|
|
- }
|
|
|
- try {
|
|
|
- infoObject = JSON.parse(infoEntry.getData().toString('UTF8'))
|
|
|
- } catch(err) {
|
|
|
dispatch({
|
|
|
type: DISPLAY_WARNING,
|
|
|
payload: {
|
|
|
- text: `There was an error unpacking the song "${results.songs[0].songName}." The song's files may be corrupt or use formatting other than UTF-8 (Why UTF-8? The IETF says so! https://tools.ietf.org/html/rfc8259#section-8.1). Please try again and contact the song's uploader, ${results.songs[0].uploader}, if problem persists.`
|
|
|
+ text: `There was an error downloading the song with hash ${hash}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.`
|
|
|
}
|
|
|
})
|
|
|
return
|
|
|
+ }
|
|
|
+ let zip = new AdmZip(data)
|
|
|
+ let zipEntries = zip.getEntries()
|
|
|
+ let infoEntry, infoObject
|
|
|
+ for(let i = 0; i < zipEntries.length; i++) {
|
|
|
+ if(zipEntries[i].entryName.substr(zipEntries[i].entryName.length - 9, 9) === 'info.json' || zipEntries[i].entryName.substr(zipEntries[i].entryName.length - 8, 9) === 'info.dat') {
|
|
|
+ infoEntry = zipEntries[i]
|
|
|
}
|
|
|
- infoObject.key = results.songs[0].key
|
|
|
- infoObject.hash = hash
|
|
|
- zip.updateFile(infoEntry.entryName, JSON.stringify(infoObject))
|
|
|
- let extractTo = (getState().settings.folderStructure === 'idKey' ? results.songs[0].key : results.songs[0].name.replace(/[\\/:*?"<>|.]/g, ''))
|
|
|
- zip.extractAllTo(path.join(getState().settings.installationDirectory, 'CustomSongs', extractTo))
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ infoObject = JSON.parse(infoEntry.getData().toString('UTF8'))
|
|
|
+ } catch(err) {
|
|
|
dispatch({
|
|
|
- type: SET_DOWNLOADED_SONGS,
|
|
|
- payload: [...getState().songs.downloadedSongs, { hash, file: path.join(getState().settings.installationDirectory, 'CustomSongs', extractTo, infoEntry.entryName) }]
|
|
|
+ type: DISPLAY_WARNING,
|
|
|
+ payload: {
|
|
|
+ text: `There was an error unpacking the song "${song.songName}." The song's files may be corrupt or use formatting other than UTF-8 (Why UTF-8? The IETF says so! https://tools.ietf.org/html/rfc8259#section-8.1). Please try again and contact the song's uploader, ${song.uploader.username}, if problem persists.`
|
|
|
+ }
|
|
|
})
|
|
|
- state = { ...getState() }
|
|
|
+ return
|
|
|
+ }
|
|
|
+ infoObject.key = song.key
|
|
|
+ infoObject.hash = hash
|
|
|
+ zip.updateFile(infoEntry.entryName, JSON.stringify(infoObject))
|
|
|
+ let extractTo
|
|
|
+ switch(getState().settings.folderStructure) {
|
|
|
+ case 'keySongNameArtistName':
|
|
|
+ extractTo = `${ song.key } (${ song.metadata.songName.replace(/[\\/:*?"<>|.]/g, '') } - ${ song.metadata.songAuthorName })`
|
|
|
+ break
|
|
|
+ case 'key':
|
|
|
+ extractTo = song.key
|
|
|
+ break
|
|
|
+ case 'songName':
|
|
|
+ extractTo = song.name.replace(/[\\/:*?"<>|.]/g, '')
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ extractTo = `${ song.key } (${ song.name.replace(/[\\/:*?"<>|.]/g, '') } - ${ song.songAuthorName })`
|
|
|
+ break
|
|
|
+ }
|
|
|
+ zip.extractAllTo(path.join(getState().settings.installationDirectory, 'Beat Saber_Data', 'CustomLevels', extractTo))
|
|
|
+ dispatch({
|
|
|
+ type: SET_DOWNLOADED_SONGS,
|
|
|
+ payload: [...getState().songs.downloadedSongs, { hash, file: path.join(getState().settings.installationDirectory, 'Beat Saber_Data', 'CustomLevels', extractTo, infoEntry.entryName) }]
|
|
|
+ })
|
|
|
+ state = { ...getState() }
|
|
|
+ dispatch({
|
|
|
+ type: SET_DOWNLOADING_COUNT,
|
|
|
+ payload: --state.songs.downloadingCount
|
|
|
+ })
|
|
|
+ if(state.songs.waitingToDownload.length > 0) {
|
|
|
+ let toDownload = state.songs.waitingToDownload.pop()
|
|
|
dispatch({
|
|
|
- type: SET_DOWNLOADING_COUNT,
|
|
|
- payload: --state.songs.downloadingCount
|
|
|
+ type: SET_WAIT_LIST,
|
|
|
+ payload: state.songs.waitingToDownload
|
|
|
})
|
|
|
- if(state.songs.waitingToDownload.length > 0) {
|
|
|
- let toDownload = state.songs.waitingToDownload.pop()
|
|
|
- dispatch({
|
|
|
- type: SET_WAIT_LIST,
|
|
|
- payload: state.songs.waitingToDownload
|
|
|
- })
|
|
|
- downloadSong(toDownload)(dispatch, getState)
|
|
|
- }
|
|
|
- })
|
|
|
+ downloadSong(toDownload)(dispatch, getState)
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
- let len = 0
|
|
|
- let chunks = 0
|
|
|
+ let len = 0
|
|
|
+ let chunks = 0
|
|
|
|
|
|
- req.on('response', (data) => {
|
|
|
- len = data.headers['content-length']
|
|
|
- })
|
|
|
+ req.on('response', (data) => {
|
|
|
+ len = data.headers['content-length']
|
|
|
+ })
|
|
|
|
|
|
- req.on('data', (chunk) => {
|
|
|
- chunks += chunk.length
|
|
|
- dispatch({
|
|
|
- type: UPDATE_PROGRESS,
|
|
|
- payload: {
|
|
|
- utc,
|
|
|
- hash: results.songs[0].hashMd5,
|
|
|
- progress: Math.trunc((chunks / len) * 100)
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
- } else {
|
|
|
+ req.on('data', (chunk) => {
|
|
|
+ chunks += chunk.length
|
|
|
dispatch({
|
|
|
- type: DISPLAY_WARNING,
|
|
|
+ type: UPDATE_PROGRESS,
|
|
|
payload: {
|
|
|
- text: `There was an error downloading the song with hash ${hash}. The song requested is no longer be available for download.`
|
|
|
+ utc,
|
|
|
+ hash: song.hash,
|
|
|
+ progress: Math.trunc((chunks / len) * 100)
|
|
|
}
|
|
|
})
|
|
|
- }
|
|
|
+ })
|
|
|
})
|
|
|
.catch(err => {
|
|
|
state = { ...getState() }
|
|
@@ -346,19 +365,19 @@ export const deleteSong = (identity) => (dispatch, getState) => {
|
|
|
type: SET_VIEW,
|
|
|
payload: getState().view.previousView
|
|
|
})
|
|
|
- let dirs = file.split('\\')
|
|
|
- let csd = dirs.indexOf('CustomSongs')
|
|
|
- for(let i = 2; i < file.split('\\').length - csd; i++) {
|
|
|
+ let dirs = file.split(path.sep)
|
|
|
+ let cld = dirs.indexOf('CustomLevels')
|
|
|
+ for(let i = 2; i < file.split(path.sep).length - cld; i++) {
|
|
|
dirs.pop()
|
|
|
}
|
|
|
let downloadedSongs = [ ...getState().songs.downloadedSongs ]
|
|
|
downloadedSongs.splice(downloadedSongs.findIndex(song => song.file === file), 1)
|
|
|
- rimraf(dirs.join('\\'), (err) => {
|
|
|
+ rimraf(dirs.join(path.sep), (err) => {
|
|
|
if(err) {
|
|
|
dispatch({
|
|
|
type: DISPLAY_WARNING,
|
|
|
payload: {
|
|
|
- text: `There was an error deleting the song located at ${dirs.join('\\')}. BeatDrop may have insufficient permissions or the file may be in use by another program. Please try closing any programs that may be using this song and try again.`
|
|
|
+ text: `There was an error deleting the song located at ${dirs.join(path.sep)}. BeatDrop may have insufficient permissions or the file may be in use by another program. Please try closing any programs that may be using this song and try again.`
|
|
|
}
|
|
|
})
|
|
|
return
|
|
@@ -408,7 +427,7 @@ export const checkDownloadedSongs = () => (dispatch, getState) => {
|
|
|
if(!--pending) cb(null, songs)
|
|
|
})
|
|
|
} else {
|
|
|
- if(files[i].toLowerCase() === 'info.json') {
|
|
|
+ if(files[i].toLowerCase() === 'info.dat' || files[i].toLowerCase() === 'info.json') {
|
|
|
fs.readFile(file, { encoding: 'UTF-8' }, (err, data) => {
|
|
|
if(err) return cb(err)
|
|
|
let song = JSON.parse(data)
|
|
@@ -462,7 +481,7 @@ export const checkDownloadedSongs = () => (dispatch, getState) => {
|
|
|
payload: true
|
|
|
})
|
|
|
|
|
|
- walk(path.join(getState().settings.installationDirectory, 'CustomSongs'), (err, songs) => {
|
|
|
+ walk(path.join(getState().settings.installationDirectory, 'Beat Saber_Data', 'CustomLevels'), (err, songs) => {
|
|
|
dispatch({
|
|
|
type: SET_DOWNLOADED_SONGS,
|
|
|
payload: songs
|