cloudapp-dl
Version:
CloudApp/Zight API client and CLI. Use as a CLI tool to download videos or as a programmatic library to interact with the Zight API.
521 lines (489 loc) • 15.9 kB
JavaScript
#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import {
handleLogin,
handleLogout,
handleAccount,
handleConfig,
handleList,
handleWhoami,
handleExport,
handleDownloadById,
handleDownloadByUrl,
handleDownloadList,
handleBulkDownload,
handleVideoRequest,
handleVideoRequestQuick,
handleCollections,
handleRequestsList,
handleRequestEdit,
handleRequestDelete,
handleRequestDetails,
handleRequestDownload,
handleUpload,
handleBulkUpload,
handleDelete,
handleRestore,
handleTrash,
handleEmptyTrash,
handleNotifications,
handleMarkNotificationsRead
} from './lib/commands.js';
// Configure yargs with commands
const argv = yargs(hideBin(process.argv))
.scriptName('cloudapp-dl')
.usage('$0 <command> [options]')
// Login command
.command('login', 'Login to your Zight account', (yargs) => {
return yargs
.option('email', {
alias: 'e',
type: 'string',
description: 'Your Zight email address'
})
.option('password', {
alias: 'p',
type: 'string',
description: 'Your Zight password'
});
}, handleLogin)
// Logout command
.command('logout', 'Logout and clear session', () => {}, handleLogout)
// Account command
.command('account', 'Display your Zight account details', () => {}, handleAccount)
// Whoami command
.command('whoami', 'Show current login status', () => {}, handleWhoami)
// Config command
.command('config', 'View or manage configuration', (yargs) => {
return yargs
.option('clear', {
type: 'boolean',
description: 'Clear all configuration data'
})
.option('path', {
type: 'boolean',
description: 'Show config file path'
});
}, handleConfig)
// List command
.command('list', 'List your drops/files from Zight', (yargs) => {
return yargs
.option('page', {
type: 'number',
default: 1,
description: 'Page number'
})
.option('per-page', {
alias: 'perPage',
type: 'number',
default: 12,
description: 'Items per page (multiples of 12). Multiple pages fetched with delays.'
});
}, handleList)
// Export command
.command('export', 'Export items to CSV file', (yargs) => {
return yargs
.option('out', {
alias: 'o',
type: 'string',
description: 'Output CSV file path (default: zight-export-YYYY-MM-DD.csv)'
})
.option('start-page', {
alias: 'startPage',
type: 'number',
description: 'Start from this page (default: 1)'
})
.option('end-page', {
alias: 'endPage',
type: 'number',
description: 'End at this page (default: last page)'
});
}, handleExport)
// Get command - download a single file by ID
.command('get <id>', 'Download a single file by ID', (yargs) => {
return yargs
.positional('id', {
type: 'string',
description: 'The file ID to download (e.g., WnuPyJR5)'
})
.option('out', {
alias: 'o',
type: 'string',
default: '.',
description: 'Output directory'
})
.option('no-title', {
type: 'boolean',
description: 'Use file ID as filename instead of title'
});
}, (argv) => handleDownloadById({ ...argv, title: !argv.noTitle }))
// Download command - download a single file by URL
.command('download <url>', 'Download a single file by URL', (yargs) => {
return yargs
.positional('url', {
type: 'string',
description: 'The Zight share URL (e.g., https://share.zight.com/ABC123)'
})
.option('out', {
alias: 'o',
type: 'string',
default: '.',
description: 'Output directory'
})
.option('no-title', {
type: 'boolean',
description: 'Use file ID as filename instead of title'
});
}, (argv) => handleDownloadByUrl({ ...argv, title: !argv.noTitle }))
// Download list command - download multiple files from a URL list
.command('download-list <file>', 'Download multiple files from a URL list file', (yargs) => {
return yargs
.positional('file', {
type: 'string',
description: 'Path to text file containing URLs (one per line)'
})
.option('out', {
alias: 'o',
type: 'string',
default: './downloads',
description: 'Output directory for downloaded files'
})
.option('prefix', {
alias: 'p',
type: 'string',
description: 'Prefix for filenames (e.g., "video" → video-1.mp4, video-2.mp4)'
})
.option('timeout', {
alias: 't',
type: 'number',
default: 2000,
description: 'Delay between downloads in milliseconds'
})
.option('no-title', {
type: 'boolean',
description: 'Use file IDs as filenames instead of titles'
});
}, (argv) => handleDownloadList({ ...argv, title: !argv.noTitle }))
// Bulk download command - download from account
.command('bulk-download', 'Bulk download files from your Zight account', (yargs) => {
return yargs
.option('out', {
alias: 'o',
type: 'string',
default: './downloads',
description: 'Output directory for downloaded files'
})
.option('start-page', {
alias: 'startPage',
type: 'number',
description: 'Start from this page (default: 1)'
})
.option('end-page', {
alias: 'endPage',
type: 'number',
description: 'End at this page (default: last page)'
})
.option('limit', {
type: 'number',
description: 'Maximum number of files to download'
})
.option('videos-only', {
alias: 'videosOnly',
type: 'boolean',
description: 'Only download video files'
})
.option('timeout', {
alias: 't',
type: 'number',
default: 2000,
description: 'Delay between downloads in milliseconds'
})
.option('no-title', {
type: 'boolean',
description: 'Use file IDs as filenames instead of titles'
});
}, (argv) => handleBulkDownload({ ...argv, title: !argv.noTitle }))
// Video request command - create a link for others to record a video
.command('request', 'Create a video recording request link (interactive)', (yargs) => {
return yargs
.option('title', {
alias: 't',
type: 'string',
description: 'Title for the request'
})
.option('message', {
alias: 'm',
type: 'string',
description: 'Message/instructions for the recorder'
})
.option('custom-id', {
alias: 'customId',
type: 'string',
description: 'Custom identifier for the request'
})
.option('expires', {
alias: 'e',
type: 'string',
description: 'Expiration date (e.g., "12/31/2025 5:00pm")'
})
.option('collection', {
alias: 'c',
type: 'string',
description: 'Collection ID to add recordings to'
});
}, handleVideoRequest)
// Quick video request command - instant generation
.command('request-quick', 'Instantly create a video request link', (yargs) => {
return yargs
.option('title', {
alias: 't',
type: 'string',
description: 'Custom title (default: "[email] needs your help with a short video.")'
})
.option('message', {
alias: 'm',
type: 'string',
description: 'Custom message (default: generic help message)'
})
.option('custom-id', {
alias: 'customId',
type: 'string',
description: 'Custom identifier for the request'
})
.option('expires', {
alias: 'e',
type: 'string',
description: 'Expiration date (e.g., "12/31/2025 5:00pm")'
})
.option('collection', {
alias: 'c',
type: 'string',
description: 'Collection ID to add recordings to'
});
}, handleVideoRequestQuick)
// Collections command - list your collections
.command('collections', 'List your collections', () => {}, handleCollections)
// List video requests command
.command('requests', 'List your video recording requests', (yargs) => {
return yargs
.option('verbose', {
alias: 'v',
type: 'boolean',
description: 'Show full request links'
});
}, handleRequestsList)
// Edit video request command
.command('request-edit <id>', 'Edit a video recording request', (yargs) => {
return yargs
.positional('id', {
type: 'string',
description: 'The request ID to edit'
})
.option('title', {
alias: 't',
type: 'string',
description: 'New title'
})
.option('message', {
alias: 'm',
type: 'string',
description: 'New message'
})
.option('custom-id', {
alias: 'customId',
type: 'string',
description: 'New custom identifier'
})
.option('expires', {
alias: 'e',
type: 'string',
description: 'New expiration date (e.g., "12/31/2025 5:00pm" or "never")'
})
.option('collection', {
alias: 'c',
type: 'string',
description: 'New collection ID (empty string to remove)'
});
}, handleRequestEdit)
// Delete video request command
.command('request-delete <id>', 'Delete a video recording request', (yargs) => {
return yargs
.positional('id', {
type: 'string',
description: 'The request ID to delete'
})
.option('yes', {
alias: 'y',
type: 'boolean',
description: 'Skip confirmation prompt'
});
}, handleRequestDelete)
// Request details command - show items in a request
.command('request-details <id>', 'Show details and items for a video request', (yargs) => {
return yargs
.positional('id', {
type: 'string',
description: 'The request ID to view'
})
.option('verbose', {
alias: 'v',
type: 'boolean',
description: 'Show download URLs for each item'
});
}, handleRequestDetails)
// Request download command - download all items from a request
.command('request-download <id>', 'Download all items from a video request', (yargs) => {
return yargs
.positional('id', {
type: 'string',
description: 'The request ID to download items from'
})
.option('out', {
alias: 'o',
type: 'string',
description: 'Output directory',
default: '.'
})
.option('timeout', {
alias: 't',
type: 'number',
description: 'Delay between downloads in ms',
default: 2000
});
}, handleRequestDownload)
// Upload a single file
.command('upload <file>', 'Upload a file to Zight', (yargs) => {
return yargs
.positional('file', {
type: 'string',
description: 'Path to the file to upload'
});
}, handleUpload)
// Bulk upload files
.command('bulk-upload <path>', 'Upload multiple files from a directory', (yargs) => {
return yargs
.positional('path', {
type: 'string',
description: 'Path to file or directory to upload'
})
.option('timeout', {
alias: 't',
type: 'number',
description: 'Delay between uploads in ms',
default: 2000
});
}, handleBulkUpload)
// Delete a file
.command('delete <id>', 'Delete a file (move to trash)', (yargs) => {
return yargs
.positional('id', {
type: 'string',
description: 'The item ID to delete'
})
.option('permanent', {
type: 'boolean',
description: 'Permanently delete (no recovery)',
default: false
})
.option('yes', {
alias: 'y',
type: 'boolean',
description: 'Skip confirmation prompt'
});
}, handleDelete)
// List trash
.command('trash', 'List items in trash', () => {}, handleTrash)
// Restore from trash
.command('restore <id>', 'Restore a file from trash', (yargs) => {
return yargs
.positional('id', {
type: 'string',
description: 'The item ID to restore'
});
}, handleRestore)
// Empty trash
.command('empty-trash', 'Permanently delete all items in trash', (yargs) => {
return yargs
.option('yes', {
alias: 'y',
type: 'boolean',
description: 'Skip confirmation prompt'
});
}, handleEmptyTrash)
// Notifications
.command('notifications', 'View your notifications', (yargs) => {
return yargs
.option('limit', {
alias: 'l',
type: 'number',
description: 'Number of notifications to show',
default: 20
})
.option('all', {
alias: 'a',
type: 'boolean',
description: 'Show all notifications (read and unread)'
})
.option('unread', {
alias: 'u',
type: 'boolean',
description: 'Show only unread notifications'
})
.option('verbose', {
alias: 'v',
type: 'boolean',
description: 'Show action links'
})
.option('mark-read', {
type: 'boolean',
description: 'Mark all notifications as read'
});
}, (argv) => {
if (argv.markRead) {
handleMarkNotificationsRead(argv);
} else {
handleNotifications(argv);
}
})
// Help command
.command('help', 'Show help information', () => {}, () => {
yargs(hideBin(process.argv)).showHelp();
})
.example('$0 login', 'Login to your Zight account')
.example('$0 account', 'View your account details')
.example('$0 list', 'List your drops/files')
.example('$0 list --per-page 48', 'List 48 items per page')
.example('$0 export', 'Export ALL items to CSV')
.example('$0 export --start-page 1 --end-page 10', 'Export pages 1-10 to CSV')
.example('$0 get WnuPyJR5', 'Download a file by ID')
.example('$0 download https://share.zight.com/ABC123', 'Download a file by URL')
.example('$0 download-list urls.txt', 'Download files from a URL list')
.example('$0 download-list urls.txt --out ./videos', 'Download to specific directory')
.example('$0 bulk-download', 'Download ALL files from your account')
.example('$0 bulk-download --limit 50', 'Download first 50 files')
.example('$0 bulk-download --videos-only', 'Download only video files')
.example('$0 request', 'Create a video request (interactive)')
.example('$0 request-quick', 'Instantly create a request with defaults')
.example('$0 requests', 'List all your video requests')
.example('$0 request-details wgsX51', 'View request details and submitted items')
.example('$0 request-download wgsX51', 'Download all items from a request')
.example('$0 request-edit ABC123 --title "New Title"', 'Edit a request')
.example('$0 request-delete ABC123', 'Delete a request')
.example('$0 upload ./video.mp4', 'Upload a file')
.example('$0 bulk-upload ./screenshots/', 'Upload all files in a directory')
.example('$0 delete WnuPyJR5', 'Move a file to trash')
.example('$0 delete WnuPyJR5 --permanent', 'Permanently delete a file')
.example('$0 trash', 'List items in trash')
.example('$0 restore WnuPyJR5', 'Restore a file from trash')
.example('$0 empty-trash', 'Permanently delete all trash items')
.example('$0 notifications', 'View notifications')
.example('$0 notifications --unread', 'View only unread notifications')
.example('$0 notifications --mark-read', 'Mark all notifications as read')
.example('$0 collections', 'List your collections')
.help()
.alias('help', 'h')
.version()
.alias('version', 'v')
.wrap(100)
.argv;