作者:matrix
发布时间:2024-09-30
分类:Golang 零零星星
😀 免费的才是最贵的。新浪微博的图床早就挂了,目前的图片会限制请求头 referer
。
今天空了才把这部分图片迁移到本地。记录下这个临时脚本。
脚本下载 WordPress 文章中的新浪图片到本地,然后数据库中的图片链接会执行替换。
配置好信息之后正式执行记得放开 #94行的TODO。 自行测试~
package main
import (
"database/sql"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"regexp"
_ "github.com/go-sql-driver/mysql"
)
const (
//TODO
domain = "www.hhtjim.com" //WordPress 域名
db_user = "root" //db 信息
db_password = "root" //db 信息
db_host_port = "127.0.0.1:33060" //db 信息
db_name = "wordpress_db" //db 信息
savePathBase = "/home/www/htdoc/wordpress/wp-content/uploads/2024/sinaimg/" //图片下载保存位置
newBase = "https://" + domain + "/wp-content/uploads/2024/sinaimg/" // 替换后的图片 url path
referer = "https://m.weibo.cn"
dsn = db_user + ":" + db_password + "@tcp(" + db_host_port + ")/" + db_name
query = "SELECT ID, post_content,post_content_filtered FROM wp_posts WHERE post_type = 'post' AND post_content LIKE '%sinaimg.cn%' ORDER BY ID DESC;"
)
var (
re = regexp.MustCompile(`//([a-zA-Z\d]+.sinaimg.cn)/([\w]+/[\w_-]+.(?:jpg|png|gif))`)
)
func main() {
// 连接数据库
db, err := sql.Open("mysql", dsn)
if err != nil {
fmt.Println("Failed to connect to database:", err)
return
}
defer db.Close()
rows, err := db.Query(query)
if err != nil {
fmt.Println("Failed to query database:", err)
return
}
defer rows.Close()
for rows.Next() {
var id int
var postContent string
var post_content_filtered string
if err := rows.Scan(&id, &postContent, &post_content_filtered); err != nil {
fmt.Println("Failed to scan row:", err)
continue
}
updatedContent := re.ReplaceAllStringFunc(postContent, func(match string) string {
matches := re.FindStringSubmatch(match)
if len(matches) != 3 {
return match
}
imgURL := "https:" + match
savePath := matches[2]
if _, err := os.Stat(savePath); os.IsNotExist(err) {
if err := downloadImage(imgURL, savePath); err != nil {
fmt.Println("Failed to download image:", err)
return match
}
}
return newBase + savePath
})
updatedContentFiltered := re.ReplaceAllStringFunc(post_content_filtered, func(match string) string {
matches := re.FindStringSubmatch(match)
if len(matches) != 3 {
return match
}
imgURL := "https:" + match
savePath := matches[2]
if _, err := os.Stat(savePath); os.IsNotExist(err) {
if err := downloadImage(imgURL, savePathBase+savePath); err != nil {
fmt.Println("Failed to download image:", err)
return match
}
}
return newBase + savePath
})
fmt.Println(id, updatedContent, updatedContentFiltered)
// fmt.Printf("https://%s?p=%d\n", domain, id)
continue //TODO
// break
_, err := db.Exec("UPDATE wp_posts SET post_content = ?,post_content_filtered=? WHERE ID = ?", updatedContent, updatedContentFiltered, id)
if err != nil {
fmt.Println("Failed to update database:", err)
continue
}
}
}
func downloadImage(imgURL, savePath string) error {
resp, err := http.Get(imgURL)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to download image: %s", resp.Status)
}
dir := filepath.Dir(savePath)
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
file, err := os.Create(savePath)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, resp.Body)
return err
}
作者:matrix
发布时间:2024-07-12
分类:零零星星
R.I.P.
2024年09月25日 google快照已死🕯️
https://www.solidot.org/story?sid=79336
Google 搜索结果的查看缓存功能下线其实很久了,每次都得手动 `cache:https://www.hhtjim.com/` 就很麻烦。
有空搞了个油猴脚本能自动在Google搜索结果中添加 [Cache]
链接到该网页的缓存版本 🥳🥳 这就方便多了
安装地址
https://greasyfork.org/zh-CN/scripts/500422-google-cache-viewer
脚本代码
// ==UserScript==
// @name Google cache viewer
// @namespace http://hhtjim.com/
// @version 1.0.1
// @description Automatically adds a cache link to Google Search results. / Google搜索结果中添加缓存按钮
// @author Hootrix
// @include https://www.google.tld/search?*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
window.addEventListener('load', function() {
// select containers `cite[role="text"]`
const containers = document.querySelectorAll('.g.Ww4FFb.vt6azd.tF2Cxc.asEBEc');
containers.forEach(container => {
//const cite = container.querySelector('cite[role="text"]');
let cites = container.querySelectorAll('cite[role="text"]');
// last item
let cite = cites[cites.length - 1];
const link = container.querySelector('a[data-ved]');
if (cite && cite.textContent.startsWith('http')) {
//const url = cite.textContent;
const url = link.href
const cacheUrl = `https://webcache.googleusercontent.com/search?q=cache:${url}`;
const cacheDiv = document.createElement('div');
cacheDiv.className = ''; // class name eFM0qc
cacheDiv.innerHTML = `<a href="${cacheUrl}" target="_blank" style="visibility:visible;color: blue; margin-left: 10px;" rel="noopener">[Cache]</a>`;
if (cite.parentElement) {
cite.parentElement.appendChild(cacheDiv);
}
}
});
});
})();
作者:matrix
发布时间:2024-06-10
分类:零零星星
家庭网络使用iStore(Openwrt)软路由系统作为旁路网关可以更好的控制进出流量。比如拦截广告请求的域名,本地 server 域名...
局域网环境有一个常驻服务,这次给他配置一个专属域名homeserver.lan
。只要设备接入家庭网络,不管客户端设置的什么DNS服务都可以使用。
静态IP配置
将常驻服务的IP固定,方便后续访问。我自己使用的 iKuai主路由配置。
iStore(Openwrt)的话可以参考下面形式自己设置:
打开iStore终端使用uci命令配置 dhcp 服务,或者自己在页面点击完成配置
命令行方式:
uci add dhcp host
uci set dhcp.@host[-1].name='homeserver.lan'
uci set dhcp.@host[-1].mac='AA:BB:CC:DD:EE:FF' # 绑定的 mac
uci set dhcp.@host[-1].ip='192.168.11.11' # 需要访问的服务IP
uci commit dhcp
根据自己需要配置 mac 地址和 自己需要访问的IP
使用Dnsmasq配置DNS服务
目的:将软路由系统作为 DNS 服务器,自定义域名homeserver.lan
映射到IP 192.168.11.11
iStore --> 网络 --> DHCP/DNS --> 主机名映射
命令行方式:
uci add dhcp domain
uci set dhcp.@domain[-1].name='homeserver.lan'
uci set dhcp.@domain[-1].ip='192.168.11.11' #需要访问的服务IP
uci commit dhcp
配置防火墙拦截 DNS 请求
目的是确保所有客户端的 DNS 请求都经过路由网关进行拦截,除非客户端手动配置 DNS 服务为路由网关 192.168.11.12。
iStore --> 网络 --> 防火墙 --> 端口转发
命令行方式:
uci add firewall redirect
uci set firewall.@redirect[-1].target='DNAT'
uci set firewall.@redirect[-1].name='Redirect DNS' #自定义规则名称
uci add_list firewall.@redirect[-1].proto='udp'
uci set firewall.@redirect[-1].src='lan'
uci set firewall.@redirect[-1].src_dport='53'
uci set firewall.@redirect[-1].dest_ip='192.168.11.12' # 旁路由网关IP
uci set firewall.@redirect[-1].dest_port='53'
/etc/init.d/firewall restart
ping检测
使用ping
命令检查连通性
% ping homeserver.lan
PING homeserver.lan (192.168.11.11): 56 data bytes
64 bytes from 192.168.11.11: icmp_seq=0 ttl=64 time=3.906 ms
64 bytes from 192.168.11.11: icmp_seq=1 ttl=64 time=4.432 ms
64 bytes from 192.168.11.11: icmp_seq=2 ttl=64 time=9.283 ms
64 bytes from 192.168.11.11: icmp_seq=3 ttl=64 time=4.778 ms
如果没通,可以清下DNS缓存
mac下清理DNS缓存信息
sudo killall -HUP mDNSResponder
sudo dscacheutil -flushcache
自定义域名注意
.local
域名在 Mac、Linux、Windows系统下有特殊作用,就算DNS服务器配置了域名映射也无法正常使用。客户端可以nslookup
命令查看DNS服务器配置的.local
域名,但是无法完成网络请求。因为有mDNS协议的存在,.local
会独立于其他域名进行处理。
如果你一定要使用.local
,请遵循mDNS协议配置~ 见 利用mDNS协议使用局域网local域名服务
参考:
https://cloud.tencent.com/developer/article/1683190
作者:matrix
发布时间:2024-05-31
分类:零零星星
创建密钥
$ gpg --full-gen-key
### 密钥的有效期限是? 0 永不过期
agpg: 密钥 AEBCD7019762DB73 被标记为绝对信任
gpg: 吊销证书已被存储为‘/Users/root/.gnupg/openpgp-revocs.d/18A7EFFD0146D38B207B30D0AEBCD7019762DB73.rev’
公钥和私钥已经生成并被签名。
pub rsa3072 2024-04-07 [SC]
18A7EFFD0146D38B207B30D0AEBCD7019762DB73
uid hhtjim <root@hhtjim.com>
sub rsa3072 2024-04-07 [E]
这里 AEBCD7019762DB73
为简写密钥id,全写为18A7EFFD0146D38B207B30D0AEBCD7019762DB73
创建吊销凭证
生成一张"撤销证书",以后密钥作废时可以请求外部的公钥服务器撤销公钥。
gpg --gen-revoke AEBCD7019762DB73
已强行使用 ASCII 字符封装过的输出。
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: This is a revocation certificate
iQG2BCABCAAgFiEEGKfv/QFG04sgezDQrrzXAZdi23MFAmYS+P0CHQIACgkQrrzX
AZdi23Pyswv/ePcki/yEsXLKRbiwaJkBVeuVzxdjSj/5WvnEimR+SZH+XH2M7WW+
1hvk9JkEl5tepBha6DcnJXSBeZdRs9I8zmTdh08KzbF3ujsz+tnwgkRVTykllAbw
G6ylqt8MFxYpjqLzNnmCviByAFcqSLS7a4sHAhMMYEJNlcgc6/5YXSIzYu8a5psd
AxLb44kzHTL4lVsQgSFw+hxJA7EfyltAX10T0IBtaVki3hIsyoWixK1NYtpHjemS
ycCaiRSVytK73F7n977Xu7vx20LXF9WMXnQogfbL4FQ+AtEXMmQcMJq2A4VXUSOg
zyKitqw7vu9pJfoTmwPepPa4TkNwhI1qLQDhrajCtC0Ga757+K3ffJIimY2H8L/9
qQqc9mh+mSE0cR1uanSi1kC9NVqBGUuu0g1nWpZxaRyHjPVxR9T8kNbaqm+d5OYB
9QFAV7tHItCMWIYWwdUS0dByqswRZyv3zJs40cimlpZwJxt7RVP3NiPp3Y9XzHv+
HgcIXK/1DpOg
=JXdU
-----END PGP PUBLIC KEY BLOCK-----
已创建吊销证书。
发布公钥到公网服务器
发布到公网后,其他人可以很方便的进行下载来使用(签名检查,解密....)
$ gpg --keyserver keys.openpgp.org --send-keys AEBCD7019762DB73
keyserver 是指定的公网服务器
keys.openpgp.org可以搜索密钥id
,如果要邮箱搜索需要进行验证:
电子邮件地址验证:
当你首次上传密钥到 keys.openpgp.org,该服务器会发送一个验证链接到与该密钥关联的电子邮件地址。只有点击了这个链接并完成验证过程后,电子邮件地址才会与该密钥关联,并且在搜索中可见。
导入别人的公钥
gpg --keyserver keys.openpgp.org --recv-keys B1F6E658B6A3DC2A2E30A09D29A7777777777777
删除密钥
删除别人的公钥
gpg --delete-key B1F6E658B6A3DC2A2E30A09D29A7777777777777
导出私钥
gpg --armor --output private-key.gpg --export-secret-keys AEBCD7019762DB73
参考:
https://www.ruanyifeng.com/blog/2013/07/GPG.html
作者:matrix
发布时间:2024-03-26
分类:零零星星
最近几年总是黄推泛滥,不管你有没有关注总会在评论区看到😂
网页刷推时要是看到就很尴尬了,索性把所有图片全部打码,鼠标悬浮才显示。
完美解决🍺🍺🍺
安装地址
https://greasyfork.org/zh-CN/scripts/492051-twitter-safeview-auto-blur-with-hover-reveal
脚本代码
// ==UserScript==
// @name Twitter SafeView: Auto-Blur with Hover Reveal
// @namespace http://hhtjim.com/
// @version 1.0
// @description 自动模糊所有图片,悬停时才显示完整清晰图像。Automatically blurs all images and displays full clear images only when hovering.
// @author You
// @match https://twitter.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const debounceDelay = 100; // milliseconds
// Debounce function to limit the rate of execution
function debounce(func, delay) {
let debounceTimer;
return function() {
const context = this;
const args = arguments;
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => func.apply(context, args), delay);
};
}
let mouseX = 0, mouseY = 0;
document.addEventListener('mousemove', debounce(function(e) {
mouseX = e.clientX;
mouseY = e.clientY;
updateImageBlur();
}, debounceDelay));
document.addEventListener('scroll', debounce(function(e) {
updateImageBlur();
}, debounceDelay));
// Function to check if the mouse is over the element
function isMouseOverElement(element) {
const rect = element.getBoundingClientRect();
return mouseX > rect.left && mouseX < rect.right && mouseY > rect.top && mouseY < rect.bottom;
}
// Function to update image blur
function updateImageBlur() {
// console.log('updateImageBlur')
//列表
document.querySelectorAll('article[data-testid="tweet"]').forEach(function(tweetDiv) {
// Apply or remove blur based on mouse position
if (isMouseOverElement(tweetDiv)) {
closeBlur(tweetDiv)
} else {
applyBlur(tweetDiv)
}
});
}
// Apply blur to the div and nested img
const applyBlur = (document) => {
// 推文
document.querySelectorAll('div[data-testid="tweetPhoto"], div[data-testid="card.layoutLarge.media"]').forEach(function(div) {
div.style.filter = 'blur(8px)';
const img = div.querySelector('img');
if (img) img.style.filter = 'blur(8px)';
});
};
const closeBlur = (document) => {
document.querySelectorAll('div[data-testid="tweetPhoto"], div[data-testid="card.layoutLarge.media"]').forEach(function(div) {
div.style.filter = '';
const img = div.querySelector('img');
if (img) img.style.filter = '';
});
};
// Observe for changes in the document
const observer = new MutationObserver(debounce(function() {
updateImageBlur();
},debounceDelay));
// Configuration of the observer
const config = { childList: true, subtree: true };
// var target = document.querySelector('section[aria-labelledby="accessible-list-1"]')
var target = document.body
// Start observing the target node for configured mutations
if(target){
observer.observe(target, config);
}
// Initial application of blur to images
updateImageBlur();
})();
作者:matrix
发布时间:2024-01-31
分类:零零星星
服务器配置
配置文件的目录
/root/hysteria
自签证书key crt生成
openssl req -x509 -nodes -newkey ec:<(openssl ecparam -name prime256v1) -keyout /root/hysteria/server.key -out /root/hysteria/server.crt -subj "/CN=bing.com" -days 36500
# sudo chown hysteria /root/hysteria/server.key
# sudo chown hysteria /root/hysteria/server.crt
新建hysteria2.yaml文件
listen: :443 #监听端口
#使用CA证书
#acme:
# domains:
# - hhtjim.com #你的域名,需要先解析到服务器ip
# email: test@hhtjim.com
#使用自签证书
tls:
cert: /app/server.crt
key: /app/server.key
auth:
type: password
password: 999999 #设置认证密码
masquerade:
type: proxy
proxy:
url: https://www.baidu.com #伪装网址
rewriteHost: true
最终需要的三个文件
hysteria2.yaml
server.crt
server.key
启动服务
docker run -v /root/hysteria:/app/ --net=host --rm -it tobyxdd/hysteria server -c /app/hysteria2.yaml
客户端使用
新建配置文件hysteria2-client.yaml
# 服务器信息及端口
server: server.hhtjim.com:443
auth: 999999
# 根据本地带宽设置上下行
bandwidth:
up: 20 mbps
down: 300 mbps
tls:
insecure: true #使用自签时需要改成true
socks5:
listen: 127.0.0.1:1084
http:
listen: 127.0.0.1:8084
启动
docker run -v $(pwd)/hysteria2-client.yaml:/app/hysteria2.yaml --network=host --name=hysteria2-client -d tobyxdd/hysteria client -c /app/hysteria2.yaml
参考:
https://vpsxb.net/5008/
https://raw.githubusercontent.com/chika0801/hysteria-install/main/config_server.yaml
https://bulianglin.com/archives/hysteria2.html
部署Docker版Hysteria服务端
作者:matrix
发布时间:2023-12-05
分类:零零星星
Parsec
https://Parsec.app/
Parsec是专门针对游戏玩家的远程桌面工具,有很好的低延迟体验。
我用Parsec的Mac端连接PC端来远程玩游戏,完全可替代微软的Microsoft Remote Desktop。MRD虽然可以稍微优化下网络延迟($ sysctl net.inet.tcp.delayed_ack=0
),但是效果还是差强人意,MRD远程时拖拽窗口和游戏的高频操作依然能感受到明显延迟。不过MRD在作为办公远程方面还是不错的,毕竟什么粘贴复制那些还是方便。
注册
登录注册需要有外网
访问能力,免费版本的个人使用完全够用。
https://dash.parsec.app/signup/
按照官网提示流程操作即可,这里不打算手把手截图了
安装
widnows: https://builds.parsec.app/package/parsec-windows.exe
mac: https://builds.parsec.app/package/parsec-macos.pkg
软件安装后需要重启,如果没接显示器内部会虚拟出显示器,然后GPU压缩视频流P2P传输数据
登录
mac控制端,Windows被控端 各自登录同一个账号。如果出现登录-800
的错误码则是网络问题,你需要自己配置代理
Parsec代理配置文件路径:
#Windows
#Per User installation 方式:
%appdata%\Parsec\config.txt
#Shared installation 方式:
%programdata%\Parsec\config.txt
# macOS / Linux / Raspberry Pi
~/.parsec/config.txt
config.txt代理配置内容
# 代理地址
app_proxy_address = 127.0.0.1
# 代理协议 http / https
app_proxy_scheme = http
app_proxy = true
# 代理端口
app_proxy_port = 1087
官方代理配置参考:
https://support.parsec.app/hc/en-us/articles/5805484240269-Configure-App-Level-HTTP-Proxy
远程
打开被控端,本地主机Computers下面出现当前机器名称。点击分享Share
后复制链接到 mac控制端浏览器,打开后点击连接就可以了
游戏体验很跟手~
参考:
https://zhuanlan.zhihu.com/p/557637085
https://www.bilibili.com/read/cv16988873/
https://www.pjkui.com/98/title/macOS使用windows远程桌面RDP反应速度很慢解决方案
作者:matrix
发布时间:2023-06-23
分类:零零星星
https://github.com/Hootrix/keyword_alert_bot
针对keyword_alert_bot
项目早就有添加docker镜像的想法,这次趁着有机会就完成这个feature,也算是使用下GitHub的CI/CD。
我的想法是利用github action功能,推送代码更新后自动打包docker镜像且安装所有依赖。打包的时候把最新版本号写入到代码中(当前日期作为版本号)。使用者把docker镜像pull后可以轻松运行整个bot。
流水线配置
项目的 .github/workflows/main.yml
路径下新建文件:
name: CI/CD Pipeline
on:
push:
# 指定分支push操作触发流水线
branches:
# - dev.20230419 # debug
- master
jobs:
# 自定义job流水线名字
build-and-push:
# 指定运行环境 ubuntu最新版本
runs-on: ubuntu-latest
# 设计流水线阶段
steps:
# 名称
- name: Check out code
# 使用预先定义好的action。actions/checkout@v2 是 GitHub 官方提供,目的是将代码检出(checkout)到运行器上
uses: actions/checkout@v2
with: # 配置参数
fetch-depth: 2 # 表示只获取最新的两个commit提交记录
# 设置python3.7环境
- name: Set up Python 3.7
uses: actions/setup-python@v3
with:
python-version: 3.7
# 安装pipenv依赖管理
- name: Install pipenv
run: |
python -m pip install --upgrade pip
python -m pip install pipenv
# 标记是否存在py文件的更新,用于后续docker镜像打包的判断
- name: Check for file changes
id: file_check
run: |
if git diff --name-only HEAD^ | grep -q ".py$"; then
echo "::set-output name=updated::true"
else
echo "::set-output name=updated::false"
fi
# 安装项目依赖
- name: Install dependencies and lock
if: steps.file_check.outputs.updated == 'true'
run: |
pipenv install --dev
pipenv lock
# 设置最新版本号 如 20230520.91a4ca1
- name: Create version file
run: |
COMMIT_ID=$(git rev-parse --short HEAD)
# 写入版本信息到指定文件
echo "__version__ = '$(TZ='Asia/Shanghai' date +'%Y%m%d').$COMMIT_ID'" > utils/__version__.py
# 登录DockerHub
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
# 存在更新条件 则推送到指定docker镜像仓库 tag为latest
- name: Build and push Docker image
if: steps.file_check.outputs.updated == 'true'
uses: docker/build-push-action@v2
with:
context: .
push: true
# 推送到指定仓库镜像地址
tags: yha8897/keyword_alert_bot:latest
# 使用gh命令创建github release 执行版本发布
- name: Create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# 读取指定文件的版本号。根据自己项目设置
VERSION=$(python -c "from utils.__version__ import __version__; print(__version__)")
echo $VERSION
# 执行版本发布
gh release create $VERSION
说明:
注意上面配置中的${{ secrets.DOCKER_HUB_USERNAME }}
,${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
表示github action自动读取环境变量中的DOCKER_HUB_USERNAME
,DOCKER_HUB_ACCESS_TOKEN
即 docker hub的登录名和密码
DOCKER_HUB_ACCESS_TOKEN
需要自己生成>>,权限设置Read & Write
即可。
之后打开github项目页面的settings
>> Secrets and variables
>> Actions
>> New repository secret
按钮
TOKEN配置
填写你的docker hub的对应值。
${{ secrets.GITHUB_TOKEN }}
属于特殊环境变量(GITHUB_开头的都算),会自动读取你账户运行的权限,不需要自己单独设置。
触发流水线
配置完成后,提交或者合入代码到上面👆「branches」指定的master分支就能自动出发CI/CD
docker镜像会自动推送
参考:
https://raw.githubusercontent.com/Hootrix/keyword_alert_bot/master/.github/workflows/main.yml
https://docs.github.com/zh/actions/using-workflows/using-github-cli-in-workflows
https://zhuanlan.zhihu.com/p/526696611
- 1
- 2
- 3
- 4
- 5
... - 23