canvaslms-cli 1.7.4 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +63 -0
  3. package/dist/commands/announcements.js +2 -2
  4. package/dist/commands/announcements.js.map +1 -1
  5. package/dist/commands/assignments.d.ts.map +1 -1
  6. package/dist/commands/assignments.js +153 -3
  7. package/dist/commands/assignments.js.map +1 -1
  8. package/dist/commands/download.d.ts +7 -0
  9. package/dist/commands/download.d.ts.map +1 -0
  10. package/dist/commands/download.js +157 -0
  11. package/dist/commands/download.js.map +1 -0
  12. package/dist/commands/files.d.ts.map +1 -1
  13. package/dist/commands/files.js +5 -4
  14. package/dist/commands/files.js.map +1 -1
  15. package/dist/commands/gpa.d.ts +5 -0
  16. package/dist/commands/gpa.d.ts.map +1 -0
  17. package/dist/commands/gpa.js +334 -0
  18. package/dist/commands/gpa.js.map +1 -0
  19. package/dist/commands/grades.d.ts.map +1 -1
  20. package/dist/commands/grades.js +2 -1
  21. package/dist/commands/grades.js.map +1 -1
  22. package/dist/commands/groups.js +2 -2
  23. package/dist/commands/groups.js.map +1 -1
  24. package/dist/commands/modules.d.ts.map +1 -1
  25. package/dist/commands/modules.js +3 -1
  26. package/dist/commands/modules.js.map +1 -1
  27. package/dist/commands/star.d.ts +3 -0
  28. package/dist/commands/star.d.ts.map +1 -0
  29. package/dist/commands/star.js +131 -0
  30. package/dist/commands/star.js.map +1 -0
  31. package/dist/commands/submit.d.ts.map +1 -1
  32. package/dist/commands/submit.js +2 -2
  33. package/dist/commands/submit.js.map +1 -1
  34. package/dist/index.d.ts +3 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +3 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/lib/api-client.d.ts +5 -1
  39. package/dist/lib/api-client.d.ts.map +1 -1
  40. package/dist/lib/api-client.js +38 -24
  41. package/dist/lib/api-client.js.map +1 -1
  42. package/dist/lib/display.d.ts.map +1 -1
  43. package/dist/lib/display.js +8 -11
  44. package/dist/lib/display.js.map +1 -1
  45. package/dist/src/index.js +39 -1
  46. package/dist/src/index.js.map +1 -1
  47. package/dist/types/index.d.ts +3 -0
  48. package/dist/types/index.d.ts.map +1 -1
  49. package/package.json +20 -21
  50. package/dist/commands/api.d.ts +0 -3
  51. package/dist/commands/api.d.ts.map +0 -1
  52. package/dist/commands/api.js +0 -8
  53. package/dist/commands/api.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,100 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.9.0] - 2026-01-04
