1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
--[[
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2017 William Wilgus
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
]]
if ... == nil then rb.splash(rb.HZ * 3, "use 'require'") end
require("printtable")
local _lcd = require("lcd")
local _timer = require("timer")
--------------------------------------------------------------------------------
--[[ returns a sorted tables of directories and (another) of files
-- path is the starting path; norecurse == true.. only that path will be searched
-- findfile & finddir are definable search functions
-- if not defined all files/dirs are returned if false is passed.. none
-- or you can provide your own function see below..
-- f_t and d_t allow you to pass your own tables for re-use but isn't necessary
]]
local function get_files(path, norecurse, finddir, findfile, sort_by, f_t, d_t)
local quit = false
local sort_by_function -- forward declaration
local filepath_function -- forward declaration
local files = f_t or {}
local dirs = d_t or {}
local function f_filedir(name)
--default find function
-- example: return name:find(".mp3", 1, true) ~= nil
if name:len() <= 2 and (name == "." or name == "..") then
return false
end
return true
end
local function d_filedir(name)
--default discard function
return false
end
if finddir == nil then
finddir = f_filedir
elseif type(finddir) ~= "function" then
finddir = d_filedir
end
if findfile == nil then
findfile = f_filedir
elseif type(findfile) ~= "function" then
findfile = d_filedir
end
local function _get_files(path, cancelbtn)
local sep = ""
local filepath
local finfo_t
if string.sub(path, - 1) ~= "/" then sep = "/" end
for fname, isdir, finfo_t in luadir.dir(path, true) do
if isdir and finddir(fname) then
table.insert(dirs, path .. sep ..fname)
elseif not isdir and findfile(fname) then
filepath = filepath_function(path, sep, fname, finfo_t.attribute, finfo_t.size, finfo_t.time)
table.insert(files, filepath)
end
if rb.get_plugin_action(0) == cancelbtn then
return true
end
end
end
local function cmp_alphanum (op1, op2)
local type1= type(op1)
local type2 = type(op2)
if type1 ~= type2 then
return type1 < type2
else
if type1 == "string" then
op1 = op1:upper()
op2 = op2:upper()
return sort_by_function(op1, op2)
end
return op1 < op2
end
end
_lcd:splashf(1, "Searching for Files")
if sort_by == "name" then
sort_by_function = function(s1, s2) return s1 < s2 end
filepath_function = function(path, sep, fname, fattrib, fsize, ftime)
return string.format("%s%s%s;", path, sep, fname)
end
elseif sort_by == "size" then
filepath_function = function(path, sep, fname, fattrib, fsize, ftime)
return string.format("%s%s%s; At:%d, Sz:%d, Tm:%d", path, sep, fname, fattrib, fsize, ftime)
end
sort_by_function = function(s1, s2)
local v1, v2
v1 = string.match(s1, "SZ:(%d+)")
v2 = string.match(s2, "SZ:(%d+)")
if v1 or v2 then
return tonumber(v1 or 0) < tonumber(v2 or 0)
end
return s1 < s2
end
elseif sort_by == "date" then
filepath_function = function(path, sep, fname, fattrib, fsize, ftime)
return string.format("%s%s%s; At:%d, Sz:%d, Tm:%d", path, sep, fname, fattrib, fsize, ftime)
end
sort_by_function = function(s1, s2)
local v1, v2
v1 = string.match(s1, "TM:(%d+)")
v2 = string.match(s2, "TM:(%d+)")
if v1 or v2 then
return tonumber(v1 or 0) < tonumber(v2 or 0)
end
return s1 < s2
end
end
table.insert(dirs, path) -- root
for key,value in pairs(dirs) do
--luadir.dir may error out so we need to do the call protected
-- _get_files(value, CANCEL_BUTTON)
_, quit = pcall(_get_files, value, CANCEL_BUTTON)
if quit == true or norecurse then
break;
end
end
table.sort(files, cmp_alphanum)
table.sort(dirs, cmp_alphanum)
return dirs, files
end -- get_files
--------------------------------------------------------------------------------
-- uses print_table and get_files to display simple file browser
-- sort_by "date" "name" "size"
-- descending true/false
function file_choose(dir, title, sort_by, descending)
local dstr, hstr = ""
if not title then
dstr = "%d items found in %0d.%02d seconds"
else
hstr = title
end
if not sort_by then sort_by = "name" end
sort_by = sort_by:lower()
-- returns whole seconds and remainder
local function tick2seconds(ticks)
local secs = (ticks / rb.HZ)
local csecs = (ticks - (secs * rb.HZ))
return secs, csecs
end
local norecurse = true
local f_finddir = nil -- function to match directories; nil all, false none
local f_findfile = nil -- function to match files; nil all, false none
local p_settings = {wrap = true, hasheader = true}
local timer
local files = {}
local dirs = {}
local item = 1
_lcd:clear()
while item > 0 do
if not title then
timer = _timer()
end
dirs, files = get_files(dir, norecurse, f_finddir, f_findfile, sort_by, dirs, files)
local parentdir = dirs[1]
for i = 1, #dirs do
dirs[i] = "\t" .. dirs[i]
end
if not descending then
for i = 1, #files do
-- only store file name .. strip attributes from end
table.insert(dirs, "\t" .. string.match(files[i], "[^;]+") or "?")
end
else
for i = #files, 1, -1 do
-- only store file name .. strip attributes from end
table.insert(dirs, "\t" .. string.match(files[i], "[^;]+") or "?")
end
end
for i=1, #files do files[i] = nil end -- empty table for reuse
if not title then
hstr = string.format(dstr, #dirs - 1, tick2seconds(timer:stop()))
end
table.insert(dirs, 1, hstr)
item = print_table(dirs, #dirs, p_settings)
-- If item was selected follow directory or return filename
if item > 0 then
dir = string.gsub(dirs[item], "%c+","")
if not rb.dir_exists("/" .. dir) then
return dir
end
end
if dir == parentdir then
dir = dir:sub(1, dir:match(".*()/") - 1)
if dir == "" then dir = "/" end
end
for i=1, #dirs do dirs[i] = nil end -- empty table for reuse
end
end -- file_choose
--------------------------------------------------------------------------------
|