dxmms2 1.0.0

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 (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: []