aniview 2.1.2 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6824d7f28e7bebe026f0081c09d7442e99d50e64
4
- data.tar.gz: e645a210dcd58f0d039430e64ffd9b9254a4cbe0
3
+ metadata.gz: 4b35aefbae5c33c60dd90e34e39ba25538fb537d
4
+ data.tar.gz: f930e37c98cab765b2baaf880e1631e9b8cee308
5
5
  SHA512:
6
- metadata.gz: dad87f8040707a9718894b85f4ab715b20d38947a3c6007a61b8bdbfe4718c430ce13ec80c5d54398a58fa5813927d88547509b4e43f6c0bc1feb468429b0434
7
- data.tar.gz: 865b2b9710b445419ae625aa8ad9b95703ea1e9edecd148e5b55df6fc95e5848cb110ca56e231c496371c5704a25b4fdb140961b1cdf1950b0e8db2bd763d874
6
+ metadata.gz: 0cb7100a4503b321ebac1a28582d856fc2b536fbae03ffa7dbc3d9bcacb5d5506e3ba8f75871822f749695afff13c9249bee1fc6bdb309c2d0265e366e49cace
7
+ data.tar.gz: def2061bba9ae07a58886a26a0f8d468632d98623c1d13be405f895651be834e4d737aebc7df084fcf79b5bd44ac274012c264f35bdad467c245078b4428597c
data/bin/aniview CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  begin
4
- require 'aniview'
4
+ require 'aniview'
5
5
  rescue LoadError
6
- require_relative '../lib/aniview' if File.exist?(File.join(File.dirname(__FILE__), '../lib/aniview.rb'))
6
+ require_relative '../lib/aniview' if File.exist?(File.join(File.dirname(__FILE__), '../lib/aniview.rb'))
7
7
  end
8
8
 
9
9
  unless defined? Aniview
10
- puts "cant find aniview library"
11
- exit
10
+ puts "cant find aniview library"
11
+ exit
12
12
  end
13
13
 
14
14
  Aniview::main(ARGV)
data/lib/aniview.rb CHANGED
@@ -32,6 +32,7 @@ module Aniview
32
32
  case arg
33
33
  when "-d"
34
34
  argv.delete_at(0)
35
+ daemonize = true
35
36
  main_class = Aniview::Daemon.new(argv)
36
37
  when "-h"
37
38
  self.show_help
@@ -49,7 +50,6 @@ module Aniview
49
50
  process = fork do
50
51
  main_class.run
51
52
  end
52
-
53
53
  Process.detach(process)
54
54
  else
55
55
  main_class.run
@@ -11,17 +11,19 @@ module Aniview
11
11
  include Aniview::Util
12
12
 
13
13
  attr_accessor :last_modified
14
+ attr_accessor :accessible
14
15
  attr_accessor :path
15
16
 
16
17
  def initialize(path_, seen = false)
17
- @watched = seen
18
+ @watched = seen
19
+ @accessible = true
18
20
  begin
19
21
  @last_modified = File::Stat.new(path_).mtime
20
22
  rescue Errno::ENOENT
21
23
  @last_modified = "0"
22
24
  end
23
25
  @watched_on = 0
24
- @path = path_
26
+ @path = path_
25
27
 
