Skip to content

Commit

Permalink
Merge e6791db into 1a3e36a
Browse files Browse the repository at this point in the history
  • Loading branch information
martindale committed May 7, 2015
2 parents 1a3e36a + e6791db commit 29d439c
Show file tree
Hide file tree
Showing 107 changed files with 20,954 additions and 3,688 deletions.
1 change: 1 addition & 0 deletions .coveralls.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
service_name: travis-ci
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ logs
results

npm-debug.log
config.js

config.js
7 changes: 7 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
language: node_js
node_js:
- '0.10'
services:
- mongodb
- redis-server
after_script: istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage
35 changes: 28 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,47 @@
# soundtrack.io
soundtrack.io
=============
[![Build Status](https://img.shields.io/travis/martindale/soundtrack.io.svg?branch=soundtrack.io&style=flat-square)](https://travis-ci.org/martindale/soundtrack.io)
[![Coverage Status](https://img.shields.io/coveralls/martindale/soundtrack.io/soundtrack.io.svg?style=flat-square)](https://coveralls.io/r/martindale/soundtrack.io)

soundtrack.io is a collaborative online jukebox.
soundtrack.io is a collaborative online jukebox. It is an experimental Internet radio platform. Vote on what plays next, like Reddit for music. Aggregates streams from sources like YouTube and SoundCloud, so when a song is queued, it has multiple locations to play from if any one source fails for any particular reason.

## Getting Started

Before you begin you will need to have nodejs, redis, and mongodb installed.
Homebrew is recommended for OS X users.

brew install nodejs mongodb redis
redis-server &
mongod &
```
brew install nodejs mongodb redis
```

Once you have them installed, go ahead and clone the repository.
In the logged output, you'll find some instructions for starting both mongodb and redis – you can follow those instructions, or execute once with `redis-server & mongod &`

git clone git@github.com:fractaloop/soundtrack.io.git
Once you have them installed (and running!), go ahead and clone the repository.

git clone git@github.com:martindale/soundtrack.io.git
cd soundtrack.io

You will need to fetch the dependencies and then you can start up the server.

npm install
node soundtrack.js

### Testing Rooms
Now that soundtrack has multiple rooms, you'll need to configure your local hostname lookups to point at the appropriate locations. In `/etc/hosts` (or equivalent for your OS):

```
127.0.0.1 localhost.localdomain
127.0.0.1 test.localhost.localdomain
```

You'll need to add an entry for each subdomain you want to test. Also, the `.localdomain` component is important for sessions, as some browsers expect a top level domain for cookies to work correctly!

## API

Deleting tracks:
`$.ajax('/playlist/520e6bda3cb680003700049c', { type: 'DELETE', data: { index: 1 } });`

## Contributing
Want to help? Claim something in [the "ready" column on our Waffle.io](https://waffle.io/martindale/soundtrack.io) by assigning it to yourself.

[Fork. Commit. Pull request.](https://help.github.com/articles/fork-a-repo)
11 changes: 11 additions & 0 deletions addJob.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
var config = require('./config');

var Monq = require('monq');
var monq = Monq('mongodb://localhost:27017/' + config.database.name );
var jobs = monq.queue( config.database.name );

/**/jobs.enqueue('artist:update', { id: '52166226a1d626d547000338' } , function(err, job) {
/*/jobs.enqueue('test', { id: '5390073d1559212f560012b4' } , function(err, job) {/**/
console.log('enqueued: ' , job );
process.exit();
});
15 changes: 12 additions & 3 deletions config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
module.exports = {
app: {
safe: process.env.SOUNDTRACK_APP_SAFE || false
name: 'soundtrack'
, safe: process.env.SOUNDTRACK_APP_SAFE || false
, host: process.env.SOUNDTRACK_APP_HOST || 'soundtrack.io'
, port: process.env.SOUNDTRACK_APP_PORT || 13000
},
database: {
name: process.env.SOUNDTRACK_DB_NAME || 'soundtrack'
, host: 'localhost'
, hosts: ['localhost']
},
redis: {
host: process.env.SOUNDTRACK_REDIS_HOST || 'localhost'
, port: process.env.SOUNDTRACK_REDIS_PORT || 6379
},
sessions: {
key: 'put yourself a fancy little key here'
Expand All @@ -22,5 +27,9 @@ module.exports = {
soundcloud: {
id: process.env.SOUNDTRACK_SOUNDCLOUD_ID || 'id here'
, secret: process.env.SOUNDTRACK_SOUNDCLOUD_SECRET || 'secret here'
},
spotify: {
id: process.env.SOUNDTRACK_SPOTIFY_ID || 'id here',
secret: process.env.SOUNDTRACK_SPOTIFY_SECRET || 'secret here'
}
}
}
194 changes: 174 additions & 20 deletions controllers/artists.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,192 @@
var rest = require('restler')
, _ = require('underscore');
, _ = require('underscore')
, async = require('async');

module.exports = {
list: function(req, res, next) {
Artist.find({}).sort('name').exec(function(err, artists) {
res.render('artists', {
artists: artists
var limit = (req.param('limit')) ? req.param('limit') : 100;
var query = (req.param('q')) ? { name: new RegExp('(.*)'+req.param('q')+'(.*)', 'i') } : undefined;

async.parallel([
function(done) {
Artist.count().exec( done );
},
function(done) {
Artist.find( query ).sort('name').limit( limit ).exec( function(err, artists) {
async.map( artists , function(x, countComplete) {
Track.count({ $or: [
{ _artist: x._id }
, { _credits: x._id }
] }).exec( function(err, trackCount) {
x = x.toObject();
x.tracks = trackCount;
countComplete( err, x );
});
}, done );
});
}
], function(err, results) {
res.format({
json: function() {
res.send( results[1].map(function(x) {
if (typeof(x.toObject) == 'function') {
x = x.toObject();
}
//x.value = x._id;
x.value = x.name;
return x;
}) );
},
html: function() {
res.render('artists', {
count: results[0]
, limit: limit
, artists: results[1]
});
}
});
});
},
view: function(req, res, next) {
delete: function(req, res, next) {
Artist.findOne({ slug: req.param('artistSlug') }).exec(function(err, artist) {
if (!artist) { return next(); }

Track.find({ $or: [
{ _artist: artist._id }
, { _credits: artist._id }
] }).exec(function(err, tracks) {

res.send(tracks.length);

});

});
},
edit: function(req, res, next) {
Artist.findOne({ $or: [
{ _id: req.param('artistID') }
, { slug: req.param('artistSlug') }
, { slugs: req.param('artistSlug') }
] }).sort('_id').exec(function(err, artist) {
if (!artist) { return next(); }

artist.name = req.param('name') || artist.name;
artist.bio = req.param('bio') || artist.bio;

// reset updated field, for re-crawl
artist.tracking.tracks.updated = undefined;

Artist.find({ $or: [
{ _id: req.param('artistID') }
, { slug: req.param('artistSlug') }
, { slugs: req.param('artistSlug') }
] }).exec(function(err, artists) {

var allArtistIDs = artists.map(function(x) { return x._id; });

artists.forEach(function(a) {
artist.slugs = _.union( artist.slugs , a.slugs );
});
artist.slugs = _.uniq( artist.slugs );

async.parallel([
function(done) {
Track.update({ _artist: { $in: allArtistIDs } }, {
_artist: artist._id.toString()
}, { multi: true }, done );
},
function(done) {
Track.update({ '_credits.$': { $in: allArtistIDs } }, {
$addToSet: { _credits: artist._id }
}, { multi: true }, done );
}
], function(err, results) {
if (err) { console.log(err); }

artist.save(function(err) {
if (err) { console.log(err); }

res.format({
json: function() {
res.send({
status: 'success'
, message: 'artist edited successfully'
});
},
html: function() {
res.redirect('/' + artist.slug );
}
});
});
});
});
});
},
view: function(req, res, next) {
Person.count({ slug: req.param('artistSlug') }).exec(function(err, num) {
if (num) return next();

var limit = (req.param('limit')) ? req.param('limit') : 100;

Track.find({ _artist: artist._id }).exec(function(err, tracks) {
Artist.findOne({ $or: [
{ slug: req.param('artistSlug') }
, { slugs: req.param('artistSlug') }
] }).exec(function(err, artist) {
if (!artist) { return next(); }

// handle artist renames
if (req.param('artistSlug') !== artist.slug) {
return res.redirect('/' + artist.slug);
}

Play.aggregate([
{ $match: { _track: { $in: tracks.map(function(x) { return x._id; }) } } },
{ $group: { _id: '$_track', count: { $sum: 1 } } },
{ $sort: { 'count': -1 } }
], function(err, trackScores) {
Track.find({ $or: [
{ _artist: artist._id }
, { _credits: artist._id }
] }).populate('_artist').exec(function(err, tracks) {

res.render('artist', {
artist: artist
, tracks: tracks.map(function(track) {
var plays = _.find( trackScores , function(x) { return x._id.toString() == track._id.toString() } );
track.plays = (plays) ? plays.count : 0;
return track;
})
Play.aggregate([
{ $match: { _track: { $in: tracks.map(function(x) { return x._id; }) } } },
{ $group: { _id: '$_track', count: { $sum: 1 } } },
{ $sort: { 'count': -1 } }
], function(err, trackScores) {

tracks = tracks.map(function(track) {
var plays = _.find( trackScores , function(x) { return x._id.toString() == track._id.toString() } );
track.plays = (plays) ? plays.count : 0;
return track;
}).sort(function(a, b) {
return b.plays - a.plays;
});

var trackCount = tracks.length;

tracks = tracks.slice( 0 , limit - 1 );

res.format({
json: function() {
res.send( artist );
},
html: function() {
res.render('artist', {
artist: artist
, tracks: tracks
, trackCount: trackCount
});
}
});
});

});
if (req.app.config.jobs && req.app.config.jobs.enabled) {
req.app.agency.publish('artist:update', {
id: artist._id
, timeout: 3 * 60 * 1000
}, function(err, job) {
console.log('update artist completed');
});
}

});
});
});
}
}
}
16 changes: 12 additions & 4 deletions controllers/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@ var async = require('async');

module.exports = {
view: function(req, res, next) {
Chat.find({}).sort('timestamp').populate('_author').limit(20).exec(function(err, chats) {
res.render('chats', {
chats: chats
var limit = (req.param('limit')) ? req.param('limit') : 100;

Chat.find({
_room: req.roomObj._id
}).sort('-_id').populate('_author _track _play').limit( limit ).exec(function(err, chats) {
Artist.populate( chats , {
path: '_track._artist'
}, function(err, chats) {
res.render('chats', {
chats: chats
});
});
});
},
Expand Down Expand Up @@ -37,4 +45,4 @@ module.exports = {
});
});
}
}
}
Loading

0 comments on commit 29d439c

Please sign in to comment.