Automatically downloads PDF files from course pages
Size
7.0 KB
Version
1.2.3
Created
Nov 7, 2025
Updated
about 1 month ago
1// ==UserScript==
2// @name PDF Downloader for Dr Najeeb Lectures
3// @description Automatically downloads PDF files from course pages
4// @version 1.2.3
5// @match https://*.members.drnajeeblectures.com/*
6// @icon https://members.drnajeeblectures.com/favicon.ico
7// @grant GM.xmlhttpRequest
8// @require https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js
9// ==/UserScript==
10(function() {
11 'use strict';
12
13 console.log('PDF Downloader extension loaded');
14
15 // Function to capture all pages and create PDF
16 async function captureAndDownloadPDF(filename) {
17 console.log('Starting PDF capture process...');
18
19 try {
20 const iframe = document.querySelector('#text iframe');
21 if (!iframe) {
22 alert('PDF viewer not found');
23 return;
24 }
25
26 const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
27 const canvas = iframeDoc.querySelector('canvas');
28 const pageCountEl = iframeDoc.querySelector('#page_count');
29 const pageNumInput = iframeDoc.querySelector('#page_num');
30 const nextBtn = iframeDoc.querySelector('#next');
31
32 if (!canvas || !pageCountEl || !pageNumInput || !nextBtn) {
33 alert('Could not access PDF viewer elements');
34 return;
35 }
36
37 const totalPages = parseInt(pageCountEl.textContent);
38 console.log('Total pages to capture:', totalPages);
39
40 // Make sure we start from page 1
41 pageNumInput.value = 1;
42 const changeEvent = new Event('change', { bubbles: true });
43 pageNumInput.dispatchEvent(changeEvent);
44 await new Promise(resolve => setTimeout(resolve, 2000));
45
46 // Create new PDF document
47 const { jsPDF } = window.jspdf;
48 const pdf = new jsPDF({
49 orientation: canvas.height > canvas.width ? 'portrait' : 'landscape',
50 unit: 'px',
51 format: [canvas.width, canvas.height]
52 });
53
54 // Capture each page
55 for (let pageNum = 1; pageNum <= totalPages; pageNum++) {
56 console.log(`Capturing page ${pageNum}/${totalPages}...`);
57
58 // Wait for page to render
59 await new Promise(resolve => setTimeout(resolve, 1500));
60
61 // Capture canvas as image in high quality PNG
62 const imgData = canvas.toDataURL('image/png', 1.0);
63
64 // Add page to PDF (first page is already created)
65 if (pageNum > 1) {
66 pdf.addPage([canvas.width, canvas.height]);
67 }
68
69 pdf.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height);
70 console.log(`Page ${pageNum} captured`);
71
72 // Navigate to next page (if not last page)
73 if (pageNum < totalPages) {
74 nextBtn.click();
75 console.log('Clicked next button');
76 }
77 }
78
79 // Save the PDF
80 console.log('Saving PDF...');
81 pdf.save(filename);
82 console.log('PDF saved successfully!');
83
84 // Reset to first page
85 pageNumInput.value = 1;
86 pageNumInput.dispatchEvent(new Event('change', { bubbles: true }));
87
88 } catch (error) {
89 console.error('Error creating PDF:', error);
90 alert('Failed to create PDF: ' + error.message);
91 }
92 }
93
94 // Function to extract course name for filename
95 function getCourseName() {
96 const titleElement = document.querySelector('h3.text-ellipsis');
97 if (titleElement) {
98 return titleElement.textContent.trim().replace(/[^a-z0-9]/gi, '_').substring(0, 50);
99 }
100 return 'course_notes';
101 }
102
103 // Function to create download button
104 function createDownloadButton() {
105 const iframe = document.querySelector('#text iframe');
106
107 if (!iframe) {
108 console.log('No PDF iframe found on this page');
109 return;
110 }
111
112 const buttonContainer = document.querySelector('.s-title .column.col-7');
113
114 if (!buttonContainer) {
115 console.log('Button container not found');
116 return;
117 }
118
119 // Check if button already exists
120 if (document.getElementById('pdfDownloadBtn')) {
121 console.log('Download button already exists');
122 return;
123 }
124
125 // Create download button
126 const downloadBtn = document.createElement('button');
127 downloadBtn.id = 'pdfDownloadBtn';
128 downloadBtn.className = 'btn btn-link courseNavBtn';
129 downloadBtn.innerHTML = `
130 <i class="material-icons" style="vertical-align: middle;">download</i>
131 <span class="icon-text">Download PDF</span>
132 `;
133 downloadBtn.style.cssText = `
134 color: rgb(87, 85, 217);
135 padding: 7px 8px;
136 font-size: 16px;
137 font-family: Inter, sans-serif;
138 border: none;
139 background: transparent;
140 cursor: pointer;
141 margin-right: 10px;
142 `;
143
144 // Add hover effect
145 downloadBtn.addEventListener('mouseenter', () => {
146 downloadBtn.style.opacity = '0.7';
147 });
148 downloadBtn.addEventListener('mouseleave', () => {
149 downloadBtn.style.opacity = '1';
150 });
151
152 // Add click handler
153 downloadBtn.addEventListener('click', async () => {
154 downloadBtn.disabled = true;
155 downloadBtn.innerHTML = `
156 <i class="material-icons" style="vertical-align: middle;">hourglass_empty</i>
157 <span class="icon-text">Creating PDF...</span>
158 `;
159
160 const courseName = getCourseName();
161 const filename = `${courseName}.pdf`;
162
163 await captureAndDownloadPDF(filename);
164
165 // Reset button after download
166 setTimeout(() => {
167 downloadBtn.disabled = false;
168 downloadBtn.innerHTML = `
169 <i class="material-icons" style="vertical-align: middle;">download</i>
170 <span class="icon-text">Download PDF</span>
171 `;
172 }, 1000);
173 });
174
175 // Insert button before the "Previous" button
176 const prevButton = document.getElementById('prevCourseItemBtn');
177 buttonContainer.insertBefore(downloadBtn, prevButton);
178
179 console.log('Download button added successfully');
180 }
181
182 // Wait for page to load and add button
183 function init() {
184 console.log('Initializing PDF downloader...');
185
186 // Wait for the page to fully load
187 setTimeout(() => {
188 createDownloadButton();
189 }, 2000);
190 }
191
192 // Run when page is ready
193 if (document.readyState === 'loading') {
194 document.addEventListener('DOMContentLoaded', init);
195 } else {
196 init();
197 }
198
199})();