diff --git a/profile/LICENSE.md b/profile/LICENSE.md deleted file mode 100644 index 4b727a2..0000000 --- a/profile/LICENSE.md +++ /dev/null @@ -1 +0,0 @@ -# LICENSE diff --git a/scripts/README.md b/scripts/README.md index 3a9a63c..0b4a61b 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,6 +1,6 @@ -# Feature Distribution Tools +# Repository Management Tools -This directory contains tools to distribute the feature files from `/research/` to their respective repositories. +This directory contains tools to manage files across all serpapps repositories, including feature distribution and license management. ## Automated Distribution (GitHub Action) @@ -80,4 +80,37 @@ features: # ... up to 20 features ``` -This format is compatible with the existing `generate-readme.js` script for automatic README generation. \ No newline at end of file +This format is compatible with the existing `generate-readme.js` script for automatic README generation. + +## LICENSE File Management + +### Delete LICENSE Files + +The `delete-license-files.js` script removes LICENSE files from all serpapps repositories. + +#### Prerequisites: +- GitHub CLI (`gh`) installed and authenticated +- Appropriate permissions to modify serpapps repositories + +#### Usage: +```bash +# Dry run to preview what would be deleted +node scripts/delete-license-files.js --dry-run + +# Delete LICENSE files from all repositories +node scripts/delete-license-files.js + +# Delete LICENSE files from a specific repository only +node scripts/delete-license-files.js --repo=youtube-downloader +``` + +#### What it does: +- Searches for common LICENSE file patterns (LICENSE, LICENSE.md, LICENSE.txt, etc.) +- Deletes found LICENSE files from all serpapps repositories +- Provides detailed logging and error handling +- Supports dry-run mode for safety + +#### Common LICENSE patterns detected: +- `LICENSE`, `LICENSE.md`, `LICENSE.txt`, `LICENSE.rst` +- `LICENCE`, `LICENCE.md`, `LICENCE.txt` +- Various case variations (license, License, etc.) \ No newline at end of file diff --git a/scripts/USAGE_EXAMPLES.md b/scripts/USAGE_EXAMPLES.md new file mode 100644 index 0000000..b275220 --- /dev/null +++ b/scripts/USAGE_EXAMPLES.md @@ -0,0 +1,106 @@ +# Usage Examples for Repository Management Scripts + +## LICENSE File Deletion + +### Quick Start +```bash +# Preview what would be deleted (recommended first step) +node scripts/delete-license-files.js --dry-run + +# Delete LICENSE files from all repositories +node scripts/delete-license-files.js + +# Delete LICENSE files from a specific repository +node scripts/delete-license-files.js --repo=youtube-downloader +``` + +### Step-by-Step Process + +1. **First, always run a dry-run to see what would be affected:** + ```bash + node scripts/delete-license-files.js --dry-run + ``` + +2. **Review the output to understand which repositories have LICENSE files** + +3. **If you want to test with a single repository first:** + ```bash + node scripts/delete-license-files.js --dry-run --repo=youtube-downloader + node scripts/delete-license-files.js --repo=youtube-downloader + ``` + +4. **Run the full deletion across all repositories:** + ```bash + node scripts/delete-license-files.js + ``` + +### Prerequisites + +Before running these scripts, ensure: + +1. **GitHub CLI is installed and authenticated:** + ```bash + # Install GitHub CLI (if not already installed) + # On macOS: brew install gh + # On Ubuntu: sudo apt install gh + # On Windows: winget install GitHub.cli + + # Authenticate with GitHub + gh auth login + + # Verify authentication + gh auth status + ``` + +2. **You have appropriate permissions:** + - Write access to serpapps repositories + - Permission to delete files in those repositories + +### Expected Output + +The script provides detailed logging: +- āœ… Success messages for completed operations +- āš ļø Warning messages for repositories that don't exist or aren't accessible +- āŒ Error messages for failed operations +- šŸ“Š Summary statistics at the end + +### Safety Features + +- **Dry-run mode**: Always test first with `--dry-run` +- **Single repository testing**: Use `--repo=name` to test with one repository +- **Detailed logging**: See exactly what's happening +- **Error handling**: Script continues even if individual repositories fail +- **Backup recommendations**: Consider backing up important repositories before mass operations + +### Common LICENSE File Patterns + +The script searches for and deletes these common patterns: +- `LICENSE`, `LICENSE.md`, `LICENSE.txt`, `LICENSE.rst` +- `LICENCE`, `LICENCE.md`, `LICENCE.txt` (British spelling) +- `license`, `license.md`, `license.txt` (lowercase) +- `License`, `License.md`, `License.txt` (title case) + +### Troubleshooting + +**"GitHub CLI is not authenticated"** +```bash +gh auth login +``` + +**"Repository not found or not accessible"** +- The repository might not exist +- You might not have access permissions +- The repository might be private and you're not a collaborator + +**"Command failed" errors** +- Check your internet connection +- Verify GitHub API is accessible +- Ensure you have write permissions to the repositories + +### Recovery + +If you need to restore LICENSE files: +1. The script doesn't create backups automatically +2. You can restore from git history in each repository +3. Consider using `git revert` on the deletion commits +4. Or manually recreate LICENSE files as needed \ No newline at end of file diff --git a/scripts/delete-license-files.js b/scripts/delete-license-files.js new file mode 100755 index 0000000..37aefac --- /dev/null +++ b/scripts/delete-license-files.js @@ -0,0 +1,344 @@ +#!/usr/bin/env node + +/** + * Script to delete LICENSE files from all serpapps repositories + * + * This script searches for and deletes common LICENSE file patterns from + * all repositories in the serpapps organization. + * + * Usage: + * node scripts/delete-license-files.js [--dry-run] [--repo=repo-name] + * + * Options: + * --dry-run: Preview changes without actually making them + * --repo=name: Process only a specific repository + * + * Requirements: + * - GitHub CLI (gh) installed and authenticated + * - Appropriate permissions to push to serpapps repositories + */ + +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); + +// Parse command line arguments +const args = process.argv.slice(2); +const DRY_RUN = args.includes('--dry-run'); +const SINGLE_REPO = args.find(arg => arg.startsWith('--repo='))?.split('=')[1]; + +// Common LICENSE file patterns to look for +const LICENSE_PATTERNS = [ + 'LICENSE', + 'LICENSE.md', + 'LICENSE.txt', + 'LICENSE.rst', + 'LICENCE', + 'LICENCE.md', + 'LICENCE.txt', + 'license', + 'license.md', + 'license.txt', + 'License', + 'License.md', + 'License.txt' +]; + +/** + * List of all serpapps repositories + */ +const REPOSITORIES = [ + 'vimeo-video-downloader', + 'skool-downloader', + 'youporn-video-downloader', + 'onlyfans-downloader', + 'udemy-video-downloader', + 'loom-video-downloader', + 'ai-downloader', + 'pornhub-video-downloader', + 'coursera-downloader', + 'xvideos-video-downloader', + 'spankbang-video-downloader', + 'xnxx-video-downloader', + 'redtube-video-downloader', + 'redgifs-downloader', + 'beeg-video-downloader', + 'xhamster-video-downloader', + 'tnaflix-video-downloader', + 'podia-downloader', + 'learndash-downloader', + 'circle-downloader', + 'whop-video-downloader', + 'thinkific-downloader', + 'linkedin-learning-downloader', + 'kajabi-video-downloader', + 'pexels-video-downloader', + '123movies-downloader', + '123rf-downloader', + 'adobe-stock-downloader', + 'alamy-downloader', + 'amazon-video-downloader', + 'bilibili-downloader', + 'bongacams-downloader', + 'camsoda-downloader', + 'clientclub-downloader', + 'canva-downloader', + 'creative-market-downloader', + 'm3u8-downloader', + 'netflix-downloader', + 'moodle-downloader', + 'nicovideo-downloader', + 'pdf-downloader', + 'patreon-downloader', + 'pinterest-downloader', + 'pixabay-downloader', + 'shutterstock-downloader', + 'snapchat-video-downloader', + 'skillshare-downloader', + 'soundcloud-downloader', + 'youtube-downloader', + 'vectorstock-downloader', + 'unsplash-downloader', + 'tubi-downloader', + 'thumbnail-downloader', + 'terabox-downloader', + 'storyblocks-downloader', + 'stockvault-downloader', + 'stocksy-downloader', + 'sprout-video-downloader', + 'soundgasm-downloader', + 'scribd-downloader', + 'rawpixel-downloader', + 'myfreecams-downloader', + 'livejasmin-downloader', + 'learnworlds-downloader', + 'istock-downloader', + 'instagram-downloader', + 'hulu-downloader', + 'gokollab-downloader', + 'gohighlevel-downloader', + 'giphy-downloader', + 'freepik-downloader', + 'flickr-downloader', + 'erothots-downloader', + 'erome-downloader', + 'dreamstime-downloader', + 'deviantart-downloader', + 'dailymotion-downloader', + 'chaturbate-downloader', + 'eporner-downloader', + 'tiktok-video-downloader', + 'vk-video-downloader', + 'twitter-video-downloader', + 'twitch-video-downloader', + 'tumblr-video-downloader', + 'telegram-video-downloader', + 'teachable-video-downloader', + 'stripchat-video-downloader', + 'stream-downloader', + 'kick-clip-downloader', + 'khan-academy-downloader', + 'internet-archive-downloader', + 'getty-images-downloader', + 'facebook-video-downloader', + 'depositphotos-downloader', + 'wistia-video-downloader' +]; + +function log(message, type = 'info') { + const timestamp = new Date().toISOString(); + const prefix = type === 'error' ? 'āŒ' : type === 'success' ? 'āœ…' : type === 'warning' ? 'āš ļø' : 'ā„¹ļø'; + console.log(`${prefix} [${timestamp}] ${message}`); +} + +function executeCommand(command, options = {}) { + const { cwd = process.cwd(), silent = false } = options; + + if (DRY_RUN) { + log(`[DRY RUN] Would execute: ${command}`, 'info'); + return ''; + } + + try { + const result = execSync(command, { + encoding: 'utf8', + cwd, + stdio: silent ? 'pipe' : 'inherit' + }); + return result; + } catch (error) { + throw new Error(`Command failed: ${command}\n${error.message}`); + } +} + +function checkPrerequisites() { + log('šŸ” Checking prerequisites...'); + + try { + executeCommand('gh --version', { silent: true }); + log('āœ… GitHub CLI is installed'); + } catch (error) { + throw new Error('GitHub CLI (gh) is not installed. Please install it first.'); + } + + try { + executeCommand('gh auth status', { silent: true }); + log('āœ… GitHub CLI is authenticated'); + } catch (error) { + throw new Error('GitHub CLI is not authenticated. Please run "gh auth login" first.'); + } +} + +async function deleteLicenseFiles() { + log('šŸš€ Starting LICENSE file deletion process...'); + + let repositories = REPOSITORIES; + + // Filter to single repo if specified + if (SINGLE_REPO) { + repositories = repositories.filter(repo => repo === SINGLE_REPO); + if (repositories.length === 0) { + throw new Error(`Repository '${SINGLE_REPO}' not found in the repository list`); + } + } + + log(`šŸ“ Processing ${repositories.length} repositories`); + + if (DRY_RUN) { + log('šŸ” Running in dry-run mode - no actual changes will be made'); + } + + let processedCount = 0; + let deletedCount = 0; + let errorCount = 0; + let totalLicenseFilesDeleted = 0; + const errors = []; + + for (const repoName of repositories) { + try { + log(`\nšŸ”„ Processing serpapps/${repoName}...`); + + const repoFullName = `serpapps/${repoName}`; + + // Check if repository exists and is accessible + try { + executeCommand(`gh repo view ${repoFullName} --json name`, { silent: true }); + log(`āœ… Repository ${repoFullName} is accessible`); + } catch (error) { + log(`āš ļø Repository ${repoFullName} not found or not accessible, skipping...`, 'warning'); + processedCount++; + continue; + } + + // Check for LICENSE files in the repository + let licenseFilesFound = []; + + for (const pattern of LICENSE_PATTERNS) { + try { + const result = executeCommand(`gh api repos/${repoFullName}/contents/${pattern}`, { silent: true }); + if (result && result.trim()) { + licenseFilesFound.push(pattern); + log(`šŸ“„ Found LICENSE file: ${pattern}`); + } + } catch (error) { + // File doesn't exist, which is expected for most patterns + } + } + + if (licenseFilesFound.length === 0) { + log(`āœ… No LICENSE files found in ${repoFullName}`); + processedCount++; + continue; + } + + if (!DRY_RUN) { + // Delete each LICENSE file found + for (const licenseFile of licenseFilesFound) { + try { + // Get the file to get its SHA (required for deletion) + const fileInfo = JSON.parse(executeCommand(`gh api repos/${repoFullName}/contents/${licenseFile}`, { silent: true })); + + // Delete the file using a temporary file for the payload + const tempPayloadFile = `/tmp/delete_payload_${Date.now()}.json`; + const deletePayload = { + message: `Delete ${licenseFile} file`, + sha: fileInfo.sha + }; + + fs.writeFileSync(tempPayloadFile, JSON.stringify(deletePayload)); + + executeCommand(`gh api --method DELETE repos/${repoFullName}/contents/${licenseFile} --input ${tempPayloadFile}`, { + silent: true + }); + + // Clean up temp file + fs.unlinkSync(tempPayloadFile); + + log(`šŸ—‘ļø Deleted ${licenseFile} from ${repoFullName}`, 'success'); + totalLicenseFilesDeleted++; + } catch (error) { + log(`āŒ Failed to delete ${licenseFile} from ${repoFullName}: ${error.message}`, 'error'); + errors.push(`${repoFullName}/${licenseFile}: ${error.message}`); + } + } + + if (licenseFilesFound.length > 0) { + deletedCount++; + } + } else { + log(`šŸ” [DRY RUN] Would delete ${licenseFilesFound.length} LICENSE file(s): ${licenseFilesFound.join(', ')}`); + totalLicenseFilesDeleted += licenseFilesFound.length; + deletedCount++; + } + + processedCount++; + + } catch (error) { + log(`āŒ Error processing ${repoName}: ${error.message}`, 'error'); + errors.push(`${repoName}: ${error.message}`); + errorCount++; + processedCount++; + } + } + + // Summary + log(`\nšŸ“Š Summary:`); + log(` Repositories processed: ${processedCount}`); + log(` Repositories with LICENSE files ${DRY_RUN ? 'that would be' : ''} deleted: ${deletedCount}`); + log(` Total LICENSE files ${DRY_RUN ? 'that would be' : ''} deleted: ${totalLicenseFilesDeleted}`); + log(` Errors: ${errorCount}`); + + if (errors.length > 0) { + log(`\nāŒ Errors encountered:`); + errors.forEach(error => log(` ${error}`)); + } + + return { processedCount, deletedCount, errorCount, totalFiles: totalLicenseFilesDeleted }; +} + +async function main() { + try { + checkPrerequisites(); + const results = await deleteLicenseFiles(); + + if (results.errorCount === 0) { + log(`\nšŸŽ‰ LICENSE file deletion completed successfully!`); + } else { + log(`\nāš ļø LICENSE file deletion completed with ${results.errorCount} errors.`); + } + + if (DRY_RUN) { + log(`\nšŸ’” This was a dry run. To actually delete the files, run without --dry-run flag.`); + } + + } catch (error) { + log(`āŒ Fatal error: ${error.message}`, 'error'); + process.exit(1); + } +} + +if (require.main === module) { + main(); +} + +module.exports = { deleteLicenseFiles }; \ No newline at end of file