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