Advertisement
Hakase3

NXT-OS multi-directory fix - "steam.lua"

Oct 25th, 2021
448
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.63 KB | None | 0 0
  1. --[[
  2.     @Author: NuzzyFutts
  3.     @Github: github.com/NuzzyFutts
  4.     @File: getSteamGames
  5.     @input: {table} argv - A list of inputs
  6.     Order of inputs:
  7.         1. {string} defaultSteamPath - The path of the default steam directory
  8.         2. {string} userID - The user's steam ID
  9. ]]
  10.  
  11. function main(DEFAULT_STEAM_PATH,USER_ID)
  12.    
  13.     local function hasValue (tab, val)
  14.         for index, value in ipairs(tab) do
  15.             if value == val then
  16.                 return true
  17.             end
  18.         end
  19.         return false
  20.     end
  21.  
  22.     local function isRightPath(path)
  23.         return hasValue(path,"software") and hasValue(path,"valve") and hasValue(path,"steam")
  24.     end
  25.    
  26.     local function getIDsAndLastPlayed()
  27.         local LOCAL_CONFIG_VDF_PATH = DEFAULT_STEAM_PATH.."userdata\\"..USER_ID.."\\config\\localconfig.vdf"
  28.         local vdfFile = io.open(LOCAL_CONFIG_VDF_PATH,"r")
  29.         local count = 0                             --used to keep track of lines
  30.         local found = false                         --used for easier check of if we are in the apps section
  31.         local level = 0                             --used to keep track how deep in entries we currently are before we find the apps section
  32.         local foundLevel = 0                        --Used to keep track of how deep in entries we are AFTER we have found the right apps sectgion
  33.         local currApp = {}                          --used to keep track of data for current app
  34.         local apps = {}                             --used for storing data of all apps
  35.         local prevLineType = ""                     --used to keep track of what type of info the previous line kept
  36.         local path = {}                             --used to keep track of the current path we are in inside the vdf
  37.         local prevLine = ""                         --used to keep track of what the previous line was
  38.  
  39.         if vdfFile then
  40.             for line in vdfFile:lines() do
  41.  
  42.                 count = count + 1
  43.                 line = string.lower(line)   -- we don't care about the capitalization of the data inside. Do this to reduce number of checks required
  44.  
  45.                 if found or (string.match(line,'%s*apps') and isRightPath(path)) then
  46.  
  47.                     --increment/decrement level to check for closing of individual apps
  48.                     --entries and for checking when apps section has ended
  49.                     if string.match(line,"^%s*{") then              --if on a line where an app entry is beginning
  50.                         foundLevel = foundLevel + 1
  51.                         prevLineType = "open"
  52.                     end
  53.  
  54.                     --if on a line where an app entry is ending or line before is entry and this line is an entry
  55.                     if string.match(line,"^%s*}") or (prevLineType == "id" and string.match(line,'^%s*"(%d+)"') ~= nil) then
  56.  
  57.                         --only decrement level if only first case is satisfied and second case is false
  58.                         if string.match(line,"^%s*}") then
  59.                             foundLevel = foundLevel - 1
  60.                         end
  61.                        
  62.                         -- Capture all remaining data and push it to return table
  63.                         if foundLevel == 1 then
  64.                             currApp["appID"] = appID
  65.                             table.insert(apps,currApp)
  66.  
  67.                             --if the game has never been played
  68.                             if currApp.lastPlayed == nil then
  69.                                 currApp.lastPlayed = 0              --set lastplayed timestamp to 0
  70.                             end
  71.  
  72.                             currApp = {}
  73.                             prevLineType = "close"
  74.                         end
  75.                     end
  76.                    
  77.                     --individual game parameters capture
  78.                     local temp = string.match(line,'^%s*"(%d+)"')
  79.                     if temp ~= nil then
  80.                         appID = temp
  81.                         prevLineType = "id"
  82.                     end
  83.                    
  84.                     --if currently in an app entry
  85.                     if foundLevel == 2 then
  86.                         local title = string.match(line,'^%s*"(%w*)"')
  87.  
  88.                         --if title of current line is lastplayed, get timestamp data
  89.                         if title == "lastplayed" then
  90.                             currApp["lastPlayed"] = string.match(line,'.*"(%d*)"')
  91.                         end
  92.                         prevLineType = "dataEntry"
  93.                     end
  94.  
  95.                     --sets start line for check of closing of apps section
  96.                     if not found then
  97.                         prevLineType = "begin"
  98.                         found = true
  99.                         start = count
  100.                     end
  101.  
  102.                     --checks to stop reading file if apps section has ended
  103.                     if foundLevel == 0  and start ~= count then
  104.                         break
  105.                     end
  106.                 end
  107.  
  108.                 --This block is to keep track of what the current path is. So that we don't use the wrong "apps" section
  109.                 if not found then
  110.                     if string.match(line,"^%s*{") then      --if on a line where a subentry is beginning
  111.                         path[#path + 1] = string.match(prevLine,'^%s*"(%w*)"')
  112.                         level = level + 1
  113.                     end
  114.  
  115.                     if string.match(line,"^%s*}") then      --if on a line where a subentry is ending
  116.                         table.remove(path,#path)
  117.                         level = level - 1
  118.                     end
  119.  
  120.                     prevLine = line
  121.                 end
  122.             end
  123.             vdfFile:close()
  124.         end
  125.         return apps
  126.     end
  127.  
  128.     local function getAllDirectories()
  129.         local LIBRARY_FOLDERS_VDF_PATH = DEFAULT_STEAM_PATH.."steamapps\\libraryfolders.vdf"
  130.         local libVDFFile = io.open(LIBRARY_FOLDERS_VDF_PATH,"r")                --open libraryfolders.vdf
  131.         local dirs = {DEFAULT_STEAM_PATH}                                       --initialize dirs table with default steam directory preinserted
  132.  
  133.         --if vdf file exists
  134.         if libVDFFile then
  135.  
  136.             --iterate through all the lines
  137.             for line in libVDFFile:lines() do
  138.                 local dirline = string.match(line,'^%s*"path"%s*"(.*)"')            --match format for only lines with directories
  139.                
  140.                 --if that format is on this line
  141.                 if dirline then
  142.                     newdirline = string.gsub(dirline,'\\\\','\\').."\\"
  143.                     table.insert(dirs,newdirline)                               --insert that path into the table
  144.                 end
  145.             end
  146.             libVDFFile:close()
  147.         end
  148.         return dirs                                                             --return table of directories
  149.     end
  150.  
  151.     local function checkAppManifests(directories,appTable)
  152.         local resultTable = {}
  153.         local currTable = {}
  154.  
  155.         --iterate through all steam directories
  156.         for i=2,table.getn(directories) do
  157.  
  158.             --iterate through all app possibilities in each directory
  159.             for curr = 1, table.getn(appTable) do
  160.                 local currManifest = directories[i].."steamapps/appmanifest_"..appTable[curr].appID..".acf"     --generate filepath for app
  161.                 manifestFile = io.open(currManifest,"r")                                                        --open file
  162.                
  163.                 --check if file exists
  164.                 if manifestFile then
  165.  
  166.                     --iterate through all lines
  167.                     for line in manifestFile:lines() do
  168.                         line = string.gsub(line,'[^%w%s%p]+',"")
  169.                         appName = string.match(line,'.*"name"%s*"(.*)"')                                        --obtain app name from file
  170.                        
  171.                         --if this line contains the name field
  172.                         if appName then
  173.                             currTable["appID"] = appTable[curr].appID
  174.                             currTable["lastPlayed"] = appTable[curr].lastPlayed
  175.                             currTable["appPath"] = "steam://rungameid/"..appTable[curr].appID
  176.                             currTable["bannerURL"] = "http://cdn.akamai.steamstatic.com/steam/apps/"..appTable[curr].appID.."/header.jpg"
  177.                             currTable["bannerName"] = appTable[curr].appID..".jpg"
  178.                             currTable["appName"] = appName                                                      --set appName in appTable
  179.                             currTable["installed"] = true                                                       --set installed var in appTable (only for consistency across launchers)
  180.                             currTable["hidden"] = false                                                         --PLACEHOLDER/INITIAL ASSIGNMENT parameter for if game should be hidden
  181.                             currTable["launcher"] = "Steam"                                                     --defines which launcher this game is from
  182.                             table.insert(resultTable,currTable)
  183.                             currTable = {}
  184.                             break
  185.                         end
  186.                     end
  187.                     manifestFile:close()
  188.                 end
  189.             end
  190.         end
  191.         return resultTable                                                                                      --return fully populated appTable
  192.     end
  193.  
  194.     local dirs = getAllDirectories()
  195.     local ids = getIDsAndLastPlayed()
  196.     local final = checkAppManifests(dirs,ids)
  197.  
  198.     --=====================================================================================
  199.     --                                        DEBUG
  200.     --=====================================================================================
  201.     --Debug code to log all found appNames, lastPlayed timestamps, and appIDs
  202.     for a = 1, table.getn(final) do
  203.         debug("App Name: "..final[a].appName.."","Last Played: "..final[a].lastPlayed.."","App ID: "..final[a].appID.."","")
  204.     end
  205.     debug("Total number of games found: ",table.getn(final))
  206.  
  207.     return final
  208. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement