jeblove 最近的时间轴更新
jeblove's repos on GitHub
JavaScript · 1 人关注
gist-sync-api
Python · 0 人关注
17wanxiaoCheckin-Actions
完美校园健康打卡,校内打卡,理论上支持所有学校(大概...),开启Actions,可能需要Enable一下
Shell · 0 人关注
Actions-immortalWrt-UA2F
使用 GitHub Actions 云编译ua2f的固件
Go · 0 人关注
authelia
The Single Sign-On Multi-Factor portal for web apps
0 人关注
BILIBILI-HELPER
B站,哔哩哔哩(Bilibili)自动签到投币工具,每天轻松获取65经验值,支持每日自动投币,银瓜子兑换硬币,领取大会员福利,大会员月底给自己充电等功能。呐!赶快和我一起成为Lv6吧!
0 人关注
BiliExp
B站(bilibili 哔哩哔哩)助手:1.每日投币观看分享视频(快速升6级),签到(直播+漫画), 动态抽奖,风纪投票(免费得大会员),直播挂机(小心心),天选时刻(抽奖)等日常操作(云函数+Actions+docker)(多账户)。2.漫画视频番剧音乐下载器(CLI)。3.up主视频专栏音乐投稿的python实现
0 人关注
BiliExper
0 人关注
checkin
python自动签到脚本,WPS小程序签到,有道云笔记签到
0 人关注
Configuration-privoxy
配置privoxy
0 人关注
fail2ban-confs
These confs are pulled into our fail2ban image: https://github.com/linuxserver/docker-fail2ban
0 人关注
go-proxy-bingai
用 Vue3 和 Go 搭建的微软 New Bing 演示站点,拥有一致的 UI 体验,支持 ChatGPT 提示词,支持 API 调用,国内可用。
JavaScript · 0 人关注
JD_Sign_Action
基于github actions的京东签到、领京豆
0 人关注
jeblove.github.io
Python · 0 人关注
Jellyfin2Emby
将Jellyfin用户以及用户观看记录迁移到Emby
0 人关注
Kwrt
一分钟在线定制编译 X86/64, NanoPi R2S R4S R5S R6S, 斐讯 Phicomm N1 K2P, 树莓派 Raspberry Pi, 香橙派 Orange Pi, 红米AX6, 小米AX3600, 小米AX9000, 红米AX6S 小米AX3200, 红米AC2100, 华硕ASUS, 网件NETGEAR 等主流软硬路由
Python · 0 人关注
MoviePilot
NAS媒体库自动化管理工具
Python · 0 人关注
MoviePilot-Plugins
MoviePilot官方插件市场
Shell · 0 人关注
myblog
test
Java · 0 人关注
OnList
OnList (Only List)
Vue · 0 人关注
OnList-client
Shell · 0 人关注
OpenWrt-newifi
Python · 0 人关注
tieba
白嫖github action 实现贴吧每日自动签到
jeblove

jeblove

V2EX 第 500353 号会员,加入于 2020-07-22 19:08:31 +08:00
根据 jeblove 的设置,主题列表只有在你登录之后才可查看
二手交易 相关的信息,包括已关闭的交易,不会被隐藏
jeblove 最近回复了
25 天前
回复了 mfya 创建的主题 NAS Plex 播放问题求助
是否走 plex 中转服务器了?
107 天前
回复了 falost 创建的主题 NAS 各位是如何管理手机中的录音文件呢?
有 nas 的话装个 nextcloud 之类的,里面有“自动上传”,设置录音的文件夹自动上传,还可以设置“删除原始文件”;
nextcloud 也支持在线播放音频。
150 天前
回复了 Hundredwz 创建的主题 NAS 小白家庭 nas 搭建方案,求建议
首选叠个甲,我认为当手头上只有一台 nas 的时候,all in one 没有什么不妥,只要数据备份好。
当我只有一台设备那就 all in one (起码组个阵列); 2 台我会把网络分开; 3 台我才会考虑“重要文件相互备份”、“存算分离”
现在的 nas 系统发展也不是真只专注于“存储”,怎么好用、方便,怎么来。

---

先决定底层系统
如果没有过多虚拟系统的需求
- 无花费就选黑裙,因为有 docker 需求所以不建议用 truenas scale ( app 方面经常破坏性更新)
- 花费可首选 unraid
有些虚拟系统才考虑 pve+其它 nas 系统

智能家居,首选 haos ,容器版 hass 功能残缺(没有 add-one 、恢复备份等),只要设备能接入到 hass 就能通过“巴法云”让小爱同学控制(注意不是米家控制)

