--[[
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)