aniview 0.3.0 → 1.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/lib/aniview.rb +59 -10
- data/lib/aniview/client/aniclient.rb +50 -0
- data/lib/aniview/interface/animeio/animeio.rb +2 -7
- data/lib/aniview/interface/deluge/delugec.rb +146 -49
- data/lib/aniview/interface/deluge/torrentitem.rb +4 -1
- data/lib/aniview/interface/pref/defaults.json +95 -66
- data/lib/aniview/interface/pref/pref.rb +18 -10
- data/lib/aniview/interface/pref/validate.json +32 -2
- data/lib/aniview/interface/schedule/schedule.rb +74 -0
- data/lib/aniview/interface/schedule/scheduleitem.rb +46 -0
- data/lib/aniview/interface/subscription/subscription.rb +102 -0
- data/lib/aniview/interface/subscription/subscriptiondaemon.rb +42 -0
- data/lib/aniview/util/alogger.rb +12 -3
- data/lib/aniview/util/command.rb +1 -0
- data/lib/aniview/util/format.rb +106 -105
- data/lib/aniview/util/stringhelp.rb +50 -0
- data/lib/aniview/view/delugemenu.rb +14 -3
- data/lib/aniview/view/menu.rb +2 -2
- data/lib/aniview/view/schedulemenu.rb +36 -0
- data/lib/aniview/view/subscriptionmenu.rb +35 -0
- data/lib/aniviewd.rb +167 -0
- metadata +11 -3
- data/lib/aniview/interface/rssfeed/rssfeed.rb +0 -26
data/lib/aniview/util/format.rb
CHANGED
@@ -1,120 +1,121 @@
|
|
1
1
|
class Format
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
2
|
+
def self.format_duration v
|
3
|
+
hours = Integer((v-(v%3600))/3600)
|
4
|
+
minutes = Integer( ((v-(v%60))/60) - (hours * 60))
|
5
|
+
seconds = Integer(v%60)
|
6
|
+
if hours < 1 and minutes < 1
|
7
|
+
return String(seconds)
|
8
|
+
else
|
9
|
+
seconds = "0" + String(seconds) if seconds < 10
|
10
|
+
if hours < 1
|
11
|
+
return "#{String(minutes)}:#{String(seconds)}"
|
12
|
+
else
|
13
|
+
minutes = "0" + String(minutes) if minutes < 10
|
14
|
+
return "#{String(hours)}:#{String(minutes)}:#{String(seconds)}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.format_size s
|
20
|
+
fs = Float(s)
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
22
|
+
bytecount = {
|
23
|
+
"TB" => 1000000000000.0,
|
24
|
+
"GB" => 1000000000.0,
|
25
|
+
"MB" => 1000000.0,
|
26
|
+
"KB" => 1000.0,
|
27
|
+
"B" => 1.0,
|
28
|
+
}
|
29
|
+
r = "TB"
|
30
|
+
r = "GB" if s < bytecount["TB"]
|
31
|
+
r = "MB" if s < bytecount["GB"]
|
32
|
+
r = "KB" if s < bytecount["KB"]
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
return String( Float(fs/bytecount[r] * 10.0 ).round / 10.0 ) + r
|
35
|
+
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
def self.format_progress p
|
38
|
+
return "#{Integer(p)}.#{Integer(p * 10.0) % 10}"
|
39
|
+
end
|
40
40
|
|
41
|
-
|
42
|
-
|
41
|
+
def self.parse_format string, d, cols
|
42
|
+
le = "\e[K\n"
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
pstr = []
|
45
|
+
add_to = ""
|
46
|
+
buffer_char = []
|
47
47
|
|
48
|
-
|
48
|
+
mode = "char"
|
49
49
|
|
50
|
-
|
50
|
+
padding_collected = 0
|
51
51
|
|
52
|
-
|
53
|
-
if mode == "e"
|
54
|
-
add_to += String(c)
|
55
|
-
escape_mode = false
|
56
|
-
|
57
|
-
elsif c == '%'
|
58
|
-
mode = "%"
|
59
|
-
|
60
|
-
elsif c == '$'
|
61
|
-
mode = "$"
|
62
|
-
|
63
|
-
elsif c == '@'
|
64
|
-
pstr << add_to
|
65
|
-
add_to = ""
|
66
|
-
mode = "@"
|
67
|
-
|
68
|
-
elsif c == "#"
|
69
|
-
padding_collected += 1
|
70
|
-
|
71
|
-
elsif c == "\\"
|
72
|
-
mode = "e"
|
73
|
-
mode = "char"
|
74
|
-
|
75
|
-
elsif mode == "@"
|
76
|
-
buffer_char << c
|
77
|
-
mode = "char"
|
78
|
-
|
79
|
-
elsif mode == "%"
|
80
|
-
addstr = ""
|
81
|
-
addstr = String(d[c]) if d.key?(c)
|
82
|
-
ol = addstr.length
|
83
|
-
addstr = " " + addstr while addstr.length < (ol + padding_collected)
|
84
|
-
add_to += addstr
|
85
|
-
mode = "char"
|
86
|
-
|
87
|
-
elsif mode == "$"
|
88
|
-
add_to += String($emote[c]) if $emote.key?(c)
|
89
|
-
mode = "char"
|
52
|
+
string.split('').each { |c|
|
90
53
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
54
|
+
if mode == "e"
|
55
|
+
add_to += String(c)
|
56
|
+
mode = "char"
|
57
|
+
|
58
|
+
elsif c == '%'
|
59
|
+
mode = "%"
|
60
|
+
|
61
|
+
elsif c == '$'
|
62
|
+
mode = "$"
|
63
|
+
|
64
|
+
elsif c == '@'
|
65
|
+
pstr << add_to
|
66
|
+
add_to = ""
|
67
|
+
mode = "@"
|
68
|
+
|
69
|
+
elsif c == "#"
|
70
|
+
padding_collected += 1
|
71
|
+
|
72
|
+
elsif c == "\\"
|
73
|
+
mode = "e"
|
74
|
+
|
75
|
+
elsif mode == "@"
|
76
|
+
buffer_char << c
|
77
|
+
mode = "char"
|
78
|
+
|
79
|
+
elsif mode == "%"
|
80
|
+
addstr = ""
|
81
|
+
addstr = String(d[c]) if d.key?(c)
|
82
|
+
ol = addstr.length
|
83
|
+
addstr = " " + addstr while addstr.length < (ol + padding_collected)
|
84
|
+
add_to += addstr
|
85
|
+
mode = "char"
|
86
|
+
|
87
|
+
elsif mode == "$"
|
88
|
+
add_to += String($emote[c]) if $emote.key?(c)
|
89
|
+
mode = "char"
|
96
90
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
91
|
+
else
|
92
|
+
add_to += c
|
93
|
+
|
94
|
+
end
|
95
|
+
}
|
96
|
+
pstr << add_to
|
102
97
|
|
103
|
-
|
98
|
+
midstr = ""
|
99
|
+
tl = 0
|
100
|
+
pstr.each{ |s| tl += s.length }
|
101
|
+
buffer_space = 0
|
102
|
+
buffer_space = (cols - tl) / (pstr.length - 1) if pstr.length > 1
|
104
103
|
|
105
|
-
|
106
|
-
#buffer_space += addl_space if i == pstr.length - 2
|
107
|
-
#if i == pstr.length - 1
|
108
|
-
#puts addl_space
|
109
|
-
#puts i == pstr.length - 1
|
104
|
+
addl_space = (cols - tl) % pstr.length
|
110
105
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
106
|
+
pstr.each_with_index{ |str, i|
|
107
|
+
#buffer_space += addl_space if i == pstr.length - 2
|
108
|
+
# p pstr.length
|
109
|
+
# p pstr
|
110
|
+
|
111
|
+
break if i == pstr.length - 1
|
112
|
+
buffer_ = ""
|
113
|
+
buffer_ = buffer_char[i] * buffer_space if buffer_space >= 0
|
117
114
|
|
118
|
-
|
119
|
-
|
120
|
-
|
115
|
+
midstr += str + buffer_
|
116
|
+
}
|
117
|
+
midstr += pstr[pstr.length - 1]
|
118
|
+
|
119
|
+
return midstr
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class StringHelp
|
2
|
+
|
3
|
+
#returns the minimum of three numbers
|
4
|
+
def self.minimum(a, b, c)
|
5
|
+
if a > b
|
6
|
+
return c if b > c
|
7
|
+
return b
|
8
|
+
else
|
9
|
+
return c if a > c
|
10
|
+
return a
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
#returns the levenshitein distance between two strings s and t
|
15
|
+
def self.levenshteinDistance(s, t)
|
16
|
+
s = "_" + s
|
17
|
+
t = "_" + t
|
18
|
+
|
19
|
+
d = []
|
20
|
+
for i in 0..s.length
|
21
|
+
r = []
|
22
|
+
for j in 0..t.length
|
23
|
+
r << 0
|
24
|
+
end
|
25
|
+
d << r
|
26
|
+
end
|
27
|
+
|
28
|
+
for i in 1..s.length
|
29
|
+
d[i][0]=i
|
30
|
+
end
|
31
|
+
|
32
|
+
for j in 1..t.length
|
33
|
+
d[0][j]=j
|
34
|
+
end
|
35
|
+
|
36
|
+
for j in 1..t.length
|
37
|
+
for i in 1..s.length
|
38
|
+
cost = 1
|
39
|
+
cost = 0 if s[i] == t[j]
|
40
|
+
d[i][j] = self.minimum(
|
41
|
+
d[i-1][ j ] + 1,
|
42
|
+
d[ i ][j-1] + 1,
|
43
|
+
d[i-1][j-1] + cost
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
return d[s.length][t.length]
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -10,6 +10,7 @@ class DelugeMenu < Menu
|
|
10
10
|
|
11
11
|
@attributes = {
|
12
12
|
"t" => @attributes["t"],
|
13
|
+
"s" => @interface.getStatus
|
13
14
|
}
|
14
15
|
|
15
16
|
@expanded = -1 if @items.values[@expanded] == nil
|
@@ -17,12 +18,22 @@ class DelugeMenu < Menu
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def customControl(key, sel)
|
20
|
-
if key == "space"
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
if @items != nil and @items.length > 0
|
23
|
+
item = @items.values[sel["out"]]
|
24
|
+
else
|
25
|
+
item = ""
|
26
|
+
end
|
27
|
+
|
28
|
+
if key == @pref.get("keybindings")["torrents_pause"]
|
29
|
+
@interface.toggleTorrent(item)
|
30
|
+
elsif key == @pref.get("keybindings")["torrents_remove"]
|
31
|
+
@interface.removeTorrent(item, false)
|
32
|
+
elsif key == @pref.get("keybindings")["torrents_remove_data"]
|
33
|
+
@interface.removeTorrent(item, true)
|
24
34
|
elsif key == "enter"
|
25
35
|
|
26
36
|
end
|
27
37
|
end
|
38
|
+
|
28
39
|
end
|
data/lib/aniview/view/menu.rb
CHANGED
@@ -257,10 +257,10 @@ class Menu
|
|
257
257
|
lo = "\e[#{line};1H" + cl
|
258
258
|
|
259
259
|
if in_expanded_region and @children
|
260
|
-
print @cl["2"] + lo + String(@items_formatted.values[@expanded][inner_index])
|
260
|
+
print @cl["2"] + lo + String(@items_formatted.values[@expanded][inner_index]) + "\e[K"
|
261
261
|
inner_index+=1
|
262
262
|
elsif in_outer_region
|
263
|
-
print @cl["1"] + lo + String(@items_formatted.keys[outer_index])
|
263
|
+
print @cl["1"] + lo + String(@items_formatted.keys[outer_index]) + "\e[K"
|
264
264
|
outer_index+=1
|
265
265
|
else
|
266
266
|
print "\e[#{line};1H\e[2K\n"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'menu'
|
2
|
+
require_relative '../util/format'
|
3
|
+
require_relative '../util/command'
|
4
|
+
|
5
|
+
class ScheduleMenu < Menu
|
6
|
+
|
7
|
+
def refresh
|
8
|
+
@items = @interface.makeHash @interface.send(@refresh_func)
|
9
|
+
|
10
|
+
@attributes = {
|
11
|
+
"t" => @attributes["t"],
|
12
|
+
}
|
13
|
+
|
14
|
+
@expanded = -1 if @items.values[@expanded] == nil
|
15
|
+
fixCursor
|
16
|
+
end
|
17
|
+
|
18
|
+
def customControl(key, sel)
|
19
|
+
|
20
|
+
item = @items.values[sel["out"]].attributes["t"]
|
21
|
+
|
22
|
+
if key == @pref.get("keybindings")["schedule_add_item"]
|
23
|
+
newval = Command.read(@term, "new item:")
|
24
|
+
@interface.addItem newval
|
25
|
+
|
26
|
+
elsif key == @pref.get("keybindings")["schedule_delete_item"]
|
27
|
+
@interface.removeItem sel["out"]
|
28
|
+
|
29
|
+
elsif key == @pref.get("keybindings")["schedule_edit_item"]
|
30
|
+
newval = Command.read(@term, "edit item:", item)
|
31
|
+
@interface.editItem sel["out"], newval
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'menu'
|
2
|
+
require_relative '../util/format'
|
3
|
+
require_relative '../util/command'
|
4
|
+
|
5
|
+
class SubscriptionMenu < Menu
|
6
|
+
|
7
|
+
def refresh
|
8
|
+
@items = @interface.makeHash @interface.send(@refresh_func)
|
9
|
+
|
10
|
+
@attributes = {
|
11
|
+
"t" => @attributes["t"],
|
12
|
+
"l" => @interface.getLastChecked,
|
13
|
+
"d" => @interface.checkDaemon
|
14
|
+
}
|
15
|
+
|
16
|
+
@expanded = -1 if @items.values[@expanded] == nil
|
17
|
+
fixCursor
|
18
|
+
end
|
19
|
+
|
20
|
+
def customControl(key, sel)
|
21
|
+
|
22
|
+
item = @items.values[sel["out"]].attributes["r"]
|
23
|
+
|
24
|
+
if key == @pref.get("keybindings")["subscriptions_edit"]
|
25
|
+
newval = Command.read(@term, "regexp:", item)
|
26
|
+
@interface.editItem(sel["out"], newval)
|
27
|
+
|
28
|
+
elsif key == "m"
|
29
|
+
@interface.forceMatch
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/aniviewd.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'socket'
|
3
|
+
require 'warning'
|
4
|
+
|
5
|
+
Warning.ignore([:fixnum, :bignum])
|
6
|
+
|
7
|
+
require_relative 'aniview/interface/deluge/delugec'
|
8
|
+
require_relative 'aniview/interface/pref/pref'
|
9
|
+
require_relative 'aniview/interface/schedule/schedule'
|
10
|
+
require_relative 'aniview/interface/subscription/subscription'
|
11
|
+
require_relative 'aniview/client/aniclient'
|
12
|
+
require_relative 'aniview/util/format'
|
13
|
+
|
14
|
+
require_relative 'aniview/util/alogger'
|
15
|
+
|
16
|
+
class AniViewd
|
17
|
+
|
18
|
+
def initialize(args)
|
19
|
+
|
20
|
+
@pref = Pref.new
|
21
|
+
@c = AniClient.new @pref
|
22
|
+
|
23
|
+
#@l = ALogger.new(@pref.get("daemon_log_file"), false)
|
24
|
+
|
25
|
+
args << "start" if args.length < 1
|
26
|
+
parseArgs args
|
27
|
+
|
28
|
+
@schedule = Schedule.new @pref
|
29
|
+
@delugec = DelugeC.new(@pref)
|
30
|
+
@subscription = Subscription.new(@pref, @schedule, @delugec, @c)
|
31
|
+
|
32
|
+
begin
|
33
|
+
@s = TCPServer.new @pref.get("daemon")["port"]
|
34
|
+
rescue Errno::EADDRINUSE
|
35
|
+
puts "error, something is already listening on #{@pref.get("daemon")["port"]}, maybe the \nserver is already running?"
|
36
|
+
quit
|
37
|
+
end
|
38
|
+
@looped = 0
|
39
|
+
@matches = 0
|
40
|
+
@lastchecked = "never"
|
41
|
+
|
42
|
+
$stdout.reopen(@pref.parseDir(@pref.get("daemon_log_file")), "a")
|
43
|
+
$stderr.reopen(@pref.parseDir(@pref.get("daemon_log_file")), "a")
|
44
|
+
$stdout.sync = true
|
45
|
+
$stderr.sync = true
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def parseArgs args
|
50
|
+
args.each { |a|
|
51
|
+
case a
|
52
|
+
when "help"
|
53
|
+
help
|
54
|
+
quit
|
55
|
+
when "start"
|
56
|
+
if @c.server?
|
57
|
+
puts "already running"
|
58
|
+
quit
|
59
|
+
end
|
60
|
+
when "stop"
|
61
|
+
if @c.server?
|
62
|
+
puts "quitting"
|
63
|
+
@c.stopDaemon
|
64
|
+
quit
|
65
|
+
else
|
66
|
+
puts "server isn't running"
|
67
|
+
quit
|
68
|
+
end
|
69
|
+
when "info"
|
70
|
+
if @c.server?
|
71
|
+
puts @c.info
|
72
|
+
quit
|
73
|
+
else
|
74
|
+
puts "server isn't running"
|
75
|
+
quit
|
76
|
+
end
|
77
|
+
when "up?"
|
78
|
+
puts @c.server?
|
79
|
+
quit
|
80
|
+
when "nani"
|
81
|
+
puts @c.sendMsg("what?")
|
82
|
+
quit
|
83
|
+
else
|
84
|
+
puts "unknown command, dude!"
|
85
|
+
quit
|
86
|
+
end
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def help
|
91
|
+
cmds = ["help", "start", "stop", "info", "up?", "nani"]
|
92
|
+
puts "commands:"
|
93
|
+
puts cmds.sort
|
94
|
+
end
|
95
|
+
|
96
|
+
def checkFeeds
|
97
|
+
Thread.abort_on_exception = true
|
98
|
+
Thread.new do
|
99
|
+
while true
|
100
|
+
@subscription.updateFeed
|
101
|
+
|
102
|
+
if @subscription.feed == nil
|
103
|
+
@lastchecked = "offline"
|
104
|
+
else
|
105
|
+
@lastchecked = Time.now.to_s
|
106
|
+
@matches += @subscription.matchAll
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
#p @schedule.getAll
|
111
|
+
@looped += 1
|
112
|
+
sleep Integer(@pref.get("rss_feed")["refresh_interval"])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def quit
|
118
|
+
@checkThread.exit unless @checkThread == nil
|
119
|
+
exit
|
120
|
+
end
|
121
|
+
|
122
|
+
def uptime
|
123
|
+
Format.format_duration(Time.now - @started)
|
124
|
+
end
|
125
|
+
|
126
|
+
def run
|
127
|
+
puts "--------"
|
128
|
+
puts "server started"
|
129
|
+
puts "server listening on port " + @pref.get("daemon")["port"]
|
130
|
+
|
131
|
+
trap(:QUIT) do
|
132
|
+
quit
|
133
|
+
end
|
134
|
+
|
135
|
+
@checkThread = checkFeeds
|
136
|
+
@started = Time.now
|
137
|
+
loop do
|
138
|
+
lastloop = false
|
139
|
+
client = @s.accept
|
140
|
+
|
141
|
+
message = client.gets.chomp
|
142
|
+
puts "got msg #{message} from client"
|
143
|
+
response = "okay."
|
144
|
+
|
145
|
+
case message
|
146
|
+
when "up?"
|
147
|
+
response = "true"
|
148
|
+
when "quit"
|
149
|
+
lastloop = true
|
150
|
+
response = "quitting"
|
151
|
+
when "info"
|
152
|
+
response = "uptime: #{uptime}, loops: #{@looped}, matches, #{@matches}"
|
153
|
+
when "lastchecked"
|
154
|
+
response = @lastchecked
|
155
|
+
else
|
156
|
+
response = "what?"
|
157
|
+
end
|
158
|
+
|
159
|
+
puts "responding with #{response}"
|
160
|
+
client.puts response
|
161
|
+
client.close
|
162
|
+
|
163
|
+
quit if lastloop
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|