利用github给国外文件下载加速
前言
作为一名程序员,经常需要下载一些编程相关的环境,而国内的网络环境大家都知道,有的文件用浏览器是下载不动的,于是我有了利用github下载文件的想法。
我的demo项目地址:https://github.com/bobowire/wireboy.remote.download
参考资料:
- NodeJS使用node-fetch下载文件并显示下载进度示例:https://www.jianshu.com/p/4b58711cb72a
- nodejs——发送邮件(带附件):https://www.cnblogs.com/yourstars/p/6728931.html
下载加速原理
使用github的Action远程执行文件下载(下载qt环境速度可以达到3mb/s),然后将下载的文件进行分片,每片15mb,分片后的文件以邮件附件的方式发送到国内邮箱,我们通过下载邮箱中的附件,将分片的附件合并成完整文件,从而实现不翻墙、不用下载器也能下载国外文件的目的。
简单点说
- github远程下载
- 文件分片
- 通过邮箱发到国内
- 对附件进行合并
使用方法
- 新建github项目
- 创建js文件download.js文件,内容请查阅后文
- 创建workflows/RunDownload.yml文件,内容请查阅后文
- 修改download.js中的fileURL 变量值,此为文件url地址
- 在项目github->settings->Secrets中,点击右上方“new responsitory secret”按钮,添加"EMAILPASS","SENDEMAIL","TOEMAIL"变量(授权码、发送邮箱、目标邮箱)
- 以上全部完成后,我们每次修改download.js文件的fileURL地址,github都会自动进行一次下载。原理请自行百度“github action”。
注意:
- 授权码(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: '<p>下载文件成功</p>',
        // Apple Watch specific HTML body 苹果手表指定HTML格式
        watchHtml: '<b>Hello</b> 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;
};
效果图
收件箱


github的action运行日志

利用github给国外文件下载加速的更多相关文章
- 利用Github和Hexo搭建独立的个人博客--基础篇
		利用Github和Hexo搭建独立的个人博客--基础篇 摘要:本文主要参考了使用hexo和Github上创建自己的博客.如何搭建一个独立博客--简明Github Pages与Hexo教程和使用GitH ... 
- 利用github pages创建简单的网站
		github.com 作为最流行的源代码管理工具已经风靡全球,同时在依托于github也衍生出了各种各样的应用,比如可以利用github搭建博客系统等等. 先换个话题,我们每人手头都或多或少有些&qu ... 
- 利用Github Pages生成一个快速访问的网址,展示自己的项目
		利用Github Pages展示自己的项目 写了个小项目,想要分享出去,一直在用Github管理项目,了解到Github还有Github Pages功能,然后惊喜的发现Github pages可以搭建 ... 
- Windows环境下利用github快速配置git环境
		在windows环境下利用github客户端我们可以直接拥有可视化的界面来管理工程,当然你也可以选择你喜欢的命令行工具来做.今天我分享一个比较快速的方式来配置git环境. 先去下载github的win ... 
- 利用github for windows 工具将本地的内容同步到github上
		1 利用github for windows工具来创建一个Repository,名字叫weixin,具体步骤 请参考这篇文章 根据default storage directory的设置 我知道我所创 ... 
- 如何利用GitHub搜索敏感信息
		如何利用GitHub搜索敏感信息 背景: 最近总是能听到同事说在GitHub上搜到某个敏感信息,然后利用该信息成功的检测并发现某个漏洞,最后提交到对应的SRC(安全应急响应中心)换点money.顿时心 ... 
- 我是如何利用Github Pages搭建起我的博客,细数一路的坑
		1.前言 其实早在这之前我就一直想过写博客,但由于种种原因一直没有去学习这方面的知识,最近半个月(从开始动手到搭建好)一直陆陆续续的在着手这方面的工作.从开始到搭建完成的过程中遇到了很多困难,因为在这 ... 
- Android Studio利用GitHub托管项目
		自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onL ... 
- 利用Github免费搭建个人主页(个人博客)
		之前闲着, 利用Github搭了个免费的个人主页. 涉及: Github注册 Github搭建博客 域名选购 绑定域名 更多 一 Github注册 在地址栏输入地址:http://github.co ... 
随机推荐
- 商品sku的排列组合
			<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ... 
- 题解 CF611H 【New Year and Forgotten Tree】
			Solution 提供一种新思路. 首先考虑如何判断一个状态是否合法. 考虑把所有十进制长度一样的数缩成一个点. 这样的点的个数 \(\le 5\). 蒟蒻猜了一个结论:只要满足对于所有缩出来的点的子 ... 
- 【题解】「UVA681」Convex Hull Finding
			更改了一下程序的错误. Translation 找出凸包,然后逆时针输出每个点,测试数据中没有相邻的边是共线的.多测. Solution 首先推销一下作者的笔记 由此进入>>> ( ... 
- JetBrains系列产品使用记录
			1.PyCharm中from import提示找不到定义,提示错误,但其实是没有错误的 右键项目的根路径,Mark Directory As Source Root 2.自动换行 在Editor-& ... 
- Springboot mini - Solon详解(七)- Solon Ioc 的注解对比Spring及JSR330
			Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ... 
- PB级大规模Elasticsearch集群运维与调优实践【>>戳文章免费体验Elasticsearch服务30天】
			[活动]Elasticsearch Service免费体验馆>> Elasticsearch Service自建迁移特惠政策>>Elasticsearch Service新用户 ... 
- Nessus<强大的漏扫工具>
			刷漏洞,抓鸡必备,,,,,,, 参考文章: https://blog.csdn.net/wwl012345/article/details/96998187 肝,,,,太全了,,, ps : 我不是脚 ... 
- Python进阶——什么是上下文管理器?
			在 Python 开发中,我们经常会使用到 with 语法块,例如在读写文件时,保证文件描述符的正确关闭,避免资源泄露问题. 你有没有思考过, with 背后是如何实现的?我们常常听到的上下文管理器究 ... 
- day021|python之面向对象进阶1
			面向对象进阶 目录 面向对象进阶 1 继承 1.1 继承入门 1.1.1 继承基础 1.1.2 类的基本使用 1.2 多继承 1.2.1 多继承的基本使用 1.2.2 多继承以后的重复性 1.3 类的 ... 
- C#访问Access数据库提示未安装ISAM
			解决办法 1.在前面加上Jet OLEDB:,如: Jet OLEDB:Database Password='zt' <add name="ConStrOleDb" conn ... 
