--[[
ReaScript for Reaper in Lua 5.4
Script:
1. Parses files from the specified folder, extracting timestamps [MM-SS] or [MM_SS] regardless of their position in the filename.
2. Sorts files by time.
3. Adds media items to tracks, creating new tracks as needed to avoid overlaps within 4 seconds.
4. Sets the length of each item to 4 seconds.
5. Does not modify existing tracks; only creates new ones.
6. Handles image, audio, and video files correctly.
]]
-- Settings
local folder_path = "D:/_0/test" -- Replace with your folder path
local media_extensions = {".png", ".jpg", ".jpeg", ".wav", ".mp3", ".mp4", ".avi"} -- Supported media extensions
-- Function to check if a filename has a supported extension
local function has_extension(filename, extensions)
    local lower_filename = filename:lower()
    for _, ext in ipairs(extensions) do
        if lower_filename:sub(-#ext) == ext then
            return true
        end
    end
    return false
end
-- Function to find the next available track number
local function get_next_sorted_track_number()
    local highest = 0
    local track_count = reaper.CountTracks(0)
    for i = 0, track_count - 1 do
        local track = reaper.GetTrack(0, i)
        local retval, name = reaper.GetSetMediaTrackInfo_String(track, "P_NAME", "", false)
        if retval and name then
            local num = name:match("^Sorted Items (%d+)")
            if num then
                num = tonumber(num)
                if num and num > highest then
                    highest = num
                end
            end
        end
    end
    return highest + 1
end
-- Function to extract time from filename
local function extract_time(filename)
    local pattern = "%[(%d%d)[-_](%d%d)%]"
    local min, sec = filename:match(pattern)
    if min and sec then
        return tonumber(min) * 60 + tonumber(sec)
    end
    return nil
end
-- Function to create a track with name "Sorted Items N"
local function create_sorted_track(track_number)
    local track_name = "Sorted Items " .. track_number
    local idx = reaper.CountTracks(0)
    reaper.InsertTrackAtIndex(idx, true)
    local new_track = reaper.GetTrack(0, idx)
    reaper.GetSetMediaTrackInfo_String(new_track, "P_NAME", track_name, true)
    return new_track
end
-- Function to check overlap
local function is_overlapping(existing_ranges, new_range)
    local new_start, new_end = new_range[1], new_range[2]
    for _, range in ipairs(existing_ranges) do
        local start, end_ = range[1], range[2]
        if not (new_end <= start or new_start >= end_) then
            return true
        end
    end
    return false
end
-- Main function
local function main()
    -- Save current edit cursor position and track selection
    local original_cursor_pos = reaper.GetCursorPosition()
    local selected_tracks = {}
    for i = 0, reaper.CountSelectedTracks(0) - 1 do
        selected_tracks[i + 1] = reaper.GetSelectedTrack(0, i)
    end
    -- Get list of files in the folder
    local files = {}
    local p = io.popen('dir "'..folder_path..'" /b /a:-d')
    if p then
        for filename in p:lines() do
            if has_extension(filename, media_extensions) then
                local time = extract_time(filename)
                if time then
                    table.insert(files, {name = filename, time = time})
                else
                    reaper.ShowConsoleMsg("Файл '" .. filename .. "' не содержит валидной временной метки. Пропуск.\n")
                end
            end
        end
        p:close()
    else
        reaper.ShowConsoleMsg("Не удалось открыть папку: " .. folder_path .. "\n")
        return
    end
    if #files == 0 then
        reaper.ShowMessageBox("Нет файлов с поддерживаемыми расширениями и валидными временными метками.", "Информация", 0)
        return
    end
    -- Sort files by time
    table.sort(files, function(a, b) return a.time < b.time end)
    -- Get starting track number
    local start_track_number = get_next_sorted_track_number()
    local current_track_number = start_track_number
    -- Initialize list of created tracks and their occupied ranges
    local created_tracks = {}
    -- Process each file
    for _, file in ipairs(files) do
        local full_path = folder_path .. "/" .. file.name
        local position = file.time
        local end_time = position + 4.0
        local new_range = {position, end_time}
        -- Find suitable track
        local assigned_track = nil
        for _, track_info in ipairs(created_tracks) do
            if not is_overlapping(track_info.ranges, new_range) then
                assigned_track = track_info.track
                break
            end
        end
        -- If no suitable track found, create new one
        if not assigned_track then
            local new_track = create_sorted_track(current_track_number)
            table.insert(created_tracks, {track = new_track, ranges = {}})
            assigned_track = new_track
            current_track_number = current_track_number + 1
        end
        -- Set cursor position
        reaper.SetEditCurPos(position, false, false)
        -- Select the assigned track
        reaper.SetOnlyTrackSelected(assigned_track)
        -- Insert media
        local insert_success = reaper.InsertMedia(full_path, 0)
        if insert_success == 1 then
            -- Get the last media item on the track
            local item_count = reaper.CountTrackMediaItems(assigned_track)
            local item = reaper.GetTrackMediaItem(assigned_track, item_count - 1)
            -- Set item length to 4 seconds
            reaper.SetMediaItemInfo_Value(item, "D_LENGTH", 4.0)
            -- Add new range to track
            for _, track_info in ipairs(created_tracks) do
                if track_info.track == assigned_track then
                    table.insert(track_info.ranges, new_range)
                    break
                end
            end
        else
            reaper.ShowConsoleMsg("Не удалось вставить медиа-айтем для файла: " .. full_path .. "\n")
        end
    end
    -- Restore cursor position and track selection
    reaper.SetEditCurPos(original_cursor_pos, false, false)
    reaper.Main_OnCommand(40297, 0) -- Unselect all tracks
    for _, track in ipairs(selected_tracks) do
        reaper.SetTrackSelected(track, true)
    end
    -- Update arrange view
    reaper.UpdateArrange()
end
-- Run the main function inside an undo block
reaper.Undo_BeginBlock()
main()
reaper.Undo_EndBlock("Insert media items by timestamp", -1)