jxl-muq 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +27 -0
- data/bin/muq +201 -0
- data/lib/muq.rb +265 -0
- data/muq.gemspec +15 -0
- metadata +91 -0
data/README.markdown
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Muq, a Muxtape CLI
|
2
|
+
Basic command line interface for <http://muxtape.com>.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
See `muq up -h` and `muq dn -h` for details.
|
6
|
+
|
7
|
+
Muxtape's limits are 12 songs per tape and 10MB per song.
|
8
|
+
|
9
|
+
### Upload examples
|
10
|
+
`muq up favorite.mp3 --user=bob --pass=bob --email=bob@example.com`
|
11
|
+
Create a new account for Bob and upload his favorite tune.
|
12
|
+
|
13
|
+
`muq up -u=larry -p=kensentme`
|
14
|
+
Upload every mp3 in the current directory to Larry's existing account.
|
15
|
+
|
16
|
+
`muq up some.mp3,another.mp3 -u=larry -p=kensentme --banner="Larry's Tape" --caption="Wooo" --color=ffdddd`
|
17
|
+
Upload mp3s and set banner, caption and color.
|
18
|
+
|
19
|
+
### Download examples
|
20
|
+
`muq dn hiphop` or `mux dn http://hiphop.muxtape.com/`
|
21
|
+
Download a single tape.
|
22
|
+
|
23
|
+
`muq dn hip,hop,rap,rnb`
|
24
|
+
Download multiple tapes.
|
25
|
+
|
26
|
+
## Bugs?
|
27
|
+
Fork and fix, thanks!
|
data/bin/muq
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.dirname(__FILE__) + '/../lib/muq'
|
3
|
+
require 'main'
|
4
|
+
|
5
|
+
Main do
|
6
|
+
mixin :login do
|
7
|
+
option('user', 'u') do
|
8
|
+
description 'Login (and subdomain) name.'
|
9
|
+
argument :required
|
10
|
+
required
|
11
|
+
end
|
12
|
+
|
13
|
+
option('pass', 'p') do
|
14
|
+
description 'Pwnage.'
|
15
|
+
argument :required
|
16
|
+
required
|
17
|
+
end
|
18
|
+
|
19
|
+
option('email', 'e') do
|
20
|
+
description 'Email address used to register a new account.'
|
21
|
+
argument :required
|
22
|
+
end
|
23
|
+
|
24
|
+
#option('random', 'r') do
|
25
|
+
# description 'Generate random user/pass/email if absent.'
|
26
|
+
#end
|
27
|
+
end
|
28
|
+
|
29
|
+
mixin :settings do
|
30
|
+
option('banner') do
|
31
|
+
description 'Title.'
|
32
|
+
argument :required
|
33
|
+
end
|
34
|
+
|
35
|
+
option('caption') do
|
36
|
+
description 'Subtitle.'
|
37
|
+
argument :required
|
38
|
+
end
|
39
|
+
|
40
|
+
option('color') do
|
41
|
+
description 'Color. (hex value without # prefix)'
|
42
|
+
argument :required
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
mixin :upload do
|
47
|
+
argument('mp3s') do
|
48
|
+
description 'Comma separated list of MP3s or directories to upload.'
|
49
|
+
cast :list_of_string
|
50
|
+
default "."
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
mixin :download do
|
55
|
+
argument('tapes') do
|
56
|
+
description 'Comma separated list of tape(s) to download.'
|
57
|
+
argument :required
|
58
|
+
cast :list_of_string
|
59
|
+
end
|
60
|
+
|
61
|
+
option('tracks') do
|
62
|
+
description 'Command separated list of track(s) to download.'
|
63
|
+
argument :required
|
64
|
+
cast :list_of_integer
|
65
|
+
end
|
66
|
+
|
67
|
+
argument('dir') do
|
68
|
+
description 'Base directory. A subdirectory is created for every tape.'
|
69
|
+
validate{|dir| File.directory?(dir)}
|
70
|
+
default "."
|
71
|
+
optional
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
mode :up do
|
76
|
+
mixin :login
|
77
|
+
mixin :settings
|
78
|
+
mixin :upload
|
79
|
+
end
|
80
|
+
|
81
|
+
mode :dn do
|
82
|
+
mixin :download
|
83
|
+
end
|
84
|
+
|
85
|
+
def run
|
86
|
+
params.each {|p| instance_variable_set("@#{p.name}", p.value)}
|
87
|
+
|
88
|
+
m = Muq.new
|
89
|
+
|
90
|
+
if @mode == "dn"
|
91
|
+
@tapes.each do |tape|
|
92
|
+
user = tape.scan(/(\w+)\.muxtape\.com/)
|
93
|
+
user = tape.scan(/\w+/) if user.empty?
|
94
|
+
puts "Downloading #{user}'s tape..."
|
95
|
+
FileUtils.mkdir_p("#{@dir}/#{user}")
|
96
|
+
songs = m.songs(user)
|
97
|
+
get = []
|
98
|
+
if @tracks
|
99
|
+
@tracks.each do |track|
|
100
|
+
get << songs[track-1]
|
101
|
+
end
|
102
|
+
else
|
103
|
+
get = songs
|
104
|
+
end
|
105
|
+
total = get.size
|
106
|
+
count = 1
|
107
|
+
get.each do |song|
|
108
|
+
puts "[#{count}/#{total}] #{song[:name]}"
|
109
|
+
m.download(song[:url], "#{@dir}/#{user}/#{song[:file]}")
|
110
|
+
count += 1
|
111
|
+
end
|
112
|
+
end
|
113
|
+
exit
|
114
|
+
end
|
115
|
+
|
116
|
+
#if @random
|
117
|
+
# @user ||= m.rnd_user
|
118
|
+
# @pass ||= m.rnd_pass
|
119
|
+
# @email ||= m.rnd_email
|
120
|
+
#end
|
121
|
+
|
122
|
+
if @mp3s
|
123
|
+
q = []
|
124
|
+
@mp3s.each do |mp3s|
|
125
|
+
if File.directory?(mp3s)
|
126
|
+
q += m.find_mp3s(mp3s)
|
127
|
+
elsif File.file?(mp3s)
|
128
|
+
q += mp3s.to_a
|
129
|
+
end
|
130
|
+
q = m.remove_dupes(q, @user)
|
131
|
+
begin
|
132
|
+
m.check_queue(q)
|
133
|
+
rescue Muq::TooManyFiles, Muq::FileTooLarge => e
|
134
|
+
puts e.to_s
|
135
|
+
exit 1
|
136
|
+
end
|
137
|
+
end
|
138
|
+
puts "Valid upload queue."
|
139
|
+
q_valid = true
|
140
|
+
end
|
141
|
+
|
142
|
+
if @user && @pass then
|
143
|
+
begin
|
144
|
+
m.login(@user, @pass)
|
145
|
+
puts "Valid login."
|
146
|
+
rescue Muq::InvalidLogin => e
|
147
|
+
puts e.to_s
|
148
|
+
if @email
|
149
|
+
puts "Trying to create account."
|
150
|
+
begin
|
151
|
+
m.register( @user, @pass, @email )
|
152
|
+
rescue Muq::NameTooLong, Muq::NameInUse, Muq::EmailInUse => e
|
153
|
+
puts e.to_s
|
154
|
+
m.logout
|
155
|
+
end
|
156
|
+
puts "Account '#{@user}' created with password '#{@pass}'."
|
157
|
+
m.set_color(m.rnd_color)
|
158
|
+
m.add_favorite('jxl') # nice index under 'favorited' ;)
|
159
|
+
else
|
160
|
+
puts "Can't create account without email."
|
161
|
+
m.logout
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
if @banner
|
166
|
+
m.set_banner(@banner)
|
167
|
+
puts "Banner set to '#{@banner}'"
|
168
|
+
end
|
169
|
+
|
170
|
+
if @caption
|
171
|
+
m.set_caption(@caption)
|
172
|
+
puts "Caption set to '#{@caption}'"
|
173
|
+
end
|
174
|
+
|
175
|
+
if @color
|
176
|
+
m.set_color(@color)
|
177
|
+
puts "Color set to '#{@color}'"
|
178
|
+
end
|
179
|
+
|
180
|
+
if q_valid
|
181
|
+
begin
|
182
|
+
total = q.size
|
183
|
+
count = 1
|
184
|
+
q.each do |file|
|
185
|
+
name = File.basename(file)
|
186
|
+
puts "[#{count}/#{total}] #{name}"
|
187
|
+
m.upload(file)
|
188
|
+
count += 1
|
189
|
+
end
|
190
|
+
rescue Muq::LimitReached, Muq::InvalidUpload => e
|
191
|
+
puts e.to_s
|
192
|
+
m.logout
|
193
|
+
end
|
194
|
+
puts "Done! (URL: http://#{@user}.#{m.host}/ PW: #{@pass})"
|
195
|
+
end
|
196
|
+
m.logout(:win)
|
197
|
+
else
|
198
|
+
help!
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
data/lib/muq.rb
ADDED
@@ -0,0 +1,265 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'tmpdir'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'rubygems'
|
8
|
+
rescue LoadError
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'curb'
|
12
|
+
require 'hpricot'
|
13
|
+
require 'id3lib'
|
14
|
+
|
15
|
+
class Muq
|
16
|
+
attr_accessor :c, :host
|
17
|
+
|
18
|
+
# the curb
|
19
|
+
def initialize()
|
20
|
+
@host = "muxtape.com"
|
21
|
+
@c = Curl::Easy.new do |c|
|
22
|
+
c.headers["User-Agent"] = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.14) Gecko/20080404 Iceweasel/2.0.0.14 (Debian-2.0.0.14-1)"
|
23
|
+
c.cookiejar = "#{Dir.tmpdir}/cookies.muq"
|
24
|
+
c.enable_cookies = true
|
25
|
+
c.verbose = false
|
26
|
+
end
|
27
|
+
@c
|
28
|
+
end
|
29
|
+
|
30
|
+
# create a new account
|
31
|
+
def register(user, pass, email)
|
32
|
+
raise NameTooLong, "Name too long." unless user.length < 32
|
33
|
+
post("#{@host}/create", {:name => user, :pass => pass, :email => email})
|
34
|
+
raise NameInUse, "Name in use." unless name_available?
|
35
|
+
raise EmailInUse, "Email in use." unless email_available?
|
36
|
+
end
|
37
|
+
|
38
|
+
# use existing account
|
39
|
+
def login(user, pass)
|
40
|
+
post("#{@host}/login", {:name => user, :pass => pass})
|
41
|
+
raise InvalidLogin, "Invalid login." unless valid_login?
|
42
|
+
end
|
43
|
+
|
44
|
+
# quit
|
45
|
+
def logout(win=false)
|
46
|
+
get("#{@host}/logout")
|
47
|
+
File.delete("#{Dir.tmpdir}/cookies.muq")
|
48
|
+
exit 1 unless win
|
49
|
+
exit 0
|
50
|
+
end
|
51
|
+
|
52
|
+
# find mp3s and sort in reverse order
|
53
|
+
# (the last uploaded file is displayed first on site)
|
54
|
+
def find_mp3s(dir)
|
55
|
+
Dir.glob("#{dir}/*.mp3").sort.reverse
|
56
|
+
end
|
57
|
+
|
58
|
+
# check if the queue is within the limits
|
59
|
+
def check_queue(queue)
|
60
|
+
amount = queue.size
|
61
|
+
raise TooManyFiles, "Too many files. (#{amount})" unless amount < 12
|
62
|
+
queue.each do |file|
|
63
|
+
raise FileTooLarge, "#{File.basename(file)} is too large." unless filesize_ok?(file)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# remove already uploaded mp3s from the queue
|
68
|
+
def remove_dupes(queue, user)
|
69
|
+
songs = just_songs(user)
|
70
|
+
new_queue = []
|
71
|
+
queue.each do |file|
|
72
|
+
tags = ID3Lib::Tag.new(file)
|
73
|
+
artist = tags.artist
|
74
|
+
title = tags.title
|
75
|
+
new_queue << file unless songs.include?("#{artist} - #{title}")
|
76
|
+
end
|
77
|
+
new_queue
|
78
|
+
end
|
79
|
+
|
80
|
+
# build an array of songs for the specified user
|
81
|
+
def just_songs(user)
|
82
|
+
doc = Hpricot(get("#{user}.#{@host}"))
|
83
|
+
out = []
|
84
|
+
doc.search("//li[@class='song']/div[@class='name']").each do |song|
|
85
|
+
out << song.inner_text.strip
|
86
|
+
end
|
87
|
+
out
|
88
|
+
end
|
89
|
+
|
90
|
+
# build an array of songs for the specified user
|
91
|
+
# (including download url and filename)
|
92
|
+
def songs(user)
|
93
|
+
doc = Hpricot(get("#{user}.#{@host}"))
|
94
|
+
scripts = doc.search("//script[@type='text/javascript']").inner_text
|
95
|
+
kettle = scripts.match(/new Kettle\((.*)\)/)[1]
|
96
|
+
split = kettle.scan(/\[.+?\]/)
|
97
|
+
hex = eval("Array.new(#{split[0]})")
|
98
|
+
sig = eval("Array.new(#{split[1]})")
|
99
|
+
out = []
|
100
|
+
if hex.size == sig.size
|
101
|
+
total = hex.size
|
102
|
+
total.times do |i|
|
103
|
+
name = doc.search("//li[@id='song#{hex[i]}']/div[@class='name']").inner_text.strip
|
104
|
+
url = "http://muxtape.s3.amazonaws.com/songs/"
|
105
|
+
url += "#{hex[i]}?PLEASE=DO_NOT_STEAL_MUSIC&#{sig[i]}" # rly sry lulz
|
106
|
+
out << {:name => name, :file => filename(name, i+1), :url => url}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
out
|
110
|
+
end
|
111
|
+
|
112
|
+
# file upload
|
113
|
+
def upload(file)
|
114
|
+
@c.url = "#{@host}/upload"
|
115
|
+
raise LimitReached, "Song limit reached." unless room_left?
|
116
|
+
@c.multipart_form_post = true
|
117
|
+
@c.http_post(Curl::PostField.file('file', file))
|
118
|
+
@c.multipart_form_post = false
|
119
|
+
raise InvalidUpload, "Can't handle encoding." unless valid_upload?
|
120
|
+
end
|
121
|
+
|
122
|
+
# file download
|
123
|
+
def download(url, file)
|
124
|
+
Curl::Easy.download(url, file)
|
125
|
+
end
|
126
|
+
|
127
|
+
# set the banner/title
|
128
|
+
def set_banner(banner="")
|
129
|
+
set(:command => "bannercaption", :args => "none", :banner => banner)
|
130
|
+
end
|
131
|
+
|
132
|
+
# set the caption/sub-title
|
133
|
+
def set_caption(caption="")
|
134
|
+
set(:command => "bannercaption", :args => "none", :caption => caption)
|
135
|
+
end
|
136
|
+
|
137
|
+
# set the header color (hex value without # prefix)
|
138
|
+
def set_color(color="")
|
139
|
+
set(:command => "color", :args => color)
|
140
|
+
end
|
141
|
+
|
142
|
+
# change the password
|
143
|
+
def set_pass(pass)
|
144
|
+
set(:command => "password", :args => %Q{{"password1":"#{pass}","password2":"#{pass}"}} )
|
145
|
+
end
|
146
|
+
|
147
|
+
# add a user to favorites
|
148
|
+
def add_favorite(user)
|
149
|
+
set(:command => "favorite", :args => user)
|
150
|
+
end
|
151
|
+
|
152
|
+
# remove a user from favorites
|
153
|
+
def rm_favorite(user)
|
154
|
+
set(:command => "unfavorite", :args => user)
|
155
|
+
end
|
156
|
+
|
157
|
+
# random values
|
158
|
+
def rnd_user
|
159
|
+
rnd_string(rnd_size, false)
|
160
|
+
end
|
161
|
+
|
162
|
+
def rnd_pass
|
163
|
+
rnd_string
|
164
|
+
end
|
165
|
+
|
166
|
+
def rnd_email
|
167
|
+
"#{rnd_string}@#{rnd_string}.#{rnd_string(rnd_size(2,4), false)}"
|
168
|
+
end
|
169
|
+
|
170
|
+
def rnd_color
|
171
|
+
"#{rnd_string(6, true, "a", "f")}"
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
# http get
|
176
|
+
def get(url)
|
177
|
+
@c.url = url
|
178
|
+
@c.http_get
|
179
|
+
@c.body_str
|
180
|
+
end
|
181
|
+
|
182
|
+
# http post
|
183
|
+
def post(url, hash)
|
184
|
+
@c.url = url
|
185
|
+
fields = []
|
186
|
+
hash.each_pair do |key, value|
|
187
|
+
fields << Curl::PostField.content(key.to_s, value).to_s
|
188
|
+
end
|
189
|
+
@c.http_post(url, fields)
|
190
|
+
end
|
191
|
+
|
192
|
+
# change a setting
|
193
|
+
def set(hash)
|
194
|
+
post("#{@host}/settings/ajax", hash)
|
195
|
+
end
|
196
|
+
|
197
|
+
# grep body
|
198
|
+
def cant_find(regex)
|
199
|
+
@c.body_str.grep(regex).empty?
|
200
|
+
end
|
201
|
+
|
202
|
+
# errors checks
|
203
|
+
def filesize_ok?(file)
|
204
|
+
File.size(file) < (10 * 1024 * 1024)
|
205
|
+
end
|
206
|
+
|
207
|
+
def email_available?
|
208
|
+
cant_find(/already a user with that email address/)
|
209
|
+
end
|
210
|
+
|
211
|
+
def name_available?
|
212
|
+
cant_find(/that name is unavailable/)
|
213
|
+
end
|
214
|
+
|
215
|
+
def valid_login?
|
216
|
+
cant_find(/Invalid name or password\./)
|
217
|
+
end
|
218
|
+
|
219
|
+
def logged_in?
|
220
|
+
cant_find(/You must be \<a href=\"\/login\"\>logged in\<\/a\>/)
|
221
|
+
end
|
222
|
+
|
223
|
+
def room_left?
|
224
|
+
cant_find(/reached your limit of 12 songs/)
|
225
|
+
end
|
226
|
+
|
227
|
+
def valid_upload?
|
228
|
+
cant_find(/Try it one more time, if it fails again/)
|
229
|
+
end
|
230
|
+
|
231
|
+
# random-fu
|
232
|
+
def rnd_size(from=1, to=10)
|
233
|
+
(from + rand * to).floor
|
234
|
+
end
|
235
|
+
|
236
|
+
def rnd_string(size=rnd_size, num=true, from="a", to="z")
|
237
|
+
chars = (from..to).to_a
|
238
|
+
chars += ('0'..'9').to_a unless num == false
|
239
|
+
(1..size).collect{|a| chars[rand(chars.size)] }.join
|
240
|
+
end
|
241
|
+
|
242
|
+
# funky filename
|
243
|
+
def filename(name, nr)
|
244
|
+
file = name.downcase
|
245
|
+
file = file.gsub(" - ", "-")
|
246
|
+
file = file.gsub("/", "")
|
247
|
+
file = file.gsub(".", "")
|
248
|
+
file = file.gsub(",", "")
|
249
|
+
file = file.gsub(" ", " ")
|
250
|
+
file = file.gsub(" ", "_")
|
251
|
+
file = "#{"%02.0f" % nr}-#{file}-muq.mp3"
|
252
|
+
end
|
253
|
+
|
254
|
+
# you FAIL
|
255
|
+
class FAIL < RuntimeError; end
|
256
|
+
class InvalidLogin < FAIL; end
|
257
|
+
class NotLoggedIn < FAIL; end
|
258
|
+
class NameTooLong < FAIL; end
|
259
|
+
class NameInUse < FAIL; end
|
260
|
+
class EmailInUse < FAIL; end
|
261
|
+
class TooManyFiles < FAIL; end
|
262
|
+
class FileTooLarge < FAIL; end
|
263
|
+
class InvalidUpload < FAIL; end
|
264
|
+
class LimitReached < FAIL; end
|
265
|
+
end
|
data/muq.gemspec
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "muq"
|
3
|
+
s.version = "0.0.1"
|
4
|
+
s.summary = "Muxtape.com CLI"
|
5
|
+
s.description = "Command line interface for Muxtape."
|
6
|
+
s.author = "Ron Damen"
|
7
|
+
s.email = "jxl@ganja.nl"
|
8
|
+
s.homepage = "http://github.com/jxl/muq/"
|
9
|
+
s.files = ["README.markdown", "muq.gemspec", "bin/muq", "lib/muq.rb"]
|
10
|
+
s.executables = "muq"
|
11
|
+
s.add_dependency("main", ["> 0.0.0"])
|
12
|
+
s.add_dependency("curb", ["> 0.0.0"])
|
13
|
+
s.add_dependency("hpricot", ["> 0.0.0"])
|
14
|
+
s.add_dependency("id3lib-ruby", ["> 0.0.0"])
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jxl-muq
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ron Damen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-04-26 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: main
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.0.0
|
23
|
+
version:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: curb
|
26
|
+
version_requirement:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ">"
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 0.0.0
|
32
|
+
version:
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: hpricot
|
35
|
+
version_requirement:
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.0.0
|
41
|
+
version:
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: id3lib-ruby
|
44
|
+
version_requirement:
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 0.0.0
|
50
|
+
version:
|
51
|
+
description: Command line interface for Muxtape.
|
52
|
+
email: jxl@ganja.nl
|
53
|
+
executables:
|
54
|
+
- muq
|
55
|
+
extensions: []
|
56
|
+
|
57
|
+
extra_rdoc_files: []
|
58
|
+
|
59
|
+
files:
|
60
|
+
- README.markdown
|
61
|
+
- muq.gemspec
|
62
|
+
- bin/muq
|
63
|
+
- lib/muq.rb
|
64
|
+
has_rdoc: false
|
65
|
+
homepage: http://github.com/jxl/muq/
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
version:
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.0.1
|
87
|
+
signing_key:
|
88
|
+
specification_version: 2
|
89
|
+
summary: Muxtape.com CLI
|
90
|
+
test_files: []
|
91
|
+
|