Archives
Trending
Support
Login
clear text
XML
Django
JavaScript
MATLAB
C
C++
C#
Python
SQL
Shell
Bash
Markdown
YAML
JSON
HTML
CSS
PHP
Java
Ruby
Go
Rust
Swift
Kotlin
Arduino
TypeScript
Perl
Autohotkey
Lua
SQF
R
Scala
Haskell
Groovy
Dart
Clojure
VB.NET
Objective-C
PowerShell
Bash
CoffeeScript
Verilog
-- KSSH Storage System Dynamic Installer local GITHUB_REPO = "Temperdox/KSSH_Storage_Revised" local GITHUB_BRANCH = "master" local GITHUB_PATH = "src" local VERSION = "0.0.2" -- Ignore patterns - files/dirs that should not be downloaded local IGNORE_PATTERNS = { "^%.git", -- .git directory "^%.gitignore$", -- .gitignore file "README%.md$", -- README files "%.backup$", -- backup files "install%.lua$", -- installer itself "^test", -- test directories "^docs", -- documentation } -- Color scheme (keeping your existing colors) local COLORS = { background = colors.black, text = colors.white, highlight = colors.gray, highlightText = colors.black, success = colors.lime, error = colors.red, warning = colors.orange, info = colors.purple, skip = colors.yellow } -- Installation mode local INSTALL_MODE = { CLEAN = "clean", UPDATE = "update" } -- GitHub API Functions local function getGitHubAPIUrl(path) -- Use GitHub API to get directory contents return string.format( "https://api.github.com/repos/%s/contents/%s/%s?ref=%s", GITHUB_REPO, GITHUB_PATH, path or "", GITHUB_BRANCH ) end local function getRawFileUrl(path) -- Direct raw file URL return string.format( "https://raw.githubusercontent.com/%s/%s/%s/%s", GITHUB_REPO, GITHUB_BRANCH, GITHUB_PATH, path ) end local function shouldIgnore(path) -- Check if path matches any ignore pattern for _, pattern in ipairs(IGNORE_PATTERNS) do if string.match(path, pattern) then return true end end return false end local function fetchDirectoryContents(path, fileList, errorList) fileList = fileList or {} errorList = errorList or {} local apiUrl = getGitHubAPIUrl(path) -- Add headers to avoid rate limiting (if possible in CC) local headers = { ["User-Agent"] = "CC-Installer/" .. VERSION, ["Accept"] = "application/vnd.github.v3+json" } local response = http.get(apiUrl, headers) if not response then table.insert(errorList, "Failed to fetch directory: " .. (path or "root")) return fileList, errorList end local content = response.readAll() response.close() -- Parse JSON response local ok, data = pcall(textutils.unserializeJSON, content) if not ok or not data then table.insert(errorList, "Failed to parse GitHub API response for: " .. (path or "root")) return fileList, errorList end -- Handle case where data is a single file (not a directory) if data.type and data.type == "file" then data = {data} elseif not data[1] then table.insert(errorList, "No contents found in: " .. (path or "root")) return fileList, errorList end -- Process each item for _, item in ipairs(data) do local fullPath = path and (path .. "/" .. item.name) or item.name -- Check if we should ignore this item if not shouldIgnore(fullPath) and not shouldIgnore(item.name) then if item.type == "file" then -- Add file to list table.insert(fileList, { path = fullPath, size = item.size, sha = item.sha, download_url = item.download_url or getRawFileUrl(fullPath) }) elseif item.type == "dir" then -- Recursively fetch subdirectory fetchDirectoryContents(fullPath, fileList, errorList) end end end return fileList, errorList end local function getSystemFiles(systemType) -- Dynamically fetch files from GitHub based on system type local basePath = systemType == "storage" and "storage" or "turtle" local fileList, errors = fetchDirectoryContents(basePath) return fileList, errors end -- Modified download function to work with dynamic file structure local function downloadFile(fileInfo, destination, mode) local url = fileInfo.download_url or getRawFileUrl(fileInfo.path) local response = http.get(url) if not response then return false, "Failed to download: " .. fileInfo.path end local content = response.readAll() response.close() -- In update mode, check if file content is identical using SHA if available if mode == INSTALL_MODE.UPDATE and fs.exists(destination) then local existingFile = fs.open(destination, "r") if existingFile then local existingContent = existingFile.readAll() existingFile.close() if existingContent == content then -- Files are identical, skip return true, nil, true -- third return value indicates skip end end end -- Create directory if needed local dir = fs.getDir(destination) if dir ~= "" and not fs.exists(dir) then fs.makeDir(dir) end -- Backup existing file in update mode if mode == INSTALL_MODE.UPDATE and fs.exists(destination) then local backupPath = destination .. ".backup" if fs.exists(backupPath) then fs.delete(backupPath) end fs.copy(destination, backupPath) end -- Write file local file = fs.open(destination, "w") if not file then return false, "Failed to write: " .. destination end file.write(content) file.close() return true, nil, false end -- Modified install function to work with dynamic files local function installFiles(fileList, systemType, mode) local total = #fileList local completed = 0 local skipped = 0 local updated = 0 local errors = {} -- Clean install removes everything first if mode == INSTALL_MODE.CLEAN then cleanInstall(systemType) end for _, fileInfo in ipairs(fileList) do completed = completed + 1 local percent = (completed / total) * 100 -- Extract filename for display local displayName = fileInfo.path:match("([^/]+)$") or fileInfo.path -- Determine local path (remove system prefix) local localPath = fileInfo.path if systemType == "storage" then localPath = fileInfo.path:gsub("^storage/", "") else localPath = fileInfo.path:gsub("^turtle/", "") end -- Show current file being processed local statusMsg = mode == INSTALL_MODE.UPDATE and "Checking: " .. displayName or "Downloading: " .. displayName local success, err, wasSkipped = downloadFile(fileInfo, localPath, mode) if not success then table.insert(errors, err) showProgress("Installing " .. systemType, "ERROR: " .. displayName, percent, COLORS.error) elseif wasSkipped then skipped = skipped + 1 showProgress("Installing " .. systemType, "Skipped (unchanged): " .. displayName, percent, COLORS.skip) else updated = updated + 1 showProgress("Installing " .. systemType, "Updated: " .. displayName, percent, COLORS.success) end sleep(0.05) -- Small delay for visual feedback end return #errors == 0, errors, { total = total, updated = updated, skipped = skipped, errors = #errors } end -- Add a prefetch check function local function preflightCheck(systemType) clearScreen() drawHeader("Checking GitHub Repository...") local w, h = term.getSize() term.setCursorPos(2, 4) term.write("Fetching file list from GitHub...") local fileList, errors = getSystemFiles(systemType) if #errors > 0 then term.setCursorPos(2, 6) term.setTextColor(COLORS.error) term.write("Failed to fetch file list:") term.setTextColor(COLORS.text) local y = 8 for _, err in ipairs(errors) do term.setCursorPos(2, y) term.write("- " .. err) y = y + 1 end term.setCursorPos(2, y + 1) term.write("Press any key to exit") os.pullEvent("key") return nil end term.setCursorPos(2, 6) term.setTextColor(COLORS.success) term.write("Found " .. #fileList .. " files to process") term.setTextColor(COLORS.text) -- Show file structure preview term.setCursorPos(2, 8) term.write("File structure:") local dirs = {} for _, fileInfo in ipairs(fileList) do local dir = fs.getDir(fileInfo.path) if dir ~= "" and not dirs[dir] then dirs[dir] = true end end local y = 9 for dir, _ in pairs(dirs) do if y < h - 3 then term.setCursorPos(4, y) term.write("- " .. dir .. "/") y = y + 1 end end if y >= h - 3 then term.setCursorPos(4, y) term.write("... and more") end term.setCursorPos(2, h - 1) term.write("Press ENTER to continue or Q to cancel") while true do local event, key = os.pullEvent("key") if key == keys.enter then return fileList elseif key == keys.q then return nil end end end -- Keep all your existing UI functions (they're well done) -- clamp, clearScreen, drawHeader, drawList, move, pickFromList, showProgress, etc. -- ... (include all the UI functions from your original code here) -- Modified main function local function main() -- Show splash screen showSplash() -- Detect system type local systemType = detectSystemType() -- Check for existing installation local existingInstall = detectExistingInstallation() local installMode = INSTALL_MODE.CLEAN if existingInstall then installMode = promptInstallMode() if not installMode then clearScreen() print("Installation cancelled.") return end end -- Present options local options = { "Storage Computer", "Crafting Turtle", "Cancel" } local descriptions = { "Main storage management system with inventory, sorting, and order processing", "Turtle-based crafting system with recipe learning and remote control", "Exit installer without making changes" } local selection = pickFromList("KSSH Installer - Select System Type", options, descriptions) if not selection or selection == 3 then clearScreen() print("Installation cancelled.") return end local selectedType = options[selection] local selectedSystem = selectedType == "Storage Computer" and "storage" or "turtle" -- Confirm installation if not confirmInstall(systemType, selectedType, installMode) then clearScreen() print("Installation cancelled.") return end -- Preflight check - fetch file list from GitHub local fileList = preflightCheck(selectedSystem) if not fileList then clearScreen() print("Installation cancelled.") return end -- Perform installation local success, errors, stats = installFiles(fileList, selectedSystem, installMode) if not success then clearScreen() term.setTextColor(COLORS.error) print("Installation failed with errors:") term.setTextColor(COLORS.text) for _, err in ipairs(errors) do print(" - " .. err) end print("\nPress any key to exit") os.pullEvent("key") return end -- Check for startup file local hasStartup = fs.exists("startup.lua") -- Show completion screen showComplete(selectedType, hasStartup, stats, installMode) -- Set computer label if not set if not os.getComputerLabel() then if selectedType == "Storage Computer" then os.setComputerLabel("KSSH_Storage_" .. os.getComputerID()) else os.setComputerLabel("KSSH_Turtle_" .. os.getComputerID()) end end -- Final prompt for auto-start -- ... (keep your existing auto-start code) end -- Include all the missing UI functions from your original code -- (I'll add the key ones here for completeness) local function clamp(x, a, b) return math.max(a, math.min(b, x)) end local function clearScreen() term.setBackgroundColor(COLORS.background) term.setTextColor(COLORS.text) term.clear() term.setCursorPos(1, 1) end local function drawHeader(title) local w, h = term.getSize() term.setCursorPos(1, 1) term.setBackgroundColor(COLORS.info) term.setTextColor(COLORS.background) term.clearLine() local titleText = " " .. title .. " " local x = math.floor((w - #titleText) / 2) + 1 term.setCursorPos(x, 1) term.write(titleText) term.setBackgroundColor(COLORS.background) term.setTextColor(COLORS.text) end local function showProgress(title, message, percent, color) clearScreen() drawHeader(title) local w, h = term.getSize() local barWidth = math.min(40, w - 4) local barX = math.floor((w - barWidth) / 2) local barY = math.floor(h / 2) -- Message term.setCursorPos(math.floor((w - #message) / 2), barY - 2) if color then term.setTextColor(color) end term.write(message) term.setTextColor(COLORS.text) -- Progress bar term.setCursorPos(barX, barY) term.write("[") local filled = math.floor(barWidth * (percent / 100)) term.setTextColor(COLORS.success) term.write(string.rep("=", filled)) term.setTextColor(COLORS.text) term.write(string.rep(" ", barWidth - filled)) term.write("]") -- Percentage local percentText = math.floor(percent) .. "%" term.setCursorPos(math.floor((w - #percentText) / 2), barY + 2) term.write(percentText) end -- Add the rest of your UI functions here... -- Run the installer main()
Mark as private (unlisted)
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year
everlasting (like CCCP)