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.
- checksums.yaml +4 -4
- data/README.md +8 -9
- data/bin/aniview +17 -9
- data/config/view.yml +3 -0
- data/lib/aniview.rb +1 -60
- data/modules/animeio/README.md +2 -0
- data/modules/animeio/config/daemon.yml +4 -0
- data/modules/animeio/config/view.yml +22 -0
- data/modules/animeio/lib/animeio.rb +24 -0
- data/modules/animeio/lib/animeio/anime_indexer.rb +99 -0
- data/modules/animeio/lib/animeio/animefile.rb +91 -0
- data/modules/animeio/lib/animeio/animeio.rb +175 -0
- data/modules/animeio/lib/animeio/animeio_view.rb +41 -0
- data/modules/animeio/lib/animeio/animeseries.rb +61 -0
- data/modules/mpv/README.md +2 -0
- data/modules/mpv/config/daemon.yml +2 -0
- data/modules/mpv/lib/mpv.rb +27 -0
- data/modules/mpv/lib/mpv/filename_widget.rb +16 -0
- data/modules/mpv/lib/mpv/mpv_controller.rb +85 -0
- data/modules/mpv/lib/mpv/time_widget.rb +29 -0
- metadata +33 -107
- data/lib/aniview/client/aniclient.rb +0 -118
- data/lib/aniview/interface/animeio/animefile.rb +0 -93
- data/lib/aniview/interface/animeio/animeio.rb +0 -321
- data/lib/aniview/interface/animeio/animeseries.rb +0 -60
- data/lib/aniview/interface/bridge.rb +0 -11
- data/lib/aniview/interface/deluge/delugec.rb +0 -172
- data/lib/aniview/interface/deluge/torrentitem.rb +0 -24
- data/lib/aniview/interface/item.rb +0 -24
- data/lib/aniview/interface/mpv/mpvbridge.rb +0 -149
- data/lib/aniview/interface/pref/defaults.json +0 -105
- data/lib/aniview/interface/pref/pref.rb +0 -209
- data/lib/aniview/interface/pref/prefitem.rb +0 -19
- data/lib/aniview/interface/pref/validate.json +0 -105
- data/lib/aniview/interface/schedule/schedule.rb +0 -99
- data/lib/aniview/interface/schedule/scheduleitem.rb +0 -59
- data/lib/aniview/interface/subscription/subscription.rb +0 -123
- data/lib/aniview/util/error.rb +0 -9
- data/lib/aniview/util/folder_listen.rb +0 -53
- data/lib/aniview/util/term.rb +0 -44
- data/lib/aniview/util/util.rb +0 -167
- data/lib/aniview/view/aiomenu.rb +0 -69
- data/lib/aniview/view/color.rb +0 -69
- data/lib/aniview/view/delugemenu.rb +0 -38
- data/lib/aniview/view/menu.rb +0 -325
- data/lib/aniview/view/prefmenu.rb +0 -26
- data/lib/aniview/view/schedulemenu.rb +0 -28
- data/lib/aniview/view/statusline.rb +0 -60
- data/lib/aniview/view/subscriptionmenu.rb +0 -37
- data/lib/application.rb +0 -306
- data/lib/daemon.rb +0 -188
@@ -1,123 +0,0 @@
|
|
1
|
-
require 'simple-rss'
|
2
|
-
require 'open-uri'
|
3
|
-
|
4
|
-
require_relative "../schedule/scheduleitem"
|
5
|
-
require_relative '../bridge'
|
6
|
-
|
7
|
-
module Aniview
|
8
|
-
module Interface
|
9
|
-
class Subscription < Bridge
|
10
|
-
|
11
|
-
include Observable
|
12
|
-
|
13
|
-
def initialize pref, schedule, delugec, client
|
14
|
-
@c = client
|
15
|
-
@pref = pref
|
16
|
-
@schedule = schedule
|
17
|
-
@delugec = delugec
|
18
|
-
#SimpleRSS.feed_tags << :"torrent:magnetURI"
|
19
|
-
#<![CDATA[
|
20
|
-
end
|
21
|
-
|
22
|
-
def log s
|
23
|
-
puts "#{Time.now.to_s} [subscription] " + s
|
24
|
-
end
|
25
|
-
|
26
|
-
def checkDaemon
|
27
|
-
if @c.server?
|
28
|
-
"daemon up"
|
29
|
-
else
|
30
|
-
"daemon down"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def getLastChecked
|
35
|
-
@c.lastchecked
|
36
|
-
end
|
37
|
-
|
38
|
-
def getNextCheck
|
39
|
-
@c.sendMsg "nextcheck"
|
40
|
-
end
|
41
|
-
|
42
|
-
def syncMatches
|
43
|
-
@schedule.mergeItems @c.getItems
|
44
|
-
end
|
45
|
-
|
46
|
-
def updateFeed
|
47
|
-
begin
|
48
|
-
SimpleRSS.item_tags << :"torrent:magnetURI"
|
49
|
-
@rss = SimpleRSS.parse open(@pref.get("rss_feed")["url"])
|
50
|
-
|
51
|
-
rescue SocketError
|
52
|
-
@rss = nil
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def feed
|
57
|
-
@rss
|
58
|
-
end
|
59
|
-
|
60
|
-
def match regexp, verbose=false
|
61
|
-
re = Regexp.new regexp
|
62
|
-
matches = []
|
63
|
-
@rss.items.each{ |item|
|
64
|
-
#log "-> checking against #{item[:title]}" if verbose
|
65
|
-
re.match item[:title] { matches << item }
|
66
|
-
}
|
67
|
-
return matches
|
68
|
-
end
|
69
|
-
|
70
|
-
def matchAll (verbose: false)
|
71
|
-
updateFeed if @rss == nil
|
72
|
-
return [] if @rss == nil
|
73
|
-
|
74
|
-
log "matching all" if verbose
|
75
|
-
|
76
|
-
total_matches = 0
|
77
|
-
@schedule.schedule.each { |subs|
|
78
|
-
log "matching #{subs.attributes["r"]}" if verbose
|
79
|
-
matches = match subs.attributes["r"], verbose
|
80
|
-
log "found #{matches.length} matches" if verbose
|
81
|
-
#log "#{matches}" if verbose
|
82
|
-
|
83
|
-
if matches.length >= 1
|
84
|
-
|
85
|
-
downloaddir = @pref.parseDir(subs.attributes["p"]) + "/"
|
86
|
-
newfile = downloaddir + matches[0][:title]
|
87
|
-
|
88
|
-
next if File.exist? newfile
|
89
|
-
log "attempting to downloading file" if verbose
|
90
|
-
log "set download dir to #{newfile}" if verbose
|
91
|
-
log "#{matches[0].link}" if verbose
|
92
|
-
s = @delugec.addTorrent matches[0].link, @pref.parseDir(subs.attributes["p"]), verbose: true
|
93
|
-
log "adding torrent, status #{s}" if verbose
|
94
|
-
subs.setSeen if s
|
95
|
-
@schedule.save
|
96
|
-
total_matches+=1
|
97
|
-
end
|
98
|
-
}
|
99
|
-
log "match complete, #{total_matches} found" if verbose
|
100
|
-
return total_matches
|
101
|
-
end
|
102
|
-
|
103
|
-
def forceMatch
|
104
|
-
@mthread = Thread.new do
|
105
|
-
updateFeed
|
106
|
-
matchAll
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def items
|
111
|
-
@schedule.items
|
112
|
-
end
|
113
|
-
|
114
|
-
def editItem loc, newval
|
115
|
-
@schedule.schedule[loc].setRegexp newval
|
116
|
-
@schedule.save
|
117
|
-
changed
|
118
|
-
notify_observers
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
data/lib/aniview/util/error.rb
DELETED
@@ -1,53 +0,0 @@
|
|
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
|
data/lib/aniview/util/term.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
module Aniview
|
2
|
-
module Util
|
3
|
-
class Term
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@tput=Hash[
|
7
|
-
"smcup" => %x(tput smcup),
|
8
|
-
"rmcup" => %x(tput rmcup),
|
9
|
-
"civis" => %x(tput civis),
|
10
|
-
"cnorm" => %x(tput cnorm),
|
11
|
-
"el1" => "\e[2K",
|
12
|
-
"bold" => %x(tput bold),
|
13
|
-
"nobold" => %x(tput sgr0),
|
14
|
-
]
|
15
|
-
end
|
16
|
-
|
17
|
-
def save; print @tput["smcup"]; return self; end
|
18
|
-
def restore; print @tput["rmcup"]; return self; end
|
19
|
-
def hide_cursor; print @tput["civis"]; return self; end
|
20
|
-
def show_cursor; print @tput["cnorm"]; return self; end
|
21
|
-
def clear_line; print @tput["el1"]; return self; end
|
22
|
-
def echo_off; %x(stty -echo); return self; end
|
23
|
-
def echo_on; %x(stty echo); return self; end
|
24
|
-
def clear; print "\033[2J"; return self; end
|
25
|
-
def bold; print @tput["bold"]; return self; end
|
26
|
-
def nobold; print @tput["nobold"]; return self; end
|
27
|
-
|
28
|
-
def cols; return HighLine::SystemExtensions.terminal_size[0]; end
|
29
|
-
def rows; return HighLine::SystemExtensions.terminal_size[1]; end
|
30
|
-
|
31
|
-
def self.cols; return HighLine::SystemExtensions.terminal_size[0]; end
|
32
|
-
def self.rows; return HighLine::SystemExtensions.terminal_size[1]; end
|
33
|
-
|
34
|
-
def getKey
|
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")
|
36
|
-
end
|
37
|
-
|
38
|
-
def reset
|
39
|
-
self.restore.show_cursor.echo_on
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
data/lib/aniview/util/util.rb
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
require 'base64'
|
2
|
-
require 'readline'
|
3
|
-
|
4
|
-
module Aniview
|
5
|
-
module Util
|
6
|
-
def self.readline(term, prompt = "", default = "")
|
7
|
-
term.bold.echo_on
|
8
|
-
print "\033[" + String(term.rows) + ";1H" + Aniview::View::Color.white
|
9
|
-
term.show_cursor
|
10
|
-
Readline.completion_append_character = ""
|
11
|
-
Readline.pre_input_hook = -> do
|
12
|
-
Readline.insert_text "#{default}"
|
13
|
-
Readline.redisplay
|
14
|
-
Readline.pre_input_hook = nil
|
15
|
-
end
|
16
|
-
input = Readline.readline(prompt, false)
|
17
|
-
term.hide_cursor.nobold.echo_off.clear
|
18
|
-
return input
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.error_message(message)
|
22
|
-
#use statusline to show error messages
|
23
|
-
print "\e[#{Term.rows - 1};1H\e[31m #{message}\e[K"
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.format_duration v
|
27
|
-
hours = Integer((v-(v%3600))/3600)
|
28
|
-
minutes = Integer( ((v-(v%60))/60) - (hours * 60))
|
29
|
-
seconds = Integer(v%60)
|
30
|
-
seconds = "0" + String(seconds) if seconds < 10
|
31
|
-
if hours < 1 and minutes < 1
|
32
|
-
"0:#{seconds}"
|
33
|
-
else
|
34
|
-
if hours < 1
|
35
|
-
return "#{String(minutes)}:#{String(seconds)}"
|
36
|
-
else
|
37
|
-
minutes = "0" + String(minutes) if minutes < 10
|
38
|
-
return "#{String(hours)}:#{String(minutes)}:#{String(seconds)}"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.format_size s
|
44
|
-
fs = Float(s)
|
45
|
-
|
46
|
-
bytecount = {
|
47
|
-
"TB" => 1000000000000.0,
|
48
|
-
"GB" => 1000000000.0,
|
49
|
-
"MB" => 1000000.0,
|
50
|
-
"KB" => 1000.0,
|
51
|
-
"B" => 1.0,
|
52
|
-
}
|
53
|
-
r = "TB"
|
54
|
-
r = "GB" if s < bytecount["TB"]
|
55
|
-
r = "MB" if s < bytecount["GB"]
|
56
|
-
r = "KB" if s < bytecount["KB"]
|
57
|
-
|
58
|
-
return String( Float(fs/bytecount[r] * 10.0 ).round / 10.0 ) + r
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.format_progress p
|
62
|
-
return "#{Integer(p)}.#{Integer(p * 10.0) % 10}"
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.parse_format string, d, cols
|
66
|
-
le = "\e[K\n"
|
67
|
-
|
68
|
-
pstr = []
|
69
|
-
add_to = ""
|
70
|
-
buffer_char = []
|
71
|
-
|
72
|
-
mode = "char"
|
73
|
-
|
74
|
-
padding_collected = 0
|
75
|
-
|
76
|
-
string.split('').each { |c|
|
77
|
-
|
78
|
-
if mode == "e"
|
79
|
-
add_to += String(c)
|
80
|
-
mode = "char"
|
81
|
-
|
82
|
-
elsif c == '%'
|
83
|
-
mode = "%"
|
84
|
-
|
85
|
-
elsif c == '$'
|
86
|
-
mode = "$"
|
87
|
-
|
88
|
-
elsif c == '@'
|
89
|
-
pstr << add_to
|
90
|
-
add_to = ""
|
91
|
-
mode = "@"
|
92
|
-
|
93
|
-
elsif c == "#"
|
94
|
-
padding_collected += 1
|
95
|
-
|
96
|
-
elsif c == "\\"
|
97
|
-
mode = "e"
|
98
|
-
|
99
|
-
elsif mode == "@"
|
100
|
-
buffer_char << c
|
101
|
-
mode = "char"
|
102
|
-
|
103
|
-
elsif mode == "%"
|
104
|
-
addstr = d.key?(c) ? String(d[c]) : ""
|
105
|
-
padding = padding_collected > addstr.length ? " " * (padding_collected - addstr.length) : ""
|
106
|
-
addstr = padding + addstr
|
107
|
-
add_to += addstr
|
108
|
-
mode = "char"
|
109
|
-
padding_collected = 0
|
110
|
-
|
111
|
-
else
|
112
|
-
add_to += c
|
113
|
-
|
114
|
-
end
|
115
|
-
}
|
116
|
-
pstr << add_to
|
117
|
-
|
118
|
-
buffer_char << " " if buffer_char.length == 0
|
119
|
-
|
120
|
-
midstr = ""
|
121
|
-
tl = 0
|
122
|
-
pstr.each{ |s| tl += s.length }
|
123
|
-
buffer_space = 0
|
124
|
-
buffer_space = (cols - tl) / (pstr.length - 1) if pstr.length > 1
|
125
|
-
|
126
|
-
addl_space = (cols - tl) % pstr.length
|
127
|
-
|
128
|
-
pstr.each_with_index{ |str, i|
|
129
|
-
break if i == pstr.length - 1
|
130
|
-
buffer_ = ""
|
131
|
-
buffer_ = buffer_char[i] * buffer_space if buffer_space >= 0
|
132
|
-
|
133
|
-
midstr += str + buffer_
|
134
|
-
}
|
135
|
-
midstr += pstr[pstr.length - 1]
|
136
|
-
|
137
|
-
return midstr[0..cols-1]
|
138
|
-
end
|
139
|
-
|
140
|
-
def self.encode_object d
|
141
|
-
Base64.strict_encode64(Marshal.dump d)
|
142
|
-
end
|
143
|
-
|
144
|
-
def self.decode_object e
|
145
|
-
begin
|
146
|
-
Marshal.load(Base64.decode64(e))
|
147
|
-
rescue ArgumentError
|
148
|
-
{}
|
149
|
-
rescue TypeError
|
150
|
-
{}
|
151
|
-
end
|
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
|
166
|
-
end
|
167
|
-
end
|
data/lib/aniview/view/aiomenu.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
require_relative 'menu'
|
2
|
-
require_relative '../util/util'
|
3
|
-
|
4
|
-
module Aniview
|
5
|
-
module View
|
6
|
-
class AioMenu < Menu
|
7
|
-
include Aniview::Util
|
8
|
-
|
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
|
21
|
-
@attributes = {
|
22
|
-
"t" => @attributes["t"],
|
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")
|
29
|
-
}
|
30
|
-
end
|
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)
|
37
|
-
return if @items == {}
|
38
|
-
path = @items.values[sel["out"]][sel["in"]].path
|
39
|
-
|
40
|
-
empty = path == "empty"
|
41
|
-
|
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
|
62
|
-
|
63
|
-
changed
|
64
|
-
notify_observers
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|