Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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, dirName);
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, dirName: string): Promise<ScriptInfo[]> {
const scripts: ScriptInfo[] = [];

const scanDirectory = async (currentPath: string, relativePath: string = ''): 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
Loading