diff --git a/src/app/_components/DownloadedScriptsTab.tsx b/src/app/_components/DownloadedScriptsTab.tsx index 799d4b9..ebdabd0 100644 --- a/src/app/_components/DownloadedScriptsTab.tsx +++ b/src/app/_components/DownloadedScriptsTab.tsx @@ -37,7 +37,7 @@ export function DownloadedScriptsTab({ onInstallScript }: DownloadedScriptsTabPr const gridRef = useRef(null); const { data: scriptCardsData, isLoading: githubLoading, error: githubError, refetch } = api.scripts.getScriptCardsWithCategories.useQuery(); - const { data: localScriptsData, isLoading: localLoading, error: localError } = api.scripts.getCtScripts.useQuery(); + const { data: localScriptsData, isLoading: localLoading, error: localError } = api.scripts.getAllDownloadedScripts.useQuery(); const { data: scriptData } = api.scripts.getScriptBySlug.useQuery( { slug: selectedSlug ?? '' }, { enabled: !!selectedSlug } diff --git a/src/app/_components/ScriptsGrid.tsx b/src/app/_components/ScriptsGrid.tsx index 520fdc5..a01c266 100644 --- a/src/app/_components/ScriptsGrid.tsx +++ b/src/app/_components/ScriptsGrid.tsx @@ -34,7 +34,7 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) { const gridRef = useRef(null); const { data: scriptCardsData, isLoading: githubLoading, error: githubError, refetch } = api.scripts.getScriptCardsWithCategories.useQuery(); - const { data: localScriptsData, isLoading: localLoading, error: localError } = api.scripts.getCtScripts.useQuery(); + const { data: localScriptsData, isLoading: localLoading, error: localError } = api.scripts.getAllDownloadedScripts.useQuery(); const { data: scriptData } = api.scripts.getScriptBySlug.useQuery( { slug: selectedSlug ?? '' }, { enabled: !!selectedSlug } diff --git a/src/app/page.tsx b/src/app/page.tsx index 16cce0c..db9106a 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -21,7 +21,7 @@ export default function Home() { // Fetch data for script counts const { data: scriptCardsData } = api.scripts.getScriptCardsWithCategories.useQuery(); - const { data: localScriptsData } = api.scripts.getCtScripts.useQuery(); + const { data: localScriptsData } = api.scripts.getAllDownloadedScripts.useQuery(); const { data: installedScriptsData } = api.installedScripts.getAllInstalledScripts.useQuery(); // Calculate script counts diff --git a/src/server/api/routers/scripts.ts b/src/server/api/routers/scripts.ts index fdd801f..3b27e42 100644 --- a/src/server/api/routers/scripts.ts +++ b/src/server/api/routers/scripts.ts @@ -27,6 +27,16 @@ export const scriptsRouter = createTRPCRouter({ }; }), + // Get all downloaded scripts from all directories + getAllDownloadedScripts: publicProcedure + .query(async () => { + const scripts = await scriptManager.getAllDownloadedScripts(); + return { + scripts, + directoryInfo: scriptManager.getScriptsDirectoryInfo() + }; + }), + // Get script content for viewing getScriptContent: publicProcedure diff --git a/src/server/lib/scripts.ts b/src/server/lib/scripts.ts index 1d3da37..33038f1 100644 --- a/src/server/lib/scripts.ts +++ b/src/server/lib/scripts.ts @@ -141,6 +141,95 @@ export class ScriptManager { } } + /** + * Get all downloaded scripts from all directories (ct, tools, vm, vw) + */ + async getAllDownloadedScripts(): Promise { + this.initializeConfig(); + const allScripts: ScriptInfo[] = []; + + // Define all script directories to scan + const scriptDirs = ['ct', 'tools', 'vm', 'vw']; + + for (const dirName of scriptDirs) { + try { + const dirPath = join(this.scriptsDir!, dirName); + + // Check if directory exists + try { + await stat(dirPath); + } catch { + // Directory doesn't exist, skip it + continue; + } + + const scripts = await this.getScriptsFromDirectory(dirPath); + allScripts.push(...scripts); + } catch (error) { + console.error(`Error reading ${dirName} scripts directory:`, error); + // Continue with other directories even if one fails + } + } + + return allScripts.sort((a, b) => a.name.localeCompare(b.name)); + } + + /** + * Get scripts from a specific directory (recursively) + */ + private async getScriptsFromDirectory(dirPath: string): Promise { + const scripts: ScriptInfo[] = []; + + const scanDirectory = async (currentPath: string, relativePath = ''): Promise => { + const files = await readdir(currentPath); + + for (const file of files) { + const filePath = join(currentPath, file); + const stats = await stat(filePath); + + if (stats.isFile()) { + const extension = extname(file); + + // Check if file extension is allowed + if (this.allowedExtensions!.includes(extension)) { + // Check if file is executable + const executable = await this.isExecutable(filePath); + + // Extract slug from filename (remove .sh extension) + const slug = file.replace(/\.sh$/, ''); + + // Try to get logo from JSON data + let logo: string | undefined; + try { + const scriptData = await localScriptsService.getScriptBySlug(slug); + logo = scriptData?.logo ?? undefined; + } catch { + // JSON file might not exist, that's okay + } + + scripts.push({ + name: file, + path: filePath, + extension, + size: stats.size, + lastModified: stats.mtime, + executable, + logo, + slug + }); + } + } else if (stats.isDirectory()) { + // Recursively scan subdirectories + const subRelativePath = relativePath ? join(relativePath, file) : file; + await scanDirectory(filePath, subRelativePath); + } + } + }; + + await scanDirectory(dirPath); + return scripts; + } + /** * Check if a file is executable */