
日志
莹夜
·
ubuntu 20.04使用netplan添加he的ipv6通道
network:
version: 2
tunnels:
he-ipv6:
mode: sit
remote: endpoint服务器ip
local: 本机ip
addresses:
- "address"
gateway6: gateway
莹夜
·
使用com.gluonhq:gluonfx-maven-plugin
插件生成exe文件报以下错误。
java.lang.UnsatisfiedLinkError: no awt in java.library.path
解决方案:从JAVA_HOME下复制awt.dll
、java.dll
、server/jvm.dll
这三个文件到exe所在的文件夹。
但接下来一般会伴随着java.lang.NoSuchFieldError
…,还是不去使用awt
/swing
相关的内容吧。
莹夜
·
java时区转换 String -> Date -> Calendar -> Instant -> LocalDateTime,用起来感觉很麻烦。
String uploadDate = "2023-01-20T04:46:00+00:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
Calendar calendar = Calendar.getInstance();
calendar.setTime(sdf.parse(uploadDate));
LocalDateTime localDateTime = LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.of("Asia/Tokyo"));
System.out.println(localDateTime.getHour());
莹夜
·
Lapce一个文本编辑器,打开速度很快,可以像VSCode那样安装众多语言的开发插件,且同样支持远程开发。
Windows版本分为单文件版和安装版。
莹夜
·
<!DOCTYPE html>
<html lang="zh-CN">
<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>PaperMC版本选择</title>
<style type="text/css">
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
select {
outline: none;
width: 110px;
}
#app,
#statusText,
#downloadSlot {
margin-top: 20px;
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<div id="version">
<span>选择游戏版本: </span>
<select id="versionsSlot"></select>
</div>
<div id="build">
<span>选择文件版本: </span>
<select id="buildsSlot"></select>
</div>
</div>
<p id="downloadSlot">
<button id="download">下载</button>
</p>
<p id="statusText"></p>
<custom-tag text="hello web component"></custom-tag>
</body>
<script type="text/javascript">
(() => {
/** @type {HTMLSelectElement} */
const versionsSlot = document.querySelector("#versionsSlot");
/** @type {HTMLSelectElement} */
const buildsSlot = document.querySelector("#buildsSlot");
/** @type {HTMLParagraphElement} */
const statusText = document.querySelector("#statusText");
/** @type {HTMLButtonElement} */
const downloadBtn = document.querySelector("#download");
function selectStatusChange(b) {
versionsSlot.disabled = b;
buildsSlot.disabled = b;
downloadBtn.disabled = b;
if (b) {
statusText.innerText = "加载中..."
} else {
statusText.innerText = "";
}
}
async function init() {
selectStatusChange(true);
/** @type {Array<String>} */
const versions = await getAllVersion();
appendVersion(versions);
/** @type {Array<String>} */
const builds = await getBuilds(versions[0]);
appendBuild(builds);
versionsSlot.onchange = async () => {
selectStatusChange(true);
const builds = await getBuilds(versionsSlot.value);
buildsSlot.innerHTML = "";
appendBuild(builds);
selectStatusChange(false);
}
downloadBtn.onclick = async () => {
selectStatusChange(true);
await getJar(versionsSlot.value, buildsSlot.value);
selectStatusChange(false);
}
selectStatusChange(false);
}
function appendVersion(versions) {
const fragment = document.createDocumentFragment();
for (let i in versions) {
const o = document.createElement("option");
o.innerText = versions[i];
o.value = versions[i];
fragment.appendChild(o);
}
versionsSlot.appendChild(fragment);
}
function appendBuild(builds) {
const fragment = document.createDocumentFragment();
for (let i in builds) {
const o = document.createElement("option");
o.innerText = builds[i]['build'];
o.value = builds[i]['build'];
fragment.appendChild(o);
}
buildsSlot.appendChild(fragment);
}
async function getAllVersion() {
const data = await fetch("https://api.papermc.io/v2/projects/paper");
if (data.ok) {
const { versions } = await data.json();
return versions.reverse();
} else {
return null;
}
}
async function getBuilds(version) {
const data = await fetch(`https://api.papermc.io/v2/projects/paper/versions/${version}/builds`);
if (data.ok) {
const { builds } = await data.json();
return builds.reverse();
} else {
return null;
}
}
async function getJar(version, build) {
const fileName = `paper-${version}-${build}.jar`;
try {
const data = await fetch(`https://api.papermc.io/v2/projects/paper/versions/${version}/builds/${build}/downloads/${fileName}`);
if (data.ok) {
statusText.innerText = `正在下载文件 ${data.url}`;
const b = await data.blob();
const jar = new File([b], fileName, {
type: "application/java-archive"
});
const link = URL.createObjectURL(jar);
const a = document.createElement("a");
a.download = fileName;
a.href = link;
a.click();
} else {
console.log(`status: ${data.status}, statusText: ${data.statusText}`);
alert("请求失败");
}
} catch (e) {
console.error(e);
alert("请求失败");
}
}
init();
})();
</script>
</html>
不用忍受paper那时不时卡死的swagger了
莹夜
·
jvm http代理
java -DproxySet=true -DproxyHost=127.0.0.1 -DproxyPort=10809 -jar xxx.jar
莹夜
·
提取字幕
ffmpeg -i in.mkv -an -vn -scodec copy -map 0:s:x out.ass
0:s:x的x为第几个字幕,数字从0开始。
输出的字幕格式需要根据视频内的来指定,有ass,srt,sup等等…
莹夜
·
莹夜
·
openssh-server升级后无法使用ssh-rsa私钥进行登录解决方案:
往/etc/ssh/sshd_config文件的最后追加这一行
PubkeyAcceptedKeyTypes=+ssh-rsa
然后再重启ssh服务
莹夜
·
图片规格批量处理
<!DOCTYPE html>
<html lang="zh-CN">
<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>图片规格批量压缩</title>
<script src="https://unpkg.com/jszip@3.10.1/dist/jszip.min.js"></script>
<style>
#machining_root {
padding-top: 20px;
text-align: center;
}
#machining_root input {
width: 150px;
}
#machining_root #compress {
width: 50px;
outline: none;
border-width: 1px;
border-style: none none solid none;
font-size: 16px;
text-align: center;
}
</style>
</head>
<body>
<div id="machining_root">
<div style="margin-bottom: 6px;">
<label for="compress">图片质量保留</label>
<input id="compress" type="text" value="90" />
<span>%</span>
</div>
<input type="file" accept="image/*" multiple="true" onchange="handlerFile(event)" />
<p class="filename"></p>
<p class="progress"></p>
</div>
</body>
<script type="text/javascript">
// QQ发图允许的最大图片像素数: 20249108: 3638 * 5566
// 但忘记怎么试出来的了
const maxRectSize = 2560 * 1440;
// 允许的最大宽度是4500
const maxRectWidth = 4500;
// 允许的最大高度是10000
const maxRectHeight = 9000;
/** @type {Array<HTMLInputElement>} */
const [compress, filename] = [document.querySelector("#machining_root #compress"), document.querySelector("#machining_root .filename")];
const progress = document.querySelector("#machining_root .progress");
async function handlerFile(e) {
const compressVal = parseFloat(compress.value);
if (isNaN(compressVal)) {
progress.innerText = `compress: ${compress.value} 不是一个有效的数字`;
return;
}
e.target.setAttribute("disabled", true);
/** @type {Array<File>} */
const files = Array.from(e.target.files);
if (files.length <= 0) {
e.target.removeAttribute("disabled");
return;
}
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const zip = new JSZip();
for (let i = 0; i < files.length; i++) {
const file = files[i];
filename.innerText = "正在处理: " + file.name;
progress.innerText = `处理进度: ${i + 1}/${files.length}`;
const img = new Image();
img.src = URL.createObjectURL(file);
await new Promise(resolve => {
img.onload = () => {
resolve();
}
});
const [imgWidth, imgHeight] = getReasonableSize(getReasonablePixels(img));
canvas.width = imgWidth;
canvas.height = imgHeight;
ctx.drawImage(img, 0, 0, imgWidth, imgHeight);
const blobLink = await new Promise(resolve => {
canvas.toBlob(resolve, "image/jpeg", 0.01 * compressVal);
});
const fn = file.name.substring(0, file.name.lastIndexOf(".")) + ".jpg";
zip.file(fn, new File([blobLink], fn));
}
filename.innerText = "";
progress.innerText = "";
zip.generateAsync({ type: "blob" })
.then((zipBlob) => {
const aTag = document.createElement("a");
aTag.download = Date.now() + ".zip";
aTag.href = URL.createObjectURL(zipBlob);
aTag.click();
e.target.removeAttribute("disabled");
});
}
/**
* 获取不超过QQ发送图片像素上限的分辨率
* @param {HTMLImageElement} r
* @returns [number, number]
*/
function getReasonablePixels(r) {
let _p = 1;
if (r.width * r.height > maxRectSize) {
while ((r.width * _p) * (r.height * _p) > maxRectSize) {
_p -= 0.01;
}
return [r.width * _p, r.height * _p];
} else {
return [r.width, r.height];
}
}
/**
* 获取宽不超过4500,高不超过10000的分辨率
* @param {[number, number]} r
* @returns [number, number]
*/
function getReasonableSize(r) {
if (r[0] > maxRectWidth || r[1] > maxRectHeight) {
let _p = 1;
if (r[0] > r[1]) {
_p = (maxRectWidth / r[0]).toFixed(3);
r[0] = maxRectWidth;
r[1] = r[1] * _p;
} else {
_p = (maxRectHeight / r[1]).toFixed(3);
r[1] = maxRectHeight;
r[0] = r[0] * _p;
}
}
return r;
}
</script>
</html>