1. 程式人生 > >利用github給國外檔案下載加速

利用github給國外檔案下載加速

# 前言 作為一名程式設計師,經常需要下載一些程式設計相關的環境,而國內的網路環境大家都知道,有的檔案用瀏覽器是下載不動的,於是我有了利用github下載檔案的想法。 我的demo專案地址:https://github.com/bobowire/wireboy.remote.download 參考資料: 1. NodeJS使用node-fetch下載檔案並顯示下載進度示例:https://www.jianshu.com/p/4b58711cb72a 2. nodejs——傳送郵件(帶附件):https://www.cnblogs.com/yourstars/p/6728931.html # 覺得好玩的,大家可以點個贊~ # 下載加速原理 使用github的Action遠端執行檔案下載(下載qt環境速度可以達到3mb/s),然後將下載的檔案進行分片,每片15mb,分片後的檔案以郵件附件的方式傳送到國內郵箱,我們通過下載郵箱中的附件,將分片的附件合併成完整檔案,從而實現不FQ、不用下載器也能下載國外檔案的目的。 ## 簡單點說 1. github遠端下載 2. 檔案分片 3. 通過郵箱發到國內 4. 對附件進行合併 # 使用方法 1. 新建github專案 2. 建立js檔案download.js檔案,內容請查閱後文 3. 建立workflows/RunDownload.yml檔案,內容請查閱後文 4. 修改download.js中的fileURL 變數值,此為檔案url地址 5. 在專案github->settings->Secrets中,點選右上方“new responsitory secret”按鈕,新增"EMAILPASS","SENDEMAIL","TOEMAIL"變數(授權碼、傳送郵箱、目標郵箱) 6. 以上全部完成後,我們每次修改download.js檔案的fileURL地址,github都會自動進行一次下載。原理請自行百度“github action”。 注意: 1. 授權碼(EMAILPASS)是指“郵箱第三方登入授權碼”,如何獲取授權碼,以QQ郵箱為例,請點選:http://jingyan.baidu.com/article/fedf0737af2b4035ac8977ea.html # github Action檔案(RunDownload.yml) ``` name: Github wireboy.remote.download on: push: branches: - main schedule: - cron: '* * * * *' jobs: build: runs-on: ubuntu-latest steps: - name: Checkout codes uses: actions/checkout@v2 - name: Use Node.js uses: actions/setup-node@v1 with: node-version: '12.x' - name: Run run: npm install - run: node download.js env: EMAILPASS: ${{ secrets.EMAILPASS }} SENDEMAIL: ${{ secrets.SENDEMAIL }} TOEMAIL: ${{ secrets.TOEMAIL }} ``` # 原始碼(download.js) ``` const fetch = require("node-fetch"); const fs = require("fs"); const path = require("path"); const progressStream = require('progress-stream'); const nodemailer = require('nodemailer'); //下載 的檔案 地址 (https://nodejs.org/dist/v12.18.3/node-v12.18.3-x64.msi) let fileURL = 'https://nodejs.org/dist/v12.18.3/node-v12.18.3-x64.msi'; //下載儲存的檔案路徑 let fileSavePath = path.join(__dirname, path.basename(fileURL)); //快取檔案路徑 let tmpFileSavePath = fileSavePath + ".tmp"; //建立寫入流 const fileStream = fs.createWriteStream(tmpFileSavePath).on('error', function (e) { console.error('error==>', e) }).on('ready', function () { console.log("開始下載:", fileURL); }).on('finish', function () { //下載完成後重新命名檔案 fs.renameSync(tmpFileSavePath, fileSavePath); console.log('檔案下載完成:', fileSavePath); const readstream = fs.createReadStream(fileSavePath); let i = 0; console.time('readtime'); let patchIndex = 0; readstream.on('readable', () => { { console.log('start read'); let chunk = readstream.read(1024 * 1024 * 15); while (null !== chunk) { patchIndex = patchIndex + 1; console.log('read times:'+patchIndex) console.log(fileSavePath+'.email_'+patchIndex); let emailFile = fs.createWriteStream(fileSavePath+'.email_'+patchIndex).on('finish',function(){ }) emailFile.write(chunk); emailFile.end(); let msg = createEmailMessage(patchIndex+'_'+path.basename(fileURL),fileSavePath+'.email_'+patchIndex,path.basename(fileURL) + '(' + patchIndex + ')'); console.log('Send Mail ' + patchIndex + ' times'); console.log(path.basename(fileURL)); var transporter = createTransporter(); transporter.sendMail(msg, (error, info) => { if (error) { console.log('Error occurred'); console.log(error.message); return; } console.log('Message sent successfully!'); console.log('Server responded with "%s"', info.response); transporter.close(); }); chunk = readstream.read(1024 * 1024 * 10); } console.log('end read'); } }); readstream.on('close', () => { console.timeEnd('readtime'); }); }); //請求檔案 fetch(fileURL, { method: 'GET', headers: { 'Content-Type': 'application/octet-stream' }, // timeout: 100, }).then(res => { //獲取請求頭中的檔案大小資料 let fsize = res.headers.get("content-length"); //建立進度 let str = progressStream({ length: fsize, time: 100 /* ms */ }); // 下載進度 str.on('progress', function (progressData) { //不換行輸出 let percentage = Math.round(progressData.percentage) + '%'; console.log(percentage); // process.stdout.write('\033[2J'+); // console.log(progress); /* { percentage: 9.05, transferred: 949624, length: 10485760, remaining: 9536136, eta: 42, runtime: 3, delta: 295396, speed: 949624 } */ }); res.body.pipe(str).pipe(fileStream); }).catch(e => { //自定義異常處理 console.log(e); }); var createTransporter = function(){ return nodemailer.createTransport({ service: 'qq', auth: { user: process.env.SENDEMAIL,//傳送者郵箱 pass: process.env.EMAILPASS //郵箱第三方登入授權碼 }, // logger: bunyan.createLogger({ // name: 'nodemailer' // }),//列印日誌 debug: true },{ from: process.env.SENDEMAIL,//傳送者郵箱 headers: { 'X-Laziness-level': 1000 } }); } console.log('SMTP Configured'); var createEmailMessage = function(filename,filepath,subject){ var message = { // Comma separated lsit of recipients 收件人用逗號間隔 to: process.env.TOEMAIL, // Subject of the message 資訊主題 subject: subject, // plaintext body text: '請查閱附件', // Html body html: '

下載檔案成功

', // Apple Watch specific HTML body 蘋果手錶指定HTML格式 watchHtml: 'Hello to myself', // An array of attachments 附件 attachments: [ // String attachment // { // filename: 'notes.txt', // content: 'Some notes about this e-mail', // contentType: 'text/plain' // optional,would be detected from the filename 可選的,會檢測檔名 // }, // // Binary Buffer attchment // { // filename: 'image.png', // content: Buffer.from('iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/' + // '//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U' + // 'g9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC', 'base64'), // cid: '00001' // should be as unique as possible 儘可能唯一 // }, // File Stream attachment { filename: filename, path: filepath, // cid: '00002' // should be as unique as possible 儘可能唯一 } ] }; return message; }; ``` # 效果圖 ## 收件箱 ![](https://img2020.cnblogs.com/blog/614311/202101/614311-20210115001717516-947066890.png) ![](https://img2020.cnblogs.com/blog/614311/202101/614311-20210115001911025-2046540940.png) # github的action執行日誌 ![](https://img2020.cnblogs.com/blog/614311/202101/614311-20210115001757088-11701945