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
http://localhost:1345/text.txt
http://localhost:1345/app/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 .
编译
最后,我们只需要将其编译使其脱离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.