文件本地网络互传

AlphaBrate Net Transfer Project

准备工作

灵感来源

Idea来源:电脑经常剪完视频想发到手机上,不过用xx网盘,x信,xQ传的很慢,还有时候网线出问题,还很麻烦 (那个就是写个这玩意更麻烦)
不过我还是选择做一下
这是AlphaBrate Team的项目,在这篇文章中,作为其成员,我将提供代码解说。
项目源码:https://github.com/alphabrate/nettransfer/

环境配置

Node JS

引用库

express
os
glob
electron

库用途

本地服务器:Express
获取文件列表:glob
GUI:Electron
ipv4:os

主文件

服务器:server.js
GUI:gui/gui.js


开始制作

服务器

server.js

引用库
const express = require("express"); // localhost server
const { networkInterfaces } = require('os'); // use to get user ipv4
const glob = require("glob"); // use to read path
获取ipv4地址 (本地ip)

用于向用户展示可连接的连接

const nets = networkInterfaces(); // return of network interface
const results = Object.create(null); // defind result
for (const name of Object.keys(nets)) { // geting ip
    for (const net of nets[name]) {
        // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
        // 'IPv4' is in Node <= 17, from 18 it's a number 4 or 6
        const familyV4Value = typeof net.family === 'string' ? 'IPv4' : 4
        if (net.family === familyV4Value && !net.internal) {
            if (!results[name]) {
                results[name] = [];
            }
            results[name].push(net.address);
        }
    }
}
const ipv4 = results["Wi-Fi"][0]; // ipv4 of user

ipv4将会是向用户展示的地址

生成连接和创建本地服务器
const app = express(); //
app.use(express.static("files")); // use folder: files as the static lib.
const pt = 1345; // port
const link = "http://" + ipv4 + ":" + pt; // generate the link
const file = __dirname + "\\files"; // generate the path that user put 

app.listen(pt,()=>{
    console.log("(C) AlphaBrate"); // Copyright info
    console.log("The Web is ready, please go to 'Net Transfer' tab."); //
}); // create server.

用户可以通过 ipv4:1345 (link) 访问

主页

我们需要一个便于用户操作的主页

基础代码
app.get("/",(req,res)=>{
    // Get file list
});
获取文件列表 Get file list
frs = []; // List of files
glob("files/*", function (er, files) {
    files.forEach(w=>{
        frs.push(w.split("files/")[1]);
    });
    // Render HTML
});
渲染HTML Render HTML

res.end() html,向其 <script> 内添加 frs 列表,让他自己渲染

res.end(`<!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Net Transfer</title>
        #STYLE#
    </head>
    <body>
        <div class="body">
            <h1>#SVG#</h1>
                <div style="display:flex;flex-direction:column;align-items:center;font-size:24px;" id="eta"></div>
        </div>
        <script>
                const files = ${JSON.stringify(frs)};
                files.forEach(w=>{
                    document.getElementById("eta").innerHTML += "<a href=" + w + ">" + w + "</a>";
                });
        </script>
    </body>
    </html>`)

#SVG# 被省略 (SVG图标)
#STYLE# 被省略 (CSS Style)

const files = ${JSON.stringify(frs)}; 将原本在server.js的变量:frs 套入了向用户展示的html的<script>中,<script>files 的每个元素执行一次向 #eta 加上一个<a>

生成<a>的规则:
由于我们使用了 app.use(express.static("files"));,所有被请求的静态文件都会在/files/中寻找,所以我们只需要将用户定向到 /:file 就行了

GUI 页面制作

由于无法在 GUI 中在获取一次文件列表 (或比较麻烦)
我们选择用 server.js 将 GUI 页面制作出来后再用 electron 提供本地窗口

这里的代码和上个部分很相似