照片:
- 如果系统是群晖就优先用群晖自带;
- 其它 nas 系统,无花费用 immich (没有其它更好的可选),有花费就 mtphoto (正在使用,没感觉太大问题)
视为较为重要的文件,nas 有 raid 等校验还不算稳,最好定时加密同步、备份到网盘,例如“duplicati”(其它重要文件也一样)

影音:
- 有影片存储到 nas 上就考虑 jellyfin 、emby 、plex (后两者硬解等功能需要付费);
- 不存储影片,可以了解“小雅”,或直接网盘配合软件(那些支持直接链接网盘的播放器软件)

旁路由,普通使用(指有需要的设备才手动指向旁路由)的话虚拟机来也没什么问题;但最好能把网络与 nas 分开。
软路由系统一般都是 openwrt ,只是看装哪个
x86 的话,istoreOS 、骷髅头( https://github.com/DHDAXCW/OpenWRT_x86_x64
还有云编译( https://github.com/kiddin9/OpenWrt_x86-r2s-r4s-r5s-N1

---

容器所在问题,要考虑到容器的文件备份,比较建议用在 nas 系统上的 docker 服务(如果 pve 就加一个 nas 系统),还有虚拟机那些后续有空也最好设置定时备份存储在指定位置。

265g 装些系统还行,加上些容器的文件就不太够了。

外部访问,优先用公网 v4 、v6 ,其次装个 tailscale 作为备用。

还有既然搞 nas 了,就没太必要“付费网盘”,不然直接冲个网盘 vip 不用 nas (不是说用 nas 就不用网盘,而是没必要在网盘上花钱),有了 nas ,就把网盘(阿里云、宽带运营商的云盘等)作为备份渠道。
164 天前
回复了 muzihuaner 创建的主题 分享创造 用 cloudflare worker 搭建一个 Docker 镜像
@lazyyz 应该是的,毕竟得靠 cf 服务器中转流量
165 天前
回复了 messiah163 创建的主题 NAS 百度网盘内容下载 NAS 方案
我用 johngong/baidunetdisk:latest
非会员有 30 秒还是一分钟加速下载,下载不大的文件都是趁它不注意一下子下完,偏大的文件就慢慢挂着。
165 天前
回复了 muzihuaner 创建的主题 分享创造 用 cloudflare worker 搭建一个 Docker 镜像
感谢,用了下发现不能拉取 dockerhub 官方镜像(如 node 、mariadb ),正常输入
```
docker pull 域名/node
```
实际上应该为
```
docker pull 域名/library/node
```
这样有些不太方便

加上判断是否官方镜像,修改调试了些时间,成功可用
```
'use strict'

const hub_host = 'registry-1.docker.io'
const auth_url = 'https://auth.docker.io'
const workers_url = 'https://dh.jeblove.com'
/**
* static files (404.html, sw.js, conf.js)
*/

/** @type {RequestInit} */
const PREFLIGHT_INIT = {
// status: 204,
headers: new Headers({
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
'access-control-max-age': '1728000',
}),
}

/**
* @param {any} body
* @param {number} status
* @param {Object<string, string>} headers
*/
function makeRes(body, status = 200, headers = {}) {
headers['access-control-allow-origin'] = '*'
return new Response(body, {status, headers})
}


/**
* @param {string} urlStr
*/
function newUrl(urlStr) {
try {
return new URL(urlStr)
} catch (err) {
return null
}
}


addEventListener('fetch', e => {
const ret = fetchHandler(e)
.catch(err => makeRes('cfworker error:\n' + err.stack, 502))
e.respondWith(ret)
})


/**
* @param {FetchEvent} e
*/
async function fetchHandler(e) {
const getReqHeader = (key) => e.request.headers.get(key);

let url = new URL(e.request.url);

// 修改 pre head get 请求
// 是否含有 %2F ,用于判断是否具有用户名与仓库名之间的连接符
// 同时检查 %3A 的存在
if (!/%2F/.test(url.search) && /%3A/.test(url.toString())) {
let modifiedUrl = url.toString().replace(/%3A(?=.*?&)/, '%3Alibrary%2F');
url = new URL(modifiedUrl);
console.log(`handle_url: ${url}`)
}

if (url.pathname === '/token') {
let token_parameter = {
headers: {
'Host': 'auth.docker.io',
'User-Agent': getReqHeader("User-Agent"),
'Accept': getReqHeader("Accept"),
'Accept-Language': getReqHeader("Accept-Language"),
'Accept-Encoding': getReqHeader("Accept-Encoding"),
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0'
}
};
let token_url = auth_url + url.pathname + url.search
return fetch(new Request(token_url, e.request), token_parameter)
}

// 修改 head 请求
if (/^\/v2\/[^/]+\/[^/]+\/[^/]+$/.test(url.pathname) && !/^\/v2\/library/.test(url.pathname)) {
url.pathname = url.pathname.replace(/\/v2\//, '/v2/library/');
console.log(`modified_url: ${url.pathname}`)
}

url.hostname = hub_host;

let parameter = {
headers: {
'Host': hub_host,
'User-Agent': getReqHeader("User-Agent"),
'Accept': getReqHeader("Accept"),
'Accept-Language': getReqHeader("Accept-Language"),
'Accept-Encoding': getReqHeader("Accept-Encoding"),
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0'
},
cacheTtl: 3600
};

if (e.request.headers.has("Authorization")) {
parameter.headers.Authorization = getReqHeader("Authorization");
}

let original_response = await fetch(new Request(url, e.request), parameter)
let original_response_clone = original_response.clone();
let original_text = original_response_clone.body;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

if (new_response_headers.get("Www-Authenticate")) {
let auth = new_response_headers.get("Www-Authenticate");
let re = new RegExp(auth_url, 'g');
new_response_headers.set("Www-Authenticate", response_headers.get("Www-Authenticate").replace(re, workers_url));
}

if (new_response_headers.get("Location")) {
return httpHandler(e.request, new_response_headers.get("Location"))
}

let response = new Response(original_text, {
status,
headers: new_response_headers
})
return response;

}


/**
* @param {Request} req
* @param {string} pathname
*/
function httpHandler(req, pathname) {
const reqHdrRaw = req.headers

// preflight
if (req.method === 'OPTIONS' &&
reqHdrRaw.has('access-control-request-headers')
) {
return new Response(null, PREFLIGHT_INIT)
}

let rawLen = ''

const reqHdrNew = new Headers(reqHdrRaw)

const refer = reqHdrNew.get('referer')

let urlStr = pathname

const urlObj = newUrl(urlStr)

/** @type {RequestInit} */
const reqInit = {
method: req.method,
headers: reqHdrNew,
redirect: 'follow',
body: req.body
}
return proxy(urlObj, reqInit, rawLen)
}


/**
*
* @param {URL} urlObj
* @param {RequestInit} reqInit
*/
async function proxy(urlObj, reqInit, rawLen) {
const res = await fetch(urlObj.href, reqInit)
const resHdrOld = res.headers
const resHdrNew = new Headers(resHdrOld)

// verify
if (rawLen) {
const newLen = resHdrOld.get('content-length') || ''
const badLen = (rawLen !== newLen)

if (badLen) {
return makeRes(res.body, 400, {
'--error': `bad len: ${newLen}, except: ${rawLen}`,
'access-control-expose-headers': '--error',
})
}
}
const status = res.status
resHdrNew.set('access-control-expose-headers', '*')
resHdrNew.set('access-control-allow-origin', '*')
resHdrNew.set('Cache-Control', 'max-age=1500')

resHdrNew.delete('content-security-policy')
resHdrNew.delete('content-security-policy-report-only')
resHdrNew.delete('clear-site-data')

return new Response(res.body, {
status,
headers: resHdrNew
})
}
```
改动处:

- 57 行,添加修改 head 前的 get 请求
- 72 行,添加修改 head 请求

另外好像版本问题有额外的报错,改动有

- 12 行
- 150 行


👇
```
# docker pull xxx.com/node
Using default tag: latest
latest: Pulling from node
c6cf28de8a06: Downloading [> ] 506.8kB/49.58MB
891494355808: Downloading [========> ] 4.184MB/24.05MB
```
207 天前
回复了 bankroft 创建的主题 NAS 躁动的心,想入手 emby/plex
@jeblove 当然,这是我从 jellyfin 、emby 使用者的角度看待,局限性不小,作为个小参考吧
207 天前
回复了 bankroft 创建的主题 NAS 躁动的心,想入手 emby/plex
入正还是比较建议 plex 的。
emby 兼容更新不如 jellyfin ,例如,之前 4.7 一直不支持 qsv (测试过 vaapi 对 12 代没完全适配); 4.8 有个 qsv ,但是对中文特效字幕有异常(偏移)。
jellyfin 就没这些事,就是美化、不支持二级目录等这些小问题。
emby 的组车也不好,有设备数限制,如果设备数少也行,我是开放给朋友所以设备数会多些。
加上 emby 有开心版体验。
总结,感觉 jellyfin 与 emby 差距不大,入正建议 plex
2023-11-22 00:05:46 +08:00
回复了 deanwin 创建的主题 优惠信息 便宜看起点付费文章的办法
连载中的小说盗版看之前的部分,接近最新几章就转到起点,看广告获得兑换券(章节卡)就基本能不花钱(花小钱)追看一两本。一天大概是 50 点章节卡
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1864 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 12ms · UTC 16:24 · PVG 00:24 · LAX 08:24 · JFK 11:24
Developed with CodeLauncher
♥ Do have faith in what you're doing.