the_little_streamer 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/README.md +25 -0
  2. data/bin/the_little_streamer +218 -0
  3. metadata +97 -0
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # The Little Streamer
2
+
3
+ Extremely simple music streamer using Sinatra.
4
+
5
+ ## Install
6
+
7
+ gem install the_little_streamer
8
+
9
+ ## Use
10
+
11
+ the_little_streamer /path/to/music
12
+
13
+ Browse to http://localhost:4567
14
+
15
+ ## Dependencies
16
+
17
+ * [Sinatra](http://www.sinatrarb.com/)
18
+ * [ruby-taglib2](https://github.com/rumblehq/ruby-taglib2)
19
+ * A browser that supports HTML5, like [Chrome](http://www.google.com/chrome/)
20
+
21
+ You may also want to use [Mongrel](https://github.com/fauna/mongrel) instead of WEBrick, as it will be way faster. Just install it and Sinatra will prefer it over WEBrick.
22
+
23
+ ## License
24
+
25
+ [MIT](http://www.opensource.org/licenses/mit-license.php)
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env ruby
2
+ #This is a simple Sinatra application to play mp3/ogg files through a browser
3
+ #using the HTML5 audio tag
4
+
5
+ require 'rubygems'
6
+ require 'taglib2'
7
+ require 'sinatra'
8
+ require 'cgi'
9
+ require 'pathname'
10
+
11
+ #Supply a directory with all the music in it
12
+ abort "Point me to the music!" unless ARGV[0]
13
+
14
+ #Wrap up in HTML
15
+ def html body
16
+ <<-HTML
17
+ <html>
18
+ <body>
19
+ #{body}
20
+ </body>
21
+ </html>
22
+ HTML
23
+ end
24
+
25
+ #Create a link
26
+ def link root, path, text = path
27
+ "<a href='#{root}#{CGI.escape path}'>#{text}</a>"
28
+ end
29
+
30
+ #Audio tag
31
+ def audio path
32
+ <<-HTML
33
+ <audio id='player' onEnded='javascript:play_next()' src=#{("/" << CGI.escapeHTML(path)).inspect} autobuffer controls autoplay >
34
+ You need the power of HTML5!
35
+ </audio>
36
+ <script type="text/javascript">
37
+ document.getElementById('player').volume = 0.3;
38
+ </script>
39
+ HTML
40
+ end
41
+
42
+ #Javascript for playlist
43
+ def playlist songs
44
+ <<-JAVASCRIPT
45
+ <script type="text/javascript">
46
+ var player = document.getElementById('player');
47
+ var artist = document.getElementById('artist');
48
+ var album = document.getElementById('album');
49
+ var title = document.getElementById('song_title');
50
+ var playlist = [#{songs.map { |s| song_to_js s }.join "," }]
51
+ var current_song = 0;
52
+
53
+ play_next = function(reverse) {
54
+ if(reverse && current_song > 0)
55
+ current_song--;
56
+ else if(!reverse && current_song < playlist.length)
57
+ current_song++;
58
+ else
59
+ return;
60
+
61
+ var song = playlist[current_song];
62
+ player.src = song.path;
63
+ artist.innerHTML = song.artist
64
+ album.innerHTML = song.album
65
+ title.innerHTML = song.title
66
+ player.play();
67
+ }
68
+ </script>
69
+ JAVASCRIPT
70
+ end
71
+
72
+ #Javascript for a song
73
+ def song_to_js song
74
+ <<-JAVASCRIPT
75
+ { artist: #{song.artist.inspect},
76
+ album: #{song.album.inspect},
77
+ title: #{song.title.inspect},
78
+ path: #{(CGI.escapeHTML "/" << song.path).inspect} }
79
+ JAVASCRIPT
80
+ end
81
+
82
+ #Back/forward links
83
+ def prev_and_next
84
+ "<a href='javascript:play_next(true)'>Prev</a>&nbsp;&nbsp;&nbsp;<a href='javascript:play_next()'>Next</a>"
85
+ end
86
+
87
+ #HTML for playing all songs by artist
88
+ def play_artist artist
89
+ songs = []
90
+
91
+ Music[artist].each_value do |album|
92
+ album.values.sort_by { |s| s.track }.each do |song|
93
+ songs << song
94
+ end
95
+ end
96
+
97
+ html <<-HTML
98
+ #{song_info songs.first}<br/>
99
+ #{audio songs.first.path}<br/>
100
+ #{prev_and_next}
101
+ #{playlist songs}
102
+ HTML
103
+ end
104
+
105
+ #HTML for playing all songs on an album
106
+ def play_album artist, album
107
+ songs = Music[artist][album].values.sort_by { |s| s.track }
108
+
109
+ html <<-HTML
110
+ #{song_info songs.first}<br/>
111
+ #{audio songs.first.path}<br/>
112
+ #{prev_and_next}
113
+ #{playlist songs}
114
+ HTML
115
+ end
116
+
117
+ #HTML for song information header
118
+ def song_info song
119
+ "\"<span id='song_title'>#{song.title}</span>\" by <span id='artist'>#{song.artist}</span> (<span id='album'>#{song.album}</span>)"
120
+ end
121
+
122
+ #Storing all music information in here
123
+ Music = Hash.new do |h,k|
124
+ h[k] = Hash.new do |hash, key|
125
+ hash[key] = Hash.new
126
+ end
127
+ end
128
+
129
+ #Song information
130
+ Song = Struct.new :artist, :album, :title, :track, :path
131
+
132
+ #Used to figure out path to music files
133
+ root = Pathname.new ARGV[0]
134
+
135
+ #Make song files public
136
+ set :public, ARGV[0]
137
+
138
+ #Make sure Sinatra sings
139
+ set :run, true
140
+
141
+ #Grab information from all the song files
142
+ Dir.glob "#{ARGV[0]}/**/*.{mp3,ogg}" do |file|
143
+ begin
144
+ info = TagLib2::File.new(file)
145
+
146
+ artist, album, title, track = info.artist, info.album, info.title, info.track
147
+ artist ||= "Unknown"
148
+ album ||= "Unknown"
149
+ info = nil
150
+
151
+ if title
152
+ [artist, album, title].each { |i| i.tr!('/', '-') }
153
+ Music[artist][album][title] = Song.new(artist, album, title, track, Pathname.new(file).relative_path_from(root).to_s)
154
+ end
155
+ rescue Exception => e
156
+ $stderr.puts e if $DEBUG
157
+ end
158
+ end
159
+
160
+ GC.start #Clean up after TagLib2
161
+
162
+ #List artists
163
+ get '/' do
164
+ path = '/artist/'
165
+ html Music.keys.sort.map { |a| link path, a }.join "<br/>"
166
+ end
167
+
168
+ #List albums by given artist
169
+ get '/artist/:artist/?' do |artist|
170
+ unless Music[artist].empty?
171
+ path = "/artist/#{artist}/album/"
172
+ html Music[artist].keys.sort.map { |a| link path, a }.join("<br/>") << "<br/><br/>" <<
173
+ link("/artist/#{artist}/", "play", "Play All")
174
+ else
175
+ html "Could not find <b>#{artist}</b>."
176
+ end
177
+ end
178
+
179
+ #Play songs by given artist
180
+ get '/artist/:artist/play/?' do |artist|
181
+ unless Music[artist].empty?
182
+ play_artist artist
183
+ else
184
+ html "Could not find <b>#{artist}</b>."
185
+ end
186
+ end
187
+
188
+ #List songs on given album
189
+ get '/artist/:artist/album/:album/?' do |artist, album|
190
+ unless Music[artist][album].empty?
191
+ path = "/artist/#{artist}/album/#{album}/song/"
192
+ html Music[artist][album].values.sort_by { |s| s.track || 0}.map { |s| link path, s.title }.join("<br/>") << "<br/><br/>" <<
193
+ link("/artist/#{artist}/album/#{album}/", "play", "Play All")
194
+ else
195
+ html "Could not find <b>#{album}</b> for <b>#{artist}</b>."
196
+ end
197
+ end
198
+
199
+ #Play all songs from a given album
200
+ get '/artist/:artist/album/:album/play/?' do |artist, album|
201
+ if Music[artist][album]
202
+ play_album artist, album
203
+ else
204
+ html "Could not find <b>#{album}</b> by <b>#{artist}</b>."
205
+ end
206
+ end
207
+
208
+ #Play song!
209
+ get '/artist/:artist/album/:album/song/:song/?' do |artist, album, title|
210
+ if song = Music[artist][album][title]
211
+ html <<-HTML
212
+ #{song_info song}<br/>
213
+ #{audio song.path}
214
+ HTML
215
+ else
216
+ html "Could not find <b>#{title}</b> on <b>#{album}</b> by <b>#{artist}</b>."
217
+ end
218
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: the_little_streamer
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Justin Collins
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-14 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: sinatra
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 15
30
+ segments:
31
+ - 1
32
+ - 0
33
+ version: "1.0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: ruby-taglib2
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 11
45
+ segments:
46
+ - 1
47
+ - 2
48
+ version: "1.02"
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ description: Point the Little Streamer to your music directory and it will serve up the tunes using the HTML5 audio tag.
52
+ email:
53
+ executables:
54
+ - the_little_streamer
55
+ extensions: []
56
+
57
+ extra_rdoc_files: []
58
+
59
+ files:
60
+ - bin/the_little_streamer
61
+ - README.md
62
+ has_rdoc: true
63
+ homepage: http://github.com/presidentbeef/the_little_streamer
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options: []
68
+
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.4.1
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Sinatra application for streaming music.
96
+ test_files: []
97
+