9
+
10
+ ### Added
11
+
12
+ - **GPA Calculator**: New `canvas gpa` command to calculate overall GPA
13
+ - Calculate GPA across all active courses on 4.0 scale
14
+ - Option to include past/completed courses with `-p` flag
15
+ - Shows individual course grades, letter grades, and GPA points
16
+ - Summary table with total credits and quality points
17
+ - Letter grade to GPA conversion (A=4.0, B=3.0, etc.)
18
+ - Smart interpretation and feedback based on GPA
19
+
20
+ - **What-If Grade Calculator**: New `canvas what-if` command
21
+ - Calculate what grade you need on remaining work to achieve target grade
22
+ - Interactive prompts for current grade, weight, and desired final grade
23
+ - Clear feedback on achievability and difficulty
24
+ - Shows maximum possible grade if goal is unachievable
25
+ - Helpful color-coded results
26
+
27
+ - **Bulk File Download**: New `canvas download` command
28
+ - Download all files from a course at once
29
+ - Preserves Canvas folder structure locally
30
+ - Progress tracking for each file download
31
+ - Skips already downloaded files automatically
32
+ - Custom output directory support with `-o` flag
33
+ - Download summary with success/failure counts
34
+
35
+ - **Advanced Assignment Filtering**: Enhanced `canvas assignments` command
36
+ - New `--all-courses` (`-a`) flag to view assignments from all courses
37
+ - New `--missing` (`-m`) flag to show only missing assignments
38
+ - New `--due-this-week` (`-w`) flag to show assignments due within 7 days
39
+ - Combine filters (e.g., `-a -m` for all missing assignments)
40
+ - Smart sorting by due date
41
+ - Cross-course assignment view with course names
42
+ - Color-coded status indicators (submitted, missing, pending)
43
+
44
+ ### Changed
45
+
46
+ - **Assignment Display**: Improved multi-course assignment display
47
+ - Shows course code/name for each assignment
48
+ - Better status indicators with visual symbols (✓, ✗, ○)
49
+ - Color-coded due dates (red for overdue, yellow for soon, green for later)
50
+ - Enhanced table layout for cross-course views
51
+
52
+ ### Improved
53
+
54
+ - **README Documentation**: Added comprehensive documentation for new features
55
+ - Shield badges for npm version, license, workflow status, and downloads
56
+ - New features section highlighting recent additions
57
+ - Detailed usage examples for all new commands
58
+ - Command combinations and filter examples
59
+
60
+ ## [1.8.0] - 2025-12-21
61
+
62
+ ### Added
63
+
64
+ - **Star/Unstar Commands**: New commands to manage course favorites
65
+ - `canvas star [course-name]` - Add courses to favorites (alias: `s`)
66
+ - `canvas unstar [course-name]` - Remove courses from favorites (alias: `us`)
67
+ - Interactive course selection when no course name provided
68
+ - Unstar command only shows starred courses for safety
69
+ - Better user experience for managing course favorites
70
+
71
+ ### Changed
72
+
73
+ - **Interactive Course Selection**: Unified course selection across all commands
74
+ - All commands now support interactive course selection when course name is omitted
75
+ - Consistent numbered list display for multi-match scenarios
76
+ - Star indicators (⭐) shown next to favorited courses
77
+ - Improved user experience with readline-based selection
78
+ - Applied to: assignments, announcements, files, grades, modules, submit, star, unstar
79
+
80
+ ### Improved
81
+
82
+ - **Test Suite**: Cleaned up E2E tests for better maintainability
83
+ - Removed redundant option tests (31% reduction in test file size)
84
+ - Focused tests on command functionality and aliases
85
+ - All 55 tests passing with improved clarity
86
+
87
+ ### Fixed
88
+
89
+ - **Git Hooks**: Fixed Husky pre-commit hook auto-staging behavior
90
+ - Removed automatic `git add -u` command
91
+ - Developers now have full control over staged files
92
+ - Enables proper atomic commits
93
+
94
+ ### Development
95
+
96
+ - **Dependencies**: Updated development tooling
97
+ - oxfmt updated to 0.19.0
98
+ - oxlint updated to 1.34.0
99
+ - @types/node updated to 22.10.5
100
+ - CI workflow now uses `bun ci` for deterministic builds
101
+
8
102
  ## [1.7.4] - 2025-12-20
9
103
 
10
104
  ### Changed
