mirror of
https://github.com/kristoferssolo/solorice.git
synced 2026-03-18 08:09:40 +00:00
235 lines
7.2 KiB
Lua
235 lines
7.2 KiB
Lua
--- @since 26.1.22
|
|
|
|
local M = {}
|
|
local const = require(".const")
|
|
local utils = require(".utils")
|
|
|
|
function M:peek(job)
|
|
local preload_status, preload_err = self:preload(job)
|
|
-- Stop if preload failed
|
|
if not preload_status then
|
|
return
|
|
end
|
|
|
|
local cache_img_url = ya.file_cache({
|
|
skip = 0,
|
|
args = job.args,
|
|
file = job.file,
|
|
area = job.area,
|
|
})
|
|
|
|
local cache_img_url_no_skip = ya.file_cache({ file = job.file, skip = 0 })
|
|
|
|
local hide_metadata = utils.get_state(const.STATE_KEY.hide_metadata)
|
|
local mediainfo_height = 0
|
|
local lines = {}
|
|
local limit = job.area.h
|
|
local last_line = 0
|
|
local EOF_mediainfo = true
|
|
local is_wrap = rt.preview.wrap == "yes" or rt.preview.wrap == ui.Wrap.YES
|
|
|
|
if not hide_metadata then
|
|
local cache_mediainfo_path = tostring(cache_img_url_no_skip) .. const.suffix
|
|
local output = utils.read_mediainfo_cached_file(cache_mediainfo_path)
|
|
if output then
|
|
local max_width = math.max(1, job.area.w)
|
|
if output:match("^Error:") then
|
|
job.args.force_reload_mediainfo = true
|
|
preload_status, preload_err = self:preload(job)
|
|
if not preload_status or preload_err then
|
|
return
|
|
end
|
|
output = utils.read_mediainfo_cached_file(cache_mediainfo_path)
|
|
end
|
|
|
|
output = output:gsub("\n+$", "")
|
|
|
|
local iter = output:gmatch("[^\n]*")
|
|
local str = iter()
|
|
|
|
while str ~= nil do
|
|
local next_str = iter()
|
|
local label, value = str:match("(.*[^ ]) +: (.*)")
|
|
local line
|
|
if label then
|
|
if not const.skip_labels[label] then
|
|
line = ui.Line({
|
|
ui.Span(label .. ": "):style(ui.Style():fg("reset"):bold()),
|
|
ui.Span(value):style(th.spot.tbl_col or ui.Style():fg("blue")),
|
|
})
|
|
end
|
|
elseif str ~= "General" then
|
|
line = ui.Line({ ui.Span(str):style(th.spot.title or ui.Style():fg("green")) })
|
|
end
|
|
|
|
if line then
|
|
local line_height = ui.height
|
|
and ui.height(str, { width = max_width, ansi = true, wrap = rt.preview.wrap })
|
|
or (math.max(1, is_wrap and math.ceil(ui.width(line) / max_width) or 1))
|
|
if next_str == nil and line_height == 1 then
|
|
EOF_mediainfo = true
|
|
end
|
|
if (last_line + line_height) > job.skip then
|
|
table.insert(lines, line)
|
|
end
|
|
if (last_line + line_height) >= job.skip + limit then
|
|
last_line = job.skip + limit
|
|
EOF_mediainfo = false
|
|
break
|
|
end
|
|
last_line = last_line + line_height
|
|
end
|
|
str = next_str
|
|
end
|
|
end
|
|
mediainfo_height = math.min(limit, last_line)
|
|
end
|
|
|
|
if not hide_metadata and EOF_mediainfo and #lines == 0 and job.skip > 0 then
|
|
ya.emit("peek", {
|
|
math.max(0, (job.skip - (utils.get_state(const.STATE_KEY.units) or 0))),
|
|
only_if = job.file.url,
|
|
upper_bound = true,
|
|
})
|
|
return
|
|
end
|
|
|
|
utils.force_render()
|
|
-- NOTE: Hacky way to prevent image overlap with old metadata area
|
|
if utils.get_state(const.STATE_KEY.prev_metadata_area) then
|
|
ya.preview_widget(job, {
|
|
ui.Clear(ui.Rect(utils.get_state(const.STATE_KEY.prev_metadata_area))),
|
|
})
|
|
end
|
|
|
|
local rendered_img_rect = cache_img_url
|
|
and fs.cha(cache_img_url)
|
|
and ya.image_show(
|
|
cache_img_url,
|
|
ui.Rect({
|
|
x = job.area.x,
|
|
y = job.area.y,
|
|
w = job.area.w,
|
|
h = mediainfo_height > 0 and math.max(job.area.h - mediainfo_height, job.area.h / 2) or job.area.h,
|
|
})
|
|
)
|
|
or nil
|
|
local image_height = rendered_img_rect and rendered_img_rect.h or 0
|
|
|
|
-- Handle image preload error
|
|
if preload_err then
|
|
table.insert(lines, ui.Line(tostring(preload_err)):style(th.spot.title or ui.Style():fg("red")))
|
|
end
|
|
|
|
ya.preview_widget(job, {
|
|
ui.Text(lines)
|
|
:area(ui.Rect({
|
|
x = job.area.x,
|
|
y = job.area.y + image_height,
|
|
w = job.area.w,
|
|
h = job.area.h - image_height,
|
|
}))
|
|
:wrap(is_wrap and ui.Wrap.YES or ui.Wrap.NO),
|
|
})
|
|
|
|
-- NOTE: Hacky way to prevent image overlap with old metadata area
|
|
utils.set_state(const.STATE_KEY.prev_metadata_area, not hide_metadata and {
|
|
x = job.area.x,
|
|
y = job.area.y + image_height,
|
|
w = job.area.w,
|
|
h = job.area.h - image_height,
|
|
} or nil)
|
|
end
|
|
|
|
function M:preload(job)
|
|
local cmd = "mediainfo"
|
|
local err_msg = ""
|
|
local is_valid_utf8_path = utils.is_valid_utf8(tostring(job.file.path or job.file.cache or job.file.url))
|
|
|
|
-- NOTE: Preload image
|
|
|
|
local mime = job.mime:match(".*/(.*)$")
|
|
local is_svg = mime == "svg+xml"
|
|
local is_magick = const.magick_image_mimes[mime]
|
|
local no_skip_job = { skip = 0, file = job.file, args = job.args, area = job.area }
|
|
local cache_img_url = ya.file_cache(no_skip_job)
|
|
local cache_img_url_cha = cache_img_url and fs.cha(cache_img_url)
|
|
|
|
-- NOTE: Only generate preview image when cache image is not exist
|
|
if not cache_img_url_cha or cache_img_url_cha.len <= 0 then
|
|
local cache_img_status, image_preload_err
|
|
if not is_valid_utf8_path then
|
|
-- NOTE: Case not valid utf8 path, use trick to generate preview image
|
|
if is_svg then
|
|
local cache_img_url_tmp = Url(cache_img_url .. ".tmp")
|
|
if fs.cha(cache_img_url_tmp) then
|
|
fs.remove("file", cache_img_url_tmp)
|
|
end
|
|
local tmp_file_path, _ = type(fs.unique) == "function" and fs.unique("file", cache_img_url_tmp)
|
|
or fs.unique_name(cache_img_url_tmp)
|
|
-- svg under invalid utf8 path
|
|
cache_img_status, image_preload_err = require("magick")
|
|
.with_limit()
|
|
:arg({
|
|
"-background",
|
|
"none",
|
|
tostring(job.file.path or job.file.cache or job.file.url.path or job.file.url),
|
|
"-auto-orient",
|
|
"-strip",
|
|
string.format("%dx%d>", rt.preview.max_width, rt.preview.max_height),
|
|
"-quality",
|
|
rt.preview.image_quality,
|
|
string.format("PNG32:%s", tostring(tmp_file_path)),
|
|
})
|
|
:status()
|
|
if cache_img_status then
|
|
os.rename(tostring(tmp_file_path), tostring(cache_img_url))
|
|
end
|
|
end
|
|
else
|
|
-- NOTE: Case valid utf8 path, use image, svg, or magick module
|
|
local image_module = is_svg and "svg" or (is_magick and "magick" or "image")
|
|
cache_img_status, image_preload_err = require(image_module):preload(no_skip_job)
|
|
end
|
|
|
|
if not cache_img_status and image_preload_err then
|
|
ya.dbg("mediainfo", image_preload_err)
|
|
err_msg = err_msg .. (image_preload_err and (tostring(image_preload_err)) or "")
|
|
end
|
|
end
|
|
|
|
-- NOTE: Get mediainfo and save to cache folder
|
|
local cache_mediainfo_url = Url(tostring(ya.file_cache({ file = job.file, skip = 0 })) .. const.suffix)
|
|
local cache_mediainfo_cha = fs.cha(cache_mediainfo_url)
|
|
-- Case peek function called preload to refetch mediainfo
|
|
if cache_mediainfo_cha and not job.args.force_reload_mediainfo then
|
|
return true, err_msg ~= "" and ("Error: " .. err_msg) or nil
|
|
end
|
|
|
|
local output, err
|
|
if is_valid_utf8_path then
|
|
output, err = Command(cmd)
|
|
:arg({ tostring(job.file.path or job.file.cache or job.file.url.path or job.file.url) })
|
|
:output()
|
|
else
|
|
cmd = "cd "
|
|
.. utils.path_quote(tostring((job.file.path or job.file.cache or job.file.url.path or job.file.url).parent))
|
|
.. " && "
|
|
.. cmd
|
|
.. " "
|
|
.. utils.path_quote(tostring((job.file.path or job.file.cache or job.file.url).name))
|
|
output, err = Command(const.SHELL):arg({ "-c", cmd }):output()
|
|
end
|
|
if err then
|
|
ya.dbg("mediainfo", tostring(err))
|
|
err_msg = err_msg .. string.format("Failed to start `%s`. \n Do you have `%s` installed?\n", cmd, cmd)
|
|
end
|
|
|
|
return fs.write(
|
|
cache_mediainfo_url,
|
|
(err_msg ~= "" and ("Error: " .. err_msg) or "") .. (output and output.stdout or "")
|
|
)
|
|
end
|
|
|
|
return M
|