aniview 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 827d5b9084b305647f640fd4cf3ba14ce15bcea5
4
- data.tar.gz: 3e10b4ccf9d9f02cfee4260921eb7f22ae097339
3
+ metadata.gz: 0ea930584ab074643f3257cfb4ead82380d28a8e
4
+ data.tar.gz: dd51a52724248c507c8fcf171181ed73aa30acd0
5
5
  SHA512:
6
- metadata.gz: 69a1e2a4ba2c11f38811bb5eb951993f5ea41228796c77f397a9292c2f053993f653b8ecbe614df7c41a9fe3d3a88c481bc8379e73340d0ea580166974c57206
7
- data.tar.gz: 6195b01dcd02520fb7119c4b690f2266c0459ea603b96c6eaea03ab9e6aa352314800cac6b6f3052f846306886a409b7772fa0d6534ae2d29f7ad18ff73dbb97
6
+ metadata.gz: 337ae5115ba6619e0e526e8ef7d8dfc424671c36c8698d4e5b39dddb24fd6f873b715c8c383805e21d48f4cd33fc4d1ab9b7ba4cae0e16c4bf1cec8e95c813fe
7
+ data.tar.gz: 657aee82a1a6ac61017368fd4d5238813535a25dcfe36d0c7326be23883188e58b1811786bfa06ce5124d0ac885c082ea84efbbaaff70eb35fa4f34afc44222c
data/README.md CHANGED
@@ -7,6 +7,6 @@ command line anime library viewer
7
7
  ### using rubygems
8
8
  `gem install aniview`
9
9
 