26
28
  @attr = {
27
29
  "t" => "empty",
@@ -1,212 +1,263 @@
1
1
  require 'mkmf'
2
2
  require 'fileutils'
3
+ require 'observer'
4
+ require 'listen'
5
+ require 'benchmark'
6
+
3
7
  require_relative 'animefile'
4
8
  require_relative 'animeseries'
5
9
  require_relative '../../util/util'
10
+ require_relative '../bridge'
6
11
 
7
12
  module Aniview
8
13
  module Interface
9
- include Aniview::Util
10
- class AnimeIO
11
- def initialize(pref, mpvbridge)
14
+
15
+ class AnimeIO < Bridge
16
+
17
+ include Aniview::Util
18
+
19
+ include Observable
20
+
21
+ def initialize(pref, mpvbridge)
12
22
  @pref = pref
13
23
  @mpvbridge = mpvbridge
14
24
  @empty_hash = make_empty_hash
15
25
  @watch_log_tag = "♪"
16
26
  @dir_last_modified = {}
17
-
18
- self.load
19
- index_anime
20
- end
27
+ @made_changes = true
28
+
29
+ self.load
30
+ pref_changed!
31
+ relisten
32
+
33
+ @pref.add_observer(self, :pref_changed!)
34
+ @mpvbridge.add_observer(self, :animefile_changed!)
35
+ #@@local_anime.each { |key, obj| obj.add_observer(self, :animefile_changed!)}
36
+ end
37
+
38
+ 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
44
+ @listener.start
45
+ end
46
+
47
+ def cleanup
48
+ @listener.stop unless @listener == nil
49
+ end
21
50
 
22
51
  def make_empty_hash
23
52
  af = AnimeFile.new("empty")
24
53
  {AnimeSeries.new("empty", [af]) => [af]}
25
54
  end
26
55
 
27
- def save
28
- @pref.set "local_anime", Util.encode_object(@@local_anime)
29
- end
30
-
31
- def load
32
- raw = @pref.get "local_anime"
33
- if not raw == nil and raw.class == String
34
- @@local_anime = Util.decode_object raw
35
- else
36
- @@local_anime = {}
37
- end
38
- end
56
+ def save
57
+ @pref.set "local_anime", Util.encode_object(@@local_anime)
58
+ end
59
+
60
+ def load
61
+ raw = @pref.get "local_anime"
62
+ if not raw == nil and raw.class == String
63
+ @@local_anime = Util.decode_object raw
64
+ else
65
+ @@local_anime = {}
66
+ end
67
+ end
68
+
69
+ def pref_changed!
70
+ new_dirs = (@pref.get("anime_locations").split(":")).collect { |dir|
71
+ @pref.parseDir(dir)
72
+ }
73
+ if new_dirs != @anime_dirs
74
+ @anime_dirs = new_dirs
75
+ index_anime
76
+ relisten
77
+ end
78
+ end
79
+
80
+ def animefile_changed!
81
+ return unless @mpvbridge.what_changed == "local_anime"
82
+ changed
83
+ notify_observers
84
+ end
39
85
 
40
- def index_anime(force: false, verbose: false)
41
- ret = {}
42
- made_changes = false
43
86
 
44
- (@pref.get("anime_locations").split(":")).each { |dir|
45
-
46
- dir = @pref.parseDir dir
47
- dir += "/" if dir[-1] != "/"
87
+ ##
88
+ ## @brief Indexes anime files up to 1 level deep in specified anime directories
89
+ ##
90
+ ## @param force The force
91
+ ## @param verbose The verbose
92
+ ##
93
+ ## @return { description_of_the_return_value }
94
+ ##
95
+ def index_anime(force: false, verbose: false)
96
+ Thread.new {
97
+ ret = {}
98
+ made_changes = false
99
+ lal = @@local_anime.length
48
100
 
49
- dir_mtime = File::Stat.new(dir).mtime
101
+ @anime_dirs.each { |dir|
50
102
 
51
- if @dir_last_modified.key? dir
52
- if @dir_last_modified[dir] == dir_mtime
53
- #puts "skipping"
103
+ # check if the directory exists
104
+ if not File.exist? dir
105
+ if @dir_last_modified[dir] != "check"
106
+ @dir_last_modified[dir] = "check"
107
+ made_changes = true
108
+ end
54
109
  next
55
- else
56
- @dir_last_modified[dir] = dir_mtime
57
110
  end
58
- else
59
- @dir_last_modified.merge!(dir => dir_mtime)
60
- end
61
111
 
62
- files = Dir.glob("#{dir}*/*.{mkv,avi,mp4}") + Dir.glob("#{dir}/*.{mkv,avi,mp4}")
63
-
64
- files.each { |file|
65
- puts "indexing #{file}" if verbose
66
- seen_this = false
67
- if @@local_anime != nil and @@local_anime.key?(file)
68
- seen_this = @@local_anime[file].seen?
69
-
70
- last_modified = File::Stat.new(file).mtime
71
-
72
- if not force or last_modified == @@local_anime[file].last_modified
73
- ret.merge!(file => @@local_anime[file])
74
- next
75
- end
76
- end
77
- made_changes = true
78
- ret.merge!(
79
- file => AnimeFile.new(
80
- file,
81
- seen_this
82
- )
83
- )
84
- }
85
- }
86
- if @@local_anime != nil
87
- @@local_anime.merge!(ret)
88
- else
89
- @@local_anime = ret
90
- end
91
-
92
- pruned = {}
93
- @@local_anime.each{ |a|
94
- pruned.merge!(a[0] => a[1]) if File.exist? a[1].path
95
- }
96
- @@local_anime = pruned
97
- puts "made changes" if made_changes
98
- self.save if made_changes
99
- end
100
-
101
- #returns the parent directory of a file
102
- def parent(file)
103
- return File.basename(File.dirname(file))
104
- end
105
-
106
- #convert an AnimeFile array to a hash structured like
107
- #(string)parent => (AnimeFile array)[child0, child1, child2] and return it
108
- def makeHash(arr)
109
- return @empty_hash if arr[0] == nil
110
- ret = {}
111
- subarray = []
112
-
113
-
114
- sarr = arr.sort_by {|s| s.path}
115
- last_parent = parent sarr[0].path
116
-
117
- (sarr).each { |animefile|
118
-
119
- this_parent = parent animefile.path
120
-
121
- if this_parent != last_parent
122
- sorted_subarray = subarray.sort_by { |a| a.title }
123
- ret.merge!(
124
- AnimeSeries.new(
125
- last_parent,
126
- sorted_subarray
127
- ) => sorted_subarray)
128
- subarray = [animefile]
129
- else
130
- subarray << animefile
131
- end
132
-
133
- last_parent = this_parent
134
-
135
- }
136
-
137
- sorted_subarray = subarray.sort_by { |a| a.title }
138
- ret.merge!(
139
- AnimeSeries.new(
140
- parent(sarr[sarr.length - 1].path),
141
- sorted_subarray
142
- ) => sorted_subarray
143
- )
144
- return Hash[ret.sort_by{ |a| a[0].title}]
145
- end
146
-
147
- #return the difference of getAired and getWatched
148
- def getUnwatched
149
- index_anime
150
- ret = []
151
- #puts @@local_anime
152
- @@local_anime.each{ |anime|
153
- ret << anime[1] if not anime[1].seen?
154
- }
155
- return ret
156
- end
157
-
158
- #return an AnimeFile array of all mkvs in any dir specified in $pref["dirs"]
159
- def getAll
160
- index_anime
161
- return @@local_anime.values
162
- end
163
-
164
- def getAllSeries
165
- arr = getAll
112
+ puts "checking #{dir}" if verbose
113
+
114
+ # skip indexing a directory if it hasn't been modified since the last
115
+ # check (disabled because doesn't save to much time)
116
+ #
117
+ #dir_mtime = File::Stat.new(dir).mtime
118
+ #
119
+ #if @dir_last_modified.key? dir
120
+ # if @dir_last_modified[dir] == dir_mtime
121
+ # next
122
+ # else
123
+ # @dir_last_modified[dir] = dir_mtime
124
+ # end
125
+ #else
126
+ # @dir_last_modified.merge!(dir => dir_mtime)
127
+ #end
128
+
129
+ # get all files in the directory and in all subfolders of the directory
130
+ files = Dir.glob("#{dir}*/*.{mkv,avi,mp4}") + Dir.glob("#{dir}/*.{mkv,avi,mp4}")
131
+
132
+ files.each { |file|
133
+ print "indexing #{file} -> " if verbose
134
+ seen_this = false
135
+
136
+ # we have already indexed this file
137
+ if @@local_anime != nil and @@local_anime.key?(file)
138
+
139
+ # get its seen data
140
+ seen_this = @@local_anime[file].seen?
141
+ # get its last modifed data
142
+ last_modified = File::Stat.new(file).mtime
143
+ # get wether or not it is accessible
144
+ @@local_anime[file].accessible = true
145
+
146
+ # if we arent forcing or the anime hasn't been modified since the
147
+ # last check, skip it
148
+ if not force or last_modified == @@local_anime[file].last_modified
149
+ puts "unchanged" if verbose
150
+ ret.merge!(file => @@local_anime[file])
151
+ next
152
+ end
153
+ end
154
+
155
+ #puts "changed!"
156
+
157
+ # okay we are making changes to local_anime
158
+ made_changes = true
159
+
160
+ # this is the anime file we are adding
161
+ ret.merge!(
162
+ file => AnimeFile.new(
163
+ file,
164
+ seen_this
165
+ )
166
+ )
167
+ }
168
+ }
169
+
170
+ #if @@local_anime != nil
171
+ # @@local_anime.merge!(ret)
172
+ #else
173
+ @@local_anime = ret
174
+ #end
175
+
176
+ #pruned = {}
177
+ #@@local_anime.each{ |a|
178
+ # pruned.merge!(a[0] => a[1]) if File.exist? a[1].path
179
+ #}
180
+ #@@local_anime = pruned
181
+ made_changes = true if @@local_anime.length != lal
182
+ if @made_changes
183
+ self.save
184
+ changed
185
+ notify_observers
186
+ end
187
+ }
188
+ end
166
189
 
167
- last_parent = parent arr[0].path
168
- ret = [ last_parent ]
190
+ #returns the parent directory of a file
191
+ def parent(file)
192
+ return File.basename(File.dirname(file))
193
+ end
169
194
 
170
- arr.each { |animefile|
171
- this_parent = parent animefile.path
172
- if this_parent != last_parent
173
- ret << this_parent
174
- end
175
- last_parent = this_parent
176
- }
177
- return ret
178
- end
195
+ #convert an AnimeFile array to a hash structured like
196
+ #(string)parent => (AnimeFile array)[child0, child1, child2] and return it
197
+ def makeHash arr
198
+ #return @empty_hash if arr[0] == nil
199
+
200
+ keys = {}
201
+ hash = {}
202
+
203
+ arr.sort_by {|i| i.title}.each { |file|
204
+ if ! keys.key?(parent file.path)
205
+ key = AnimeSeries.new parent(file.path)
206
+ keys.merge! parent(file.path) => key
207
+ hash.merge! key => []
208
+ else
209
+ key = keys[parent file.path]
210
+ end
211
+
212
+ hash[key] << file
213
+ key += file
214
+ }
215
+ hash.sort_by{ |j| j[0].title }.to_h
216
+ end
179
217
 
180
- def logWatched(file)
181
- open(@pref.parseDir(@pref.get("watch_log")), 'a') do |f|
182
- f.puts %x(date).chomp + " ./" + File.basename(file) + " " + @watch_log_tag
183
- end
184
- end
218
+ #return the difference of getAired and getWatched
219
+ def unwatched
220
+ makeHash @@local_anime.reject { |f, a| a.seen? }.values
221
+ end
185
222
 
186
- def addWatched(file)
187
- @@local_anime[file].watch
188
- self.save
189
- end
223
+ #return an AnimeFile array of all mkvs in any dir specified in $pref["dirs"]
224
+ def items
225
+ makeHash @@local_anime.values
226
+ end
190
227
 
191
- def rmWatched(path = "zoz")
228
+ def logWatched(file)
229
+ open(@pref.parseDir(@pref.get("watch_log")), 'a') do |f|
230
+ f.puts %x(date).chomp + " ./" + File.basename(file) + " " + @watch_log_tag
231
+ end
232
+ end
192
233
 
193
- if @@local_anime.key? path
194
- @@local_anime[path].unwatch
195
- return
196
- end
234
+ def addWatched(file)
235
+ @@local_anime[file].watch
236
+ self.save
237
+ changed
238
+ notify_observers
239
+ end
197
240
 
198
- r = []
199
- @@local_anime.values.each_with_index{ |v, i| r << {Integer(v.seenOn) => @@local_anime.keys[i]} if v.seen? }
200
- return if r.length == 0
201
- last_watched = (r.sort_by{ |h| h.keys.first}.reverse)[0].values[0]
202
- @@local_anime[last_watched].unwatch
203
- self.save
204
- end
241
+ def rmWatched(path = "")
242
+ if @@local_anime.key? path
243
+ @@local_anime[path].unwatch
244
+ return
245
+ end
205
246
 
206
- #run mpv
207
- def watch(file)
208
- @mpvbridge.play file
209
- end
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
253
+ changed
254
+ notify_observers
255
+ end
256
+
257
+ def watch(file)
258
+ @mpvbridge.play file
259
+ end
260
+
210
261
  end
211
262
  end
212
263
  end