最近遇到了一个小需求,我在PC上使用clash更新订阅时,可以通过cfw的parser和mixin等功能对订阅进行修改,添加自定义内容,但手机上的工具大部分都不支持复杂的预处理或覆盖功能,因此写了一个简单的拉取订阅进行预处理以及提供订阅更新地址的小脚本。

脚本分为paser和server两部分,paser定时拉取原始订阅并进行预处理,server提供订阅更新链接并进行鉴权防止泄露。

Parser部分:

import axios from 'axios'
import jsyaml from 'js-yaml'
import fs from 'fs'
 
// 原始订阅链接
const rawFileUrl = 'https://test.com/ssss'
 
// 处理后文件路径
const savePath = './test.yaml'
 
const updateFunc = async () => {
 
  try {
    const rawFile = await axios.get(rawFileUrl)
    const rawFileData = rawFile.data
    const parsedFile = jsyaml.load(rawFileData)
 
    for (const o of parsedFile['proxy-groups']) {
      // 根据个人需求处理proxy-groups
    }
 
    const prependProxies = [
    // 添加额外的proxy
      {
        name: 'test',
        type: 'http',
        server: '100.100.100.100',
        port: '12345',
        username: '123',
        password: '243'
      }
    ]
    parsedFile.proxies = [...prependProxies, ...parsedFile.proxies]
 
    const prependProxyGroups = [
      {
        name: 'test',
        type: 'select',
        proxies: ['test']
      }
    ]
    parsedFile['proxy-groups'] = [...prependProxyGroups, ...parsedFile['proxy-groups']]
 
    const prependRules = [
      'DOMAIN-SUFFIX,gitlab.com,test',
    ]
 
    parsedFile.rules = [...prependRules, ...parsedFile.rules]
    const yamlStr = jsyaml.dump(parsedFile)
    
    fs.writeFileSync(savePath, yamlStr)
 
  } catch (e) {
    console.log(e)
  }
}
 
updateFunc()
 
setInterval(() => {
  updateFunc()
}, 1000 * 60 * 60)

Server部分:


import express from 'express'
 
const app = express()
const port = 12345
 
// 假定这是你的密钥和用户验证信息
 
const KEY = 'key123'
const USER = 'user123'
const PASSWORD = 'passwd123'
 
// 允许的文件下载列表
const ALLOWED_FILES = ['test.yaml']
 
app.get('/download', (req, res) => {
  const { key, user, password, filename } = req.query
  // 进行鉴权
  if (key === SECRET_KEY && user === AUTH_USER && password === AUTH_PASSWORD) {
    // 检查文件是否在允许下载的列表中
    if (ALLOWED_FILES.includes(filename)) {
      res.download(`./${filename}`)
    } else {
      res.status(403).send('Requested file is not allowed for download')
    }
  } else {
    res.status(403).send('Access Denied')
  }
})
 
// 为所有其他路由返回404
app.use((req, res, next) => {
  res.status(404).send('Not Found')
})
 
app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}/`)
})

将项目部署于服务器上后,用pm2自动后台运行parser和server,同时nginx反代server端口到自己定义的域名下,就可以通过自己的域名对应路径来在cfa等软件中通过url的方式更新订阅了。