summaryrefslogtreecommitdiffstats
path: root/player/lua/options.lua
blob: b05b73427b50147ec94b3153e18fe0283c3a8b7e (plain)
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
local msg = require 'mp.msg'

-- converts val to type of desttypeval
local function typeconv(desttypeval, val)
    if type(desttypeval) == "boolean" then
        if val == "yes" then
            val = true
        elseif val == "no" then
            val = false
        else
            msg.error("Error: Can't convert '" .. val .. "' to boolean!")
            val = nil
        end
    elseif type(desttypeval) == "number" then
        if tonumber(val) ~= nil then
            val = tonumber(val)
        else
            msg.error("Error: Can't convert '" .. val .. "' to number!")
            val = nil
        end
    end
    return val
end

-- performs a deep-copy of the given option value
local function opt_copy(val)
    return val -- no tables currently
end

-- compares the given option values for equality
local function opt_equal(val1, val2)
    return val1 == val2
end

-- performs a deep-copy of an entire option table
local function opt_table_copy(opts)
    local copy = {}
    for key, value in pairs(opts) do
        copy[key] = opt_copy(value)
    end
    return copy
end


local function read_options(options, identifier, on_update)
    local option_types = opt_table_copy(options)
    if identifier == nil then
        identifier = mp.get_script_name()
    end
    msg.debug("reading options for " .. identifier)

    -- read config file
    local conffilename = "script-opts/" .. identifier .. ".conf"
    local conffile = mp.find_config_file(conffilename)
    if conffile == nil then
        msg.debug(conffilename .. " not found.")
        conffilename = "lua-settings/" .. identifier .. ".conf"
        conffile = mp.find_config_file(conffilename)
        if conffile then
            msg.warn("lua-settings/ is deprecated, use directory script-opts/")
        end
    end
    local f = conffile and io.open(conffile,"r")
    if f == nil then
        -- config not found
        msg.debug(conffilename .. " not found.")
    else
        -- config exists, read values
        msg.verbose("Opened config file " .. conffilename .. ".")
        local linecounter = 1
        for line in f:lines() do
            if line:sub(#line) == "\r" then
                line = line:sub(1, #line - 1)
            end
            if string.find(line, "#") == 1 then

            else
                local eqpos = string.find(line, "=")
                if eqpos == nil then

                else
                    local key = string.sub(line, 1, eqpos-1)
                    local val = string.sub(line, eqpos+1)

                    -- match found values with defaults
                    if option_types[key] == nil then
                        msg.warn(conffilename..":"..linecounter..
                            " unknown key '" .. key .. "', ignoring")
                    else
                        local convval = typeconv(option_types[key], val)
                        if convval == nil then
                            msg.error(conffilename..":"..linecounter..
                                " error converting value '" .. val ..
                                "' for key '" .. key .. "'")
                        else
                            options[key] = convval
                        end
                    end
                end
            end
            linecounter = linecounter + 1
        end
        io.close(f)
    end

    --parse command-line options
    local prefix = identifier.."-"
    -- command line options are always applied on top of these
    local conf_and_default_opts = opt_table_copy(options)

    local function parse_opts(full, options)
        for key, val in pairs(full) do
            if string.find(key, prefix, 1, true) == 1 then
                key = string.sub(key, string.len(prefix)+1)

                -- match found values with defaults
                if option_types[key] == nil then
                    msg.warn("script-opts: unknown key " .. key .. ", ignoring")
                else
                    local convval = typeconv(option_types[key], val)
                    if convval == nil then
                        msg.error("script-opts: error converting value '" .. val ..
                            "' for key '" .. key .. "'")
                    else
                        options[key] = convval
                    end
                end
            end
        end
    end

    --initial
    parse_opts(mp.get_property_native("options/script-opts"), options)

    --runtime updates
    if on_update then
        local last_opts = opt_table_copy(options)

        mp.observe_property("options/script-opts", "native", function(name, val)
            local new_opts = opt_table_copy(conf_and_default_opts)
            parse_opts(val, new_opts)
            local changelist = {}
            for key, val in pairs(new_opts) do
                if not opt_equal(last_opts[key], val) then
                    -- copy to user
                    options[key] = opt_copy(val)
                    changelist[key] = true
                end
            end
            last_opts = new_opts
            if next(changelist) ~= nil then
                on_update(changelist)
            end
        end)
    end

end

-- backwards compatibility with broken read_options export
_G.read_options = read_options

return {
    read_options = read_options,
}