10
- ### Find out more on the wiki
11
- + [Default Keybingings](https://github.com/annacrombie/aniview/wiki/Default-Keybindings)
12
- + [Format Strings](https://github.com/annacrombie/aniview/wiki/Format-Strings)
10
+ ## documentation
11
+ + [rubydoc.info](http://www.rubydoc.info/gems/aniview/)
12
+ + [wiki](https://github.com/annacrombie/aniview/wiki/)
@@ -14,7 +14,7 @@ module Aniview
14
14
  attr_accessor :accessible
15
15
  attr_accessor :path
16
16
 
17
- def initialize(path_, seen = false)
17
+ def initialize(path_, seen: false, watched_on: 0)
18
18
  @watched = seen
19
19
  @accessible = true
20
20
  begin
@@ -22,7 +22,7 @@ module Aniview
22
22
  rescue Errno::ENOENT
23
23
  @last_modified = "0"
24
24
  end
25
- @watched_on = 0
25
+ @watched_on = watched_on
26
26
  @path = path_
27
27
 
28
28
  @attr = {
@@ -37,6 +37,7 @@ module Aniview
37
37
  "l" => "",
38
38
  "f" => "",
39
39
  "b" => "",
40
+ "w" => seen? ? "x" : " "
40
41
  }
41
42
 
42
43
  if (@path == "empty")
@@ -55,15 +56,15 @@ module Aniview
55
56
  "l" => mov.colorspace,
56
57
  "f" => mov.frame_rate,
57
58
  "b" => String(mov.bitrate) + "kb/s",
59
+ "w" => seen? ? "x" : " "
58
60
  }
59
61
  end
60
-
61
62
  end
62
63
 
63
64
  def title
64
65
  return @attr["t"]
65
66
  end
66
-
67
+
67
68
  def seen?
68
69
  return @watched
69
70
  end
@@ -75,10 +76,12 @@ module Aniview
75
76
  def watch
76
77
  @watched = true
77
78
  @watched_on = DateTime.now.strftime('%Q')
79
+ @attr["w"] = "x"
78
80
  end
79
81
 
80
82
  def unwatch
81
83
  @watched = false
84
+ @attr["w"] = " "
82
85
  end
83
86
 
84
87
  def string
@@ -7,6 +7,7 @@ require 'benchmark'
7
7
  require_relative 'animefile'
8
8
  require_relative 'animeseries'
9
9
  require_relative '../../util/util'
10
+ require_relative '../../util/folder_listen'
10
11
  require_relative '../bridge'
11
12
 
12
13
  module Aniview
@@ -27,24 +28,34 @@ module Aniview
27
28
  @made_changes = true
28
29
 
29
30
  self.load
30
- pref_changed!
31
- relisten
31
+ pref_changed!(verbose: false)
32
+ #relisten
32
33
 
33
34
  @pref.add_observer(self, :pref_changed!)
34
35
  @mpvbridge.add_observer(self, :animefile_changed!)
35
36
  #@@local_anime.each { |key, obj| obj.add_observer(self, :animefile_changed!)}
36
37
  end
37
38
 
39
+ def listen_to_all_dirs
40
+ #listen to all
41
+ all_dirs = (@pref.get("anime_locations").split(":")).map { |dir| @pref.parseDir(dir) }
42
+ @folder_listener = FolderListen.to(all_dirs) { index_anime }
43
+ @folder_listener.start
44
+ end
45
+
38
46
  def relisten
39
- @listener.stop unless @listener == nil
40
- return if @anime_dirs == nil or @anime_dirs[0] == ""
41
- @listener = Listen.to(*@anime_dirs, only: /\.mkv$/) do |modified, added, removed|
42
- index_anime
43
- end
47
+ cleanup
48
+
49
+ listen_to_all_dirs
50
+
51
+ return if @anime_dirs == nil or @anime_dirs[0] == "" or @anime_dirs.length == 0
52
+
53
+ @listener = Listen.to(*@anime_dirs, only: /\.mkv$/) { index_anime }
44
54
  @listener.start
45
55
  end
46
56
 
47
57
  def cleanup
58
+ @folder_listener.stop unless @folder_listener == nil
48
59
  @listener.stop unless @listener == nil
49
60
  end
50
61
 
@@ -66,23 +77,24 @@ module Aniview
66
77
  end
67
78
  end
68
79
 
69
- def pref_changed!
80
+ def pref_changed!(verbose: true)
70
81
  new_dirs = (@pref.get("anime_locations").split(":")).collect { |dir|
71
- @pref.parseDir(dir)
72
- }
82
+ parsed_dir = @pref.parseDir(dir)
83
+ parsed_dir if File.exist?(parsed_dir)
84
+ }.compact
73
85
  if new_dirs != @anime_dirs
74
86
  @anime_dirs = new_dirs
75
- index_anime
87
+ index_anime(verbose: verbose)
76
88
  relisten
77
89
  end
78
90
  end
79
91
 
80
92
  def animefile_changed!
81
- return unless @mpvbridge.what_changed == "local_anime"
93
+ return unless @mpvbridge.what_changed[:local_anime]
94
+ save
82
95
  changed
83
96
  notify_observers
84
97
  end
85
-
86
98
 
87
99
  ##
88
100
  ## @brief Indexes anime files up to 1 level deep in specified anime directories
@@ -92,24 +104,36 @@ module Aniview
92
104
  ##
93
105
  ## @return { description_of_the_return_value }
94
106
  ##
95
- def index_anime(force: false, verbose: false)
107
+ def index_anime(force: false, verbose: true, very_verbose: false)
108
+ puts "Indexing anime" if very_verbose
96
109
  Thread.new {
97
110
  ret = {}
98
111
  made_changes = false
99
112
  lal = @@local_anime.length
100
113
 
101
- @anime_dirs.each { |dir|
114
+ @anime_dirs.each_with_index { |dir, i|
115
+
116
+ avs_file = dir + "/.avs"
117
+
118
+ if File.exist?(avs_file)
119
+ puts "found avs_data" if very_verbose
120
+ avs_data = JSON.parse(File.open(avs_file, "r") { |f| f.read })
121
+ else
122
+ puts "no avs_data" if very_verbose
123
+ avs_data = {}
124
+ end
125
+
102
126
 
103
127
  # check if the directory exists
104
- if not File.exist? dir
105
- if @dir_last_modified[dir] != "check"
128
+ unless File.exist? dir
129
+ unless @dir_last_modified[dir] == "check"
106
130
  @dir_last_modified[dir] = "check"
107
131
  made_changes = true
108
132
  end
109
133
  next
110
134
  end
111
135
 
112
- puts "checking #{dir}" if verbose
136
+ puts "checking #{dir}" if very_verbose
113
137
 
114
138
  # skip indexing a directory if it hasn't been modified since the last
115
139
  # check (disabled because doesn't save to much time)
@@ -129,15 +153,37 @@ module Aniview
129
153
  # get all files in the directory and in all subfolders of the directory
130
154
  files = Dir.glob("#{dir}*/*.{mkv,avi,mp4}") + Dir.glob("#{dir}/*.{mkv,avi,mp4}")
131
155
 
132
- files.each { |file|
133
- print "indexing #{file} -> " if verbose
134
- seen_this = false
156
+ files.each_with_index { |file, j|
157
+ if verbose
158
+ pct = Util.format_progress ((j + 1) / Float(files.length)) * ( (i + 1) / Float(@anime_dirs.length)) * 100
159
+ Util.error_message("#{pct}% #{File.basename(file)}")
160
+ end
161
+
162
+ print "indexing #{file} -> " if very_verbose
163
+ params = {:seen => false, :watched_on => 0}
164
+
165
+ #check if this anime has a stored watched value
166
+ if avs_data.key?(file)
167
+ puts "found stored data for this file" if very_verbose
168
+ params = {
169
+ :seen => avs_data[file]["seen"],
170
+ :watched_on => avs_data[file]["watched_on"]
171
+ }
172
+ puts params if very_verbose
173
+ else
174
+ puts "no data on this file" if very_verbose
175
+ avs_data.merge!({file => params})
176
+ end
135
177
 
136
178
  # we have already indexed this file
137
179
  if @@local_anime != nil and @@local_anime.key?(file)
138
180
 
181
+ puts "this file is in the index" if very_verbose
182
+
139
183
  # get its seen data
140
- seen_this = @@local_anime[file].seen?
184
+ params[:seen] = @@local_anime[file].seen?
185
+ params[:watched_on] = @@local_anime[file].seenOn
186
+ puts params if very_verbose
141
187
  # get its last modifed data
142
188
  last_modified = File::Stat.new(file).mtime
143
189
  # get wether or not it is accessible
@@ -146,7 +192,7 @@ module Aniview
146
192
  # if we arent forcing or the anime hasn't been modified since the
147
193
  # last check, skip it
148
194
  if not force or last_modified == @@local_anime[file].last_modified
149
- puts "unchanged" if verbose
195
+ puts "unchanged" if very_verbose
150
196
  ret.merge!(file => @@local_anime[file])
151
197
  next
152
198
  end
@@ -159,12 +205,15 @@ module Aniview
159
205
 
160
206
  # this is the anime file we are adding
161
207
  ret.merge!(
162
- file => AnimeFile.new(
163
- file,
164
- seen_this
165
- )
208
+ file => AnimeFile.new(file, params)
166
209
  )
167
210
  }
211
+
212
+ mavsf = @pref.get("avs_files")["create?"]
213
+ oimfs = @pref.get("avs_files")["only_on_mounted_fs?"]
214
+ if mavsf and ((oimfs and Util.mounted_filesystem?(dir)) or not oimfs)
215
+ File.open(avs_file, "w") { |f| f.puts JSON.generate(avs_data)}
216
+ end
168
217
  }
169
218
 
170
219
  #if @@local_anime != nil
@@ -184,6 +233,7 @@ module Aniview
184
233
  changed
185
234
  notify_observers
186
235
  end
236
+ #
187
237
  }
188
238
  end
189
239
 
@@ -201,7 +251,7 @@ module Aniview
201
251
  hash = {}
202
252
 
203
253
  arr.sort_by {|i| i.title}.each { |file|
204
- if ! keys.key?(parent file.path)
254
+ unless keys.key?(parent file.path)
205
255
  key = AnimeSeries.new parent(file.path)
206
256
  keys.merge! parent(file.path) => key
207
257
  hash.merge! key => []
@@ -210,7 +260,7 @@ module Aniview
210
260
  end
211
261
 
212
262
  hash[key] << file
213
- key += file
263
+ key << file
214
264
  }
215
265
  hash.sort_by{ |j| j[0].title }.to_h
216
266
  end
@@ -230,10 +280,10 @@ module Aniview
230
280
  f.puts %x(date).chomp + " ./" + File.basename(file) + " " + @watch_log_tag
231
281
  end
232
282
  end
233
-
283
+
234
284
  def addWatched(file)
235
285
  @@local_anime[file].watch
236
- self.save
286
+ save
237
287
  changed
238
288
  notify_observers
239
289
  end
@@ -241,15 +291,14 @@ module Aniview
241
291
  def rmWatched(path = "")
242
292
  if @@local_anime.key? path
243
293
  @@local_anime[path].unwatch
244
- return
294
+ else
295
+ r = []
296
+ @@local_anime.values.each_with_index{ |v, i| r << {Integer(v.seenOn) => @@local_anime.keys[i]} if v.seen? }
297
+ return if r.length == 0
298
+ last_watched = (r.sort_by{ |h| h.keys.first}.reverse)[0].values[0]
299
+ @@local_anime[last_watched].unwatch
245
300
  end
246
-
247
- r = []
248
- @@local_anime.values.each_with_index{ |v, i| r << {Integer(v.seenOn) => @@local_anime.keys[i]} if v.seen? }
249
- return if r.length == 0
250
- last_watched = (r.sort_by{ |h| h.keys.first}.reverse)[0].values[0]
251
- @@local_anime[last_watched].unwatch
252
- self.save
301
+ save
253
302
  changed
254
303
  notify_observers
255
304
  end
@@ -258,6 +307,15 @@ module Aniview
258
307
  @mpvbridge.play file
259
308
  end
260
309
 
310
+ def watch_list(files)
311
+ File.open("/tmp/aniview_list.m3u", "w") { |f|
312
+ files.each { |file|
313
+ f.puts file.path
314
+ }
315
+ }
316
+ @mpvbridge.playlist("/tmp/aniview_list.m3u", files.map { |f| [f.path, f] }.to_h)
317
+ end
318
+
261
319
  end
262
320
  end
263
321
  end
@@ -16,6 +16,9 @@ module Aniview
16
16
  "c" => 0,
17
17
  "d" => 0,
18
18
  "s" => 0,
19
+ "p" => 0,
20
+ "w" => 0,
21
+ "W" => 0
19
22
  }
20
23
 
21
24
  @children = children
@@ -24,10 +27,25 @@ module Aniview
24
27
 
25
28
  def + af
26
29
  @attr["d"] += af.attr["d"]
27
- @attr["D"] = Util.format_duration @attr["d"]
30
+ @attr["D"] = Util.format_duration(@attr["d"])
28
31
  @attr["s"] += af.attr["s"]
29
- @attr["S"] = Util.format_size @attr["s"]
32
+ @attr["S"] = Util.format_size(@attr["s"])
30
33
  @attr["c"] += 1
34
+ @attr["w"] += 1 if af.seen?
35
+ @attr["W"] += af.attr["d"] if af.seen?
36
+ end
37
+
38
+ def << af
39
+ @children << af
40
+ self + af
41
+ average
42
+ end
43
+
44
+ def average
45
+ @attr["p"] = @attr["w"] * 100.0 / @attr["c"]
46
+ @attr["q"] = @attr["d"] > 0 ? @attr["W"] * 100.0 / @attr["d"] : 0
47
+ @attr["Q"] = Util.format_progress @attr["q"]
48
+ @attr["P"] = Util.format_progress @attr["p"]
31
49
  end
32
50
 
33
51
  def title
@@ -11,12 +11,13 @@ module Aniview
11
11
  include Observable
12
12
 
13
13
  attr_accessor :playing
14
+ attr_accessor :playing_file
14
15
  attr_accessor :what_changed
15
16
 
16
17
  def initialize pref
17
18
  @pref = pref
18
19
  @mpv_enabled = true
19
- @logger = Logger.new('mpv.log')
20
+ @logger = Logger.new(@pref.parseDir('$conf_dir/mpv.log'))
20
21
  @logger.level = Logger::DEBUG
21
22
  connect
22
23
  @what_changed = ""
@@ -24,17 +25,25 @@ module Aniview
24
25
  end
25
26
 
26
27
  def event_handler event
27
- case event
28
+ @logger.debug event
29
+ case event["event"]
30
+ #file-loaded
28
31
  when "start-file"
29
32
  @playing = true
30
- @what_changed = "playing_status"
33
+ @what_changed = {:playing_status => :start}
31
34
  changed
32
35
  notify_observers
33
36
  when "end-file"
34
37
  @playing = false
35
- @what_changed = "playing_status"
38
+ @what_changed = {:playing_status => :end}
36
39
  changed
37
40
  notify_observers
41
+ when "property-change"
42
+ case event["name"]
43
+ when "path"
44
+ @playing_file = @playing_files[event["data"]]
45
+ end
46
+ else
38
47
  end
39
48
  end
40
49
 
@@ -50,6 +59,8 @@ module Aniview
50
59
  begin
51
60
  @mpv = MPV::Session.new(user_args: @pref.get("mpv_args").split(" "))
52
61
  @mpv.callbacks << MPV::Callback.new(self, :event_handler)
62
+ @mpv.client.command("observe_property_string", 1, "path")
63
+ #@mpv.client.command("observe_property_string", 1, "playback-abort")
53
64
  rescue MPV::MPVNotAvailableError
54
65
  rescue MPV::MPVUnsupportedFlagError
55
66
  else
@@ -60,11 +71,20 @@ module Aniview
60
71
  def play file
61
72
  return unless @mpv_enabled
62
73
  connect
63
- @playing_file = file
74
+ @playing_files = {file.path => file}
64
75
  @mpv.client.command "loadfile", file.path
65
76
  @playing = true
66
77
  end
67
-
78
+
79
+ def playlist playlist, files
80
+ return unless @mpv_enabled
81
+ connect
82
+ @playing_files = files
83
+ #@playing_file = @playing_files[0]
84
+ @mpv.client.command "loadlist", playlist
85
+ @playing = true
86
+ end
87
+
68
88
  def playing?
69
89
  @playing
70
90
  end
@@ -75,7 +95,7 @@ module Aniview
75
95
  pct = Float(percentage)
76
96
  if pct >= swp and not @playing_file.seen?
77
97
  @playing_file.watch
78
- @what_changed = "local_anime"
98
+ @what_changed = {:local_anime => :watched}
79
99
  changed
80
100
  notify_observers
81
101
  end
@@ -41,14 +41,14 @@
41
41
  },
42
42
  "format_library" :
43
43
  {
44
- "title" : " %t @ %D %S ",
45
- "parent" : " %t - %c@ %D %S ",
46
- "child" : " %t@ %D %S "
44
+ "title" : " %t@ ##%w/##%c #####%Q ########%D #######%S ",
45
+ "parent" : " %t@ ##%w/##%c #####%Q ########%D #######%S ",
46
+ "child" : " %w %t@ ########%D #######%S "
47
47
  },
48
48
  "format_library_unwatched" :
49
49
  {
50
- "title" : " %t@ %D %S ",
51
- "parent" : " %t - %c@ %D %S ",
50
+ "title" : " %t@ ##%w/##%c ########%D #######%S ",
51
+ "parent" : " %t@ ##%w/##%c ########%D #######%S ",
52
52
  "child" : " %t@ %D %S %r "
53
53
  },
54
54
  "format_torrents" :
@@ -89,6 +89,11 @@
89
89
  {
90
90
  "port" : "21312"
91
91
  },
92
+ "avs_files":
93
+ {
94
+ "create?": true,
95
+ "only_on_mounted_fs?": false
96
+ },
92
97
  "set_watched_percentage" : "80",
93
98
  "log_file" : "$conf_dir/aw.log",
94
99
  "daemon_log_file" : "$conf_dir/server.log",
@@ -1,5 +1,6 @@
1
1
  require 'fileutils'
2
2
  require 'json'
3
+ require 'observer'
3
4
 
4
5
  require_relative 'prefitem'
5
6
  require_relative '../../view/color'
@@ -76,6 +77,16 @@ module Aniview
76
77
  ##
77
78
  def set(trail, destination)
78
79
  trail = [trail] if trail.class == String
80
+
81
+ destination = case destination
82
+ when "true"
83
+ true
84
+ when "false"
85
+ false
86
+ else
87
+ destination
88
+ end
89
+
79
90
  return unless valid_preference?(trail, destination)
80
91
 
81
92
  trail[0...-1].inject(@pref, :fetch)[trail.last] = destination
@@ -83,6 +94,14 @@ module Aniview
83
94
  changed
84
95
  notify_observers
85
96
  end
97
+
98
+ def pref_type(trail)
99
+ trail.inject(@validations, :fetch)
100
+ end
101
+
102
+ def get_pref(trail)
103
+ trail.inject(@pref, :fetch)
104
+ end
86
105
 
87
106
  ##
88
107
  ## @brief validates a preference
@@ -96,7 +115,7 @@ module Aniview
96
115
  def valid_preference?(trail, destination)
97
116
  skeys = [ "space", "up", "down", "left", "right", "enter" ]
98
117
 
99
- case trail.inject(@validations, :fetch)
118
+ case pref_type(trail)
100
119
  when "key"
101
120
  destination.length == 1 or skeys.include?(destination)
102
121
  when "path"
@@ -105,6 +124,8 @@ module Aniview
105
124
  Aniview::View::Color.respond_to?(destination)
106
125
  when "int"
107
126
  destination.scan(/\D/).empty? and destination.length > 1
127
+ when "boolean"
128
+ destination.class == TrueClass or destination.class == FalseClass
108
129
  when "locked"
109
130
  false
110
131
  else
@@ -90,6 +90,10 @@
90
90
  {
91
91
  "port" : "int"
92
92
  },
93
+ "avs_files": {
94
+ "create?": "boolean",
95
+ "only_on_mounted_fs?": "boolean"
96
+ },
93
97
  "set_watched_percentage" : "int",
94
98
  "log_file" : "path",
95
99
  "daemon_log_file" : "path",
@@ -50,10 +50,6 @@ module Aniview
50
50
 
51
51
  rescue SocketError
52
52
  @rss = nil
53
-
54
- #rescue
55
- # @rss = nil
56
-
57
53
  end
58
54
  end
59
55
 
@@ -0,0 +1,53 @@
1
+ # watch for changes in a folder's existance
2
+
3
+ module Aniview
4
+ module Util
5
+ module FolderListen
6
+
7
+ def self.to(dirs, &block)
8
+ Listener.new(dirs, &block)
9
+ end
10
+
11
+ ##
12
+ ## @brief Similar to Listen gem but uses polling and is only intended
13
+ ## to be used on a small number of files. the Listen gem
14
+ ## wouldn't support watching an individual FOLDER to see if
15
+ ## the folder went away so this is that!
16
+ ##
17
+ class Listener
18
+ def initialize(dirs, &block)
19
+ @dirs = dirs
20
+ @block = block
21
+ @sleep_duration = 1
22
+ @dir_hash = dir_hash
23
+ end
24
+
25
+ def dir_hash
26
+ @dirs.map { |dir| [dir, File.exist?(dir)]}.to_h
27
+ end
28
+
29
+ def changed?
30
+ @dir_hash != dir_hash
31
+ end
32
+
33
+ def stop
34
+ @listen_thread.exit if @listen_thread
35
+ end
36
+
37
+ def start
38
+ Thread.abort_on_exception = true
39
+ @listen_thread = Thread.new do
40
+ while true
41
+ if changed?
42
+ @block.call
43
+ @dir_hash = dir_hash
44
+ end
45
+ sleep 1
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,6 +1,7 @@
1
1
  module Aniview
2
2
  module Util
3
3
  class Term
4
+
4
5
  def initialize
5
6
  @tput=Hash[
6
7
  "smcup" => %x(tput smcup),
@@ -12,7 +13,7 @@ module Aniview
12
13
  "nobold" => %x(tput sgr0),
13
14
  ]
14
15
  end
15
-
16
+
16
17
  def save; print @tput["smcup"]; return self; end
17
18
  def restore; print @tput["rmcup"]; return self; end
18
19
  def hide_cursor; print @tput["civis"]; return self; end
@@ -23,21 +24,21 @@ module Aniview
23
24
  def clear; print "\033[2J"; return self; end
24
25
  def bold; print @tput["bold"]; return self; end
25
26
  def nobold; print @tput["nobold"]; return self; end
26
-
27
+
27
28
  def cols; return HighLine::SystemExtensions.terminal_size[0]; end
28
29
  def rows; return HighLine::SystemExtensions.terminal_size[1]; end
29
30
 
30
31
  def self.cols; return HighLine::SystemExtensions.terminal_size[0]; end
31
32
  def self.rows; return HighLine::SystemExtensions.terminal_size[1]; end
32
-
33
+
33
34
  def getKey
34
35
  return STDIN.getch.gsub("\r", "enter").gsub(" ", "space").gsub("A", "up").gsub("B", "down").gsub("C", "right").gsub("D", "left").gsub("\e", "skip").gsub("[", "skip")
35
36
  end
36
-
37
+
37
38
  def reset
38
39
  self.restore.show_cursor.echo_on
39
40
  end
40
-
41
+
41
42
  end
42
43
  end
43
44
  end
@@ -9,7 +9,7 @@ module Aniview
9
9
  term.show_cursor
10
10
  Readline.completion_append_character = ""
11
11
  Readline.pre_input_hook = -> do
12
- Readline.insert_text default
12
+ Readline.insert_text "#{default}"
13
13
  Readline.redisplay
14
14
  Readline.pre_input_hook = nil
15
15
  end
@@ -18,9 +18,9 @@ module Aniview
18
18
  return input
19
19
  end
20
20
 
21
- def self.error_message
21
+ def self.error_message(message)
22
22
  #use statusline to show error messages
23
- print "\e[#{Term.rows};2H Message"
23
+ print "\e[#{Term.rows - 1};1H\e[31m #{message}\e[K"
24
24
  end
25
25
 
26
26
  def self.format_duration v
@@ -101,12 +101,12 @@ module Aniview
101
101
  mode = "char"
102
102
 
103
103
  elsif mode == "%"
104
- addstr = ""
105
- addstr = String(d[c]) if d.key?(c)
106
- ol = addstr.length
107
- addstr = " " + addstr while addstr.length < (ol + padding_collected)
104
+ addstr = d.key?(c) ? String(d[c]) : ""
105
+ padding = padding_collected > addstr.length ? " " * (padding_collected - addstr.length) : ""
106
+ addstr = padding + addstr
108
107
  add_to += addstr
109
108
  mode = "char"
109
+ padding_collected = 0
110
110
 
111
111
  else
112
112
  add_to += c
@@ -150,5 +150,18 @@ module Aniview
150
150
  {}
151
151
  end
152
152
  end
153
+
154
+ def self.mounted_filesystem? dir
155
+ %x(mount).split("\n").map { |l|
156
+ mounted = /on (.*?) /.match(l)[1]
157
+ if mounted == "/"
158
+ false
159
+ else
160
+ dir.split("/").zip(mounted.split("/")).reduce(true) { |m,v|
161
+ m and (v[0] == v[1] or v[1] == nil)
162
+ }
163
+ end
164
+ }.reduce { |a,b| a or b}
165
+ end
153
166
  end
154
167
  end
@@ -7,56 +7,62 @@ module Aniview
7
7
  include Aniview::Util
8
8
 
9
9
  def refresh_attributes
10
+ if @items.length > 0
11
+ unformatted_P = sum_attribute("p") / @items.length
12
+ else
13
+ unformatted_P = 0
14
+ end
15
+
16
+ if sum_attribute("d") > 0
17
+ unformatted_Q = sum_attribute("W") * 100.0 / sum_attribute("d")
18
+ else
19
+ unformatted_Q = 0
20
+ end
10
21
  @attributes = {
11
22
  "t" => @attributes["t"],
12
- "D" => Util.format_duration(getDuration),
13
- "S" => Util.format_size(getSize)
23
+ "D" => Util.format_duration(sum_attribute("d")),
24
+ "S" => Util.format_size(sum_attribute("s")),
25
+ "P" => Util.format_progress(unformatted_P),
26
+ "Q" => Util.format_progress(unformatted_Q),
27
+ "c" => sum_attribute("c"),
28
+ "w" => sum_attribute("w")
14
29
  }
15
30
  end
16
-
17
- def getDuration
18
- dur = 0
19
- @items.each{ |p, c| dur += p.attr["d"] }
20
- return dur
21
- end
22
-
23
- def getSize
24
- size = 0
25
- @items.each{ |child|
26
- size += child[0].attributes["s"]
27
- }
28
- return size
29
- end
30
-
31
- def customControl(key, sel)
31
+
32
+ def sum_attribute k
33
+ @items.inject(0) { |mem, c| mem += c[0].attr[k] }
34
+ end
35
+
36
+ def customControl(key, sel)
32
37
  return if @items == {}
33
- path = @items.values[sel["out"]][sel["in"]].path
38
+ path = @items.values[sel["out"]][sel["in"]].path
34
39
 
35
40
  empty = path == "empty"
36
41
 
37
- if key == @pref.get("keybindings")["menu_nav_expand"]
38
- expand(sel["out"])
39
- elsif key == "r"
40
- refresh
41
- elsif key == "enter" and not empty
42
-
43
- @interface.watch(@items.values[sel["out"]][sel["in"]])
44
-
45
- @interface.logWatched(path)
46
-
47
- refresh
48
- elsif key == @pref.get("keybindings")["anime_set_watched"] and not empty
49
- @interface.addWatched(path)
50
- elsif key == @pref.get("keybindings")["anime_undo_set_watched"]
51
- @interface.rmWatched()
52
- elsif key == @pref.get("keybindings")["anime_set_unwatched"] and not empty
53
- @interface.rmWatched(path)
54
- moveCursor("down")
55
- end
42
+ if key == @pref.get("keybindings")["menu_nav_expand"]
43
+ expand(sel["out"])
44
+ elsif key == "r"
45
+ refresh
46
+ elsif key == "enter" and not empty
47
+
48
+ if sel["in_expanded"]
49
+ @interface.watch(@items.values[sel["out"]][sel["in"]])
50
+ @interface.logWatched(path)
51
+ else
52
+ @interface.watch_list(@items.values[sel["out"]])
53
+ end
54
+ elsif key == @pref.get("keybindings")["anime_set_watched"] and not empty
55
+ @interface.addWatched(path)
56
+ elsif key == @pref.get("keybindings")["anime_undo_set_watched"]
57
+ @interface.rmWatched
58
+ elsif key == @pref.get("keybindings")["anime_set_unwatched"] and not empty
59
+ @interface.rmWatched(path)
60
+ moveCursor("down")
61
+ end
56
62
 
57
63
  changed
58
64
  notify_observers
59
- end
65
+ end
60
66
  end
61
67
  end
62
68
  end
@@ -9,18 +9,17 @@ module Aniview
9
9
  include Aniview::Util
10
10
  include Observable
11
11
 
12
- attr_accessor :visible
12
+ attr_accessor :attributes
13
+ attr_accessor :format
13
14
 
14
15
  def initialize(refresh_function: :items, interface:, name:, pref:, format:, term:, children: true, visible: false, logger: nil)
15
16
  @attributes = {}
16
17
 
17
18
  @logger = logger
18
19
 
19
- @visible = visible
20
-
21
20
  @refresh_function = refresh_function
22
21
  @interface = interface
23
- setName name
22
+ @attributes["t"] = name
24
23
  @pref = pref
25
24
  @format = format
26
25
  @term = term
@@ -65,7 +64,7 @@ module Aniview
65
64
  refresh
66
65
  changed
67
66
  notify_observers
68
- sleep 0.07
67
+ sleep 1
69
68
  end
70
69
  end
71
70
  when :stop
@@ -73,7 +72,7 @@ module Aniview
73
72
  end
74
73
  end
75
74
 
76
- def setRfunc(new_method)
75
+ def rfunc=(new_method)
77
76
  @refresh_function = new_method
78
77
  @items_formatted = {}
79
78
  @items_hash = {}
@@ -100,15 +99,7 @@ module Aniview
100
99
  adjustView
101
100
  draw if redraw
102
101
  end
103
-
104
- def setName(name)
105
- @attributes["t"] = name
106
- end
107
-
108
- def setFormat(format_)
109
- @format = format_
110
- end
111
-
102
+
112
103
  def refresh
113
104
  @items = @interface.send(@refresh_function)
114
105
  refreshFormats
@@ -11,8 +11,13 @@ module Aniview
11
11
  title = @items[sel["out"]].attributes["t"]
12
12
  value = @items[sel["out"]].attributes["v"]
13
13
  if key == "enter"
14
- newval = Util.readline(@term, title + ":", value)
15
- @interface.set(path, newval)
14
+ case @interface.pref_type(path)
15
+ when "boolean"
16
+ @interface.set(path, (not @interface.get_pref(path)))
17
+ else
18
+ newval = Util.readline(@term, title + ":", value)
19
+ @interface.set(path, newval)
20
+ end
16
21
  refresh
17
22
  end
18
23
  end
@@ -75,11 +75,10 @@ module Aniview
75
75
 
76
76
  @aiomenu = View::AioMenu.new(
77
77
  interface: @aio,
78
- name: @pref.get("menu_titles")["unwatched"],
78
+ name: @pref.get("menu_titles")["library"],
79
79
  pref: @pref,
80
- format: "format_library_unwatched",
80
+ format: "format_library",
81
81
  term: @term,
82
- refresh_function: :unwatched,
83
82
  logger: @logger
84
83
  )
85
84
  @prefmenu = View::PrefMenu.new(
@@ -172,24 +171,28 @@ module Aniview
172
171
  #
173
172
  # @return nil
174
173
  #
175
- def changeView newView
174
+ def change_view(view:, rfunc: :items, format:nil, name:nil)
176
175
  @view.delete_observers
177
176
  @view.pause
178
- newView.unpause
179
- newView.add_observer(self, :drawview)
180
- newView.change_screen_size redraw: false
181
- newView.expand -1
182
- @view = newView
177
+ view.attributes["t"] = name if name
178
+ view.format = format if format
179
+ view.rfunc = rfunc
180
+ view.add_observer(self, :drawview)
181
+ view.change_screen_size redraw: false
182
+ view.expand -1
183
+ view.unpause
184
+ @view = view
183
185
  end
184
186
 
185
187
  def drawview
186
188
  @view.draw
189
+ @statusline.draw
187
190
  @rcount ||= 0
188
191
  #puts "refreshed view #{@rcount+=1}"
189
192
  end
190
193
 
191
194
  def togglestatusline
192
- return unless @mpvbridge.what_changed == "playing_status"
195
+ return unless @mpvbridge.what_changed[:playing_status]
193
196
  unless @statusthread
194
197
  @statusthread = Thread.new do
195
198
  while true
@@ -218,13 +221,23 @@ module Aniview
218
221
  # @return nil
219
222
  #
220
223
  def run
224
+ nm = @pref.get("menu_titles")
225
+ views = {
226
+ :unwatched => {view: @aiomenu, name: nm["unwatched"], format: "format_library_unwatched", rfunc: :unwatched},
227
+ :library => {view: @aiomenu, name: nm["library"], format: "format_library"},
228
+ :torrents => {view: @delugemenu},
229
+ :preferences => {view: @prefmenu},
230
+ :schedule => {view: @schedulemenu},
231
+ :subscription => {view: @subscriptionmenu}
232
+ }
221
233
 
222
- @view = @aiomenu
234
+ current_view = 0
235
+ @view = @aiomenu
236
+
223
237
  @view.add_observer(self, :drawview)
224
- @statusline.draw
225
-
226
238
  @mpvbridge.add_observer(self, :togglestatusline)
227
239
  @statusline.add_observer(self, :drawmessage)
240
+ @statusline.draw
228
241
 
229
242
  mutex = Mutex.new
230
243
  Signal.trap('SIGWINCH', proc {
@@ -243,31 +256,34 @@ module Aniview
243
256
  @shoulddraw = false
244
257
 
245
258
  kb = @pref.get("keybindings")
246
- nm = @pref.get("menu_titles")
247
259
 
248
260
  case key
249
261
  when kb["goto_unwatched"]
250
- changeView @aiomenu
251
- @view.setName nm["unwatched"]
252
- @view.setFormat("format_library_unwatched")
253
- @view.setRfunc(:unwatched)
262
+ change_view(views[:unwatched])
263
+ current_view = 0
254
264
  when kb["goto_library"]
255
- changeView @aiomenu
256
- @view.setName nm["library"]
257
- @view.setFormat("format_library")
258
- @view.setRfunc(:items)
265
+ change_view(views[:library])
266
+ current_view = 1
259
267
  when kb["goto_torrents"]
260
- changeView @delugemenu
261
- @view.setName nm["torrents"]
268
+ change_view(views[:torrents])
269
+ current_view = 2
262
270
  when kb["goto_preferences"]
263
- changeView @prefmenu
264
- @view.setName nm["preferences"]
271
+ change_view(views[:preferences ])
272
+ current_view = 5
265
273
  when kb["goto_schedule"]
266
- changeView @schedulemenu
267
- @view.setName nm["schedule"]
274
+ change_view(views[:schedule])
275
+ current_view = 3
268
276
  when kb["goto_subscriptions"]
269
- changeView @subscriptionmenu
270
- @view.setName nm["subscriptions"]
277
+ change_view(views[:subscription])
278
+ current_view = 4
279
+ when "right"
280
+ current_view += 1
281
+ current_view = views.length - 1 if current_view >= views.length
282
+ change_view(views.values[current_view])
283
+ when "left"
284
+ current_view -= 1
285
+ current_view = 0 if current_view < 0
286
+ change_view(views.values[current_view])
271
287
  when ":"
272
288
  @view.pause
273
289
  if @statusthread
@@ -282,6 +298,7 @@ module Aniview
282
298
  end
283
299
  @view.control(key)
284
300
  end
301
+
285
302
  end
286
303
  end
287
304
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aniview
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - annacrombie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-25 00:00:00.000000000 Z
11
+ date: 2017-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: streamio-ffmpeg
@@ -156,6 +156,7 @@ files:
156
156
  - "./lib/aniview/interface/schedule/scheduleitem.rb"
157
157
  - "./lib/aniview/interface/subscription/subscription.rb"
158
158
  - "./lib/aniview/util/error.rb"
159
+ - "./lib/aniview/util/folder_listen.rb"
159
160
  - "./lib/aniview/util/term.rb"
160
161
  - "./lib/aniview/util/util.rb"
161
162
  - "./lib/aniview/view/aiomenu.rb"