aniview 3.2.1 → 5.1.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -9
  3. data/bin/aniview +17 -9
  4. data/config/view.yml +3 -0
  5. data/lib/aniview.rb +1 -60
  6. data/modules/animeio/README.md +2 -0
  7. data/modules/animeio/config/daemon.yml +4 -0
  8. data/modules/animeio/config/view.yml +22 -0
  9. data/modules/animeio/lib/animeio.rb +24 -0
  10. data/modules/animeio/lib/animeio/anime_indexer.rb +99 -0
  11. data/modules/animeio/lib/animeio/animefile.rb +91 -0
  12. data/modules/animeio/lib/animeio/animeio.rb +175 -0
  13. data/modules/animeio/lib/animeio/animeio_view.rb +41 -0
  14. data/modules/animeio/lib/animeio/animeseries.rb +61 -0
  15. data/modules/mpv/README.md +2 -0
  16. data/modules/mpv/config/daemon.yml +2 -0
  17. data/modules/mpv/lib/mpv.rb +27 -0
  18. data/modules/mpv/lib/mpv/filename_widget.rb +16 -0
  19. data/modules/mpv/lib/mpv/mpv_controller.rb +85 -0
  20. data/modules/mpv/lib/mpv/time_widget.rb +29 -0
  21. metadata +33 -107
  22. data/lib/aniview/client/aniclient.rb +0 -118
  23. data/lib/aniview/interface/animeio/animefile.rb +0 -93
  24. data/lib/aniview/interface/animeio/animeio.rb +0 -321
  25. data/lib/aniview/interface/animeio/animeseries.rb +0 -60
  26. data/lib/aniview/interface/bridge.rb +0 -11
  27. data/lib/aniview/interface/deluge/delugec.rb +0 -172
  28. data/lib/aniview/interface/deluge/torrentitem.rb +0 -24
  29. data/lib/aniview/interface/item.rb +0 -24
  30. data/lib/aniview/interface/mpv/mpvbridge.rb +0 -149
  31. data/lib/aniview/interface/pref/defaults.json +0 -105
  32. data/lib/aniview/interface/pref/pref.rb +0 -209
  33. data/lib/aniview/interface/pref/prefitem.rb +0 -19
  34. data/lib/aniview/interface/pref/validate.json +0 -105
  35. data/lib/aniview/interface/schedule/schedule.rb +0 -99
  36. data/lib/aniview/interface/schedule/scheduleitem.rb +0 -59
  37. data/lib/aniview/interface/subscription/subscription.rb +0 -123
  38. data/lib/aniview/util/error.rb +0 -9
  39. data/lib/aniview/util/folder_listen.rb +0 -53
  40. data/lib/aniview/util/term.rb +0 -44
  41. data/lib/aniview/util/util.rb +0 -167
  42. data/lib/aniview/view/aiomenu.rb +0 -69
  43. data/lib/aniview/view/color.rb +0 -69
  44. data/lib/aniview/view/delugemenu.rb +0 -38
  45. data/lib/aniview/view/menu.rb +0 -325
  46. data/lib/aniview/view/prefmenu.rb +0 -26
  47. data/lib/aniview/view/schedulemenu.rb +0 -28
  48. data/lib/aniview/view/statusline.rb +0 -60
  49. data/lib/aniview/view/subscriptionmenu.rb +0 -37
  50. data/lib/application.rb +0 -306
  51. data/lib/daemon.rb +0 -188
