Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to sort directorys by date + underlay files? #82

Closed
critkitten opened this issue Dec 7, 2022 · 8 comments
Closed

Possible to sort directorys by date + underlay files? #82

critkitten opened this issue Dec 7, 2022 · 8 comments
Labels
use-addons request should be completed with an addon

Comments

@critkitten
Copy link

This addon is very nice. Thank You !

One thing i thin is missing: the option to enable sort by date. Even just for folder creation date and plus sort by file creation in folders.
Is this even possible in lua? I'm using linux.

@CogentRedTester CogentRedTester added the use-addons request should be completed with an addon label Dec 8, 2022
@CogentRedTester
Copy link
Owner

CogentRedTester commented Dec 8, 2022

It is possible to do using mpv's utils.file_info function. This is the sort of thing to implement as an addon.

Here is an example of an addon that will always attempt to sort the directory based on when a file was last modified:

local msg = require 'mp.msg'
local utils = require 'mp.utils'
local fb = require 'file-browser'

local parser = {
    priority = 105,
    version = '1.0.0'
}

-- stores a table of the parsers loaded by file-browser
-- we will use this to check if a parser is for a local file system
local parsers

function parser:setup()
    parsers = fb.get_parsers()
end

-- do not bother to run on uri paths
function parser:can_parse(directory)
    return not fb.get_protocol(directory)
end

function parser:parse(directory)
    local list, opts = self:defer(directory)
    if not list then return list, opts end

    -- Only run this on parsers that are for the local filesystem.
    -- We assume that custom addons for the local filesystem are setting the keybind_name field to 'file'
    -- for compatability.
    if parsers[opts.id] then
        if parsers[opts.id].keybind_name ~= 'file' and parsers[opts.id].name ~= 'file' then
            return list, opts
        end
    end

    directory = opts.directory or directory
    local cache = {}

    -- gets the file info of an item
    -- uses memoisation to speed things up 
    function get_file_info(item)
        if cache[item] then return cache[item] end

        local path = fb.get_full_path(item, directory)
        local file_info = utils.file_info(path)
        if not file_info then
            msg.warn('failed to read file info for', path)
            return {}
        end

        cache[item] = file_info
        return file_info
    end

    -- sorts the items based on the latest modification time
    -- if mtime is undefined due to a file read failure then use 0
    table.sort(list, function (a, b)
        return (get_file_info(a).mtime or 0) > (get_file_info(b).mtime or 0)
    end)

    opts.sorted = true
    return list, opts
end

return parser

This will slow directory reads down of course, but it probably won't be all that noticeable on local filesystems. It will definitely be noticeable when recursively opening directories since this IO operation isn't asynchronous meaning the whole browser will freeze during the operation. Ideally you could replace this with asynchronous platform specific terminal commands that will find the date.

I'm not sure you'd always want to do this sorting, but it would be trivial to modify the script to toggle the sorting with a keybind.

@CogentRedTester
Copy link
Owner

Here is a modified version that switches between sorting by modification date and alphabetical order when pressing ^. You could potentially add more sorting modes to this cycle as well.

local msg = require 'mp.msg'
local utils = require 'mp.utils'
local fb = require 'file-browser'

local parser = {
    priority = 105,
    version = '1.2.0'
}

-- stores a table of the parsers loaded by file-browser
-- we will use this to check if a parser is for a local file system
local parsers

local do_sorting = false

function parser:setup()
    parsers = fb.get_parsers()
end

-- do not bother to run on uri paths
function parser:can_parse(directory)
    return do_sorting and not fb.get_protocol(directory)
end

function parser:parse(directory)
    local list, opts = self:defer(directory)
    if not list then return list, opts end

    -- Only run this on parsers that are for the local filesystem.
    -- We assume that custom addons for the local filesystem are setting the keybind_name field to 'file'
    -- for compatability.
    if parsers[opts.id] then
        if parsers[opts.id].keybind_name ~= 'file' and parsers[opts.id].name ~= 'file' then
            return list, opts
        end
    end

    directory = opts.directory or directory
    local cache = {}

    -- gets the file info of an item
    -- uses memoisation to speed things up 
    function get_file_info(item)
        if cache[item] then return cache[item] end

        local path = fb.get_full_path(item, directory)
        local file_info = utils.file_info(path)
        if not file_info then
            msg.warn('failed to read file info for', path)
            return {}
        end

        cache[item] = file_info
        return file_info
    end

    -- sorts the items based on the latest modification time
    -- if mtime is undefined due to a file read failure then use 0
    table.sort(list, function (a, b)
        return (get_file_info(a).mtime or 0) > (get_file_info(b).mtime or 0)
    end)

    opts.sorted = true
    return list, opts
