Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/_components/DownloadedScriptsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function DownloadedScriptsTab({ onInstallScript }: DownloadedScriptsTabPr
const gridRef = useRef<HTMLDivElement>(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 }
Expand Down
2 changes: 1 addition & 1 deletion src/app/_components/ScriptsGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
const gridRef = useRef<HTMLDivElement>(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 }
Expand Down
2 changes: 1 addition & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions src/server/api/routers/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
89 changes: 89 additions & 0 deletions src/server/lib/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,95 @@ export class ScriptManager {
}
}

/**
* Get all downloaded scripts from all directories (ct, tools, vm, vw)
*/
async getAllDownloadedScripts(): Promise<ScriptInfo[]> {
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<ScriptInfo[]> {
const scripts: ScriptInfo[] = [];

const scanDirectory = async (currentPath: string, relativePath = ''): Promise<void> => {
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
*/
Expand Down