@@ -1,118 +0,0 @@
1
- require 'socket'
2
- require_relative '../util/util'
3
-
4
-
5
- module Aniview
6
- module Client
7
- class AniClient
8
- include Aniview::Util
9
-
10
- # initializes a new AniClient @
11
- #
12
- # @param pref see preferences
13
- #
14
- # @return nil
15
- #
16
- def initialize(pref)
17
- @pref = pref
18
- end
19
-
20
- # connects to aniview daemon
21
- #
22
- # @return [TCPSocket, false] false if unsuccessful
23
- #
24
- def connect
25
- begin
26
- TCPSocket.new 'localhost', @pref.get("daemon")["port"]
27
- rescue Errno::ECONNREFUSED
28
- return false
29
- end
30
- end
31
-
32
- # sends message to aniview daemon
33
- #
34
- # @param msg the message to send
35
- #
36
- # @return the daemons response, or "" if there is an error. If the
37
- # daemon is offline, "offline" is returned
38
- #
39
- def sendMsg msg
40
- begin
41
- s = connect
42
- return "offline" if s == false
43
- s.puts msg
44
- r = s.gets.chomp
45
- s.close
46
- return r
47
- rescue Errno::ECONNRESET
48
- return ""
49
- end
50
- end
51
-
52
- # sends the message "quit" to the daemon
53
- #
54
- # see #sendMsg
55
- #
56
- # @return "okay"
57
- #
58
- def stopDaemon
59
- sendMsg "quit"
60
- end
61
-
62
- # sends the message "info" to the daemon
63
- #
64
- # see #sendMsg
65
- #
66
- # @return daemon info string including uptime and number of loops and
67
- # matches
68
- #
69
- def info
70
- sendMsg "info"
71
- end
72
-
73
- # sends the message "lastchecked" to the daemon
74
- #
75
- # see #sendMsg
76
- #
77
- # @return string of the last time the daemon checked the rss feed for
78
- # new matches
79
- #
80
- def lastchecked
81
- sendMsg "lastchecked"
82
- end
83
-
84
- # sends the message "items" to the daemon and decodes the serialized
85
- # object using Util.decode_object
86
- #
87
- # see #sendMsg
88
- #
89
- # @return The items.
90
- #
91
- def getItems
92
- Util.decode_object(sendMsg "items")
93
- end
94
-
95
- # sends the message "itemshash" to the daemon
96
- #
97
- # see #sendMsg
98
- #
99
- # @return item.cereal of all items
100
- #
101
- def getAllCereal
102
- sendMsg "itemshash"
103
- end
104
-
105
- # checks if the server is online (sends message "up?" to the daemon)
106
- #
107
- # see #sendMsg
108
- #
109
- # @return [true, false]
110
- #
111
- def server?
112
- return false unless sendMsg("up?") == "true"
113
- return true
114
- end
115
-
116
- end
117
- end
118
- end
@@ -1,93 +0,0 @@
1
- require 'streamio-ffmpeg'
2
- require 'date'
3
-
4
- require_relative '../../util/util'
5
- require_relative '../item'
6
-
7
- module Aniview
8
- module Interface
9
- class AnimeFile < Item
10
-
11
- include Aniview::Util
12
-
13
- attr_accessor :last_modified
14
- attr_accessor :accessible
15
- attr_accessor :path
16
-
17
- def initialize(path_, seen: false, watched_on: 0)
18
- @watched = seen
19
- @accessible = true
20
- begin
21
- @last_modified = File::Stat.new(path_).mtime
22
- rescue Errno::ENOENT
23
- @last_modified = "0"
24
- end
25
- @watched_on = watched_on
26
- @path = path_
27
-
28
- @attr = {
29
- "t" => "empty",
30
- "d" => 0,
31
- "D" => "0",
32
- "s" => 0,
33
- "S" => "0",
34
- "r" => 0x0,
35
- "a" => "n.a.",
36
- "v" => "",
37
- "l" => "",
38
- "f" => "",
39
- "b" => "",
40
- "w" => seen? ? "x" : " "
41
- }
42
-
43
- if (@path == "empty")
44
- else
45
- mov = FFMPEG::Movie.new(@path)
46
-
47
- @attr = {
48
- "t" => self.string,
49
- "d" => mov.duration,
50
- "D" => Util.format_duration(mov.duration),
51
- "s" => mov.size,
52
- "S" => Util.format_size(mov.size),
53
- "r" => mov.resolution,
54
- "a" => mov.audio_codec,
55
- "v" => mov.video_codec,
56
- "l" => mov.colorspace,
57
- "f" => mov.frame_rate,
58
- "b" => String(mov.bitrate) + "kb/s",
59
- "w" => seen? ? "x" : " "
60
- }
61
- end
62
- end
63
-
64
- def title
65
- return @attr["t"]
66
- end
67
-
68
- def seen?
69
- return @watched
70
- end
71
-
72
- def seenOn
73
- return @watched_on
74
- end
75
-
76
- def watch
77
- @watched = true
78
- @watched_on = DateTime.now.strftime('%Q')
79
- @attr["w"] = "x"
80
- end
81
-
82
- def unwatch
83
- @watched = false
84
- @attr["w"] = " "
85
- end
86
-
87
- def string
88
- return (File.basename("#{@path}").gsub(/\s*\[.+?\]\s*/) {}).gsub(/(\.mkv)|(\.avi)|(\.mp4)/, "").gsub("_", " ").gsub(/\s*\(.+?\)\s*/) {}
89
- end
90
-
91
- end
92
- end
93
- end
@@ -1,321 +0,0 @@
1
- require 'mkmf'
2
- require 'fileutils'
3
- require 'observer'
4
- require 'listen'
5
- require 'benchmark'
6
-
7
- require_relative 'animefile'
8
- require_relative 'animeseries'
9
- require_relative '../../util/util'
10
- require_relative '../../util/folder_listen'
11
- require_relative '../bridge'
12
-
13
- module Aniview
14
- module Interface
15
-
16
- class AnimeIO < Bridge
17
-
18
- include Aniview::Util
19
-
20
- include Observable
21
-
22
- def initialize(pref, mpvbridge)
23
- @pref = pref
24
- @mpvbridge = mpvbridge
25
- @empty_hash = make_empty_hash
26
- @watch_log_tag = "♪"
27
- @dir_last_modified = {}
28
- @made_changes = true
29
-
30
- self.load
31
- pref_changed!(verbose: false)
32
- #relisten
33
-
34
- @pref.add_observer(self, :pref_changed!)
35
- @mpvbridge.add_observer(self, :animefile_changed!)
36
- #@@local_anime.each { |key, obj| obj.add_observer(self, :animefile_changed!)}
37
- end
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
-
46
- def relisten
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 }
54
- @listener.start
55
- end
56
-
57
- def cleanup
58
- @folder_listener.stop unless @folder_listener == nil
59
- @listener.stop unless @listener == nil
60
- end
61
-
62
- def make_empty_hash
63
- af = AnimeFile.new("empty")
64
- {AnimeSeries.new("empty", [af]) => [af]}
65
- end
66
-
67
- def save
68
- @pref.set "local_anime", Util.encode_object(@@local_anime)
69
- end
70
-
71
- def load
72
- raw = @pref.get "local_anime"
73
- if not raw == nil and raw.class == String
74
- @@local_anime = Util.decode_object raw
75
- else
76
- @@local_anime = {}
77
- end
78
- end
79
-
80
- def pref_changed!(verbose: true)
81
- new_dirs = (@pref.get("anime_locations").split(":")).collect { |dir|
82
- parsed_dir = @pref.parseDir(dir)
83
- parsed_dir if File.exist?(parsed_dir)
84
- }.compact
85
- if new_dirs != @anime_dirs
86
- @anime_dirs = new_dirs
87
- index_anime(verbose: verbose)
88
- relisten
89
- end
90
- end
91
-
92
- def animefile_changed!
93
- return unless @mpvbridge.what_changed[:local_anime]
94
- save
95
- changed
96
- notify_observers
97
- end
98
-
99
- ##
100
- ## @brief Indexes anime files up to 1 level deep in specified anime directories
101
- ##
102
- ## @param force The force
103
- ## @param verbose The verbose
104
- ##
105
- ## @return { description_of_the_return_value }
106
- ##
107
- def index_anime(force: false, verbose: true, very_verbose: false)
108
- puts "Indexing anime" if very_verbose
109
- Thread.new {
110
- ret = {}
111
- made_changes = false
112
- lal = @@local_anime.length
113
-
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
-
126
-
127
- # check if the directory exists
128
- unless File.exist? dir
129
- unless @dir_last_modified[dir] == "check"
130
- @dir_last_modified[dir] = "check"
131
- made_changes = true
132
- end
133
- next
134
- end
135
-
136
- puts "checking #{dir}" if very_verbose
137
-
138
- # skip indexing a directory if it hasn't been modified since the last
139
- # check (disabled because doesn't save to much time)
140
- #
141
- #dir_mtime = File::Stat.new(dir).mtime
142
- #
143
- #if @dir_last_modified.key? dir
144
- # if @dir_last_modified[dir] == dir_mtime
145
- # next
146
- # else
147
- # @dir_last_modified[dir] = dir_mtime
148
- # end
149
- #else
150
- # @dir_last_modified.merge!(dir => dir_mtime)
151
- #end
152
-
153
- # get all files in the directory and in all subfolders of the directory
154
- files = Dir.glob("#{dir}*/*.{mkv,avi,mp4}") + Dir.glob("#{dir}/*.{mkv,avi,mp4}")
155
-
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
177
-
178
- # we have already indexed this file
179
- if @@local_anime != nil and @@local_anime.key?(file)
180
-
181
- puts "this file is in the index" if very_verbose
182
-
183
- # get its seen data
184
- params[:seen] = @@local_anime[file].seen?
185
- params[:watched_on] = @@local_anime[file].seenOn
186
- puts params if very_verbose
187
- # get its last modifed data
188
- last_modified = File::Stat.new(file).mtime
189
- # get wether or not it is accessible
190
- @@local_anime[file].accessible = true
191
-
192
- # if we arent forcing or the anime hasn't been modified since the
193
- # last check, skip it
194
- if not force or last_modified == @@local_anime[file].last_modified
195
- puts "unchanged" if very_verbose
196
- ret.merge!(file => @@local_anime[file])
197
- next
198
- end
199
- end
200
-
201
- #puts "changed!"
202
-
203
- # okay we are making changes to local_anime
204
- made_changes = true
205
-
206
- # this is the anime file we are adding
207
- ret.merge!(
208
- file => AnimeFile.new(file, params)
209
- )
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
217
- }
218
-
219
- #if @@local_anime != nil
220
- # @@local_anime.merge!(ret)
221
- #else
222
- @@local_anime = ret
223
- #end
224
-
225
- #pruned = {}
226
- #@@local_anime.each{ |a|
227
- # pruned.merge!(a[0] => a[1]) if File.exist? a[1].path
228
- #}
229
- #@@local_anime = pruned
230
- made_changes = true if @@local_anime.length != lal
231
- if @made_changes
232
- self.save
233
- changed
234
- notify_observers
235
- end
236
- #
237
- }
238
- end
239
-
240
- #returns the parent directory of a file
241
- def parent(file)
242
- return File.basename(File.dirname(file))
243
- end
244
-
245
- #convert an AnimeFile array to a hash structured like
246
- #(string)parent => (AnimeFile array)[child0, child1, child2] and return it
247
- def makeHash arr
248
- #return @empty_hash if arr[0] == nil
249
-
250
- keys = {}
251
- hash = {}
252
-
253
- arr.sort_by {|i| i.title}.each { |file|
254
- unless keys.key?(parent file.path)
255
- key = AnimeSeries.new parent(file.path)
256
- keys.merge! parent(file.path) => key
257
- hash.merge! key => []
258
- else
259
- key = keys[parent file.path]
260
- end
261
-
262
- hash[key] << file
263
- key << file
264
- }
265
- hash.sort_by{ |j| j[0].title }.to_h
266
- end
267
-
268
- #return the difference of getAired and getWatched
269
- def unwatched
270
- makeHash @@local_anime.reject { |f, a| a.seen? }.values
271
- end
272
-
273
- #return an AnimeFile array of all mkvs in any dir specified in $pref["dirs"]
274
- def items
275
- makeHash @@local_anime.values
276
- end
277
-
278
- def logWatched(file)
279
- open(@pref.parseDir(@pref.get("watch_log")), 'a') do |f|
280
- f.puts %x(date).chomp + " ./" + File.basename(file) + " " + @watch_log_tag
281
- end
282
- end
283
-
284
- def addWatched(file)
285
- @@local_anime[file].watch
286
- save
287
- changed
288
- notify_observers
289
- end
290
-
291
- def rmWatched(path = "")
292
- if @@local_anime.key? path
293
- @@local_anime[path].unwatch
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
300
- end
301
- save
302
- changed
303
- notify_observers
304
- end
305
-
306
- def watch(file)
307
- @mpvbridge.play file
308
- end
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
-
319
- end
320
- end
321
- end