2019-11-05 23:17:28 +00:00
|
|
|
local DataStorage = require("datastorage")
|
2020-09-15 18:39:32 +00:00
|
|
|
local FFIUtil = require("ffi/util")
|
2019-11-05 23:17:28 +00:00
|
|
|
local LuaSettings = require("luasettings")
|
|
|
|
local lfs = require("libs/libkoreader-lfs")
|
2023-12-10 06:05:34 +00:00
|
|
|
local logger = require("logger")
|
2019-11-05 23:17:28 +00:00
|
|
|
local util = require("util")
|
|
|
|
|
|
|
|
local collection_file = DataStorage:getSettingsDir() .. "/collection.lua"
|
|
|
|
|
2023-12-10 06:05:34 +00:00
|
|
|
local ReadCollection = {
|
2024-05-01 06:01:59 +00:00
|
|
|
coll = nil, -- hash table
|
|
|
|
coll_order = nil, -- hash table
|
2023-12-10 06:05:34 +00:00
|
|
|
last_read_time = 0,
|
|
|
|
default_collection_name = "favorites",
|
|
|
|
}
|
2019-11-05 23:17:28 +00:00
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
-- read, write
|
|
|
|
|
2023-12-10 06:05:34 +00:00
|
|
|
local function buildEntry(file, order, mandatory)
|
|
|
|
file = FFIUtil.realpath(file)
|
|
|
|
if not file then return end
|
|
|
|
if not mandatory then -- new item
|
|
|
|
local attr = lfs.attributes(file)
|
|
|
|
if not attr or attr.mode ~= "file" then return end
|
|
|
|
mandatory = util.getFriendlySize(attr.size or 0)
|
|
|
|
end
|
|
|
|
return {
|
|
|
|
file = file,
|
|
|
|
text = file:gsub(".*/", ""),
|
|
|
|
mandatory = mandatory,
|
|
|
|
order = order,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
function ReadCollection:_read()
|
|
|
|
local collection_file_modification_time = lfs.attributes(collection_file, "modification")
|
|
|
|
if collection_file_modification_time then
|
|
|
|
if collection_file_modification_time <= self.last_read_time then return end
|
|
|
|
self.last_read_time = collection_file_modification_time
|
|
|
|
end
|
2019-11-05 23:17:28 +00:00
|
|
|
local collections = LuaSettings:open(collection_file)
|
2023-12-10 06:05:34 +00:00
|
|
|
if collections:hasNot(self.default_collection_name) then
|
|
|
|
collections:saveSetting(self.default_collection_name, {})
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
2023-12-10 06:05:34 +00:00
|
|
|
logger.dbg("ReadCollection: reading from collection file")
|
|
|
|
self.coll = {}
|
2024-05-01 06:01:59 +00:00
|
|
|
self.coll_order = {}
|
2023-12-10 06:05:34 +00:00
|
|
|
for coll_name, collection in pairs(collections.data) do
|
|
|
|
local coll = {}
|
|
|
|
for _, v in ipairs(collection) do
|
|
|
|
local item = buildEntry(v.file, v.order)
|
|
|
|
if item then -- exclude deleted files
|
|
|
|
coll[item.file] = item
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
|
|
|
end
|
2023-12-10 06:05:34 +00:00
|
|
|
self.coll[coll_name] = coll
|
2024-05-01 06:01:59 +00:00
|
|
|
if not collection.settings then -- favorites, first run
|
|
|
|
collection.settings = { order = 1 }
|
|
|
|
end
|
|
|
|
self.coll_order[coll_name] = collection.settings.order
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
2023-12-10 06:05:34 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function ReadCollection:write(collection_name)
|
|
|
|
local collections = LuaSettings:open(collection_file)
|
2024-05-01 06:01:59 +00:00
|
|
|
for coll_name in pairs(collections.data) do
|
|
|
|
if not self.coll[coll_name] then
|
|
|
|
collections:delSetting(coll_name)
|
|
|
|
end
|
|
|
|
end
|
2023-12-10 06:05:34 +00:00
|
|
|
for coll_name, coll in pairs(self.coll) do
|
|
|
|
if not collection_name or coll_name == collection_name then
|
2024-05-01 06:01:59 +00:00
|
|
|
local data = { settings = { order = self.coll_order[coll_name] } }
|
2023-12-10 06:05:34 +00:00
|
|
|
for _, item in pairs(coll) do
|
|
|
|
table.insert(data, { file = item.file, order = item.order })
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
2023-12-10 06:05:34 +00:00
|
|
|
collections:saveSetting(coll_name, data)
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
|
|
|
end
|
2023-12-10 06:05:34 +00:00
|
|
|
logger.dbg("ReadCollection: writing to collection file")
|
|
|
|
collections:flush()
|
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
-- info
|
|
|
|
|
|
|
|
function ReadCollection:isFileInCollection(file, collection_name)
|
2023-12-10 06:05:34 +00:00
|
|
|
file = FFIUtil.realpath(file) or file
|
2024-05-01 06:01:59 +00:00
|
|
|
return self.coll[collection_name][file] and true or false
|
|
|
|
end
|
|
|
|
|
|
|
|
function ReadCollection:isFileInCollections(file)
|
|
|
|
file = FFIUtil.realpath(file) or file
|
|
|
|
for _, coll in pairs(self.coll) do
|
|
|
|
if coll[file] then
|
|
|
|
return true
|
2023-12-10 06:05:34 +00:00
|
|
|
end
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
2024-05-01 06:01:59 +00:00
|
|
|
return false
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
function ReadCollection:getCollectionsWithFile(file)
|
|
|
|
file = FFIUtil.realpath(file) or file
|
|
|
|
local collections = {}
|
|
|
|
for coll_name, coll in pairs(self.coll) do
|
|
|
|
if coll[file] then
|
|
|
|
collections[coll_name] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return collections
|
2023-12-10 06:05:34 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function ReadCollection:getCollectionMaxOrder(collection_name)
|
|
|
|
local max_order = 0
|
|
|
|
for _, item in pairs(self.coll[collection_name]) do
|
|
|
|
if max_order < item.order then
|
|
|
|
max_order = item.order
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
|
|
|
end
|
2023-12-10 06:05:34 +00:00
|
|
|
return max_order
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
-- manage items
|
2019-11-05 23:17:28 +00:00
|
|
|
|
|
|
|
function ReadCollection:addItem(file, collection_name)
|
2023-12-10 06:05:34 +00:00
|
|
|
local max_order = self:getCollectionMaxOrder(collection_name)
|
|
|
|
local item = buildEntry(file, max_order + 1)
|
|
|
|
self.coll[collection_name][item.file] = item
|
|
|
|
self:write(collection_name)
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
function ReadCollection:addRemoveItemMultiple(file, collections_to_add)
|
|
|
|
file = FFIUtil.realpath(file) or file
|
|
|
|
for coll_name, coll in pairs(self.coll) do
|
|
|
|
if collections_to_add[coll_name] then
|
|
|
|
if not coll[file] then
|
|
|
|
local max_order = self:getCollectionMaxOrder(coll_name)
|
|
|
|
coll[file] = buildEntry(file, max_order + 1)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if coll[file] then
|
|
|
|
coll[file] = nil
|
|
|
|
end
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
|
|
|
end
|
2024-05-01 06:01:59 +00:00
|
|
|
self:write()
|
|
|
|
end
|
|
|
|
|
|
|
|
function ReadCollection:addItemsMultiple(files, collections_to_add)
|
|
|
|
for file in pairs(files) do
|
|
|
|
file = FFIUtil.realpath(file) or file
|
|
|
|
for coll_name in pairs(collections_to_add) do
|
|
|
|
local coll = self.coll[coll_name]
|
|
|
|
if not coll[file] then
|
|
|
|
local max_order = self:getCollectionMaxOrder(coll_name)
|
|
|
|
coll[file] = buildEntry(file, max_order + 1)
|
|
|
|
end
|
|
|
|
end
|
2023-12-10 06:05:34 +00:00
|
|
|
end
|
2024-05-01 06:01:59 +00:00
|
|
|
self:write()
|
2019-11-05 23:17:28 +00:00
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
function ReadCollection:removeItem(file, collection_name, no_write) -- FM: delete file; FMColl: remove file
|
|
|
|
file = FFIUtil.realpath(file) or file
|
|
|
|
if collection_name then
|
|
|
|
if self.coll[collection_name][file] then
|
|
|
|
self.coll[collection_name][file] = nil
|
|
|
|
if not no_write then
|
|
|
|
self:write(collection_name)
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
else
|
|
|
|
local do_write
|
|
|
|
for _, coll in pairs(self.coll) do
|
|
|
|
if coll[file] then
|
|
|
|
coll[file] = nil
|
|
|
|
do_write = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if do_write then
|
|
|
|
if not no_write then
|
|
|
|
self:write()
|
|
|
|
end
|
|
|
|
return true
|
2023-12-10 06:05:34 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
function ReadCollection:removeItems(files) -- FM: delete files
|
2023-12-10 06:05:34 +00:00
|
|
|
local do_write
|
|
|
|
for file in pairs(files) do
|
|
|
|
if self:removeItem(file, nil, true) then
|
|
|
|
do_write = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if do_write then
|
|
|
|
self:write()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
function ReadCollection:removeItemsByPath(path) -- FM: delete folder
|
2023-12-10 06:05:34 +00:00
|
|
|
local do_write
|
|
|
|
for coll_name, coll in pairs(self.coll) do
|
|
|
|
for file_name in pairs(coll) do
|
|
|
|
if util.stringStartsWith(file_name, path) then
|
2024-05-01 06:01:59 +00:00
|
|
|
coll[file_name] = nil
|
2023-12-10 06:05:34 +00:00
|
|
|
do_write = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if do_write then
|
|
|
|
self:write()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function ReadCollection:_updateItem(coll_name, file_name, new_filepath, new_path)
|
|
|
|
local coll = self.coll[coll_name]
|
|
|
|
local item_old = coll[file_name]
|
|
|
|
local order, mandatory = item_old.order, item_old.mandatory
|
|
|
|
new_filepath = new_filepath or new_path .. "/" .. item_old.text
|
|
|
|
coll[file_name] = nil
|
|
|
|
local item = buildEntry(new_filepath, order, mandatory) -- no lfs call
|
|
|
|
coll[item.file] = item
|
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
function ReadCollection:updateItem(file, new_filepath) -- FM: rename file, move file
|
|
|
|
file = FFIUtil.realpath(file) or file
|
|
|
|
local do_write
|
|
|
|
for coll_name, coll in pairs(self.coll) do
|
|
|
|
if coll[file] then
|
|
|
|
self:_updateItem(coll_name, file, new_filepath)
|
|
|
|
do_write = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if do_write then
|
|
|
|
self:write()
|
2023-12-10 06:05:34 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
function ReadCollection:updateItems(files, new_path) -- FM: move files
|
2023-12-10 06:05:34 +00:00
|
|
|
local do_write
|
|
|
|
for file in pairs(files) do
|
2024-05-01 06:01:59 +00:00
|
|
|
file = FFIUtil.realpath(file) or file
|
|
|
|
for coll_name, coll in pairs(self.coll) do
|
|
|
|
if coll[file] then
|
|
|
|
self:_updateItem(coll_name, file, nil, new_path)
|
|
|
|
do_write = true
|
|
|
|
end
|
2023-12-10 06:05:34 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
if do_write then
|
|
|
|
self:write()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
function ReadCollection:updateItemsByPath(path, new_path) -- FM: rename folder, move folder
|
2023-12-10 06:05:34 +00:00
|
|
|
local len = #path
|
|
|
|
local do_write
|
|
|
|
for coll_name, coll in pairs(self.coll) do
|
|
|
|
for file_name in pairs(coll) do
|
|
|
|
if file_name:sub(1, len) == path then
|
|
|
|
self:_updateItem(coll_name, file_name, new_path .. file_name:sub(len + 1))
|
|
|
|
do_write = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if do_write then
|
|
|
|
self:write()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-05-01 06:01:59 +00:00
|
|
|
function ReadCollection:getOrderedCollection(collection_name)
|
|
|
|
local ordered_coll = {}
|
|
|
|
for _, item in pairs(self.coll[collection_name]) do
|
|
|
|
table.insert(ordered_coll, item)
|
|
|
|
end
|
|
|
|
table.sort(ordered_coll, function(v1, v2) return v1.order < v2.order end)
|
|
|
|
return ordered_coll
|
|
|
|
end
|
|
|
|
|
|
|
|
function ReadCollection:updateCollectionOrder(collection_name, ordered_coll)
|
|
|
|
local coll = self.coll[collection_name]
|
|
|
|
for i, item in ipairs(ordered_coll) do
|
|
|
|
coll[item.file].order = i
|
|
|
|
end
|
|
|
|
self:write(collection_name)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- manage collections
|
|
|
|
|
|
|
|
function ReadCollection:addCollection(coll_name)
|
|
|
|
local max_order = 0
|
|
|
|
for _, order in pairs(self.coll_order) do
|
|
|
|
if max_order < order then
|
|
|
|
max_order = order
|
|
|
|
end
|
|
|
|
end
|
|
|
|
self.coll_order[coll_name] = max_order + 1
|
|
|
|
self.coll[coll_name] = {}
|
|
|
|
self:write(coll_name)
|
|
|
|
end
|
|
|
|
|
|
|
|
function ReadCollection:renameCollection(coll_name, new_name)
|
|
|
|
self.coll_order[new_name] = self.coll_order[coll_name]
|
|
|
|
self.coll[new_name] = self.coll[coll_name]
|
|
|
|
self.coll_order[coll_name] = nil
|
|
|
|
self.coll[coll_name] = nil
|
|
|
|
self:write(new_name)
|
|
|
|
end
|
|
|
|
|
|
|
|
function ReadCollection:removeCollection(coll_name)
|
|
|
|
self.coll_order[coll_name] = nil
|
|
|
|
self.coll[coll_name] = nil
|
|
|
|
self:write()
|
|
|
|
end
|
|
|
|
|
|
|
|
function ReadCollection:updateCollectionListOrder(ordered_coll)
|
|
|
|
for i, item in ipairs(ordered_coll) do
|
|
|
|
self.coll_order[item.name] = i
|
|
|
|
end
|
|
|
|
self:write()
|
|
|
|
end
|
|
|
|
|
2023-12-10 06:05:34 +00:00
|
|
|
ReadCollection:_read()
|
|
|
|
|
2019-11-05 23:17:28 +00:00
|
|
|
return ReadCollection
|