in_our_time 0.7.0 → 0.7.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 956e4e9773aad8f71897640c04d397bd566f512d
4
- data.tar.gz: 39f0098a0bb42d7f4a16d04fb518f68bfb2fb61a
3
+ metadata.gz: f7366e48fb9235107463e7af22d3b04b30ea7368
4
+ data.tar.gz: 3ef1be69c2de15068ad48ac13ae7bec99f6498bc
5
5
  SHA512:
6
- metadata.gz: 62af2485c95313e901ac884a6eb111a8cc2d407aafa64a1feda55e27c48ac85c1c3183781d4cc0d8c5f672aeeddf11a6bffc693aaafbde34d957e21d04605d30
7
- data.tar.gz: b6bb8e7f15b7f92ce50fe922fc04f418c7058506dbd78b09ce069bd1b8ad77b13a18064dbdf1dbc578df45e379c947f849ae1d294271e28bcd9f0acaa17980cd
6
+ metadata.gz: 30258e410871e24e8f7e8f93d95fd8e8a4464b11d321b5659a8b5f80e79e10091a8c269973d794f084b289f62dda29690d0be8ce8cc8a5d4f1ddaf06d1a85f1d
7
+ data.tar.gz: 3928c59f30aff170246a1480fbc1e0965c0386c115e43f7fc387d9876ed78b9cca85d9e1fae810766a9eef5441a2c9df8dc8b7c54a1370bb8486bdeb219c0fe4
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.0
1
+ 0.7.3
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ require "time"
2
3
  lib = File.expand_path('../lib', __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
 
@@ -20,7 +21,7 @@ Gem::Specification.new do |spec|
20
21
 
21
22
  spec.require_paths = ["lib"]
22
23
  spec.required_ruby_version = '>= 2.0.0'
23
- spec.add_runtime_dependency 'oga', '~> 2.2'
24
+ spec.add_runtime_dependency 'oga', '>= 2.1.4'
24
25
  spec.add_runtime_dependency 'colorize', '>= 0.8.1'
25
26
  spec.add_development_dependency 'version', '>= 1.0.0'
26
27
  end
@@ -13,30 +13,74 @@ require_relative 'keyboard_events'
13
13
  class InOurTime
14
14
  ROOT = File.expand_path '~/'
15
15
  HERE = File.dirname(__FILE__)
16
- CONFIG_DIR = '.in_our_time'
17
- CONFIG_NAME = 'config.yml'
16
+ CONFIG_DIR = '.in_our_time'.freeze
17
+ CONFIG_NAME = 'config.yml'.freeze
18
18
  IN_OUR_TIME = File.join ROOT, CONFIG_DIR
19
19
  VERSION = File.join HERE, '..','..','VERSION'
20
20
  DEFAULT_CONFIG = File.join HERE, '..','..',CONFIG_NAME
21
21
  CONFIG = File.join IN_OUR_TIME,CONFIG_NAME
22
22
  UPDATE_INTERVAL = 604800
23
- AUDIO_DIRECTORY = 'audio'
24
- RSS_DIRECTORY = 'rss'
23
+ AUDIO_DIRECTORY = '../../../../Volumes/UNTITLED/.in_our_time/audio'.freeze
24
+ # AUDIO_DIRECTORY = 'audio'.freeze
25
+ RSS_DIRECTORY = 'rss'.freeze
25
26
 
26
27
  class Tic
27
28
  def initialize
29
+ Thread.abort_on_exception = true
28
30
  @flag = false
31
+ init_processes
29
32
  run
30
33
  end
31
34
 
35
+ def init_processes
36
+ @processes =
37
+ { process: {
38
+ timeout: 5,
39
+ value: 0 },
40
+ playing_time: {
41
+ timeout: 1,
42
+ value: 0 },
43
+ ended: {
44
+ timeout: 1,
45
+ value: 0 }
46
+ }
47
+ end
48
+
49
+ def inc_processes
50
+ @processes.each { |process| process[:value] += 1 }
51
+ end
52
+
32
53
  def kill
33
54
  Thread.kill(@th_tic) if @th_tic
34
55
  end
35
56
 
57
+ def timeout? type
58
+ @processes[type]
59
+ return unless @processes[type][:value] > @processes[type][:timeout]
60
+ @processes[type][:value] = 0
61
+ true
62
+ end
63
+
64
+ def process
65
+ timeout? :process
66
+ end
67
+
68
+ def playing_time
69
+ timeout? :playing_time
70
+ end
71
+
72
+ def ended
73
+ timeout? :ended
74
+ end
75
+
36
76
  def run
77
+ Thread.abort_on_exception = true
37
78
  @th_tic = Thread.new do
38
79
  loop do
39
- sleep 1
80
+ sleep 0.2
81
+ @processes[:process][:value] += 1
82
+ @processes[:playing_time][:value] += 1
83
+ @processes[:ended][:value] += 1
40
84
  @flag = true
41
85
  end
42
86
  end
@@ -49,8 +93,102 @@ class InOurTime
49
93
  end
50
94
  end
51
95
 
96
+ class PlayTime
97
+ def initialize(dur)
98
+ @duration = dur
99
+ @start_time = Time.now
100
+ update
101
+ end
102
+
103
+ def changed?
104
+ ! unchanged?
105
+ end
106
+
107
+ def read
108
+ store
109
+ format_time
110
+ end
111
+
112
+ def ended?
113
+ (@duration + 20) < @seconds
114
+ end
115
+
116
+ def unchanged?
117
+ (update == stored) || paused?
118
+ end
119
+
120
+ def store
121
+ @stored = @seconds
122
+ end
123
+
124
+ def stored
125
+ @stored
126
+ end
127
+
128
+ def plural x
129
+ x == 1 ? '' : 's'
130
+ end
131
+
132
+ def mins
133
+ @seconds / 60
134
+ end
135
+
136
+ def secs
137
+ @seconds % 60
138
+ end
139
+
140
+ def format x
141
+ x < 10 ? '0' + x.to_s : x.to_s
142
+ end
143
+
144
+ def format_minutes
145
+ format mins
146
+ end
147
+
148
+ def format_secs
149
+ format secs
150
+ end
151
+
152
+ def format_remaining_time
153
+ secs = @duration - @seconds
154
+ format(secs/60) + ':' + format(secs%60)
155
+ end
156
+
157
+ def format_time
158
+ ' (' + format_minutes + ':' + format_secs +
159
+ ' / ' + format_remaining_time + ')'
160
+ end
161
+
162
+ def update
163
+ @seconds = (Time.now - @start_time).to_i
164
+ end
165
+
166
+ def pause
167
+ @paused = Time.now
168
+ end
169
+
170
+ def paused?
171
+ @paused
172
+ end
173
+
174
+ def unpause
175
+ @start_time = @start_time + (Time.now - @paused)
176
+ @paused = false
177
+ end
178
+
179
+ def forward
180
+ @start_time -= 1.5
181
+ end
182
+
183
+ def rewind
184
+ @start_time += 1.5
185
+ end
186
+ end
187
+
52
188
  def initialize
53
- @content = ''
189
+ Thread.abort_on_exception = true
190
+ @queued = Array.new
191
+ @content = String.new
54
192
  @selected = 0
55
193
  clear
56
194
  print "\e[?25h"
@@ -80,7 +218,7 @@ class InOurTime
80
218
  STDIN.echo = true
81
219
  STDIN.cooked!
82
220
  puts "\n\n#{@error_msg}" if @error_msg
83
- puts 'Quitting...'
221
+ puts 'Quitting...'.freeze
84
222
  sleep 0.5
85
223
  exit code
86
224
  end
@@ -91,7 +229,7 @@ class InOurTime
91
229
  end
92
230
 
93
231
  def iot_print x, col = @text_colour, now = false
94
- content = ''
232
+ content = String.new
95
233
  content << x.colorize(col) if @config[:colour]
96
234
  content << x unless @config[:colour]
97
235
  unless now
@@ -101,9 +239,9 @@ class InOurTime
101
239
  end
102
240
  end
103
241
 
104
- def iot_puts x = '', col = @text_colour
105
- iot_print x, col
106
- iot_print "\n\r"
242
+ def iot_puts x = '', col = @text_colour, now = false
243
+ iot_print x, col, now
244
+ iot_print "\n\r", now
107
245
  end
108
246
 
109
247
  def clear_content
@@ -132,18 +270,18 @@ class InOurTime
132
270
  end
133
271
 
134
272
  def dev_mode?
135
- ENV['IN_OUR_TIME'] == 'development'
273
+ ENV['IN_OUR_TIME'] == 'development'.freeze
136
274
  end
137
275
 
138
276
  def puts_title colour
139
277
  title =
140
- %q{ _____ ____ _______ _
278
+ %q{ _____ ____ _______ _
141
279
  |_ _| / __ \ |__ __(_)
142
280
  | | _ __ | | | |_ _ _ __ | | _ _ __ ___ ___
143
281
  | | | '_ \ | | | | | | | '__| | | | | '_ ` _ \ / _ \
144
282
  _| |_| | | | | |__| | |_| | | | | | | | | | | | __/
145
283
  |_____|_| |_| \____/ \__,_|_| |_| |_|_| |_| |_|\___|
146
- }
284
+ }.freeze
147
285
 
148
286
  title.split("\n").map{|l| iot_print(l + "\r\n", colour)} if(window_width > 61)
149
287
  iot_puts("In Our Time\r", colour) unless(window_width > 61)
@@ -200,7 +338,7 @@ class InOurTime
200
338
 
201
339
  def set_height
202
340
  height = window_height
203
- while(height -2 % 10 != 0) ; height -=1 ; end
341
+ while(((height - 2) % 10) != 0) ; height -= 1 ; end
204
342
  height = 10 if height < 10
205
343
  @page_height = height if(@config[:page_height] == :auto)
206
344
  @page_height = @config[:page_height] unless(@config[:page_height] == :auto)
@@ -210,8 +348,8 @@ class InOurTime
210
348
  width = window_width
211
349
  while(width % 10 != 0) ; width -=1 ; end
212
350
  width = 20 if width < 20
213
- @page_width = width - 1 if(@config[:page_width] == :auto)
214
- @page_width = @config[:page_width] unless(@config[:page_width] == :auto)
351
+ @page_width = width - 1 if(@config[:page_width] == :auto)
352
+ @page_width = @config[:page_width] unless(@config[:page_width] == :auto)
215
353
  end
216
354
 
217
355
  def window_height
@@ -249,25 +387,16 @@ class InOurTime
249
387
  end
250
388
 
251
389
  def rss_addresses
390
+ filename = "/episodes/downloads.rss"
252
391
  host = 'http://www.bbc.co.uk/programmes'
253
- [ "/b006qykl/episodes/downloads.rss",
254
- "/p01drwny/episodes/downloads.rss",
255
- "/p01dh5yg/episodes/downloads.rss",
256
- "/p01f0vzr/episodes/downloads.rss",
257
- "/p01gvqlg/episodes/downloads.rss",
258
- "/p01gyd7j/episodes/downloads.rss"
259
- ].collect{|page| host + page}
392
+ [ "/b006qykl", "/p01drwny", "/p01dh5yg",
393
+ "/p01f0vzr", "/p01gvqlg", "/p01gyd7j"
394
+ ].collect{|page| host + page + filename}
260
395
  end
261
396
 
262
397
  def local_rss
263
- [
264
- "culture.rss",
265
- "history.rss",
266
- "in_our_time.rss",
267
- "philosophy.rss",
268
- "religion.rss",
269
- "science.rss"
270
- ]
398
+ [ "culture.rss", "history.rss", "in_our_time.rss",
399
+ "philosophy.rss", "religion.rss", "science.rss"]
271
400
  end
272
401
 
273
402
  def fetch_uri uri, file
@@ -342,13 +471,14 @@ class InOurTime
342
471
  end
343
472
 
344
473
  def build_program(bin)
345
- title = bin[tags[0]].shift.text
474
+ title = bin['title'].shift.text
346
475
  { title: title,
347
- subtitle: bin[tags[1]].shift.text,
348
- summary: bin[tags[2]].shift.text,
349
- duration: bin[tags[3]].shift.text,
350
- date: bin[tags[4]].shift.text[0..15],
351
- link: bin[tags[5]].shift.text,
476
+ subtitle: bin['itunes:subtitle'].shift.text,
477
+ summary: bin['itunes:summary'].shift.text,
478
+ duration: bin['itunes:duration'].shift.text,
479
+ date: bin['pubDate'].shift.text[0..15],
480
+ link: bin['link'].shift.text,
481
+ url: bin['url'].shift,
352
482
  have_locally: have_locally?(title)
353
483
  }
354
484
  end
@@ -376,6 +506,10 @@ class InOurTime
376
506
  bin[tag] = [] if bin[tag].nil?
377
507
  bin[tag] = @doc.xpath(item_path(tag))
378
508
  end
509
+ bin['url'] = []
510
+ @doc.xpath(item_path('enclosure')).each do |x|
511
+ bin['url'] << x.get('url')
512
+ end
379
513
  build_programs(bin)
380
514
  end
381
515
  uniquify_programs
@@ -418,12 +552,51 @@ class InOurTime
418
552
  redraw
419
553
  end
420
554
 
421
- def list_key
422
- title = @playing ? @playing : (@sorted_titles[@last_selected || 0])
555
+ def title_focus
556
+ @playing ? @playing : (@sorted_titles[@last_selected || 0])
557
+ end
558
+
559
+ def top_selected
560
+ @selected == 0
561
+ end
562
+
563
+ def end_selected
564
+ @selected == @titles_count - 1
565
+ end
566
+
567
+ def top_title_focus
568
+ title_focus == @sorted_titles.first
569
+ end
570
+
571
+ def end_title_focus
572
+ title_focus == @sorted_titles.last
573
+ end
574
+
575
+ def top_or_end?
576
+ top_selected || end_selected
577
+ end
578
+
579
+ def store_selected
580
+ @last_selected = @selected
581
+ end
582
+
583
+ def top_or_end_title_focus
584
+ top_title_focus || end_title_focus
585
+ end
586
+
587
+ def jump_key
423
588
  if top_or_end?
424
- draw_by_title title
589
+ if top_or_end_title_focus
590
+ if top_selected
591
+ list_end
592
+ else
593
+ list_top
594
+ end
595
+ else
596
+ draw_by_title title_focus
597
+ end
425
598
  else
426
- @last_selected = @selected
599
+ store_selected
427
600
  list_top_or_end
428
601
  end
429
602
  end
@@ -437,18 +610,12 @@ class InOurTime
437
610
  end
438
611
  end
439
612
 
440
- def top_or_end?
441
- @selected == 0 || @selected == @titles_count - 1
442
- end
443
-
444
613
  def list_top
445
- @last_selected = @selected
446
614
  @selected = 0
447
615
  draw_selected
448
616
  end
449
617
 
450
618
  def list_end
451
- @last_selected = @selected
452
619
  @selected = @titles_count - 1
453
620
  draw_selected
454
621
  end
@@ -497,7 +664,7 @@ class InOurTime
497
664
 
498
665
  def player_cmd
499
666
  if use_mpg123?
500
- "mpg123 --remote-err -Cqk#{pre_delay}"
667
+ "mpg123 -Cvk#{pre_delay}"
501
668
  else
502
669
  get_player
503
670
  end
@@ -517,12 +684,12 @@ class InOurTime
517
684
  @sorted_titles.each do |title|
518
685
  title.split(' ').each do |word|
519
686
  if distances[title].nil?
520
- distances[title] = Levenshtein::distance(search_term, word)
687
+ distances[title] = Levenshtein.distance(search_term, word)
521
688
  else
522
689
  distances[title] =
523
690
  distances[title] >
524
- Levenshtein::distance(search_term, word.downcase) ?
525
- Levenshtein::distance(search_term, word.downcase) :
691
+ Levenshtein.distance(search_term, word.downcase) ?
692
+ Levenshtein.distance(search_term, word.downcase) :
526
693
  distances[title]
527
694
  end
528
695
  end
@@ -534,11 +701,14 @@ class InOurTime
534
701
 
535
702
  def print_search_results results
536
703
  puts
537
- puts "0: Search Again!"
704
+ iot_print "0:", @count_sel_colour, :now
705
+ iot_puts " Search Again!", @system_colour, :now
706
+ puts
538
707
  puts
539
708
  5.times do |count|
540
- print "#{count + 1}: "
541
- puts results[count][0]
709
+ iot_print "#{count + 1}:", @count_sel_colour, :now
710
+ iot_print " #{results[count][0]}", @system_colour, :now
711
+ puts
542
712
  end
543
713
  puts
544
714
  end
@@ -555,7 +725,8 @@ class InOurTime
555
725
  end
556
726
 
557
727
  def get_search_term
558
- puts "Enter Search Term or just Return for Random:"
728
+ iot_puts "Enter Search Term or just Return for Random:", @system_colour, :now
729
+ puts
559
730
  puts
560
731
  print "Search Term: "
561
732
  gets.chomp
@@ -563,7 +734,7 @@ class InOurTime
563
734
 
564
735
  def get_search_choice
565
736
  print "Enter Choice: "
566
- temp = gets.chomp
737
+ temp = $stdin.getch.chomp
567
738
  temp == '0' ? :search_again : temp
568
739
  end
569
740
 
@@ -598,7 +769,7 @@ class InOurTime
598
769
  render
599
770
  10.times do
600
771
  begin
601
- res = Net::HTTP.get_response(URI.parse(prg[:link]))
772
+ res = Net::HTTP.get_response(URI.parse(prg[:url]))
602
773
  rescue SocketError => e
603
774
  print_error_and_delay "Error: Failed to connect to Internet! (#{e.class})"
604
775
  render
@@ -620,11 +791,10 @@ class InOurTime
620
791
  end
621
792
  retries += 1
622
793
  end
623
- if retries >= 10
624
- print_error_and_delay "Max retries downloading #{prg[:title]}"
625
- render
626
- @no_play = true
627
- end
794
+ return if retries < 10
795
+ print_error_and_delay "Max retries downloading #{prg[:title]}"
796
+ render
797
+ @no_play = true
628
798
  end
629
799
 
630
800
  # Cross-platform way of finding an executable in the $PATH.
@@ -647,16 +817,58 @@ class InOurTime
647
817
  quit 1
648
818
  end
649
819
 
820
+ def init_countdown(duration)
821
+ @play_time = PlayTime.new(duration) unless use_mpg123?
822
+ end
823
+
650
824
  def run_program prg
651
- download prg
652
825
  unless @no_play
653
826
  @playing = prg[:title]
654
827
  player = player_cmd.split(' ').first
655
- unknown_player(player) unless which(player)
828
+ unknown_player(player) unless which(File.basename player)
656
829
  window_title prg[:title]
657
830
  cmd = player_cmd + ' ' + filename_from_title(@playing)
658
831
  @messages = []
659
- @p_out, @p_in, @pid = PTY.spawn(cmd)
832
+ init_countdown prg[:duration].to_i
833
+ @player_th = Thread.new do
834
+ buf = ''
835
+ p_out, @p_in, @pid = PTY.spawn(cmd)
836
+ sleep 1
837
+ count = 0
838
+ loop do
839
+ unless use_mpg123?
840
+ sleep 1
841
+ else
842
+ x = p_out.getc unless p_out.eof?
843
+ if(((count >= 6) && (count <= 10)) ||
844
+ ((count > 15) && (count < 21)) )
845
+ buf << x
846
+ count += 1
847
+ elsif(((count == 0) && (x == 'T')) ||
848
+ ((count == 1) && (x == 'i')) ||
849
+ ((count == 2) && (x == 'm')) ||
850
+ ((count == 3) && (x == 'e')) ||
851
+ ((count == 4) && (x == ':')) ||
852
+ ((count == 5) && (x == ' ')) ||
853
+ ((count >= 12) && (count <= 15)))
854
+ count += 1
855
+ elsif count == 11
856
+ @running_time = buf
857
+ buf = ''
858
+ count += 1
859
+ elsif count == 21
860
+ @remaining_time = buf
861
+ buf = ''
862
+ count = 0
863
+ sleep 0.3
864
+ p_out.flush
865
+ else
866
+ count = 0
867
+ sleep 0.001
868
+ end
869
+ end
870
+ end
871
+ end
660
872
  end
661
873
  @no_play = nil
662
874
  end
@@ -677,6 +889,7 @@ class InOurTime
677
889
  begin
678
890
  @p_in.puts str
679
891
  rescue Errno::EIO
892
+ kill_audio
680
893
  reset
681
894
  end
682
895
  end
@@ -684,6 +897,8 @@ class InOurTime
684
897
  def pause
685
898
  return unless control_play?
686
899
  @paused = @paused ? false : true
900
+ @play_time.pause if @paused unless use_mpg123?
901
+ @play_time.unpause unless @paused unless use_mpg123?
687
902
  write_player " "
688
903
  redraw
689
904
  end
@@ -693,11 +908,15 @@ class InOurTime
693
908
  end
694
909
 
695
910
  def forward
696
- write_player ":" if control_play?
911
+ return unless control_play?
912
+ write_player ":"
913
+ @play_time.forward unless use_mpg123?
697
914
  end
698
915
 
699
916
  def rewind
700
- write_player ";" if control_play?
917
+ return unless control_play?
918
+ write_player ";"
919
+ @play_time.rewind unless use_mpg123?
701
920
  end
702
921
 
703
922
  def instructions
@@ -706,11 +925,30 @@ class InOurTime
706
925
  iot_print "for instructions", @system_colour
707
926
  end
708
927
 
928
+ def print_playing
929
+ iot_print("Playing: ", @count_colour)
930
+ end
931
+
932
+ def print_paused
933
+ iot_print("Paused: ", @count_colour)
934
+ end
935
+
936
+ def print_play_time
937
+ if use_mpg123?
938
+ iot_print(@playing, @selection_colour)
939
+ iot_print(' (' + @running_time, @selection_colour) unless @running_time.nil?
940
+ iot_print(' / ' + @remaining_time, @selection_colour) unless @remaining_time.nil?
941
+ iot_puts(')', @selection_colour) unless @running_time.nil?
942
+ else
943
+ iot_puts(@playing + @play_time.read, @selection_colour)
944
+ end
945
+ end
946
+
709
947
  def print_playing_maybe
710
948
  if @playing
711
- iot_print("Playing: ", @count_colour) unless @paused
712
- iot_print("Paused: ", @count_colour) if @paused
713
- iot_puts @playing, @selection_colour
949
+ print_playing unless @paused
950
+ print_paused if @paused
951
+ print_play_time
714
952
  elsif @started.nil?
715
953
  @started = true
716
954
  instructions
@@ -718,11 +956,19 @@ class InOurTime
718
956
  end
719
957
 
720
958
  def kill_audio
721
- return unless @playing
722
- @playing = nil
723
- return unless @pid.is_a?(Integer)
724
- Process.kill('QUIT', @pid)
725
- sleep 0.2
959
+ loop do
960
+ Thread.kill(@player_th) if @player_th
961
+ return unless @playing
962
+ begin
963
+ break unless @pid.is_a?(Integer)
964
+ Process.kill('QUIT', @pid)
965
+ _, status = Process.wait2 @pid
966
+ break if status.exited?
967
+ rescue Errno::ESRCH
968
+ break
969
+ end
970
+ sleep 0.2
971
+ end
726
972
  reset
727
973
  end
728
974
 
@@ -769,6 +1015,7 @@ class InOurTime
769
1015
 
770
1016
  def load_help_maybe
771
1017
  return unless help_option?
1018
+ @config[:colour] = false
772
1019
  help
773
1020
  puts
774
1021
  exit 0
@@ -776,37 +1023,43 @@ class InOurTime
776
1023
 
777
1024
  def help_screen
778
1025
  [] <<
779
- " In Our Time Player (#{@version})" <<
780
- " " <<
781
- " Play/Stop - X / Enter " <<
782
- " Next/Prev - Up / Down " <<
783
- " Next/Prev Page - Right / Left " <<
784
- " Sort - S " <<
785
- " Search - ? " <<
786
- " Theme Toggle - T " <<
787
- " List Top/End - L " <<
788
- " Update - U " <<
789
- " Download - D " <<
790
- " Info - I " <<
791
- " Help - H " <<
792
- " Quit - Q " <<
793
- " mpg123 Control - " <<
794
- " Pause/Resume - P / Spacebar " <<
795
- " Forward Skip - F " <<
796
- " Reverse Skip - R " <<
1026
+ " In Our Time Payer (#{@version}) " <<
797
1027
  " " <<
1028
+ " Play/Stop - Enter/X " <<
1029
+ " Next/Prev - Up/Down " <<
1030
+ " Next/Prev Page - Right/Left " <<
1031
+ " Arrange - A " <<
1032
+ " Search - ? " <<
1033
+ " Theme Toggle - T " <<
1034
+ " Jump Around List - J " <<
1035
+ " Update - U " <<
1036
+ " Download - D " <<
1037
+ " Enqueue - E " <<
1038
+ " Shuffle Play - S " <<
1039
+ " Shuffle Next - N " <<
1040
+ " Info - I " <<
1041
+ " Help - H " <<
1042
+ " Quit - Q " <<
1043
+ " mpg123 Control - " <<
1044
+ " Pause/Resume - P/Spacebar " <<
1045
+ " Forward Skip - F " <<
1046
+ " Reverse Skip - R " <<
798
1047
  "Config: #{CONFIG} "
799
1048
  end
800
1049
 
801
- def help_partial x,y; help_screen[x..y] end
802
- def help_title; help_partial(0, 1) end
803
- def help_main; help_partial(2, 13) end
804
- def help_cfg; help_partial(18, -1) end
1050
+ def title_xy; [0,0] end
1051
+ def main_xy; [1, help_screen.size - 7] end
1052
+ def mpg_xy; [help_screen.size - 6, -2] end
1053
+ def cfg_xy; [help_screen.size - 1, -1] end
1054
+ def help_partial(x); help_screen[x[0]..x[1]] end
1055
+ def help_title; help_partial(title_xy) end
1056
+ def help_main; help_partial(main_xy) end
1057
+ def help_cfg; help_partial(cfg_xy) end
805
1058
 
806
1059
  def help_mpg
807
- scr = help_partial(14,17)
808
- scr[0].rstrip! << ' (enabled) ' if use_mpg123?
809
- scr[0].rstrip! << ' (disabled) ' unless use_mpg123?
1060
+ scr = help_partial(mpg_xy)
1061
+ scr[0].rstrip! << ' (enabled) ' if use_mpg123?
1062
+ scr[0].rstrip! << ' (disabled) ' unless use_mpg123?
810
1063
  scr
811
1064
  end
812
1065
 
@@ -817,6 +1070,8 @@ class InOurTime
817
1070
  @count_colour if use_mpg123?
818
1071
  when :cfg
819
1072
  @system_colour
1073
+ when :title
1074
+ @system_colour
820
1075
  else
821
1076
  @text_colour
822
1077
  end
@@ -835,14 +1090,13 @@ class InOurTime
835
1090
  help_render :title
836
1091
  help_render :main
837
1092
  help_render :mpg
838
- help_render :cfg
1093
+ # help_render :cfg
839
1094
  end
840
1095
 
841
1096
  def help
842
1097
  unless @help
843
1098
  clear_content
844
1099
  print_help
845
- print_playing_maybe unless help_option?
846
1100
  @help = true
847
1101
  render
848
1102
  else
@@ -966,21 +1220,6 @@ class InOurTime
966
1220
  render
967
1221
  end
968
1222
 
969
- def check_process
970
- if(@playing && @pid.is_a?(Integer))
971
- begin
972
- write_player( "\e")
973
- if @pid.is_a? Integer
974
- Process.kill 0, @pid
975
- end
976
- rescue Errno::ESRCH
977
- reset
978
- end
979
- else
980
- @pid = nil
981
- end
982
- end
983
-
984
1223
  def page_forward
985
1224
  return unless @line_count < @titles_count
986
1225
  @selected = @line_count
@@ -1006,23 +1245,23 @@ class InOurTime
1006
1245
  end
1007
1246
 
1008
1247
  def play
1009
- if(@playing != @sorted_titles[@selected]) || (! @playing)
1010
- kill_audio
1011
- title = @sorted_titles[@selected]
1012
- pr = select_program title
1013
- run_program pr
1014
- redraw
1015
- else
1016
- kill_audio
1017
- end
1248
+ title = @sorted_titles[@selected]
1249
+ playing = @playing
1250
+ prg = select_program(title)
1251
+ download prg unless playing
1252
+ download prg if playing && (playing != title)
1253
+ kill_audio
1254
+ return unless (! playing) || (playing != title)
1255
+ run_program prg
1256
+ redraw
1018
1257
  end
1019
1258
 
1020
1259
  def update_key
1021
- update
1022
- parse_rss
1023
- sort_titles
1024
- @selected = 0
1025
- draw_selected
1260
+ update
1261
+ parse_rss
1262
+ sort_titles
1263
+ @selected = 0
1264
+ draw_selected
1026
1265
  end
1027
1266
 
1028
1267
  def download_key
@@ -1032,6 +1271,18 @@ class InOurTime
1032
1271
  draw_selected
1033
1272
  end
1034
1273
 
1274
+ def enqueue
1275
+ @queued << @sorted_titles[@selected]
1276
+ end
1277
+
1278
+ def next_program
1279
+ kill_audio
1280
+ end
1281
+
1282
+ def shuffle_key
1283
+ @queued = @sorted_titles.shuffle
1284
+ end
1285
+
1035
1286
  def quit_key
1036
1287
  kill_audio
1037
1288
  quit
@@ -1039,9 +1290,10 @@ class InOurTime
1039
1290
 
1040
1291
  def do_action ip
1041
1292
  case ip
1042
- when :pause, :forward, :rewind, :list_key, :page_forward, :page_back,
1293
+ when :pause, :forward, :rewind, :jump_key, :page_forward, :page_back,
1043
1294
  :previous, :next, :play, :sort_key, :theme_toggle, :update_key,
1044
- :info, :help, :quit_key, :search, :download_key
1295
+ :info, :help, :quit_key, :search, :download_key, :enqueue,
1296
+ :next_program, :shuffle_key
1045
1297
  self.send ip
1046
1298
  end
1047
1299
  end
@@ -1051,6 +1303,60 @@ class InOurTime
1051
1303
  @help = nil unless ip == :help
1052
1304
  end
1053
1305
 
1306
+ def ping_player
1307
+ write_player("\e")
1308
+ end
1309
+
1310
+ def check_player_process
1311
+ Process.kill 0, @pid
1312
+ end
1313
+
1314
+ def check_process
1315
+ return unless @playing
1316
+ if @pid.is_a?(Integer)
1317
+ begin
1318
+ write_player("\e")
1319
+ sleep 0.1
1320
+ if @pid.is_a? Integer
1321
+ check_player_process
1322
+ end
1323
+ rescue Errno::ESRCH
1324
+ kill_audio
1325
+ end
1326
+ else
1327
+ kill_audio
1328
+ unless @queued.empty?
1329
+ title = @queued.shift
1330
+ prg = select_program(title)
1331
+ download prg
1332
+ run_program(prg)
1333
+ draw_by_title title
1334
+ end
1335
+ end
1336
+ end
1337
+
1338
+ def check_finished
1339
+ return if use_mpg123?
1340
+ return unless @playing
1341
+ return unless @play_time.ended?
1342
+ kill_audio
1343
+ end
1344
+
1345
+ def check_tic
1346
+ return unless @tic.toc
1347
+ # check_process if @tic.process
1348
+ # check_finished if @tic.ended
1349
+ return unless @info.nil?
1350
+ return unless @help.nil?
1351
+ check_playing_time if @tic.playing_time
1352
+ end
1353
+
1354
+ def check_playing_time
1355
+ return unless @playing
1356
+ return unless @play_time.changed? unless use_mpg123?
1357
+ redraw
1358
+ end
1359
+
1054
1360
  def run
1055
1361
  ip = ''
1056
1362
  @tic = Tic.new
@@ -1061,7 +1367,7 @@ class InOurTime
1061
1367
  loop do
1062
1368
  ip = @key.read
1063
1369
  break unless ip == :no_event
1064
- check_process if @tic.toc
1370
+ check_tic
1065
1371
  do_events
1066
1372
  end
1067
1373
  reset_info_maybe ip
@@ -36,6 +36,7 @@ class KeyboardEvents
36
36
  end
37
37
 
38
38
  def run
39
+ Thread.abort_on_exception = true
39
40
  @key = Thread.new do
40
41
  while @event != :quit_key
41
42
  str = ''
@@ -72,6 +73,8 @@ class KeyboardEvents
72
73
  when "\e"
73
74
  @mode = :escape
74
75
  :no_event
76
+ when 'a', 'A'
77
+ :sort_key
75
78
  when 'd', 'D'
76
79
  :download_key
77
80
  when 'f', 'F'
@@ -80,8 +83,10 @@ class KeyboardEvents
80
83
  :help
81
84
  when 'i', 'I'
82
85
  :info
83
- when 'l', 'L'
84
- :list_key
86
+ when 'j', 'J'
87
+ :jump_key
88
+ when 'e', 'E'
89
+ :enqueue
85
90
  when 'p', 'P', ' '
86
91
  :pause
87
92
  when 'q', 'Q', "\u0003", "\u0004"
@@ -89,7 +94,9 @@ class KeyboardEvents
89
94
  when 'r', 'R'
90
95
  :rewind
91
96
  when 's', 'S'
92
- :sort_key
97
+ :shuffle_key
98
+ when 'n', 'N'
99
+ :next_program
93
100
  when 't', 'T'
94
101
  :theme_toggle
95
102
  when 'u', 'U'
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: in_our_time
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martyn Jago
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-12 00:00:00.000000000 Z
11
+ date: 2018-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oga
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2.2'
19
+ version: 2.1.4
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '2.2'
26
+ version: 2.1.4
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: colorize
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -94,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
94
  version: '0'
95
95
  requirements: []
96
96
  rubyforge_project:
97
- rubygems_version: 2.5.1
97
+ rubygems_version: 2.6.13
98
98
  signing_key:
99
99
  specification_version: 4
100
100
  summary: Select, play, and download BBC 'In Our Time' podcasts - all from the command