aniview 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/aniview +6 -0
- data/lib/aniview.rb +121 -5
- data/lib/aniview/interface/animeio/animefile.rb +74 -0
- data/lib/aniview/interface/animeio/animeio.rb +191 -0
- data/lib/aniview/interface/animeio/animeseries.rb +52 -0
- data/lib/aniview/util/command.rb +23 -0
- data/lib/aniview/util/format.rb +36 -0
- data/lib/aniview/util/logger.rb +9 -0
- data/lib/aniview/util/pref.rb +137 -0
- data/lib/aniview/util/term.rb +37 -0
- data/lib/aniview/view/aiomenu.rb +67 -0
- data/lib/aniview/view/emote.rb +97 -0
- data/lib/aniview/view/menu.rb +283 -0
- data/lib/aniview/view/prefmenu.rb +36 -0
- metadata +60 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d81c0b1844154bc94629cf7169c785a92666a668
|
4
|
+
data.tar.gz: d616a2e6e77f1e2760d21f8c32b71353d67c51c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36e06051afb3ec9d24319d2ab87e7ced2b12d9c80fa9f47ec0ebad466d2bd76582ac151cada7e9619cd6a20e89596eb03daf9b6485bc6b1338f2b44c66749401
|
7
|
+
data.tar.gz: be788e75a654904503993761973bf88c626ea02a293971b1868b1755f188b368df603486ff0106ea2b3d34a4f9e18c9aea6f3602c8f1ec5f67f5154df0b72b0a
|
data/bin/aniview
ADDED
data/lib/aniview.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'highline'
|
2
|
-
require 'rubygems'
|
3
2
|
require 'highline/import'
|
4
3
|
require 'json'
|
5
4
|
require 'thread'
|
5
|
+
require 'io/console'
|
6
6
|
|
7
7
|
require_relative 'aniview/view/aiomenu'
|
8
8
|
require_relative 'aniview/view/prefmenu'
|
@@ -14,8 +14,124 @@ require_relative 'aniview/util/logger'
|
|
14
14
|
require_relative 'aniview/util/term'
|
15
15
|
require_relative 'aniview/util/pref'
|
16
16
|
|
17
|
-
require_relative 'aniview/aniviewdriver'
|
18
|
-
|
19
17
|
$stdout.sync = true
|
20
|
-
|
21
|
-
|
18
|
+
|
19
|
+
class AniView
|
20
|
+
def initialize
|
21
|
+
|
22
|
+
@term = Term.new
|
23
|
+
|
24
|
+
@pref = Pref.new
|
25
|
+
|
26
|
+
@format_ = {
|
27
|
+
"aiomenu_all" => {
|
28
|
+
"title" => "anime_library_title_format_str",
|
29
|
+
"parent" => "anime_library_title_show_format_str",
|
30
|
+
"child" => "anime_library_title_episode_format_str",
|
31
|
+
},
|
32
|
+
"aiomenu_uw" => {
|
33
|
+
"title" => "anime_library_unwatched_title_format_str",
|
34
|
+
"parent" => "anime_library_unwatched_title_show_format_str",
|
35
|
+
"child" => "anime_library_unwatched_title_episode_format_str",
|
36
|
+
},
|
37
|
+
"prefmenu" => {
|
38
|
+
"title" => "preferences_title_format_str",
|
39
|
+
"parent" => "preferences_item_format_str",
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
@aio = AnimeIO.new(@pref)
|
44
|
+
logger = Logger.new(@pref.get "log_file")
|
45
|
+
@aiomenu = AioMenu.new(
|
46
|
+
:getAll,
|
47
|
+
@aio,
|
48
|
+
@pref.get("menu_titles")["2"],
|
49
|
+
@pref,
|
50
|
+
@format_["aiomenu_all"],
|
51
|
+
@term
|
52
|
+
)
|
53
|
+
|
54
|
+
@prefmenu = PrefMenu.new(:getAll, @pref, @pref.get("menu_titles")["0"], @pref, @format_["prefmenu"], @term)
|
55
|
+
|
56
|
+
@term.save.hide_cursor.echo_off
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def cleanup
|
61
|
+
@term.reset
|
62
|
+
exit
|
63
|
+
end
|
64
|
+
|
65
|
+
def runCommand(cmds)
|
66
|
+
cmd_s = cmds.split
|
67
|
+
cmd = cmd_s[0]
|
68
|
+
if cmd == "quit"
|
69
|
+
self.cleanup
|
70
|
+
elsif cmd == "sync"
|
71
|
+
#alist = Anilist.new
|
72
|
+
#alist.sync
|
73
|
+
elsif cmd == "pref"
|
74
|
+
@pref.set cmd_s[1], cmd_s[2]
|
75
|
+
elsif cmd == "index"
|
76
|
+
@aio.index_anime :force => true, :verbose => true
|
77
|
+
@aiomenu.refresh
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def run
|
82
|
+
|
83
|
+
view = @aiomenu
|
84
|
+
|
85
|
+
mutex = Mutex.new
|
86
|
+
Signal.trap('SIGWINCH', proc {
|
87
|
+
Thread.new { mutex.synchronize { view.draw } }
|
88
|
+
} )
|
89
|
+
|
90
|
+
key = ""
|
91
|
+
view.refresh
|
92
|
+
view.set_screen_size(@term.rows, @term.cols)
|
93
|
+
|
94
|
+
while true
|
95
|
+
view.draw if key != "skip"
|
96
|
+
|
97
|
+
key = @term.getKey
|
98
|
+
|
99
|
+
if key == "1"
|
100
|
+
@term.clear
|
101
|
+
view = @aiomenu
|
102
|
+
view.setName(@pref.get("menu_titles")[key])
|
103
|
+
view.setFormat(@format_["aiomenu_uw"])
|
104
|
+
view.setRfunc(:getUnwatched)
|
105
|
+
|
106
|
+
elsif key == "2"
|
107
|
+
@term.clear
|
108
|
+
view = @aiomenu
|
109
|
+
view.setName(@pref.get("menu_titles")[key])
|
110
|
+
view.setFormat(@format_["aiomenu_all"])
|
111
|
+
view.setRfunc(:getAll)
|
112
|
+
|
113
|
+
elsif key == "3"
|
114
|
+
@term.clear
|
115
|
+
view = @anilistmenu
|
116
|
+
view.setName(@pref.get("menu_titles")[key])
|
117
|
+
view.setRfunc(:getCompleted)
|
118
|
+
|
119
|
+
elsif key == "0"
|
120
|
+
@term.clear
|
121
|
+
view = @prefmenu
|
122
|
+
view.setName(@pref.get("menu_titles")[key])
|
123
|
+
view.setRfunc(:getAll)
|
124
|
+
|
125
|
+
elsif key == ":"
|
126
|
+
|
127
|
+
cmd = Command.read(@term, ":")
|
128
|
+
self.runCommand cmd
|
129
|
+
|
130
|
+
elsif key == "q"
|
131
|
+
self.cleanup
|
132
|
+
end
|
133
|
+
|
134
|
+
view.control(key)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'streamio-ffmpeg'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
require_relative '../../util/format'
|
5
|
+
|
6
|
+
class AnimeFile
|
7
|
+
def initialize(path_, seen = false)
|
8
|
+
@watched = seen
|
9
|
+
@watched_on = 0
|
10
|
+
@path = path_
|
11
|
+
|
12
|
+
if (@path == "empty")
|
13
|
+
@attr = {
|
14
|
+
"t" => "empty",
|
15
|
+
"d" => 0,
|
16
|
+
"D" => "0",
|
17
|
+
"s" => 0,
|
18
|
+
"S" => "0",
|
19
|
+
"r" => 0x0,
|
20
|
+
"a" => "n.a.",
|
21
|
+
"v" => "",
|
22
|
+
"l" => "",
|
23
|
+
"f" => "",
|
24
|
+
"b" => "",
|
25
|
+
}
|
26
|
+
else
|
27
|
+
mov = FFMPEG::Movie.new(@path)
|
28
|
+
|
29
|
+
@attr = {
|
30
|
+
"t" => self.string,
|
31
|
+
"d" => mov.duration,
|
32
|
+
"D" => Format.format_duration(mov.duration),
|
33
|
+
"s" => mov.size,
|
34
|
+
"S" => Format.format_size(mov.size),
|
35
|
+
"r" => mov.resolution,
|
36
|
+
"a" => mov.audio_codec,
|
37
|
+
"v" => mov.video_codec,
|
38
|
+
"l" => mov.colorspace,
|
39
|
+
"f" => mov.frame_rate,
|
40
|
+
"b" => String(mov.bitrate) + "kb/s",
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def seen?
|
47
|
+
return @watched
|
48
|
+
end
|
49
|
+
|
50
|
+
def seenOn
|
51
|
+
return @watched_on
|
52
|
+
end
|
53
|
+
|
54
|
+
def watch
|
55
|
+
@watched = true
|
56
|
+
@watched_on = DateTime.now.strftime('%Q')
|
57
|
+
end
|
58
|
+
|
59
|
+
def unwatch
|
60
|
+
@watched = false
|
61
|
+
end
|
62
|
+
|
63
|
+
def path
|
64
|
+
return @path
|
65
|
+
end
|
66
|
+
|
67
|
+
def string
|
68
|
+
return (File.basename("#{@path}").gsub(/\s*\[.+?\]\s*/) {}).gsub(/(\.mkv)|(\.avi)|(\.mp4)/, "").gsub("_", " ").gsub(/\s*\(.+?\)\s*/) {}
|
69
|
+
end
|
70
|
+
|
71
|
+
def attributes
|
72
|
+
return @attr
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require_relative 'animefile'
|
3
|
+
require_relative 'animeseries'
|
4
|
+
|
5
|
+
class AnimeIO
|
6
|
+
|
7
|
+
def initialize(pref)
|
8
|
+
@pref = pref
|
9
|
+
@empty_hash = {
|
10
|
+
"empty" => AnimeFile.new(
|
11
|
+
"empty",
|
12
|
+
{
|
13
|
+
"d" => 0,
|
14
|
+
"s" => 0,
|
15
|
+
"r" => "0x0",
|
16
|
+
"a" => "n/a"
|
17
|
+
}
|
18
|
+
)
|
19
|
+
}
|
20
|
+
@watch_log_tag = "♪"
|
21
|
+
|
22
|
+
self.load
|
23
|
+
index_anime
|
24
|
+
end
|
25
|
+
|
26
|
+
def save
|
27
|
+
@pref.saveLocalAnime Base64.encode64(Marshal.dump @@local_anime)
|
28
|
+
end
|
29
|
+
|
30
|
+
def load
|
31
|
+
raw = @pref.get "local_anime"
|
32
|
+
if not raw == nil and raw.class == String
|
33
|
+
@@local_anime = Marshal.load(Base64.decode64(raw))
|
34
|
+
else
|
35
|
+
@@local_anime = {}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def index_anime(force: false, verbose: false)
|
40
|
+
ret = {}
|
41
|
+
(@pref.get("anime_locations").split(":")).each { |dir|
|
42
|
+
Dir.glob("#{dir}*/*.mkv").each { |file|
|
43
|
+
puts "indexing #{file}" if verbose
|
44
|
+
seen_this = false
|
45
|
+
if @@local_anime != nil and @@local_anime.key?(file)
|
46
|
+
seen_this = @@local_anime[file].seen?
|
47
|
+
if not force
|
48
|
+
ret.merge!(file => @@local_anime[file])
|
49
|
+
next
|
50
|
+
end
|
51
|
+
end
|
52
|
+
ret.merge!(
|
53
|
+
file => AnimeFile.new(
|
54
|
+
file,
|
55
|
+
seen_this
|
56
|
+
)
|
57
|
+
)
|
58
|
+
|
59
|
+
}
|
60
|
+
}
|
61
|
+
if @@local_anime != nil
|
62
|
+
@@local_anime.merge!(ret)
|
63
|
+
else
|
64
|
+
@@local_anime = ret
|
65
|
+
end
|
66
|
+
|
67
|
+
pruned = {}
|
68
|
+
@@local_anime.each{ |a|
|
69
|
+
pruned.merge!(a[0] => a[1]) if File.exist? a[1].path
|
70
|
+
}
|
71
|
+
@@local_anime = pruned
|
72
|
+
|
73
|
+
self.save
|
74
|
+
end
|
75
|
+
|
76
|
+
#returns the parent directory of a file
|
77
|
+
def parent(file)
|
78
|
+
return File.basename(File.dirname(file))
|
79
|
+
end
|
80
|
+
|
81
|
+
#convert an AnimeFile array to a hash structured like
|
82
|
+
#(string)parent => (AnimeFile array)[child0, child1, child2] and return it
|
83
|
+
def makeHash(arr)
|
84
|
+
return @empty_hash if arr[0] == nil
|
85
|
+
ret = {}
|
86
|
+
subarray = []
|
87
|
+
|
88
|
+
|
89
|
+
sarr = arr.sort_by {|s| s.path}
|
90
|
+
last_parent = parent sarr[0].path
|
91
|
+
|
92
|
+
(sarr).each { |animefile|
|
93
|
+
|
94
|
+
#puts animefile.path
|
95
|
+
|
96
|
+
this_parent = parent animefile.path
|
97
|
+
|
98
|
+
#puts animefile.path
|
99
|
+
#puts this_parent
|
100
|
+
|
101
|
+
|
102
|
+
if this_parent != last_parent
|
103
|
+
ret.merge!(
|
104
|
+
AnimeSeries.new(
|
105
|
+
last_parent,
|
106
|
+
subarray
|
107
|
+
) => subarray)
|
108
|
+
subarray = [animefile]
|
109
|
+
else
|
110
|
+
subarray << animefile
|
111
|
+
end
|
112
|
+
|
113
|
+
last_parent = this_parent
|
114
|
+
|
115
|
+
}
|
116
|
+
ret.merge!(
|
117
|
+
AnimeSeries.new(
|
118
|
+
parent(sarr[sarr.length - 1].path),
|
119
|
+
subarray
|
120
|
+
) => subarray
|
121
|
+
)
|
122
|
+
|
123
|
+
|
124
|
+
#puts ret.inspect
|
125
|
+
#exit
|
126
|
+
|
127
|
+
return Hash[ret.sort_by{ |a| a[0].title}]
|
128
|
+
end
|
129
|
+
|
130
|
+
#return the difference of getAired and getWatched
|
131
|
+
def getUnwatched
|
132
|
+
ret = []
|
133
|
+
#puts @@local_anime
|
134
|
+
@@local_anime.each{ |anime|
|
135
|
+
ret << anime[1] if not anime[1].seen?
|
136
|
+
}
|
137
|
+
return ret
|
138
|
+
end
|
139
|
+
|
140
|
+
#return an AnimeFile array of all mkvs in any dir specified in $pref["dirs"]
|
141
|
+
def getAll
|
142
|
+
return @@local_anime.values
|
143
|
+
end
|
144
|
+
|
145
|
+
def getAllSeries
|
146
|
+
arr = getAll
|
147
|
+
|
148
|
+
last_parent = parent arr[0].path
|
149
|
+
ret = [ last_parent ]
|
150
|
+
|
151
|
+
arr.each { |animefile|
|
152
|
+
this_parent = parent animefile.path
|
153
|
+
if this_parent != last_parent
|
154
|
+
ret << this_parent
|
155
|
+
end
|
156
|
+
last_parent = this_parent
|
157
|
+
}
|
158
|
+
return ret
|
159
|
+
end
|
160
|
+
|
161
|
+
def logWatched(file)
|
162
|
+
open(@pref.get("watch_log"), 'a') do |f|
|
163
|
+
f.puts %x(date).chomp + " ./" + File.basename(file) + " " + @watch_log_tag
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def addWatched(file)
|
168
|
+
@@local_anime[file].watch
|
169
|
+
self.save
|
170
|
+
end
|
171
|
+
|
172
|
+
def rmWatched(path = "zoz")
|
173
|
+
|
174
|
+
if @@local_anime.key? path
|
175
|
+
@@local_anime[path].unwatch
|
176
|
+
return
|
177
|
+
end
|
178
|
+
|
179
|
+
r = []
|
180
|
+
@@local_anime.values.each_with_index{ |v, i| r << {Integer(v.seenOn) => @@local_anime.keys[i]} if v.seen? }
|
181
|
+
return if r.length == 0
|
182
|
+
last_watched = (r.sort_by{ |h| h.keys.first}.reverse)[0].values[0]
|
183
|
+
@@local_anime[last_watched].unwatch
|
184
|
+
self.save
|
185
|
+
end
|
186
|
+
|
187
|
+
#run mpv
|
188
|
+
def watch(file)
|
189
|
+
pid = spawn("mpv -alang jpn -slang eng -msg-level=all=fatal -ass '#{file}'")
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
require_relative '../../util/format'
|
4
|
+
|
5
|
+
class AnimeSeries
|
6
|
+
def initialize(_dir, children)
|
7
|
+
@path = _dir
|
8
|
+
@children = children
|
9
|
+
|
10
|
+
dur = getDuration
|
11
|
+
size = getSize
|
12
|
+
|
13
|
+
@attr = {
|
14
|
+
"t" => String(@path),
|
15
|
+
"c" => String(@children.length),
|
16
|
+
"d" => dur,
|
17
|
+
"D" => Format.format_duration(dur),
|
18
|
+
"s" => size,
|
19
|
+
"S" => Format.format_size(size),
|
20
|
+
}
|
21
|
+
end
|
22
|
+
def getDuration
|
23
|
+
dur = 0
|
24
|
+
@children.each{ |child|
|
25
|
+
dur += child.attributes["d"]
|
26
|
+
}
|
27
|
+
return dur
|
28
|
+
end
|
29
|
+
|
30
|
+
def getSize
|
31
|
+
size = 0
|
32
|
+
@children.each{ |child|
|
33
|
+
size += child.attributes["s"]
|
34
|
+
}
|
35
|
+
return size
|
36
|
+
end
|
37
|
+
|
38
|
+
def oldestChild
|
39
|
+
oldest = DateTime.now.strftime('%Q')
|
40
|
+
@children.each{ |child|
|
41
|
+
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def title
|
46
|
+
return @path
|
47
|
+
end
|
48
|
+
|
49
|
+
def attributes
|
50
|
+
return @attr
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'readline'
|
2
|
+
|
3
|
+
class Command
|
4
|
+
def self.read(term, prompt = "", default = "")
|
5
|
+
|
6
|
+
term.bold.echo_on
|
7
|
+
|
8
|
+
print "\033[" + String(term.rows) + ";1H"
|
9
|
+
term.show_cursor
|
10
|
+
|
11
|
+
Readline.pre_input_hook = -> do
|
12
|
+
Readline.insert_text default
|
13
|
+
Readline.redisplay
|
14
|
+
Readline.pre_input_hook = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
input = Readline.readline(prompt, false)
|
18
|
+
|
19
|
+
term.hide_cursor.nobold.echo_off.clear
|
20
|
+
|
21
|
+
return input
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Format
|
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
|
+
|
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
|
+
|
34
|
+
return String( Float(fs/bytecount[r] * 10.0 ).round / 10.0 ) + r
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
class Pref
|
4
|
+
def initialize
|
5
|
+
|
6
|
+
@home = Dir.home
|
7
|
+
@conf = @home + "/.aw"
|
8
|
+
|
9
|
+
dirname = File.dirname(@conf)
|
10
|
+
unless File.directory?(dirname)
|
11
|
+
FileUtils.mkdir_p(dirname)
|
12
|
+
end
|
13
|
+
|
14
|
+
@pref_file = @conf + "/r_anime"
|
15
|
+
|
16
|
+
self.defaults if not File.exist?(@pref_file)
|
17
|
+
self.load
|
18
|
+
end
|
19
|
+
|
20
|
+
def defaults
|
21
|
+
@pref = Hash[
|
22
|
+
"anime_locations" => @home + "/airing/shows/" + ":" + @home + "/anime/",
|
23
|
+
"clr" => Hash[
|
24
|
+
"main" => "blue",
|
25
|
+
"primary" => "white",
|
26
|
+
"secondary"=> "cyan",
|
27
|
+
"selected" => "red"
|
28
|
+
],
|
29
|
+
"menu_titles" => {
|
30
|
+
"1" => "unwatched",
|
31
|
+
"2" => "anime library",
|
32
|
+
"3" => "MyAnimeList",
|
33
|
+
|
34
|
+
"7" => "torrents",
|
35
|
+
"8" => "subscriptions",
|
36
|
+
"9" => "schedule",
|
37
|
+
"0" => "preferences"
|
38
|
+
},
|
39
|
+
"anime_library_title_format_str" => " %t - $r@ %D %S ",
|
40
|
+
"anime_library_title_show_format_str" => " %t - %c@ %D %S ",
|
41
|
+
"anime_library_title_episode_format_str" => " %t@ %D %S %t",
|
42
|
+
"anime_library_unwatched_title_format_str" => " %t@ $q@ %D %S ",
|
43
|
+
"anime_library_unwatched_title_show_format_str" => " %t - %c@ %D %S ",
|
44
|
+
"anime_library_unwatched_title_episode_format_str" => " %t@ %D %S %r ",
|
45
|
+
|
46
|
+
"preferences_title_format_str" => " %t",
|
47
|
+
"preferences_item_format_str" => " %t@.%v",
|
48
|
+
|
49
|
+
#"watch_file" => @conf + "/watched",
|
50
|
+
"log_file" => @conf + "/aw.log",
|
51
|
+
"watch_log" => @conf + "/watchlog",
|
52
|
+
|
53
|
+
"local_anime" => nil
|
54
|
+
]
|
55
|
+
self.save
|
56
|
+
end
|
57
|
+
|
58
|
+
def set(s, val)
|
59
|
+
arr = [s] if s.class == String
|
60
|
+
arr = s if s.class == Array
|
61
|
+
@pref = setpref(arr, val, @pref)
|
62
|
+
save
|
63
|
+
end
|
64
|
+
|
65
|
+
def setpref(s, val, bpref)
|
66
|
+
if s.length == 1
|
67
|
+
bpref[s[0]]=val
|
68
|
+
return bpref
|
69
|
+
else
|
70
|
+
key = s.delete_at(0)
|
71
|
+
bpref[key] = setpref(s, val, bpref[key])
|
72
|
+
end
|
73
|
+
return bpref
|
74
|
+
end
|
75
|
+
|
76
|
+
def get s
|
77
|
+
return @pref[s] if @pref.key?(s)
|
78
|
+
return ""
|
79
|
+
end
|
80
|
+
|
81
|
+
def getAll
|
82
|
+
ignore = {
|
83
|
+
"local_anime" => true,
|
84
|
+
}
|
85
|
+
|
86
|
+
r = {}
|
87
|
+
@pref.each{ |item|
|
88
|
+
next if ignore.key? item[0]
|
89
|
+
title = item[0]
|
90
|
+
if item[1].class == String
|
91
|
+
val = item[1]
|
92
|
+
elsif item[1].class == Array
|
93
|
+
val = item[1].join(":")
|
94
|
+
elsif item[1].class == Hash
|
95
|
+
item[1].each { |subitem|
|
96
|
+
subtitle = title + "_" + subitem[0]
|
97
|
+
subval = subitem[1]
|
98
|
+
|
99
|
+
r.merge!(PrefItem.new(subtitle, subval, []) => PrefItem.new("", "", [item[0], subitem[0]]))
|
100
|
+
}
|
101
|
+
next
|
102
|
+
end
|
103
|
+
r.merge!(PrefItem.new(title, val, []) => PrefItem.new("", "", [item[0]]))
|
104
|
+
}
|
105
|
+
return r
|
106
|
+
end
|
107
|
+
|
108
|
+
def saveLocalAnime dump
|
109
|
+
@pref["local_anime"] = dump
|
110
|
+
self.save
|
111
|
+
end
|
112
|
+
|
113
|
+
def save
|
114
|
+
File.open(@pref_file, "w") { |f| f.write(@pref.to_json) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def load
|
118
|
+
File.open(@pref_file, "r") {|f| @pref = JSON.parse(f.read)}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class PrefItem
|
123
|
+
def initialize(title, value, path_ = [])
|
124
|
+
@path = path_
|
125
|
+
@attr = {
|
126
|
+
"t" => title,
|
127
|
+
"v" => value,
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def attributes
|
132
|
+
return @attr
|
133
|
+
end
|
134
|
+
def path
|
135
|
+
return @path
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Term
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
@tput=Hash[
|
5
|
+
"smcup" => %x(tput smcup),
|
6
|
+
"rmcup" => %x(tput rmcup),
|
7
|
+
"civis" => %x(tput civis),
|
8
|
+
"cnorm" => %x(tput cnorm),
|
9
|
+
"el1" => "\e[2K",
|
10
|
+
"bold" => %x(tput bold),
|
11
|
+
"nobold" => %x(tput sgr0),
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
def save; print @tput["smcup"]; return self; end
|
16
|
+
def restore; print @tput["rmcup"]; return self; end
|
17
|
+
def hide_cursor; print @tput["civis"]; return self; end
|
18
|
+
def show_cursor; print @tput["cnorm"]; return self; end
|
19
|
+
def clear_line; print @tput["el1"]; return self; end
|
20
|
+
def echo_off; %x(stty -echo); return self; end
|
21
|
+
def echo_on; %x(stty echo); return self; end
|
22
|
+
def clear; print "\033[2J"; return self; end
|
23
|
+
def bold; print @tput["bold"]; return self; end
|
24
|
+
def nobold; print @tput["nobold"]; return self; end
|
25
|
+
|
26
|
+
def cols; return HighLine::SystemExtensions.terminal_size[0]; end
|
27
|
+
def rows; return HighLine::SystemExtensions.terminal_size[1]; end
|
28
|
+
|
29
|
+
def getKey
|
30
|
+
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")
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset
|
34
|
+
self.restore.show_cursor.echo_on
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative 'menu'
|
2
|
+
require_relative '../util/format'
|
3
|
+
|
4
|
+
|
5
|
+
class AioMenu < Menu
|
6
|
+
|
7
|
+
def setmal malanime
|
8
|
+
@malanime = malanime
|
9
|
+
end
|
10
|
+
|
11
|
+
def refresh
|
12
|
+
@items = @interface.makeHash @interface.send(@refresh_func)
|
13
|
+
|
14
|
+
@attributes = {
|
15
|
+
"t" => @attributes["t"],
|
16
|
+
"D" => Format.format_duration(getDuration),
|
17
|
+
"S" => Format.format_size(getSize)
|
18
|
+
}
|
19
|
+
|
20
|
+
@expanded = -1 if @items.values[@expanded] == nil
|
21
|
+
fixCursor
|
22
|
+
end
|
23
|
+
|
24
|
+
def getDuration
|
25
|
+
dur = 0
|
26
|
+
@items.each{ |child|
|
27
|
+
dur += child[0].attributes["d"]
|
28
|
+
}
|
29
|
+
return dur
|
30
|
+
end
|
31
|
+
|
32
|
+
def getSize
|
33
|
+
size = 0
|
34
|
+
@items.each{ |child|
|
35
|
+
size += child[0].attributes["s"]
|
36
|
+
}
|
37
|
+
return size
|
38
|
+
end
|
39
|
+
|
40
|
+
def customControl(key, sel)
|
41
|
+
path = @items.values[sel["out"]][sel["in"]].path
|
42
|
+
|
43
|
+
if key == "space"
|
44
|
+
expand(sel["out"])
|
45
|
+
elsif key == "r"
|
46
|
+
refresh
|
47
|
+
elsif key == "enter"
|
48
|
+
|
49
|
+
@interface.watch(path)
|
50
|
+
@interface.addWatched(path)
|
51
|
+
@interface.logWatched(path)
|
52
|
+
|
53
|
+
#@malanime.update(path)
|
54
|
+
|
55
|
+
refresh
|
56
|
+
elsif key == "Z"
|
57
|
+
@interface.addWatched(path)
|
58
|
+
refresh
|
59
|
+
elsif key == "z"
|
60
|
+
@interface.rmWatched()
|
61
|
+
refresh
|
62
|
+
elsif key == "u"
|
63
|
+
@interface.rmWatched(path)
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#define ascii codes for color names
|
2
|
+
$clr = Hash[
|
3
|
+
"black" => "\e[30m", "red" => "\e[31m", "green" => "\e[32m", "yellow" => "\e[33m", "blue" => "\e[34m", "magenta" => "\e[35m", "cyan" => "\e[36m", "white" => "\e[37m",
|
4
|
+
"bright_black" => "\e[37m", "bright_red" => "\e[38m", "bright_green" => "\e[39m", "bright_yellow" => "\e[40m", "bright_blue" => "\e[41m", "bright_magenta" => "\e[42m", "bright_cyan" => "\e[43m", "bright_white" => "\e[44m",
|
5
|
+
]
|
6
|
+
|
7
|
+
$emote = {
|
8
|
+
"amazed" => '( ゚д゚)',
|
9
|
+
"a" => '( ゚д゚)',
|
10
|
+
"angry" => '(#゚Д゚)',
|
11
|
+
"b" => '(#゚Д゚)',
|
12
|
+
"bad" => '(・A・)',
|
13
|
+
"c" => '(・A・)',
|
14
|
+
"bowing" => 'm(_ _)m',
|
15
|
+
"d" => 'm(_ _)m',
|
16
|
+
"bun" => '⊂二二二( ^ω^)二⊃',
|
17
|
+
"e" => '⊂二二二( ^ω^)二⊃',
|
18
|
+
"carefree" => '(´∀`)',
|
19
|
+
"f" => '(´∀`)',
|
20
|
+
"chinese" => '(`ハ´)',
|
21
|
+
"g" => '(`ハ´)',
|
22
|
+
"crying" => '( ´Д⊂ヽ',
|
23
|
+
"h" => '(´Д⊂ヽ',
|
24
|
+
"deflagged" => '[゚д゚]',
|
25
|
+
"i" => '[゚д゚]',
|
26
|
+
"deflated" => '(´・ω・`)',
|
27
|
+
"j" => '(´・ω・`)',
|
28
|
+
"depressed" => '( ´,_ゝ`)',
|
29
|
+
"k" => '( ´,_ゝ`)',
|
30
|
+
"dontknow" => '┐(`~`;)┌',
|
31
|
+
"l" => '┐(`~`;)┌',
|
32
|
+
"evillaugh" => '( ゚∀゚)アハハ八八ノヽノヽノヽノ \ / \/ \',
|
33
|
+
"m" => '( ゚∀゚)アハハ八八ノヽノヽノヽノ \ / \/ \',
|
34
|
+
"excitement" => 'キタ━━━━━━(゚∀゚)━━━━━━!!!!!',
|
35
|
+
"n" => 'キタ━━━━━━(゚∀゚)━━━━━━!!!!!',
|
36
|
+
"goofy" => '(゚∀゚)',
|
37
|
+
"o" => '(゚∀゚)',
|
38
|
+
"happy" => '( ゚ ヮ゚)',
|
39
|
+
"p" => '( ゚ ヮ゚)',
|
40
|
+
"heh" => '(´・∀・`)',
|
41
|
+
"q" => '(´•∀•`)',
|
42
|
+
"hooray" => '\(^o^)/',
|
43
|
+
"r" => '\(^o^)/',
|
44
|
+
"hugesurprise" => 'Σ(゚Д゚)',
|
45
|
+
"s" => 'Σ(゚Д゚)',
|
46
|
+
"impatience" => '(゚Д゚;≡;゚Д゚)',
|
47
|
+
"t" => '(゚Д゚;≡;゚Д゚)',
|
48
|
+
"indifferent" => '( ´_ゝ`)',
|
49
|
+
"u" => '( ´_ゝ`)',
|
50
|
+
"intuition" => 'm9(・∀・)',
|
51
|
+
"v" => 'm9(・∀・)',
|
52
|
+
"irritable" => 'ヽ(`Д´)ノ',
|
53
|
+
"w" => 'ヽ(`Д´)ノ',
|
54
|
+
"koi" => 'щ(゚Д゚щ)',
|
55
|
+
"x" => 'щ(゚Д゚щ)',
|
56
|
+
"korean" => '<`∀´>',
|
57
|
+
"y" => '<`∀´>',
|
58
|
+
"money" => '(・∀・)つ⑩',
|
59
|
+
"z" => '(・∀・)つ⑩',
|
60
|
+
"panting" => '( ´Д`)',
|
61
|
+
"M" => '( ´Д`)',
|
62
|
+
"peace" => 'ヽ(´ー`)ノ',
|
63
|
+
"N" => 'ヽ(´ー`)ノ',
|
64
|
+
"perky" => '(`・ω・´)',
|
65
|
+
"O" => '(`・ω・´)',
|
66
|
+
"sad" => '(´;ω;`)',
|
67
|
+
"P" => '(´;ω;`)',
|
68
|
+
"sarcasm" => '(・∀・)',
|
69
|
+
"A" => '(・∀・)',
|
70
|
+
"shocked" => 'Σ(゜д゜;)',
|
71
|
+
"B" => 'Σ(゜д゜;)',
|
72
|
+
"smoking" => '(´ー`)y-~~',
|
73
|
+
"C" => '(´ー`)y-~~',
|
74
|
+
"snorlax" => '( ̄ー ̄)',
|
75
|
+
"D" => '( ̄ー ̄)',
|
76
|
+
"spooked" => '(((( ;゚Д゚)))',
|
77
|
+
"E" => '(((( ;゚Д゚)))',
|
78
|
+
"stirring" => '(*´Д`)',
|
79
|
+
"F" => '(*´Д`)',
|
80
|
+
"supercilious" => 'm9(^Д^)',
|
81
|
+
"G" => 'm9(^Д^)',
|
82
|
+
"surprised" => '( ゚Д゚)',
|
83
|
+
"H" => '( ゚Д゚)',
|
84
|
+
"tfwnogf" => '(`A`)',
|
85
|
+
"I" => '(`A`)',
|
86
|
+
"thinking" => '(´-`).。oO',
|
87
|
+
"J" => '(´-`).。oO',
|
88
|
+
"unconvincing" => 'エェェ(´д`)ェェエ',
|
89
|
+
"K" => 'エェェ(´д`)ェェエ',
|
90
|
+
"unforeseen" => '(゚д゚)',
|
91
|
+
"L" => '(゚д゚)',
|
92
|
+
"_positive" => [0, 5, 13, 14, 15, 17, 37]
|
93
|
+
}
|
94
|
+
def positive_emote
|
95
|
+
return $emote.values[$emote["_positive"][rand($emote["_positive"].length)]]
|
96
|
+
end
|
97
|
+
|
@@ -0,0 +1,283 @@
|
|
1
|
+
require_relative 'emote'
|
2
|
+
|
3
|
+
class Menu
|
4
|
+
|
5
|
+
def initialize(refresh_function, interface, name, pref, format_, term)
|
6
|
+
@term = term
|
7
|
+
@format_ = format_
|
8
|
+
@attributes = {
|
9
|
+
"t" => name,
|
10
|
+
}
|
11
|
+
@pref = pref
|
12
|
+
@refresh_func = refresh_function
|
13
|
+
@interface = interface
|
14
|
+
@expanded = -1
|
15
|
+
@selected = 0
|
16
|
+
@scrollup = false
|
17
|
+
|
18
|
+
refresh
|
19
|
+
@lastcount = getLen
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def setRfunc(name)
|
24
|
+
@refresh_func = name
|
25
|
+
refresh
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_screen_size(lines, cols)
|
29
|
+
#@term.rows = lines
|
30
|
+
#@term.cols = cols
|
31
|
+
draw
|
32
|
+
end
|
33
|
+
|
34
|
+
def setName(name)
|
35
|
+
@attributes["t"] = name
|
36
|
+
end
|
37
|
+
|
38
|
+
def setFormat(format_)
|
39
|
+
@format_ = format_
|
40
|
+
end
|
41
|
+
|
42
|
+
def refresh
|
43
|
+
@items = @interface.makeHash @interface.send(@refresh_func)
|
44
|
+
@expanded = -1 if @items.values[@expanded] == nil
|
45
|
+
fixCursor
|
46
|
+
end
|
47
|
+
|
48
|
+
def expand(i)
|
49
|
+
return if i > @items.length
|
50
|
+
if @expanded == i
|
51
|
+
@selected = @expanded
|
52
|
+
@expanded = -1
|
53
|
+
else
|
54
|
+
@selected = i
|
55
|
+
@expanded = i
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def resolveSelected(resolve_me=@selected)
|
60
|
+
in_expanded=false
|
61
|
+
inside = 0
|
62
|
+
outside = resolve_me
|
63
|
+
if @expanded > -1
|
64
|
+
if resolve_me > @expanded and resolve_me <= (@items.values[@expanded].length + @expanded)
|
65
|
+
outside = @expanded
|
66
|
+
inside = resolve_me - @expanded - 1
|
67
|
+
in_expanded=true
|
68
|
+
elsif resolve_me > @expanded
|
69
|
+
outside = resolve_me - @items.values[@expanded].length
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
return Hash["out" => outside, "in" => inside, "in_expanded" => in_expanded]
|
74
|
+
end
|
75
|
+
|
76
|
+
def moveCursor(dir)
|
77
|
+
@scrollup = false if dir == "down"
|
78
|
+
@scrollup = true if dir == "up"
|
79
|
+
@selected -= 1 if dir == "up"
|
80
|
+
@selected += 1 if dir == "down"
|
81
|
+
fixCursor
|
82
|
+
end
|
83
|
+
|
84
|
+
def fixCursor
|
85
|
+
#wrap selector
|
86
|
+
#@selected = getLen - 1 if @selected < 0
|
87
|
+
#@selected = 0 if @selected >= getLen
|
88
|
+
#
|
89
|
+
#nowrap
|
90
|
+
@selected = 0 if @selected < 0
|
91
|
+
@selected = getLen - 1 if @selected >= getLen
|
92
|
+
end
|
93
|
+
|
94
|
+
def getLen
|
95
|
+
len = @items.length
|
96
|
+
len += @items.values[@expanded].length if @expanded >= 0
|
97
|
+
return len
|
98
|
+
end
|
99
|
+
|
100
|
+
def color(index)
|
101
|
+
if index == @selected
|
102
|
+
return $clr[@pref.get("clr")["selected"]]
|
103
|
+
else
|
104
|
+
return $clr[@pref.get("clr")["secondary"]]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def draw
|
109
|
+
#the number of lines to preview
|
110
|
+
buffer = 3
|
111
|
+
|
112
|
+
#@term.rows-2 is used because 2 lines are reserved for
|
113
|
+
#the command line (the bottom line)
|
114
|
+
#and the title line (the top line)
|
115
|
+
|
116
|
+
if getLen > @term.rows - 2
|
117
|
+
finish = @selected + buffer #if not @scrollup
|
118
|
+
finish = @term.rows - 2 if finish < @term.rows - 2
|
119
|
+
finish = getLen if finish > getLen
|
120
|
+
start = finish - ( @term.rows-2 )
|
121
|
+
else
|
122
|
+
start = 0
|
123
|
+
finish = @term.rows - 2
|
124
|
+
end
|
125
|
+
|
126
|
+
drawFrom(start, finish)
|
127
|
+
end
|
128
|
+
|
129
|
+
def drawFrom(line_on, lines_to_draw)
|
130
|
+
#print menu header
|
131
|
+
printmf(
|
132
|
+
@pref.get(@format_["title"]),
|
133
|
+
1,
|
134
|
+
false,
|
135
|
+
@attributes,
|
136
|
+
"title"
|
137
|
+
)
|
138
|
+
|
139
|
+
resolved_start_position = resolveSelected line_on
|
140
|
+
|
141
|
+
outer_index = resolved_start_position["out"]
|
142
|
+
inner_index = resolved_start_position["in"]
|
143
|
+
|
144
|
+
if resolved_start_position["in_expanded"]
|
145
|
+
outer_index+=1
|
146
|
+
end
|
147
|
+
|
148
|
+
offset=line_on-1
|
149
|
+
|
150
|
+
while line_on < lines_to_draw
|
151
|
+
|
152
|
+
in_outer_region = ! (line_on >= getLen)
|
153
|
+
in_expanded_region = resolveSelected(line_on)["in_expanded"]
|
154
|
+
real_line_on = line_on-offset+1
|
155
|
+
selected = line_on == @selected
|
156
|
+
|
157
|
+
if in_expanded_region
|
158
|
+
printmf(
|
159
|
+
@pref.get(@format_["child"]),
|
160
|
+
real_line_on,
|
161
|
+
selected,
|
162
|
+
@items.values[@expanded][ inner_index ].attributes,
|
163
|
+
"inside"
|
164
|
+
)
|
165
|
+
inner_index+=1
|
166
|
+
elsif in_outer_region
|
167
|
+
printmf(
|
168
|
+
@pref.get(@format_["parent"]),
|
169
|
+
real_line_on,
|
170
|
+
selected,
|
171
|
+
@items.keys[outer_index].attributes,
|
172
|
+
"outside"
|
173
|
+
)
|
174
|
+
outer_index+=1
|
175
|
+
else
|
176
|
+
print "\e[2K\n"
|
177
|
+
end
|
178
|
+
|
179
|
+
line_on+=1
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def printmf(string, line, selected, d, loc)
|
184
|
+
lo = "\e[#{line};1H"
|
185
|
+
le = "\e[K\n"
|
186
|
+
|
187
|
+
if loc == "outside"
|
188
|
+
cl = $clr[@pref.get("clr")["primary"]]
|
189
|
+
elsif loc == "inside"
|
190
|
+
cl = $clr[@pref.get("clr")["secondary"]]
|
191
|
+
elsif loc == "title"
|
192
|
+
cl = $clr[@pref.get("clr")["main"]]
|
193
|
+
end
|
194
|
+
|
195
|
+
cl = $clr[@pref.get("clr")["selected"]] if selected
|
196
|
+
|
197
|
+
pstr = []
|
198
|
+
add_to = ""
|
199
|
+
buffer_char = []
|
200
|
+
|
201
|
+
percent_mode = false
|
202
|
+
dollar_mode = false
|
203
|
+
at_mode = false
|
204
|
+
escape_mode = false
|
205
|
+
padding_collected = 0
|
206
|
+
|
207
|
+
string.split('').each { |c|
|
208
|
+
if escape_mode == true
|
209
|
+
add_to += String(c)
|
210
|
+
escape_mode = false
|
211
|
+
elsif c == '%'
|
212
|
+
percent_mode = true
|
213
|
+
elsif c == '$'
|
214
|
+
dollar_mode = true
|
215
|
+
elsif c == '@'
|
216
|
+
pstr << add_to
|
217
|
+
add_to = ""
|
218
|
+
at_mode = true
|
219
|
+
elsif c == "#"
|
220
|
+
padding_collected += 1
|
221
|
+
elsif c == "\\"
|
222
|
+
escape_mode = true
|
223
|
+
elsif at_mode
|
224
|
+
buffer_char << c
|
225
|
+
at_mode = false
|
226
|
+
elsif percent_mode
|
227
|
+
addstr = ""
|
228
|
+
addstr = String(d[c]) if d.key?(c)
|
229
|
+
ol = addstr.length
|
230
|
+
while addstr.length < (ol + padding_collected)
|
231
|
+
addstr = " " + addstr
|
232
|
+
end
|
233
|
+
|
234
|
+
add_to += addstr
|
235
|
+
|
236
|
+
percent_mode = false
|
237
|
+
elsif dollar_mode
|
238
|
+
add_to += String($emote[c]) if $emote.key?(c)
|
239
|
+
dollar_mode = false
|
240
|
+
else
|
241
|
+
add_to += c
|
242
|
+
end
|
243
|
+
}
|
244
|
+
pstr << add_to
|
245
|
+
|
246
|
+
midstr = ""
|
247
|
+
tl = 0
|
248
|
+
pstr.each{ |s| tl += s.length }
|
249
|
+
buffer_space = 0
|
250
|
+
buffer_space = (@term.cols - tl) / (pstr.length - 1) if pstr.length > 1
|
251
|
+
|
252
|
+
addl_space = (@term.cols - tl) % pstr.length
|
253
|
+
|
254
|
+
pstr.each_with_index{ |str, i|
|
255
|
+
#buffer_space += addl_space if i == pstr.length - 2
|
256
|
+
#if i == pstr.length - 1
|
257
|
+
#puts addl_space
|
258
|
+
#puts i == pstr.length - 1
|
259
|
+
|
260
|
+
break if i == pstr.length - 1
|
261
|
+
buffer_ = ""
|
262
|
+
buffer_ = buffer_char[i] * buffer_space if buffer_space >= 0
|
263
|
+
midstr += str + buffer_
|
264
|
+
}
|
265
|
+
midstr += pstr[pstr.length - 1]
|
266
|
+
|
267
|
+
print lo + cl + midstr + le
|
268
|
+
end
|
269
|
+
|
270
|
+
def control(key)
|
271
|
+
sel = resolveSelected
|
272
|
+
if key == "up"
|
273
|
+
moveCursor("up")
|
274
|
+
elsif key == "down"
|
275
|
+
moveCursor("down")
|
276
|
+
else
|
277
|
+
customControl(key, sel)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def customControl(key, sel); end
|
282
|
+
|
283
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'menu'
|
2
|
+
require_relative '../util/format'
|
3
|
+
require_relative '../util/command'
|
4
|
+
|
5
|
+
|
6
|
+
class PrefMenu < Menu
|
7
|
+
|
8
|
+
def refresh
|
9
|
+
@items = @interface.send(@refresh_func)
|
10
|
+
|
11
|
+
@attributes = {
|
12
|
+
"t" => @attributes["t"],
|
13
|
+
}
|
14
|
+
|
15
|
+
@expanded = -1 if @items.values[@expanded] == nil
|
16
|
+
fixCursor
|
17
|
+
end
|
18
|
+
|
19
|
+
def customControl(key, sel)
|
20
|
+
path = @items.values[sel["out"]].path
|
21
|
+
title = @items.keys[sel["out"]].attributes["t"]
|
22
|
+
value = @items.keys[sel["out"]].attributes["v"]
|
23
|
+
|
24
|
+
if key == "space"
|
25
|
+
#expand(sel["out"])
|
26
|
+
elsif key == "r"
|
27
|
+
refresh
|
28
|
+
elsif key == "enter"
|
29
|
+
|
30
|
+
newval = Command.read(@term, title + ":", value)
|
31
|
+
|
32
|
+
@interface.set(path, newval)
|
33
|
+
refresh
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aniview
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- annacrombie
|
@@ -9,15 +9,69 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
date: 2017-04-17 00:00:00.000000000 Z
|
12
|
-
dependencies:
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: streamio-ffmpeg
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.0.2
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.2
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: highline
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.7'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.7.8
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.7'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.7.8
|
13
53
|
description: Browse local anime, based on cmus
|
14
54
|
email: meotleft@gmail.com
|
15
|
-
executables:
|
55
|
+
executables:
|
56
|
+
- aniview
|
16
57
|
extensions: []
|
17
58
|
extra_rdoc_files: []
|
18
59
|
files:
|
60
|
+
- bin/aniview
|
19
61
|
- lib/aniview.rb
|
20
|
-
|
62
|
+
- lib/aniview/interface/animeio/animefile.rb
|
63
|
+
- lib/aniview/interface/animeio/animeio.rb
|
64
|
+
- lib/aniview/interface/animeio/animeseries.rb
|
65
|
+
- lib/aniview/util/command.rb
|
66
|
+
- lib/aniview/util/format.rb
|
67
|
+
- lib/aniview/util/logger.rb
|
68
|
+
- lib/aniview/util/pref.rb
|
69
|
+
- lib/aniview/util/term.rb
|
70
|
+
- lib/aniview/view/aiomenu.rb
|
71
|
+
- lib/aniview/view/emote.rb
|
72
|
+
- lib/aniview/view/menu.rb
|
73
|
+
- lib/aniview/view/prefmenu.rb
|
74
|
+
homepage: https://github.com/annacrombie/aniview/
|
21
75
|
licenses:
|
22
76
|
- MIT
|
23
77
|
metadata: {}
|
@@ -27,9 +81,9 @@ require_paths:
|
|
27
81
|
- lib
|
28
82
|
required_ruby_version: !ruby/object:Gem::Requirement
|
29
83
|
requirements:
|
30
|
-
- - "
|
84
|
+
- - ">"
|
31
85
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
86
|
+
version: 2.2.0
|
33
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
88
|
requirements:
|
35
89
|
- - ">="
|