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

enhanced auto-load: add options to load only files of the same type #575

Closed
dyphire opened this issue Nov 4, 2023 · 7 comments
Closed

Comments

@dyphire
Copy link
Collaborator

dyphire commented Nov 4, 2023

Refer to the already implemented feature in the autoload.lua script to understand its usage scenarios: mpv-player/mpv#12191.

Someone has already implemented similar functions on their own fork version for reference: vvyoko@cbce120

@stax76
Copy link
Collaborator

stax76 commented Nov 5, 2023

If possible, I would prefer doing this via user script. I have a policy to exclude everything that is possible via user script, mostly same as mpv.

@dyphire
Copy link
Collaborator Author

dyphire commented Nov 5, 2023

If possible, I would prefer doing this via user script. I have a policy to exclude everything that is possible via user script, mostly same as mpv.

Implementing this through scripts would be more flexible, but I hope not to lose the sorting algorithm implemented by mpv.net, which is more consistent with the explorer.

@stax76
Copy link
Collaborator

stax76 commented Nov 5, 2023

I see, it's using the StrCmpLogical WinAPI function for sorting, which is part of the Shell API, so it's likely that File Explorer uses exactly the same.

@stax76
Copy link
Collaborator

stax76 commented Nov 6, 2023

It's possibly, not too hard, using StrCmpLogicalW in Lua. Most often mpv is compiled using LuaJIT, which has a foreign function interface, so it can access libraries that have a C interface, such as the Windows API. In your script, you would check if LuaJIT and Windows is used, and in that case use StrCmpLogicalW. The StrCmpLogicalW function is very simple, 2 strings go in, and an integer is returned, text encoding could be the only difficulty.

In case of problems, you can ask somewhere for help with the foreign function interface. mpv issue tracker, Reddit, StackOverflow etc.

https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strcmplogicalw

https://github.com/z0hm/far-scripts/blob/master/Panel.CustomSortOther.lua

https://github.com/mpv-player/mpv/issues?q=is%3Aissue+StrCmpLogicalW

@stax76
Copy link
Collaborator

stax76 commented Nov 18, 2023

This code seem to work:

local is_windows = package.config:sub(1,1) == "\\"
local is_ffi_loaded = false

local ffi = nil
local winapi = {}

if is_windows then
    is_ffi_loaded, ffi = pcall(require, "ffi")

    if is_ffi_loaded then
        winapi = {
            ffi = ffi,
            C = ffi.C,
            CP_UTF8 = 65001,
            shlwapi = ffi.load("shlwapi"),
        }

        -- ffi code from https://github.com/po5/thumbfast, Mozilla Public License Version 2.0

        ffi.cdef[[
            int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
            int __stdcall StrCmpLogicalW(wchar_t *psz1, wchar_t *psz2);
        ]]

        winapi.utf8_to_wide = function(utf8_str)
            if utf8_str then
                local utf16_len = winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, utf8_str, -1, nil, 0)

                if utf16_len > 0 then
                    local utf16_str = winapi.ffi.new("wchar_t[?]", utf16_len)

                    if winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, utf8_str, -1, utf16_str, utf16_len) > 0 then
                        return utf16_str
                    end
                end
            end

            return ""
        end
    end
end

-- http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua
function alpha_num_sort_lua(filenames)
    local function padnum(n, d)
        return #d > 0 and ("%03d%s%.12f"):format(#n, n, tonumber(d) / (10 ^ #d))
            or ("%03d%s"):format(#n, n)
    end
    local tuples = {}
    for i, f in ipairs(filenames) do
        tuples[i] = {f:lower():gsub("0*(%d+)%.?(%d*)", padnum), f}
    end
    table.sort(tuples, function(a, b)
        return a[1] == b[1] and #b[2] < #a[2] or a[1] < b[1]
    end)
    for i, tuple in ipairs(tuples) do filenames[i] = tuple[2] end
    return filenames
end

function alpha_num_sort_windows(filenames)
    table.sort(filenames, function(a, b)
        local a_wide = winapi.utf8_to_wide(a)
        local b_wide = winapi.utf8_to_wide(b)
        return winapi.shlwapi.StrCmpLogicalW(a_wide, b_wide) == -1
    end)
end

function alpha_num_sort(filenames)
    if is_windows and is_ffi_loaded then
        alpha_num_sort_windows(filenames)
    else
        alpha_num_sort_lua(filenames)
    end
end

filenames = {"11", "19", "20", "21", "0", "1", "9", "10"}

alpha_num_sort(filenames)

for key, value in pairs(filenames) do
    print(value)
end
Desktop> mpv --quiet --geometry=40%+99%+10% --script=C:\native_sort.lua
[native_sort] 0
[native_sort] 1
[native_sort] 9
[native_sort] 10
[native_sort] 11
[native_sort] 19
[native_sort] 20
[native_sort] 21
Exiting... (Quit)

@dyphire
Copy link
Collaborator Author

dyphire commented Nov 18, 2023

This code seem to work:

This is exactly the solution I am looking for. Thank you for your efforts. Do you mind if I use this code in uosc and other scripts?

@stax76
Copy link
Collaborator

stax76 commented Nov 18, 2023

Please feel free to use it in uosc and other scripts. Most Linux users, depending on which file manager they use, still have this problem. I have it often with my music files using Gnome Files/Nautilus, I think there it's harder to solve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants