Skip to content

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
  • Loading branch information
Christiaan Maks committed May 28, 2016
0 parents commit 53da694
Show file tree
Hide file tree
Showing 7 changed files with 333 additions and 0 deletions.
30 changes: 30 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directory
# Deployed apps should consider commenting this line out:
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
node_modules
spotify_appkey.key
downloads
config.json

.DS_Store
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# spotijay-lib

Download tracks from Spotify in 320kbps.

# Installation

1. `npm install`
1. Install [libspotify](https://developer.spotify.com/technologies/libspotify/)
1. Install following libraries: lame sox eye3D
- Ubuntu/Debian: `sudo apt-get install lame sox eyed3`
- Arch: `yaourt -S libspotify python2-eyed3 lame sox`
- OSX: `brew install homebrew/binary/libspotify lame sox eyeD3`
1. Copy your [appkey](https://developer.spotify.com/my-account/keys) in the root of the dir that uses this library (or specify another path, its the `__dirname` below that points to the appkey dir)

# Usage

```js
if (args.playlist) {
Spotijay(args.username, args.password, __dirname, function(err, spotify) {
spotify.downloadPlaylistByUrl(args.playlist, args.dir, errorCallback)
})
} else if (args.track) {
Spotijay(args.username, args.password, __dirname, function(err, spotify) {
spotify.getTrackByUrl(args.track, args.dir, errorCallback)
})
}
```

For more see [Spotijay](https://github.com/Christilut/Spotijay)
29 changes: 29 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
var sp = require('libspotify')
var path = require('path')

module.exports = function(username, password, dir, cb) {
var session = new sp.Session({
applicationKey: path.join(dir, 'spotify_appkey.key')
})

var downloadTrack = require('./lib/download_track')
var downloadPlaylist = require('./lib/download_playlist')
var getTrackByUrl = require('./lib/get_track')

session.login(username, password)

session.once('login', function(err) {

cb(null, {
downloadTrack: downloadTrack(session),
downloadPlaylistByUrl: downloadPlaylist(session),
getTrackByUrl: getTrackByUrl(session)
})
})

session.on('error', function(err) {
cb(err)
session.close()
process.exit()
})
}
45 changes: 45 additions & 0 deletions lib/download_playlist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
var async = require('async')
var sp = require('libspotify')

module.exports = function(session) {
var downloadTrack = require(__dirname + '/download_track')(session)

function downloadPlaylist(url, path, callback) {
var args = arguments
var playlist = sp.Playlist.getFromUrl(url)

console.log('Getting playlist contents from Spotify...')

playlist.whenReady(function() {
playlist.getTracks(function(tracks) {
var left = tracks.length

if (left) {
async.mapSeries(tracks, function(track, callback) {
console.log('Tracks left: ' + left)
left--
downloadTrack(track, path, callback)

}, function(err) {
if (err) {
callback(err)
} else {
console.log('Downloaded all tracks')
setTimeout(function() {
downloadPlaylist.apply(downloadPlaylist, args)
}, 60 * 1000)
}
})

} else {
console.log('There are no tracks on this playlist')
setTimeout(function() {
downloadPlaylist.apply(downloadPlaylist, args)
}, 60 * 1000)
}
})
})
}

return downloadPlaylist
}
148 changes: 148 additions & 0 deletions lib/download_track.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
var async = require('async')
var crypto = require('crypto')
var exec = require('child_process').exec
var fs = require('fs')
var punycode = require('punycode')

module.exports = function(session) {
return function(track, path, callback) {
var tracktitle = track.artist.name + ' - ' + track.title

if (track.availability === 'UNAVAILABLE') {
console.log('Track unavavailabe, skipping: ' + tracktitle)
return callback(null)
}

var player = session.getPlayer()

// var destiny = path + '/' + track.artist.name + '/' + track.album.name + '/' + track.name
var destiny = path + '/' + tracktitle

var hashedName = crypto.createHash('sha1').update(
tracktitle
).digest('hex')

//getting a hash cuz eyeD3 is a motherfucker with special chars.
var destinyHash = path + '/' + hashedName

// skip if already exists
if (fs.existsSync(destiny + '.mp3')) {
console.log('File already exists, skipping: ' + tracktitle + '.mp3')
return callback(null)
}

console.log('Downloading: ' + tracktitle)

if (!fs.existsSync(path)) fs.mkdirSync(path)
var ws = fs.createWriteStream(destinyHash + '.raw')

player.load(track)
player.play()
player.pipe(ws)

player.once('track-end', function() {
player.stop()
ws.end()

async.waterfall([

function(callback) {
console.log('Converting raw file to wav')
exec('sox ' + [
'-r', 44100,
'-b', 16,
'-L',
'-c', 2,
'-e', 'signed-integer',
'-t', 'raw',
'"' + destinyHash + '.raw"',
'"' + destinyHash + '.wav"'
].join(' '), function(err) {
callback(err)
})
},
function(callback) {
console.log('Converting wav file to mp3 at 320kbps')
exec('lame ' + [
'--preset', 'insane',
'-b', 320,
'-h',
'"' + destinyHash + '.wav"',
'"' + destinyHash + '.mp3"'
].join(' '), function(err) {
callback(err)
})
},
function(callback) {
track.album.coverImage(function(err, buffer) {
if (err) {
return callback(null, false)
}
fs.writeFile(destinyHash + '.png', buffer, function(err) {
callback(null, true)
})
})
},
function(cover, callback) {
console.log('Adding id3 tags')

var coverCmd = ['--add-image', '"' + destinyHash + '.png:FRONT_COVER"']

var args = [
'-t', '"' + punycode.toASCII(track.title) + '"',
'-a', '"' + punycode.toASCII(track.artist.name) + '"',
'-A', '"' + punycode.toASCII(track.album.name) + '"',
'-Y', '"' + track.album.year + '"',
'"' + destinyHash + '.mp3"'
]

// Adds the command to add a ilustration to the file
if (cover)
args = coverCmd.concat(args)

var cmd = 'eyeD3 ' + args.join(' ')

exec(cmd, function(err) {
callback(err, cover)
})

},
function(cover, callback) {
// if (config.copy)
// exec('cp ' + destinyHash + '.mp3 ' + config.copy + '/' + destinyHash + '.mp3', function(err) {
// console.log(err)
// })
// if (config.itunes)
// exec('open -a "itunes" ' + destinyHash + '.mp3 ', function(err) {
// console.log(err)
// })

// cleanup
fs.unlinkSync(destinyHash + '.raw')
fs.unlinkSync(destinyHash + '.wav')
fs.unlinkSync(destinyHash + '.png') // use flag? some may want it as cover.png or something

fs.renameSync(destinyHash + '.mp3', destiny + '.mp3')

// if (cover) {
// fs.renameSync(destinyHash + '.png', path + '/' + track.artist.name + ' - ' + track.title + '.png')
// }
callback()
}

], function(err) {
console.log('Finished: ' + tracktitle)
ws.end()
player.removeAllListeners('error')
delete player, ws
callback(err)
})

})

player.on('error', function(err) {
ws.end()
callback(err)
})
}
}
14 changes: 14 additions & 0 deletions lib/get_track.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
var async = require('async')
var sp = require('libspotify')

var downloadTrack = require(__dirname + '/download_track')

module.exports = function(session) {
return function(url, path, callback) {
var track = sp.Track.getFromUrl(url)

track.on('ready', function() {
downloadTrack(session)(track, path, callback)
})
}
}
38 changes: 38 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "spotijay-lib",
"description": "Spotify downloader library",
"version": "0.1.0",
"keywords": [
"spotify",
"spotijay",
"download"
],
"author": {
"name": "Alejandro Perezpayá",
"email": "[email protected]",
"url": "http://perezpaya.net"
},
"contributors": [
{
"name": "Alejandro Perezpayá",
"email": "[email protected]",
"url": "http://perezpaya.net"
},
{
"name": "Luis Iván Cuende",
"email": "[email protected]",
"url": "http://luisivan.net"
},
{
"name": "Christiaan Maks"
}
],
"main": "index.js",
"engines": {
"node": ">= 0.10.x"
},
"dependencies": {
"async": "~0.9.0",
"libspotify": "~0.2.2"
}
}

0 comments on commit 53da694

Please sign in to comment.