dxmms2 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (8) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/Makefile +6 -0
  4. data/README.md +7 -0
  5. data/bin/dxmms2 +668 -0
  6. data/dxmms2.gemspec +23 -0
  7. data/dxmms2.png +0 -0
  8. metadata +123 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c0558d7e7c3d2afdfce8c3cda5a5d462b19fb1e2
4
+ data.tar.gz: 717ae54b84456c746f9486f3c5703776250c7ae1
5
+ SHA512:
6
+ metadata.gz: abe3d53027584aa876d6114c529e1820fa91d92e8499afed04cb143167f030ce8c94f1ea60a5cf550375a517d6a8419e0b45fe4bf0fc1896dce0c2e00797bef4
7
+ data.tar.gz: 54e52c04408e46a6da49a815ee1d819d53f4091759d418154dea49efb61725d3e75e0b2b7fb288a2a6fe30ce20782c81db33771b4da3f4c49ab7154289172638
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,6 @@
1
+
2
+ gem:: dxmms2.gemspec
3
+ gem build $<
4
+
5
+ install::
6
+ gem install --user dxmms2-*.gem
@@ -0,0 +1,7 @@
1
+ # dxmms2
2
+ *a dmenu shell for xmms2*
3
+
4
+ Setting the dmenu width in dxmms2 requires the patch provided in this repo. The
5
+ patch hasn't been tested--application may require manual effort.
6
+
7
+ ![dxmms2 screenie](dxmms2.png)
@@ -0,0 +1,668 @@
1
+ #!/usr/bin/env ruby
2
+ require 'dmenu'
3
+ require 'xmms2_utils'
4
+ require 'stringio'
5
+ require 'uri'
6
+ require 'socket'
7
+ require 'set'
8
+
9
+ begin
10
+ require 'glib2'
11
+ $GLIB=true
12
+ rescue
13
+ $GLIB=false
14
+ end
15
+
16
+ ##########################
17
+ # simple xmms2 script #
18
+ # for dmenu #
19
+ ##########################
20
+
21
+ $xc = Xmms::client("dxmms2")
22
+
23
+ $COMMAND_SIG = "@"
24
+ # default configs {{{
25
+ $SCREEN_WIDTH=Integer(ENV.fetch('DXMMS2_MENU_WIDTH', 600))
26
+ $FONT_WIDTH=Integer(ENV.fetch('DXMMS2_FONT_WIDTH', 13)) #in pixels)
27
+ $BG_COLOR=ENV.fetch('DMENU_BG_COLOR', '#000000')
28
+ $FG_COLOR=ENV.fetch('DMENU_FG_COLOR', '#dc322f')
29
+ $SEL_BG_COLOR=ENV.fetch('DMENU_SEL_BG_COLOR', $FG_COLOR)
30
+ $SEL_FG_COLOR=ENV.fetch('DMENU_SEL_FG_COLOR', $BG_COLOR)
31
+ if $GLIB
32
+ fallback = ENV.fetch('HOME', '/')
33
+ xdg_dir = GLib.get_user_special_dir(GLib::USER_DIRECTORY_MUSIC)
34
+ if !xdg_dir.nil?
35
+ fallback = xdg_dir
36
+ end
37
+ $MUSIC_DIRECTORY = ENV.fetch('DXMMS2_MUSIC_DIRECTORY', fallback)
38
+ end
39
+
40
+ $FONT = ENV.fetch('DMENU_FONT', 'Noto Sans Mono CJK JP Regular')
41
+ $FONT = $FONT + ':pixelsize=' + $FONT_WIDTH.to_s
42
+ $LIST_ENTRIES_PER_PAGE = 15
43
+ $LINE_HEIGHT=10
44
+ # }}}
45
+
46
+ #if [ -e $CONFIG ] ; then
47
+ #source $CONFIG
48
+ #fi
49
+ class Integer
50
+ def ms_to_time_string
51
+ minutes=(self / 60000)
52
+ seconds=(self % 60000) / 1000
53
+ "%d:%02d" % [minutes, seconds]
54
+ end
55
+ end
56
+
57
+ def time_string_to_ms(str)
58
+ res = 0
59
+ s = 1
60
+ for n in str.split(":").reverse do
61
+ s = 60 * s
62
+ res = res + s * (n.to_i)
63
+ end
64
+ return res.to_i
65
+ end
66
+
67
+ def my_dmenu (entries, prompt='dxmms2', height=entries.count, width=$SCREEN_WIDTH)
68
+ height = [height, 20].min
69
+ Dmenu::dmenu(entries, prompt, height, width,
70
+ $FG_COLOR,
71
+ $BG_COLOR,
72
+ $SEL_FG_COLOR,
73
+ $SEL_BG_COLOR,
74
+ $FONT,
75
+ $LINE_HEIGHT)
76
+ end
77
+
78
+ def playlists_prompt(&call_back)
79
+ playlists = $xc.playlist_list.wait.value
80
+ playlists = playlists.delete_if {|s| s.start_with?("_")}
81
+ selected = my_dmenu(playlists)
82
+ if !call_back.nil?
83
+ if !selected.empty?
84
+ call_back.call(selected)
85
+ end
86
+ end
87
+ selected
88
+ end
89
+
90
+ def pl_list(start=nil,nentries=nil,prompt="Track: ",plname=nil)
91
+ pl = plname.nil? ? $xc.playlist : $xc.playlist(plname)
92
+ entries = pl.entries.wait.value
93
+ current = pl.current_pos.wait.value
94
+ cur = current.nil? ? 0 : current[:position]
95
+ start = start.nil? ? cur : start
96
+ list_ids(entries,prompt,start,nentries)
97
+ end
98
+
99
+ def list_ids(entries, prompt, start=0, nentries=nil, commands=nil)
100
+ # XXX: Create a list object to pass to user-supplied commands
101
+ # list object allows for setting list start, page size, list content,
102
+ # whether to redisplay the list, and maybe other things
103
+ morestring,endstring,startstring,backstring =
104
+ %w[more end start back].map{|w| $COMMAND_SIG + w}
105
+ if commands.nil?
106
+ commands = Hash.new
107
+ end
108
+
109
+ c1 = Hash.new
110
+ commands.each do |k,v|
111
+ c1[$COMMAND_SIG + k] = v
112
+ end
113
+ listing=1
114
+ nentries = (nentries.nil? ? $LIST_ENTRIES_PER_PAGE : nentries)
115
+ pos = nil
116
+ list_start = start
117
+ while ( listing == 1 ) do
118
+ start_clamped = false
119
+ end_clamped = false
120
+ items = Array.new
121
+
122
+ #clamps start
123
+ (list_start <= 0) and (list_start = 0 ; start_clamped = true)
124
+
125
+ list_end = list_start + nentries
126
+
127
+ #clamps end
128
+ (list_end > entries.length) and (list_end = entries.length ; end_clamped = true)
129
+
130
+
131
+ nw = list_end.to_s.length
132
+ i = list_start
133
+
134
+ items += xmms2_ids_to_display_list_strings(entries[list_start..list_end]).map do |string|
135
+ string = "#{i.to_s.rjust(nw)}. #{string}"
136
+ i += 1
137
+ string
138
+ end
139
+
140
+ if not start_clamped
141
+ items << backstring
142
+ items << startstring
143
+ end
144
+
145
+ if not end_clamped
146
+ items << endstring
147
+ items << morestring
148
+ end
149
+
150
+ c1.keys.each do |d|
151
+ items << d
152
+ end
153
+
154
+ choice = my_dmenu(items, prompt, items.length).gsub(/^\s+|\s+$/, "")
155
+ pos = choice[/^-?\d+|#{$COMMAND_SIG}[a-zA-Z0-9\-_.]+/]
156
+
157
+ case pos
158
+ when backstring
159
+ list_start -= nentries
160
+ when morestring
161
+ list_start += nentries
162
+ when endstring
163
+ list_start = entries.length - nentries
164
+ when startstring
165
+ list_start = 0
166
+ when *(c1.keys)
167
+ f = c1[pos]
168
+ f.call(entries)
169
+ pos = nil
170
+ listing = 0
171
+ else
172
+ listing = 0
173
+ end
174
+ end
175
+
176
+ if pos.nil?
177
+ return nil
178
+ end
179
+
180
+ pos = pos.to_i
181
+ if pos < 0
182
+ entries.length + pos
183
+ else
184
+ pos
185
+ end
186
+ end
187
+
188
+ def xmms2_ids_to_display_list_strings(ids, fields=%w[artist title url duration])
189
+ ids.map do |id|
190
+ my_info = $xc.extract_medialib_info(id, *fields)
191
+ artist_part = my_info[:artist]
192
+ some_title = (my_info[:title] or File.basename(my_info[:url]))
193
+ duration = my_info[:duration].to_i.ms_to_time_string
194
+ "#{artist_part}|||#{some_title} [#{duration}]"
195
+ end
196
+ end
197
+
198
+ def get_usertags(id)
199
+ info = $xc.extract_medialib_info(id, :usertags)
200
+ if info.has_key?(:usertags)
201
+ info[:usertags].lines.to_a
202
+ else
203
+ []
204
+ end
205
+ end
206
+
207
+ def set_tags(id, tags)
208
+ $xc.medialib_entry_property_set(id, :usertags, tags.map{|x| x.chomp}.uniq.join("\n")).wait
209
+ end
210
+
211
+ def tag_track(id, tag)
212
+ tags = get_usertags(id) << tag.chomp
213
+ set_tags(id, tags)
214
+ end
215
+
216
+ def untag_track(id, tag)
217
+ tags = get_usertags(id).reject{|x|x==tag}
218
+ set_tags(id, tags)
219
+ end
220
+
221
+ def tag_menu(ids, previous_tags)
222
+ tag_file = File.join(Xmms::userconfdir, 'usertags')
223
+ all_tags = File.new(tag_file,File::CREAT).to_a
224
+
225
+ previous_tags = previous_tags.map{|x| x.chomp}
226
+
227
+ tag_list = previous_tags.map{|k| "!" + k} + all_tags
228
+ tag_list.map!{|x| x.chomp}
229
+
230
+ tag = my_dmenu(tag_list, "Add/delete a tag")
231
+ if (!tag.empty?)
232
+ Thread.new do
233
+ if (tag[0] == "!")
234
+ ids.each do |id|
235
+ untag_track(id, tag[1..-1])
236
+ end
237
+ else
238
+ ids.each do |id|
239
+ tag_track(id, tag)
240
+ end
241
+ end
242
+ end
243
+
244
+
245
+ if (tag[0] != "!")
246
+ all_tags << tag + "\n"
247
+ all_tags.uniq!
248
+ end
249
+ File.open(tag_file, "w") do |file|
250
+ all_tags.each do |t|
251
+ file.write(t)
252
+ end
253
+ end
254
+ tag
255
+ else
256
+ nil
257
+ end
258
+ end
259
+
260
+ def get_album_info(id, *fields)
261
+ get_collection_info(get_album_collection(id), *fields)
262
+ end
263
+
264
+ def get_collection_info(coll, *fields)
265
+ data = $xc.coll_query_info(coll, fields).wait.value
266
+ data.map do |infos|
267
+ res = Hash.new
268
+ fields = fields.map! {|f| f.to_sym }
269
+ fields.each do |field|
270
+ values = infos[field]
271
+ if not values.nil?
272
+ my_value = values
273
+ if field == :url
274
+ my_value = Xmms::decode_xmms2_url(my_value)
275
+ end
276
+ res[field] = my_value.to_s.force_encoding("utf-8")
277
+ end
278
+ end
279
+ res
280
+ end
281
+ end
282
+
283
+ def get_album_ids(id)
284
+ album_coll = get_album_collection(id)
285
+ $xc.coll_query_ids(album_coll).wait.value
286
+ end
287
+
288
+ def get_album_collection(id)
289
+ album_name = $xc.extract_medialib_info(id, :album)[:album]
290
+ match_collection('album', album_name)
291
+ end
292
+
293
+ def match_collection(field, pattern, base_coll=nil)
294
+ coll = Xmms::Collection.new(Xmms::Collection::TYPE_MATCH)
295
+ if !coll.nil?
296
+ coll.operands << base_coll
297
+ else
298
+ coll.operands << Xmms::Collection.universe
299
+ end
300
+ coll.attributes["field"] = field
301
+ coll.attributes["value"] = pattern
302
+ coll
303
+ end
304
+
305
+ # The idea of this is that if I like a song around the middle of the track, I think it's a
306
+ # really good song and it's probably new since I had to listen halfway through to decide
307
+ # I liked it. I also consider that there may be an over-eagerness in my reaction early in
308
+ # a track, so I penalize that. Lastly, for me, if I like the track near the end, I'm only
309
+ # sort-of listening to it or only like it enough to appreciate it as a whole, but can't
310
+ # say much for it in parts.
311
+ #
312
+ # This should only be used additively with past `likes'
313
+ def track_appreciation_factor(playtime, track_duration)
314
+ k = [0, [playtime, track_duration].min].max.to_f / track_duration - 0.5
315
+ l = 1.0 - k.abs
316
+ l
317
+ end
318
+
319
+ $commands=%w<toggle list +fav +fav-album
320
+ tag tag-album prev next stop repeat-playlist
321
+ info change-playlist remove-playlist show-playlist
322
+ clear edit-album-metadata edit-metadata remove shuffle search
323
+ repeat-track repeat-off shutdown seek add>
324
+
325
+
326
+ def current_pl
327
+ $xc.playlist
328
+ end
329
+
330
+ def play_new_track(xc, pos=false)
331
+ if pos
332
+ xc.playlist_set_next(pos).wait
333
+ end
334
+ xc.playback_tickle.wait
335
+ xc.playback_stop.wait
336
+ xc.playback_start.wait
337
+ end
338
+
339
+ def edit_metadata(urls)
340
+ prefix = "file://"
341
+ plen = prefix.length
342
+ urls = urls.select do |x|
343
+ x.start_with?(prefix)
344
+ end.map do |x|
345
+ x[plen..-1]
346
+ end
347
+ files = urls.map{|x|"\"#{x}\""}.join(" ")
348
+ `picard #{ files }`
349
+ end
350
+
351
+ while true do
352
+ command = my_dmenu($commands).chomp
353
+ case command
354
+ # NOTE: The *break statements* in here are for the *while loop*
355
+ # not for the switch
356
+ when "list"
357
+ pos = pl_list(nil, nil, "Play Track:")
358
+ if not pos.nil?
359
+ puts "moving to positon #{pos}"
360
+ play_new_track($xc, pos)
361
+ end
362
+ break
363
+ when "add"
364
+ d = Dir.new($MUSIC_DIRECTORY)
365
+ add_dir = $COMMAND_SIG + 'add-dir'
366
+ while !d.nil?
367
+ entries = d.entries.map do |x|
368
+ if Dir.exist?(File.join(d, x))
369
+ x + '/'
370
+ else
371
+ x
372
+ end
373
+ end
374
+ choice = my_dmenu(entries.sort << add_dir, "Add entries", d.entries.length)
375
+ path = File.join(d, choice)
376
+ if choice.empty?
377
+ d = nil
378
+ elsif choice == add_dir
379
+ begin
380
+ current_pl.radd("file://" + d.path).wait
381
+ ensure
382
+ d = nil
383
+ end
384
+ else
385
+ if Dir.exists?(path)
386
+ if choice != '.'
387
+ d = Dir.new(path)
388
+ end
389
+ elsif File.exists?(path)
390
+ begin
391
+ $stderr.puts "Adding " + path
392
+ current_pl.add_entry("file://"+path).wait
393
+ ensure
394
+ d = nil
395
+ end
396
+ else
397
+ begin
398
+ $stderr.puts "Got a result we couldn't handle: "+choice.to_s
399
+ ensure
400
+ d = nil
401
+ end
402
+ end
403
+ end
404
+ end
405
+ break
406
+ when "info"
407
+ entries = current_pl.entries.wait.value
408
+ if not entries.nil?
409
+ pos = pl_list(nil,nil,"Track Info:")
410
+ if pos.nil?
411
+ break
412
+ end
413
+ id = entries[pos]
414
+ info = $xc.extract_medialib_info(id, *%w<artist title album tracknr favorite timesplayed url date duration laststarted added usertags comment>)
415
+ info = Hash[info.map { |k,v|
416
+ k = k.to_s
417
+ if %w<duration>.include?(k)
418
+ v = [v.to_i.ms_to_time_string, v]
419
+ elsif %w<laststarted added lmod>.include?(k)
420
+ v = [Time.at(v.to_i).strftime("%F"), v]
421
+ elsif k == "usertags"
422
+ v = [v.gsub(%r{\n}, ", ")]
423
+ else
424
+ v = [v]
425
+ end
426
+ [k,v]
427
+ }]
428
+ while true
429
+ field = my_dmenu(info.map {|k,v| "#{k} |||#{v[0]}"}, "Info", info.size)
430
+ if field.empty?
431
+ break
432
+ else
433
+ field = field[/^[^ ]+/]
434
+ values = info[field]
435
+ if values.length > 1
436
+ value = my_dmenu(values.map{ |v| v.to_s }, "Version?")
437
+ else
438
+ value = values[0]
439
+ end
440
+ operation = my_dmenu(%w<copy full-display back>, value)
441
+ case operation
442
+ when "copy"
443
+ `echo '#{value}' | xsel --clipboard -i`
444
+ break
445
+ when "full-display"
446
+ `echo '#{value}' | zenity --text-info`
447
+ break
448
+ when "back"
449
+ else
450
+ break
451
+ end
452
+ end
453
+ end
454
+ end
455
+ break
456
+ when "search"
457
+ fields = ["artist", "title", "genre", "album", "date", "url"]
458
+ def add(ids)
459
+ ids.each do |z|
460
+ current_pl.add_entry(z).wait
461
+ end
462
+ end
463
+
464
+ def new_playlist(title, ids)
465
+ pl_coll = Xmms::Collection.new(Xmms::Collection::TYPE_IDLIST)
466
+ pl_coll.idlist = ids
467
+ if !title.empty?
468
+ $xc.coll_save(pl_coll, title, Xmms::Collection::NS_PLAYLISTS).wait
469
+ end
470
+ end
471
+
472
+ def new_playlist_prompt(ids)
473
+ new_playlist(my_dmenu([], "Playlist name"), ids)
474
+ end
475
+
476
+ def edit_ids_metadata(ids)
477
+ edit_metadata(ids.map{ |id| $xc.extract_medialib_info(id, "url")[:url] })
478
+ end
479
+
480
+ current_collection = Xmms::Collection.universe # TODO: Support searching multiple fields as in xmmsfs
481
+ refine = false
482
+ cs = {
483
+ 'add' => proc { |k| add(k) },
484
+ 'edit-metadata' => proc { |k| edit_ids_metadata(k) },
485
+ 'new-playlist' => proc { |k| new_playlist_prompt(k) },
486
+ 'refine' => proc { |k| refine=true }
487
+ }
488
+
489
+ while true
490
+ field = my_dmenu(fields, prompt="Field")
491
+ if field.empty?
492
+ break
493
+ end
494
+ field_sym = field.to_sym
495
+ options = Set.new(get_collection_info(current_collection, field).map{|x| x.fetch(field_sym, "UNDEF")}).to_a.sort
496
+
497
+ lists = [options]
498
+ search_string = ""
499
+ # XXX: Save and display past searches
500
+ begin
501
+ lists.each_with_index do |x, i|
502
+ search_string = my_dmenu(x, prompt="Search string (#{i}/#{lists.length})", [x.length, 20].min)
503
+ break
504
+ end
505
+ rescue Exception
506
+ lists = lists.inject(Array.new){ |g, x| g + [x[0..(x.length/2 - 1)], x[x.length/2..-1]]}
507
+ retry
508
+ end
509
+
510
+ if !options.include?(search_string)
511
+ search_string.gsub!(" ","*")
512
+ elsif field == 'url'
513
+ search_string = Xmms::encode_url(search_string)
514
+ end
515
+
516
+ if search_string.empty?
517
+ break
518
+ end
519
+ search_string = "*#{search_string}*"
520
+ puts search_string
521
+ coll = match_collection(field, search_string, current_collection)
522
+ d = $xc.coll_query_ids(coll,"artist,album,tracknr").wait.value
523
+ d = d.reverse
524
+ pos = list_ids(d, prompt="Results", 0, $LIST_ENTRIES_PER_PAGE, cs)
525
+
526
+ # Make the playlist collection
527
+ new_playlist('search-result-list', d)
528
+
529
+ # add the entry and load the playlist
530
+ if !pos.nil?
531
+ pl = $xc.playlist('search-result-list')
532
+ pl.load.wait
533
+ play_new_track($xc, pos)
534
+ break
535
+ end
536
+
537
+ if refine
538
+ current_collection = coll
539
+ else
540
+ current_collection = Xmms::Collection.universe
541
+ end
542
+ end
543
+
544
+ break
545
+ when "remove"
546
+ while true
547
+ pos = pl_list(nil,nil,"Remove entry:")
548
+ if pos.nil?
549
+ break
550
+ else
551
+ current_pl.remove_entry(pos).wait
552
+ end
553
+ end
554
+ break
555
+ when "+fav"
556
+ begin
557
+ id = $xc.playback_current_id.wait.value
558
+ p = $xc.playback_playtime.wait.value
559
+ data = $xc.extract_medialib_info(id, :favorite, :duration)
560
+ old_favorite = data[:favorite].to_f
561
+ duration = data[:duration].to_i
562
+ appreciation = track_appreciation_factor(p, duration)
563
+ $xc.medialib_entry_property_set(id, :favorite, (old_favorite+appreciation).to_s).wait
564
+ end
565
+ break
566
+ when "+fav-album"
567
+ id = $xc.playback_current_id.wait.value
568
+ get_album_ids(id).each do |al_id|
569
+ old_favorite = $xc.extract_medialib_info(al_id, :favorite)[:favorite].to_f
570
+ $xc.medialib_entry_property_set(al_id, :favorite, old_favorite+1).wait
571
+ end
572
+ break
573
+ when "tag"
574
+ # TODO: refcount the tags in the tag file so they get removed
575
+ # when no file is tagged with them
576
+
577
+ id = $xc.playback_current_id.wait.value
578
+ while tag_menu([id], get_usertags(id))
579
+ end
580
+
581
+ break
582
+ when "edit-metadata"
583
+ id = $xc.playback_current_id.wait.value
584
+ url = $xc.extract_medialib_info(id, "url")[:url]
585
+ edit_metadata([url])
586
+ break
587
+ when "edit-album-metadata"
588
+ id = $xc.playback_current_id.wait.value
589
+ urls = get_album_info(id, "url").map{|x| x[:url]}
590
+ edit_metadata(urls)
591
+ break
592
+ when "tag-album"
593
+ begin
594
+ id = $xc.playback_current_id.wait.value
595
+ album_ids = get_album_ids(id)
596
+ while tag_menu(album_ids, [])
597
+ end
598
+ rescue => e
599
+ puts e
600
+ end
601
+
602
+ break
603
+ when "change-playlist"
604
+ begin
605
+ playlists_prompt do |selected|
606
+ $xc.playlist(selected).load.wait
607
+ end
608
+ end
609
+ break
610
+ when "remove-playlist"
611
+ begin
612
+ playlists_prompt do |selected|
613
+ $xc.playlist(selected).remove.wait
614
+ end
615
+ end
616
+ break
617
+ when "show-playlist"
618
+ begin
619
+ playlists_prompt do |selected|
620
+ pl_list(nil,nil,prompt=selected, plname=selected)
621
+ end
622
+ end
623
+ break
624
+ when %r{repeat-(off|track|playlist)}
625
+ case command.split(%r{-})[1]
626
+ when "off"
627
+ $xc.config_set_value('playlist.repeat_one', "0").wait
628
+ $xc.config_set_value('playlist.repeat_all', "0").wait
629
+ when "track"
630
+ $xc.config_set_value('playlist.repeat_one', "1").wait
631
+ $xc.config_set_value('playlist.repeat_all', "0").wait
632
+ when "playlist"
633
+ $xc.config_set_value('playlist.repeat_one', "0").wait
634
+ $xc.config_set_value('playlist.repeat_all', "1").wait
635
+ end
636
+ break
637
+ when "shuffle"
638
+ $xc.shuffle_by(current_pl, :artist)
639
+ #current_pl.shuffle.wait
640
+ break
641
+ when "shutdown"
642
+ $xc.quit.wait
643
+ break
644
+ when "seek"
645
+ print $xc.playback_playtime.wait.value
646
+ id = $xc.playback_current_id.wait.value
647
+ info = $xc.extract_medialib_info(id, :duration)
648
+ dur = info[:duration].to_i
649
+ interval_size = dur / 10
650
+ times = []
651
+ times << ["start", 0]
652
+ Range.new(0,dur).step(interval_size).each do |x|
653
+ times << [x.ms_to_time_string, x]
654
+ end
655
+ times << ["end", dur]
656
+ seek_location = my_dmenu(times.map{|x| x[0]}).to_s
657
+ # FIXME: This math is clearly janky. Sadly I have actual work to do.
658
+ seek = 20 * time_string_to_ms(seek_location)
659
+ puts $xc.playback_seek_ms(seek).wait.value
660
+ $stdout.flush
661
+ break
662
+ else
663
+ if not command.empty?
664
+ `xmms2 #{command}`
665
+ end
666
+ break
667
+ end
668
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "dxmms2"
5
+ spec.version = "1.0.0"
6
+ spec.authors = ["Mark Watts"]
7
+ spec.email = ["wattsmark2015@gmail.com"]
8
+ spec.summary = %q{A client for working with xmms2}
9
+ spec.description = File.new("./README.md").read()
10
+ spec.homepage = "http://github.com/mwatts15/xmms2-stuff"
11
+ spec.license = "MPL-2.0"
12
+
13
+ spec.files = `git ls-files -z`.split("\x0")
14
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.require_paths = ["."]
17
+
18
+ spec.add_development_dependency "bundler", "~> 1.7"
19
+ spec.add_development_dependency "rake", "~> 10.0"
20
+ spec.add_runtime_dependency "glib2", "~> 3.1.0"
21
+ spec.add_runtime_dependency "xmms2_utils", "~> 0.1.2"
22
+ spec.add_runtime_dependency "markw-dmenu", "~> 1.0.0"
23
+ end
Binary file
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dxmms2
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mark Watts
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: glib2
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.1.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: xmms2_utils
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: markw-dmenu
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.0.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.0.0
83
+ description: "# dxmms2\n*a dmenu shell for xmms2*\n\nSetting the dmenu width in dxmms2
84
+ requires the patch provided in this repo. The \npatch hasn't been tested--application
85
+ may require manual effort.\n\n ![dxmms2 screenie](dxmms2.png)\n"
86
+ email:
87
+ - wattsmark2015@gmail.com
88
+ executables:
89
+ - dxmms2
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - Gemfile
94
+ - Makefile
95
+ - README.md
96
+ - bin/dxmms2
97
+ - dxmms2.gemspec
98
+ - dxmms2.png
99
+ homepage: http://github.com/mwatts15/xmms2-stuff
100
+ licenses:
101
+ - MPL-2.0
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - "."
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.2.2
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: A client for working with xmms2
123
+ test_files: []