end

-- adds the keybind to toggle sorting
parser.keybinds = {
    {
        key = '^',
        name = 'toggle-sort',
        command = function()
            do_sorting = not do_sorting
            fb.rescan()
        end
    }
}

return parser

@critkitten
Copy link
Author

That's really very nice. I've tested both and they work for me too. I couldn't see any difference in speed on an NFS mount with about 50 folders. Thanks !

@dyphire
Copy link
Contributor

dyphire commented Dec 9, 2022

Added more sorting methods for switching.
Still don't know how to sort directories and files separately.
Edit: done.

local msg = require 'mp.msg'
local utils = require 'mp.utils'
local fb = require 'file-browser'

local parser = {
    priority = 105,
    version = '1.2.0'
}

-- stores a table of the parsers loaded by file-browser
-- we will use this to check if a parser is for a local file system
local parsers

local sort_mode = 0

function parser:setup()
    parsers = fb.get_parsers()
end

function parser:parse(directory)
    if sort_mode == 0 or fb.get_protocol(directory) then return end
    local list, opts = self:defer(directory)
    if not list then return list, opts end

    -- Only run this on parsers that are for the local filesystem.
    -- We assume that custom addons for the local filesystem are setting the keybind_name field to 'file'
    -- for compatability.
    if parsers[opts.id] then
        if parsers[opts.id].keybind_name ~= 'file' and parsers[opts.id].name ~= 'file' then
            return list, opts
        end
    end

    directory = opts.directory or directory
    local cache = {}

    -- gets the file info of an item
    -- uses memoisation to speed things up 
    function get_file_info(item)
        if cache[item] then return cache[item] end

        local path = fb.get_full_path(item, directory)
        local file_info = utils.file_info(path)
        if not file_info then
            msg.warn('failed to read file info for', path)
            return {}
        end

        cache[item] = file_info
        return file_info
    end

    -- sorts the items based on the latest modification time
    -- if mtime is undefined due to a file read failure then use 0
    table.sort(list, function(a, b)
        -- `dir` will compare as less than `file`
        if a.type ~= b.type then return a.type < b.type end
        if sort_mode == 1 then
            return (get_file_info(a).mtime or 0) < (get_file_info(b).mtime or 0)
        elseif sort_mode == 2 then
            return (get_file_info(a).mtime or 0) > (get_file_info(b).mtime or 0)
        elseif sort_mode == 3 then
            return (get_file_info(a).size or 0) < (get_file_info(b).size or 0)
        elseif sort_mode == 4 then
            return (get_file_info(a).size or 0) > (get_file_info(b).size or 0)
        end
    end)

    opts.sorted = true
    return list, opts
end

-- adds the keybind to toggle sorting
parser.keybinds = {
    {
        key = '^',
        name = 'toggle_sort',
        command = function()
            sort_mode = sort_mode + 1
            if sort_mode > 4 then sort_mode = 0 end
            fb.rescan()
        end
    }
}

return parser

@CogentRedTester
Copy link
Owner

Added more sorting methods for switching. Still don't know how to sort directories and files separately.

You should really add:

if sort_mode == 0 then return end

at the very top of the parse function so that performance isn't degraded when using the default sorting.

As for sorting files and directories separately you need to add:

-- `dir` will compare as less than `file`
if a.type ~= b.type then return a.type < b.type end

in whichever modes you want to sort them separately. (I have not actually had a chance to test this so it's possible I'm wrong).

@critkitten critkitten reopened this Dec 9, 2022
@dyphire
Copy link
Contributor

dyphire commented Dec 10, 2022

Added more sorting methods for switching. Still don't know how to sort directories and files separately.

You should really add:

if sort_mode == 0 then return end

at the very top of the function so that performance isn't degraded when using the default sorting.parse

As for sorting files and directories separately you need to add:

-- `dir` will compare as less than `file`
if a.type ~= b.type then return a.type < b.type end

in whichever modes you want to sort them separately. (I have not actually had a chance to test this so it's possible I'm wrong).

Thanks. It is perfect.

@Max-Enrik
Copy link

I created sorting.lua and put your code in the file into the script-modules\file-browser-addons folder.
But still, nothing happens.

It looks like I miss something.

@CogentRedTester
Copy link
Owner

I created sorting.lua and put your code in the file into the script-modules\file-browser-addons folder. But still, nothing happens.

It looks like I miss something.

Please open a separate discussion thread and upload the log file generated by mpv --log-file=log.txt --msg-level=file_browser='debug'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
use-addons request should be completed with an addon
Projects
None yet
Development

No branches or pull requests

4 participants