jxl-muq 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.
- 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
|
+
|