Skip to content

Commit

Permalink
feat(download-ppt): 支持导出为PDF
Browse files Browse the repository at this point in the history
  • Loading branch information
memset0 committed Mar 3, 2024
1 parent 045bd15 commit 1bf5603
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 30 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@

下载智云课堂自动生成的课件,支持配置最小间隔时间,还支持多种下载方式:

- 合并成 PDF 下载 (TBD)
- **导出为 PDF**:将所有课件导出为 PDF,会调用浏览器自带的打印对话框,也可以直接通过打印机打印。[点我下载示例文件](https://pan.memset0.cn/Share/2024/03/03/%E4%BD%BF%E7%94%A8%E8%84%9A%E6%9C%AC%E5%AF%BC%E5%87%BA%E7%9A%84%E8%AF%BE%E4%BB%B6%EF%BC%88%E9%AB%98%E7%BA%A7%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95%E5%88%86%E6%9E%902024-02-26%E7%AC%AC3-5%E8%8A%82%EF%BC%89.pdf)

- zip 打包下载
- **打包下载**:将所有课件添加到压缩包中,示例如下:
![](https://static.memset0.cn/img/v6/2024/03/03/uEUzlIZR.png)

由于浏览器性能限制,当图片数量过多时导出速度较慢。如果你有更好的解决方案,请联系我。



### 视频链接解析 [`download-video`](https://github.com/memset0/Learning-at-ZJU-Helper/tree/master/src/plugins/download-video)
Expand All @@ -35,5 +37,5 @@
如果需要使用被屏蔽的组件,到设置中关闭本功能即可。


> 以上功能介绍基于版本 1.1.3 生成,在最新版中可能发生改变,请参见 [项目仓库](https://github.com/memset0/Learning-at-ZJU-Helper)
> 以上功能介绍基于版本 1.1.4 生成,在最新版中可能发生改变,请参见 [项目仓库](https://github.com/memset0/Learning-at-ZJU-Helper)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "learning-at-zju-helper",
"version": "1.1.3",
"version": "1.1.4",
"description": "学在浙大/智云课堂 辅助脚本",
"main": "src/index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logger from './utils/logger.js';
import { sleep } from './utils/global.js';
import { isVideoPage } from './utils/checker.js';
import { copyToClipboard } from './utils/clipboard.js';
import { copyToClipboard } from './utils/browser.js';

class App {
constructor() {
Expand Down
6 changes: 4 additions & 2 deletions src/plugins/download-ppt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

下载智云课堂自动生成的课件,支持配置最小间隔时间,还支持多种下载方式:

- 合并成 PDF 下载 (TBD)
- **导出为 PDF**:将所有课件导出为 PDF,会调用浏览器自带的打印对话框,也可以直接通过打印机打印。[点我下载示例文件](https://pan.memset0.cn/Share/2024/03/03/%E4%BD%BF%E7%94%A8%E8%84%9A%E6%9C%AC%E5%AF%BC%E5%87%BA%E7%9A%84%E8%AF%BE%E4%BB%B6%EF%BC%88%E9%AB%98%E7%BA%A7%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95%E5%88%86%E6%9E%902024-02-26%E7%AC%AC3-5%E8%8A%82%EF%BC%89.pdf)

- zip 打包下载
- **打包下载**:将所有课件添加到压缩包中,示例如下:
![](https://static.memset0.cn/img/v6/2024/03/03/uEUzlIZR.png)

由于浏览器性能限制,当图片数量过多时导出速度较慢。如果你有更好的解决方案,请联系我。
59 changes: 46 additions & 13 deletions src/plugins/download-ppt/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import JSZip from 'jszip';
import { saveAs } from 'file-saver';
import { limitConcurrency } from '../../utils/global';
import { printToPdf } from '../../utils/browser.js';

export const name = '课件下载';
export const required = ['builtin-video-pages'];
Expand Down Expand Up @@ -50,24 +51,23 @@ export function load({ logger, elements, addButton }, options) {
logger.debug(`删除同一秒内的PPT后(共${pptList.length}个):`, pptList[0]);
}

addButton(1.1, '打包下载PPT', async ({ setStatus }) => {
addButton(1.1, '打包下载', async ({ setStatus }) => {
setStatus('加载JSZip库');
const zip = new JSZip();

setStatus('安排下载任务');
let counter = 0;
let total = pptList.length;
const imagePromises = pptList.map((ppt, index) => {
const filename = `ppt-${String(index).padStart(4, '0')}-${ppt.switchTime.replace(/\:/g, '-')}.jpg`;
return fetch(ppt.imgSrc, { method: 'GET' })
.then((response) => response.blob())
.then((blob) => {
logger.debug('添加图片', filename, blob);
setStatus(`正在下载(${++counter}/${total})`);
zip.file(filename, blob, { binary: true });
});
});
await limitConcurrency(imagePromises, 16);
await limitConcurrency(
pptList.map(async (ppt, index) => {
const filename = `ppt-${String(index).padStart(4, '0')}-${ppt.switchTime.replace(/\:/g, '-')}.jpg`;
const res = await fetch(ppt.imgSrc, { method: 'GET' });
const blob = await res.blob();
logger.debug('添加图片', filename, blob);
setStatus(`正在下载(${++counter}/${total})`);
zip.file(filename, blob, { binary: true });
}),
8
);

setStatus('生成Zip');
logger.debug(zip);
Expand All @@ -78,4 +78,37 @@ export function load({ logger, elements, addButton }, options) {
saveAs(content, 'ppt.zip');
setStatus(null);
});

addButton(1.2, '导出为PDF', async ({ setStatus }) => {
let html = '';
let counter = 0;
let total = pptList.length;
const imageList = await limitConcurrency(
pptList.map(async (ppt, index) => {
const res = await fetch(ppt.imgSrc, { method: 'GET' });
setStatus(`正在下载(${++counter}/${total})`);
const blob = await res.blob();
const blobUrl = URL.createObjectURL(blob);
logger.log(index, blobUrl);
return blobUrl;
}),
8
);

setStatus('生成PDF');
for (const image of imageList) {
html += `<div class="page"><img src="${image}" /></div>`;
}

await printToPdf(
{
width: 1280,
height: 720,
margin: 0,
},
html
);

setStatus(null);
});
}
40 changes: 40 additions & 0 deletions src/utils/browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import logger from './logger';

export function copyToClipboard(text) {
const input = document.createElement('input');
input.style.position = 'fixed';
input.style.opacity = 0;
input.value = text;
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
}

export async function printToPdf(options, html) {
const { width, height, margin } = options;
html = '<style> div.page { width: ' + (width - margin * 2) + 'px; height: ' + (height - margin * 2) + 'px; } </style>' + html;
html = '<style> /* page settings */ @page { size: ' + width + 'px ' + height + 'px; margin: ' + margin + 'px; } </style>' + html;
html = '<style> /* normalize browsers */ html, body { margin: 0 !important; padding: 0 !important; } </style>' + html;

const { style } = options;
if (style) {
html += '\n\n\n<!-- additional style --><style>' + style + '</style>\n\n\n';
}

// const document = unsafeWindow.document; // seemingly needless
const blob = new Blob([html], { type: 'text/html;charset=utf-8' });
const blobUrl = URL.createObjectURL(blob);
logger.debug('blobUrl:', blobUrl);

const $iframe = document.createElement('iframe');
$iframe.style.display = 'none';
$iframe.src = blobUrl;
document.body.appendChild($iframe);
$iframe.onload = () => {
setTimeout(() => {
$iframe.focus();
$iframe.contentWindow.print();
}, 1);
};
}
10 changes: 0 additions & 10 deletions src/utils/clipboard.js

This file was deleted.

0 comments on commit 1bf5603

Please sign in to comment.