package/README.md CHANGED
@@ -1,12 +1,53 @@
1
1
  # Canvas CLI Tool
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/canvaslms-cli.svg)](https://www.npmjs.com/package/canvaslms-cli)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js Package](https://github.com/caphefalumi/Canvas-CLI/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/caphefalumi/Canvas-CLI/actions/workflows/npm-publish.yml)
6
+ [![Downloads](https://img.shields.io/npm/dt/canvaslms-cli.svg)](https://www.npmjs.com/package/canvaslms-cli)
7
+
3
8
  A modern, user-friendly command-line interface for Canvas LMS. Manage courses, assignments, submissions, grades, and more directly from your terminal.
4
9
 
10
+ ## ✨ New Features
11
+
12
+ ### 📊 GPA Calculator
13
+
14
+ - Calculate your overall GPA across all courses on a 4.0 scale
15
+ - Include or exclude past/completed courses
16
+ - See letter grades and quality points for each course
17
+ - Automatic GPA calculation with detailed breakdown
18
+
19
+ ### 🎯 What-If Grade Calculator
20
+
21
+ - Find out what grade you need on remaining work to achieve your target
22
+ - Interactive calculator with clear feedback
23
+ - Shows if your goal is achievable
24
+
25
+ ### 📥 Bulk File Download
26
+
27
+ - Download ALL files from a course at once
28
+ - Preserves Canvas folder structure
29
+ - Skips already downloaded files
30
+ - Progress tracking for each file
31
+
32
+ ### 🔍 Advanced Assignment Filtering
33
+
34
+ - View assignments from **all courses** at once
35
+ - Filter by **missing** assignments
36
+ - Filter by **due this week**
37
+ - Combine filters (e.g., all missing assignments across all courses)
38
+ - Smart sorting by due date
39
+
5
40
  ## Features
6
41
 
7
42
  - List and filter enrolled/starred courses
43
+ - Star/unstar courses to manage favorites
44
+ - Interactive course selection for all commands
8
45
  - View assignments, grades, and submission status
46
+ - **Advanced assignment filtering** (missing, due this week, all courses)
9
47
  - Interactive file upload for assignments with visual file browser
48
+ - **Bulk download all course files** with organized folder structure
49
+ - **GPA Calculator** - Calculate overall GPA across all courses on 4.0 scale
50
+ - **What-if Grade Calculator** - Find out what you need on remaining work
10
51
  - View upcoming due dates and calendar events
11
52
  - Browse course modules and content
12
53
  - View course announcements
@@ -86,11 +127,22 @@ canvas config # Configure domain and API token
86
127
  canvas list # List starred courses
87
128
  canvas list -a # List all enrolled courses
88
129
 
130
+ # Star/Unstar Courses
131
+ canvas star # Interactive course selection to star
132
+ canvas star database # Star course matching database
133
+ canvas unstar # Interactive selection (shows only starred courses)
134
+ canvas unstar math # Unstar course matching math
135
+
89
136
  # Assignments (supports course name instead of ID)
90
137
  canvas assignments # Interactive course selection
91
138
  canvas assignments math # List assignments for course matching math
92
139
  canvas assignments -s # Show only submitted assignments
93
140
  canvas assignments -p # Show only pending assignments
141
+ canvas assignments -a # Show assignments from ALL courses
142
+ canvas assignments -m # Show MISSING assignments only
143
+ canvas assignments -w # Show assignments DUE THIS WEEK
144
+ canvas assignments -a -m # Show all missing assignments across all courses
145
+ canvas assignments -a -w # Show assignments due this week from all courses
94
146
 
95
147
  # Grades (supports course name instead of ID)
96
148
  canvas grades # Interactive course selection + detailed grades
@@ -98,6 +150,17 @@ canvas grades database # Show detailed grades for course matching databa
98
150
  canvas grades -a # Include inactive/completed courses
99
151
  canvas grades -v # Include verbose enrollment details
100
152
 
153
+ # GPA Calculator & What-If Scenarios
154
+ canvas gpa # Calculate overall GPA across all active courses
155
+ canvas gpa -p # Include past/completed courses in GPA calculation
156
+ canvas what-if # Calculate what grade you need on remaining work
157
+
158
+ # Bulk Download Files
159
+ canvas download # Interactive course selection for bulk download
160
+ canvas download math # Download all files from course matching math
161
+ canvas download -o ~/Downloads # Specify output directory
162
+ canvas download math -o ./files # Download to specific folder
163
+
101
164
  # Announcements (supports course name instead of ID)
102
165
  canvas announcements # Interactive course selection
103
166
  canvas announcements software # Show announcements for course matching software
@@ -16,12 +16,12 @@ export async function showAnnouncements(courseName, options = {}) {
16
16
  rl = result.rl;
17
17
  }
18
18
  else {
19
- const course = await getCanvasCourse(courseName);
19
+ rl = createReadlineInterface();
20
+ const course = await getCanvasCourse(courseName, rl);
20
21
  if (!course) {
21
22
  return;
22
23
  }
23
24
  selectedCourseId = course.id.toString();
24
- rl = createReadlineInterface();
25
25
  }
26
26
  const limit = parseInt(options.limit || "5") || 5;
27
27
  printInfo("Loading announcements...");
@@ -1 +1 @@
1
- {"version":3,"file":"announcements.js","sourceRoot":"","sources":["../../commands/announcements.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"announcements.js","sourceRoot":"","sources":["../../commands/announcements.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"assignments.d.ts","sourceRoot":"","sources":["../../commands/assignments.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAGV,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAE3B,wBAAsB,eAAe,CACnC,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CAiEf"}
1
+ {"version":3,"file":"assignments.d.ts","sourceRoot":"","sources":["../../commands/assignments.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAGV,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAuM3B,wBAAsB,eAAe,CACnC,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CAuEf"}
@@ -1,8 +1,157 @@
1
1
  import { makeCanvasRequest, getCanvasCourse } from "../lib/api-client.js";
2
- import { pickCourse, displayAssignments, printInfo, printError, printSuccess, printSeparator, } from "../lib/display.js";
2
+ import { createReadlineInterface } from "../lib/interactive.js";
3
+ import { pickCourse, displayAssignments, printInfo, printError, printSuccess, printSeparator, Table, } from "../lib/display.js";
3
4
  import chalk from "chalk";
5
+ async function listAllCoursesAssignments(options = {}) {
6
+ try {
7
+ printSeparator("=");
8
+ printInfo("Loading assignments from all courses...");
9
+ printSeparator("=");
10
+ const queryParams = [
11
+ "enrollment_state=active",
12
+ "include[]=term",
13
+ "per_page=100",
14
+ ];
15
+ const courses = await makeCanvasRequest("get", "courses", queryParams);
16
+ if (!courses || courses.length === 0) {
17
+ printError("No courses found.");
18
+ return;
19
+ }
20
+ console.log(chalk.cyan(`Found ${courses.length} active course(s)\n`));
21
+ const allAssignments = [];
22
+ for (const course of courses) {
23
+ try {
24
+ const assignmentParams = ["include[]=submission", "per_page=100"];
25
+ const assignments = await makeCanvasRequest("get", `courses/${course.id}/assignments`, assignmentParams);
26
+ if (assignments && assignments.length > 0) {
27
+ for (const assignment of assignments) {
28
+ allAssignments.push({
29
+ ...assignment,
30
+ courseName: course.name,
31
+ courseCode: course.course_code,
32
+ });
33
+ }
34
+ }
35
+ }
36
+ catch {
37
+ continue;
38
+ }
39
+ }
40
+ if (allAssignments.length === 0) {
41
+ printError("No assignments found in any course.");
42
+ return;
43
+ }
44
+ let filteredAssignments = allAssignments;
45
+ if (options.missing) {
46
+ filteredAssignments = filteredAssignments.filter((a) => {
47
+ const submission = a.submission;
48
+ const isNotSubmitted = !submission || !submission.submitted_at;
49
+ const hasDueDate = a.due_at !== null;
50
+ return isNotSubmitted && hasDueDate;
51
+ });
52
+ }
53
+ if (options.submitted) {
54
+ filteredAssignments = filteredAssignments.filter((a) => a.submission && a.submission.submitted_at);
55
+ }
56
+ if (options.pending) {
57
+ filteredAssignments = filteredAssignments.filter((a) => !a.submission || !a.submission.submitted_at);
58
+ }
59
+ if (options.dueThisWeek) {
60
+ const now = new Date();
61
+ const oneWeekFromNow = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
62
+ filteredAssignments = filteredAssignments.filter((a) => {
63
+ if (!a.due_at)
64
+ return false;
65
+ const dueDate = new Date(a.due_at);
66
+ return dueDate >= now && dueDate <= oneWeekFromNow;
67
+ });
68
+ }
69
+ filteredAssignments.sort((a, b) => {
70
+ if (!a.due_at)
71
+ return 1;
72
+ if (!b.due_at)
73
+ return -1;
74
+ return new Date(a.due_at).getTime() - new Date(b.due_at).getTime();
75
+ });
76
+ printSuccess(`Found ${filteredAssignments.length} assignment(s) matching criteria.\n`);
77
+ const table = new Table([
78
+ { key: "course", header: "Course", flex: 1.5, minWidth: 15 },
79
+ { key: "assignment", header: "Assignment", flex: 2.5, minWidth: 25 },
80
+ {
81
+ key: "due",
82
+ header: "Due Date",
83
+ flex: 1.2,
84
+ minWidth: 12,
85
+ color: (val) => {
86
+ if (val === "No due date")
87
+ return chalk.gray(val);
88
+ const dueDate = new Date(val);
89
+ const now = new Date();
90
+ const daysUntilDue = Math.ceil((dueDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
91
+ if (daysUntilDue < 0)
92
+ return chalk.red(val);
93
+ if (daysUntilDue <= 2)
94
+ return chalk.red.bold(val);
95
+ if (daysUntilDue <= 7)
96
+ return chalk.yellow(val);
97
+ return chalk.green(val);
98
+ },
99
+ },
100
+ {
101
+ key: "status",
102
+ header: "Status",
103
+ flex: 1,
104
+ minWidth: 10,
105
+ color: (val) => {
106
+ if (val.includes("✓"))
107
+ return chalk.green(val);
108
+ if (val.includes("✗"))
109
+ return chalk.red(val);
110
+ return chalk.yellow(val);
111
+ },
112
+ },
113
+ { key: "points", header: "Points", flex: 0.8, minWidth: 8 },
114
+ ], { showRowNumbers: true, title: undefined });
115
+ for (const assignment of filteredAssignments) {
116
+ const submission = assignment.submission;
117
+ const isSubmitted = submission && submission.submitted_at;
118
+ let statusText = "";
119
+ if (isSubmitted) {
120
+ const hasGrade = submission.score !== null && submission.score !== undefined;
121
+ statusText = hasGrade
122
+ ? `✓ Graded (${submission.score})`
123
+ : "✓ Submitted";
124
+ }
125
+ else {
126
+ const dueDate = assignment.due_at ? new Date(assignment.due_at) : null;
127
+ const isPastDue = dueDate && dueDate < new Date();
128
+ statusText = isPastDue ? "✗ Missing" : "○ Pending";
129
+ }
130
+ table.addRow({
131
+ course: assignment.courseCode ||
132
+ assignment.courseName?.substring(0, 15) ||
133
+ "Unknown",
134
+ assignment: assignment.name,
135
+ due: assignment.due_at
136
+ ? new Date(assignment.due_at).toLocaleDateString()
137
+ : "No due date",
138
+ status: statusText,
139
+ points: assignment.points_possible?.toString() || "N/A",
140
+ });
141
+ }
142
+ table.render();
143
+ printSeparator("=");
144
+ }
145
+ catch (error) {
146
+ const errorMessage = error instanceof Error ? error.message : String(error);
147
+ printError(`Error fetching assignments: ${errorMessage}`);
148
+ }
149
+ }
4
150
  export async function listAssignments(courseName, options = {}) {
5
151
  try {
152
+ if (options.allCourses) {
153
+ return await listAllCoursesAssignments(options);
154
+ }
6
155
  let course;
7
156
  let selectedCourseId;
8
157
  if (!courseName) {
@@ -16,13 +165,14 @@ export async function listAssignments(courseName, options = {}) {
16
165
  result.rl.close();
17
166
  }
18
167
  else {
19
- course = await getCanvasCourse(courseName);
168
+ const rl = createReadlineInterface();
169
+ course = await getCanvasCourse(courseName, rl);
20
170
  if (!course) {
21
171
  return;
22
172
  }
23
173
  selectedCourseId = course.id.toString();
24
174
  }
25
- printSeparator("─", 60);
175
+ printSeparator();
26
176
  const assignmentParams = ["include[]=submission", "per_page=100"];
27
177
  printInfo("Loading assignments, please wait...");
28
178
  const assignments = await makeCanvasRequest("get", `courses/${selectedCourseId}/assignments`, assignmentParams);
@@ -1 +1 @@
1
- {"version":3,"file":"assignments.js","sourceRoot":"","sources":["../../commands/assignments.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"assignments.js","sourceRoot":"","sources":["../../commands/assignments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ interface DownloadOptions {
2
+ all?: boolean;
3
+ output?: string;
4
+ }
5
+ export declare function bulkDownload(courseName?: string, options?: DownloadOptions): Promise<void>;
6
+ export {};
7
+ //# sourceMappingURL=download.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../commands/download.ts"],"names":[],"mappings":"AAoBA,UAAU,eAAe;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAgGD,wBAAsB,YAAY,CAChC,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CA0Hf"}
@@ -0,0 +1,157 @@
1
+ import { makeCanvasRequest, getCanvasCourse } from "../lib/api-client.js";
2
+ import { pickCourse, printInfo, printError, printSuccess, printSeparator, } from "../lib/display.js";
3
+ import { createReadlineInterface } from "../lib/interactive.js";
4
+ import chalk from "chalk";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import https from "https";
8
+ import http from "http";
9
+ function sanitizeFileName(name) {
10
+ return name.replace(/[<>:"/\\|?*\x00-\x1F]/g, "_").trim();
11
+ }
12
+ async function downloadFile(url, outputPath, fileName) {
13
+ return new Promise((resolve) => {
14
+ const client = url.startsWith("https") ? https : http;
15
+ const request = client.get(url, (response) => {
16
+ if (response.statusCode === 301 ||
17
+ response.statusCode === 302 ||
18
+ response.statusCode === 307 ||
19
+ response.statusCode === 308) {
20
+ const redirectUrl = response.headers.location;
21
+ if (redirectUrl) {
22
+ downloadFile(redirectUrl, outputPath, fileName).then(resolve);
23
+ return;
24
+ }
25
+ }
26
+ if (response.statusCode !== 200) {
27
+ console.log(chalk.red(` ✗ Failed to download ${fileName}: HTTP ${response.statusCode}`));
28
+ resolve(false);
29
+ return;
30
+ }
31
+ const fileStream = fs.createWriteStream(outputPath);
32
+ response.pipe(fileStream);
33
+ fileStream.on("finish", () => {
34
+ fileStream.close();
35
+ console.log(chalk.green(` ✓ Downloaded: ${fileName}`));
36
+ resolve(true);
37
+ });
38
+ fileStream.on("error", (err) => {
39
+ fs.unlink(outputPath, () => { });
40
+ console.log(chalk.red(` ✗ Error downloading ${fileName}: ${err.message}`));
41
+ resolve(false);
42
+ });
43
+ });
44
+ request.on("error", (err) => {
45
+ console.log(chalk.red(` ✗ Error downloading ${fileName}: ${err.message}`));
46
+ resolve(false);
47
+ });
48
+ });
49
+ }
50
+ async function getAllFolders(courseId) {
51
+ try {
52
+ const folders = await makeCanvasRequest("get", `courses/${courseId}/folders`, ["per_page=100"]);
53
+ return folders || [];
54
+ }
55
+ catch {
56
+ return [];
57
+ }
58
+ }
59
+ async function getFilesInFolder(folderId) {
60
+ try {
61
+ const files = await makeCanvasRequest("get", `folders/${folderId}/files`, ["per_page=100"]);
62
+ return files || [];
63
+ }
64
+ catch {
65
+ return [];
66
+ }
67
+ }
68
+ export async function bulkDownload(courseName, options = {}) {
69
+ try {
70
+ let course;
71
+ let selectedCourseId;
72
+ if (!courseName) {
73
+ const result = await pickCourse({
74
+ title: "\nSelect course to download files from...",
75
+ showAll: options.all,
76
+ });
77
+ if (!result)
78
+ return;
79
+ course = result.course;
80
+ selectedCourseId = course.id.toString();
81
+ result.rl.close();
82
+ }
83
+ else {
84
+ const rl = createReadlineInterface();
85
+ course = await getCanvasCourse(courseName, rl);
86
+ if (!course) {
87
+ return;
88
+ }
89
+ selectedCourseId = course.id.toString();
90
+ rl.close();
91
+ }
92
+ printSeparator("=");
93
+ printInfo(`Downloading files from: ${course?.name || selectedCourseId}`);
94
+ printSeparator("=");
95
+ const sanitizedCourseName = sanitizeFileName(course?.name || `course_${selectedCourseId}`);
96
+ const baseOutputDir = options.output || process.cwd();
97
+ const outputDir = path.join(baseOutputDir, sanitizedCourseName);
98
+ if (!fs.existsSync(outputDir)) {
99
+ fs.mkdirSync(outputDir, { recursive: true });
100
+ }
101
+ console.log(chalk.cyan(`\nOutput directory: ${outputDir}\n`));
102
+ printInfo("Fetching folder structure...");
103
+ const folders = await getAllFolders(selectedCourseId);
104
+ if (folders.length === 0) {
105
+ printError("No folders found in this course.");
106
+ return;
107
+ }
108
+ console.log(chalk.cyan(`Found ${folders.length} folder(s)\n`));
109
+ let totalFiles = 0;
110
+ let downloadedFiles = 0;
111
+ let failedFiles = 0;
112
+ for (const folder of folders) {
113
+ const folderPath = folder.full_name || folder.name;
114
+ const sanitizedPath = sanitizeFileName(folderPath);
115
+ const folderOutputDir = path.join(outputDir, sanitizedPath);
116
+ if (!fs.existsSync(folderOutputDir)) {
117
+ fs.mkdirSync(folderOutputDir, { recursive: true });
118
+ }
119
+ const files = await getFilesInFolder(folder.id.toString());
120
+ if (files.length > 0) {
121
+ console.log(chalk.bold(`\n📁 ${folderPath} (${files.length} files):`));
122
+ totalFiles += files.length;
123
+ for (const file of files) {
124
+ const sanitizedFileName = sanitizeFileName(file.display_name || file.filename);
125
+ const filePath = path.join(folderOutputDir, sanitizedFileName);
126
+ if (fs.existsSync(filePath)) {
127
+ console.log(chalk.gray(` ⊙ Skipped (exists): ${sanitizedFileName}`));
128
+ downloadedFiles++;
129
+ continue;
130
+ }
131
+ const success = await downloadFile(file.url, filePath, sanitizedFileName);
132
+ if (success) {
133
+ downloadedFiles++;
134
+ }
135
+ else {
136
+ failedFiles++;
137
+ }
138
+ }
139
+ }
140
+ }
141
+ printSeparator("=");
142
+ console.log(chalk.white.bold("\n📊 Download Summary:\n"));
143
+ console.log(chalk.cyan(`Total files found: ${totalFiles}`));
144
+ console.log(chalk.green(`Successfully downloaded: ${downloadedFiles}`));
145
+ if (failedFiles > 0) {
146
+ console.log(chalk.red(`Failed: ${failedFiles}`));
147
+ }
148
+ console.log(chalk.cyan(`\nAll files saved to: ${outputDir}`));
149
+ printSeparator("=");
150
+ printSuccess("\nBulk download completed!");
151
+ }
152
+ catch (error) {
153
+ const errorMessage = error instanceof Error ? error.message : String(error);
154
+ printError(`Error during bulk download: ${errorMessage}`);
155
+ }
156
+ }
157
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../commands/download.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../commands/files.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAIV,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAmH3B,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,MAAY,GACvB,OAAO,CAAC,IAAI,CAAC,CA8Kf;AAED,wBAAsB,SAAS,CAC7B,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAqJf"}
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../commands/files.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAIV,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAmH3B,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,MAAY,GACvB,OAAO,CAAC,IAAI,CAAC,CA8Kf;AAED,wBAAsB,SAAS,CAC7B,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAsJf"}
@@ -138,7 +138,7 @@ export async function browseFolder(courseId, folderId, courseName, folderPath =
138
138
  }
139
139
  console.log(chalk.cyan.bold(`\n${courseName}`));
140
140
  console.log(chalk.gray(` Path: ${folderPath}`));
141
- printSeparator("─", 60);
141
+ printSeparator();
142
142
  const menuItems = [];
143
143
  if (folderId) {
144
144
  menuItems.push({ type: "back", name: "📤 .. (Go back)" });
@@ -239,12 +239,13 @@ export async function showFiles(courseName, options = {}) {
239
239
  result.rl.close();
240
240
  }
241
241
  else {
242
- course = await getCanvasCourse(courseName);
242
+ const rl = createReadlineInterface();
243
+ course = await getCanvasCourse(courseName, rl);
243
244
  if (!course) {
244
245
  return;
245
246
  }
246
247
  }
247
- printSeparator("─", 60);
248
+ printSeparator();
248
249
  printInfo("Loading course files...");
249
250
  const files = await makeCanvasRequest("get", `courses/${course.id}/files`, ["per_page=100", "sort=updated_at", "order=desc"]);
250
251
  if (!files || files.length === 0) {
@@ -253,7 +254,7 @@ export async function showFiles(courseName, options = {}) {
253
254
  }
254
255
  console.log(chalk.cyan.bold(`\nFiles in: ${course.name}`));
255
256
  console.log(chalk.gray(` Total: ${files.length} file(s)`));
256
- printSeparator("─", 60);
257
+ printSeparator();
257
258
  const columns = [
258
259
  {
259
260
  key: "name",