app.get("/app/gui",(req,res)=>{
    frs = [];
    glob("files/*", function (er, files) {
        files.forEach(w=>{
            frs.push(w.split("files/")[1]);
        });
        res.end(`<!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Net Transfer</title>
            <style>
                :root {
                    --links: #00488A;
                    --themeColor: #7B9CFF;
                    --greenThemeColor: #E3DDA8;
                }
        
                #hoverShowCase {
                    white-space: nowrap;
                    display: none;
                    opacity: 0;
                    box-shadow: 0px 2px 5px #ffffff25;
                    position: fixed;
                    top: 0;
                    left: 0;
                    background: #000000;
                    padding: 5px 25px;
                    border-radius: 0 15px 15px 15px;
                    z-index: 999999;
                    color: white;
                    font-size: 25px;
                    letter-spacing: 0.02rem;
                }
        
                ::-webkit-scrollbar {
                    width: 0;
                }
        
                br {
                    user-select: none;
                }
        
                .body {
                    position: absolute;
                    top: 110px;
                    left: 0;
                    width: 100%;
                    height: calc(100% - 110px);
                    overflow-y: scroll;
                    overflow-x: hidden;
                }
        
                .poster {
                    width: 100%;
                }
        
                .icon {
                    position: absolute;
                    top: 50vh;
                    left: 50%;
                    transform: translate(-50%, -50%);
                }
        
                h1 {
                    display: flex;
                    justify-content: center;
                    font-size: 25px;
                    letter-spacing: 0.02rem;
                    align-items: center;
                    font-family: "Poppins", sans-serif;
                }
        
                h2 {
                    display: flex;
                    justify-content: center;
                    font-size: 25px;
                    letter-spacing: 0.02rem;
                    align-items: center;
                    font-family: "Poppins", sans-serif;
                    margin: 0;
                }
        
                h1>svg {
                    width: 80%;
                    min-width: 100px;
                    max-width: 500px;
                }
        
                iframe[copyright] {
                    position: absolute;
                    left: 50%;
                    transform: translateX(-50%);
                    height: 100%;
                    width: 80%;
                    max-width: 800px;
                }
        
                p {
                    width: 50%;
                    max-width: 800px;
                    min-width: 250px;
                    margin: 0 auto;
                    padding: 0 55px;
                    font-family: 'Inter';
                    font-style: normal;
                    font-weight: 400;
                    text-align: center;
                }
        
                a {
                    color: var(--links);
                    text-decoration-style: dotted;
                }
        
                .product {
                    position: relative;
                    margin: 50px auto;
                    width: 80%;
                    padding: 25px 0;
                    border: 2px solid var(--themeColor);
                    border-radius: 10px;
                }
        
                .product>.image>svg {
                    margin: 10px;
                }
        
                .intro>h1 {
                    margin: 75px 0;
                }
        
                .product[text-left]::before {
                    content: attr(data-text);
                    position: absolute;
                    height: 25px;
                    font-size: 25px;
                    line-height: 25px;
                    top: -13.5px;
                    left: 15px;
                    padding: 5px;
                    letter-spacing: 0.02rem;
                    font-family: "Poppins", sans-serif;
                    background: #000000;
                    color: white;
                }
        
                .product[text-right]::before {
                    content: attr(data-text);
                    position: absolute;
                    height: 25px;
                    font-size: 25px;
                    line-height: 25px;
                    top: -13.5px;
                    right: 15px;
                    padding: 5px;
                    letter-spacing: 0.02rem;
                    font-family: "Poppins", sans-serif;
                    background: #000000;
                    color: white;
                }
        
                .product>.des>p {
                    user-select: text;
                    font-size: 20px;
                    text-align: center;
                }
        
                .image {
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    flex-wrap: wrap;
                }
        
                .image>img {
                    width: 80%;
                    margin: 15px;
                    max-width: 500px;
                    border-radius: 15px;
                    box-shadow: 0 2px 10px #00000025;
                }
        
                button {
                    width: 150px;
                    height: 50px;
                    background: #7B9CFF;
                    border-radius: 5px;
                    font-family: "Poppins", sans-serif;
                    font-size: 20px;
                    font-weight: 500;
                    letter-spacing: -1px;
                    border: none;
                    outline: none;
                    transition: .3s;
                    cursor: pointer;
                }
        
                button:hover {
                    background: #429df1;
                }
        
                .des>a {
                    position: absolute;
                    left: 50%;
                    transform: translateX(-50%);
                }
        
                input {
                    width: 80vw;
                    max-width: 520px;
                    height: 60px;
                    font-size: 20px;
                    margin: 10px;
                    padding: 2px 10px;
                    border: 2px solid #ccc;
                    border-bottom: 5px solid rgb(123, 156, 255);
                    border-radius: 4px;
                    outline: none;
                    background-color: transparent;
                    font-weight: 100;
                    text-overflow: ellipsis;
                }
        
                input[readonly] {
                    border-bottom: 5px solid #ccc;
                }
            </style>
        </head>
        <body>
            <div class="body">
                #SVG#
                <div class="product">
                    <div class="des">
                        <p>Put the files in: </p>
                    </div>
                    <div class="image">
                        <input type="text" readonly value="${file}">
                    </div>
                </div>
                <div class="product">
                    <div class="des">
                        <p>Links</p>
                        <br>
                    </div>
                    <div class="image" id="eta"></div>
                </div>
            </div>
            <script>
                const files = ${JSON.stringify(frs)};
                files.forEach(w=>{
                    document.getElementById("eta").innerHTML += "<input type='text' readonly value='${link}/" + w + "'/>";
                });
            </script>
        </body>
        </html>`)
    });
});

#SVG# 被省略 (SVG图标)

服务器部分完成

server.js 部分完成,我们大部分工作也完成了
看看server.js完成效果

不要忘记添加文件到/files里面哦

/ $< node server.js
> (C) AlphaBrate
> The Web is ready, please go to 'Net Transfer' tab.

http://localhost:1345/

/


/files/text.txt

TEXT


http://localhost:1345/text.txt

TEXT


http://localhost:1345/app/gui

GUI


GUI 制作

Electron

gui.js

const { app, BrowserWindow} = require('electron');
const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    icon: __dirname + '/favicon.ico'
  });
  win.loadFile('index.html');
};
app.whenReady().then(() => {
  createWindow();
});
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') app.quit();
});
HTML

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Net Transfer</title>
</head>
<body>
    <script>
        location = "http://localhost:1345/app/gui";
    </script>
</body>
</html>

直接将页面重定向到server.js开设的/app/gui里去

GUI 部分完成

gui.js 部分完成,项目接近尾声了
看看gui.js完成效果

/gui $< npm test
> npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.

> > guiofnettransfer@1.0.0 test
> > electron .

GUI

编译

最后,我们只需要将其编译使其脱离Node JS 环境也能正常运行就行了

这是我们写的 Compile Workflow,可以参考一下

编译需要用到 pkg

1. Compile server.js
    $root> pkg server.js
    a. Change name to server.exe
    b. put the it to the compile version folder (compile/x.x.x/*)
2. Compile gui.js
    $root/gui> npm run make
    a. put all file of compiled folder to the compile version folder (compile/x.x.x/)
    b. change guiofnettransfer.exe to gui.exe
3. Compile main.bat
    a. change name to main.exe

About Project

Members in Net Transfer Project

ReTrn
BaiG
KBzet

Copyright

This Project is under MIT License.
© AlphaBrate 2022.

About this Article

Author

BaiG

Copyright

© BaiG.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值