mirror of
https://github.com/ZxwyWebSite/lx-source.git
synced 2025-07-03 10:42:18 +08:00
Compare commits
8 Commits
v1.0.3.043
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
9155f34105 | ||
|
3437281f73 | ||
|
55e7c6227e | ||
|
76e7f5a1b6 | ||
|
70238162c1 | ||
|
d7a2563a98 | ||
|
05b8f3766c | ||
|
30b3260617 |
107
.github/workflows/action.yml
vendored
Normal file
107
.github/workflows/action.yml
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
name: Action
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout git repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: ./repo
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Golang
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
go version && go env && export PATH=$PATH:$(go env GOPATH)/bin
|
||||
go install golang.org/dl/go1.20.14@latest && go1.20.14 download && go1.20.14 version
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install gcc-mingw-w64-x86-64
|
||||
sudo apt-get -y install gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
|
||||
sudo apt-get -y install gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||
wget -q https://dl.google.com/android/repository/android-ndk-r26b-linux.zip && unzip -d ~ android-ndk-r26b-linux.zip && rm android-ndk-r26b-linux.zip
|
||||
|
||||
- name: Fetch Modules
|
||||
run: |
|
||||
wget -q "https://r2eu.zxwy.link/gh/lx-source/static/ztool_20240525.zip" -O ztool.zip && unzip ztool.zip && rm ztool.zip
|
||||
wget -q "https://r2eu.zxwy.link/gh/lx-source/static/cr-go-sdk_20240525.zip" -O cr-go-sdk.zip && unzip cr-go-sdk.zip && rm cr-go-sdk.zip
|
||||
|
||||
- name: Run Action
|
||||
run: cd repo && go run action.go && mv dist ../
|
||||
|
||||
- name: Short SHA
|
||||
uses: benjlevesque/short-sha@v3.0
|
||||
id: short-sha
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: lx-source-bin_${{ env.SHA }}
|
||||
path: ./dist
|
||||
|
||||
- name: Generate Changelog
|
||||
run: cd repo && echo PACKAGE_VERSION=`go run release.go` >> $GITHUB_ENV && mv changelog.md ../
|
||||
|
||||
- name: Create git tag
|
||||
uses: pkgdeps/git-tag-action@v3
|
||||
with:
|
||||
github_token: ${{ github.token }}
|
||||
github_repo: ${{ github.repository }}
|
||||
version: ${{ env.PACKAGE_VERSION }}
|
||||
git_commit_sha: ${{ github.sha }}
|
||||
git_tag_prefix: "v"
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body_path: ./changelog.md
|
||||
prerelease: false
|
||||
draft: false
|
||||
tag_name: v${{ env.PACKAGE_VERSION }}
|
||||
files: |
|
||||
./dist/lx-source-android-386.zip
|
||||
./dist/lx-source-android-amd64.zip
|
||||
./dist/lx-source-android-arm.zip
|
||||
./dist/lx-source-android-arm64.zip
|
||||
./dist/lx-source-darwin-amd64v2-go1.20.14.zip
|
||||
./dist/lx-source-darwin-amd64v3-go1.20.14.zip
|
||||
./dist/lx-source-darwin-arm64-go1.20.14.zip
|
||||
./dist/lx-source-linux-amd64v1.zip
|
||||
./dist/lx-source-linux-amd64v2.zip
|
||||
./dist/lx-source-linux-amd64v3.zip
|
||||
./dist/lx-source-linux-amd64v4.zip
|
||||
./dist/lx-source-linux-arm5.zip
|
||||
./dist/lx-source-linux-arm5-go1.20.14.zip
|
||||
./dist/lx-source-linux-arm6.zip
|
||||
./dist/lx-source-linux-arm6-go1.20.14.zip
|
||||
./dist/lx-source-linux-arm64.zip
|
||||
./dist/lx-source-linux-arm64-go1.20.14.zip
|
||||
./dist/lx-source-linux-arm7.zip
|
||||
./dist/lx-source-linux-arm7-go1.20.14.zip
|
||||
./dist/lx-source-linux-mips64hardfloat-go1.20.14.zip
|
||||
./dist/lx-source-linux-mips64lehardfloat-go1.20.14.zip
|
||||
./dist/lx-source-linux-mips64lesoftfloat-go1.20.14.zip
|
||||
./dist/lx-source-linux-mips64softfloat-go1.20.14.zip
|
||||
./dist/lx-source-linux-mipshardfloat-go1.20.14.zip
|
||||
./dist/lx-source-linux-mipslehardfloat-go1.20.14.zip
|
||||
./dist/lx-source-linux-mipslesoftfloat-go1.20.14.zip
|
||||
./dist/lx-source-linux-mipssoftfloat-go1.20.14.zip
|
||||
./dist/lx-source-windows-amd64v1-go1.20.14.zip
|
||||
./dist/lx-source-windows-amd64v2-go1.20.14.zip
|
||||
./dist/lx-source-windows-amd64v2.zip
|
||||
./dist/lx-source-windows-amd64v3-go1.20.14.zip
|
||||
./dist/lx-source-windows-amd64v3.zip
|
||||
./dist/lx-source-windows-amd64v4.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,5 +5,4 @@ data/
|
||||
# conf.ini
|
||||
test.go
|
||||
test_test.go
|
||||
# src/sources/builtin/
|
||||
rsrc_windows_amd64.syso
|
||||
# src/sources/builtin/
|
532
action.go
Normal file
532
action.go
Normal file
@ -0,0 +1,532 @@
|
||||
//go:build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// 运行参数
|
||||
args_name = `lx-source` // 程序名称
|
||||
args_path = `dist/` // 输出目录
|
||||
args_zpak = true // 打包文件
|
||||
// args_repo = `repo/` // 源码目录
|
||||
args_home = `/home/runner` // 用户目录
|
||||
)
|
||||
|
||||
var (
|
||||
workDir string
|
||||
homeDir string
|
||||
)
|
||||
|
||||
func init() {
|
||||
if runtime.GOOS != `linux` {
|
||||
fmt.Println(`不兼容的运行环境:`, runtime.GOOS)
|
||||
os.Exit(0)
|
||||
}
|
||||
workDir, _ = os.Getwd()
|
||||
fmt.Println(`运行目录:`, workDir)
|
||||
homeDir = os.Getenv(`HOME`)
|
||||
if homeDir == `` {
|
||||
homeDir = args_home
|
||||
}
|
||||
fmt.Println(`用户目录:`, homeDir)
|
||||
}
|
||||
|
||||
type (
|
||||
// 架构参数 [v2]
|
||||
list_vers map[string]struct {
|
||||
Tags string
|
||||
}
|
||||
// CGO参数 [nil]
|
||||
list_cgos struct {
|
||||
AR string
|
||||
CC string
|
||||
CXX string
|
||||
}
|
||||
// 架构列表 [amd64]
|
||||
list_arch map[string]struct {
|
||||
Cgos *list_cgos
|
||||
Vers list_vers
|
||||
Venv string // 覆盖架构参数名 'mipsle'->'GOMIPS'
|
||||
}
|
||||
// 目标系统 [linux]
|
||||
list_goos map[string]struct {
|
||||
Arch list_arch
|
||||
}
|
||||
// 编译环境 [go1.20.14]
|
||||
list_conf map[string]struct {
|
||||
Args []string
|
||||
GoOS list_goos
|
||||
}
|
||||
)
|
||||
|
||||
// 构建参数
|
||||
var def_args = []string{
|
||||
`-trimpath`, `-buildvcs=false`,
|
||||
`-ldflags`, `-s -w -linkmode external`,
|
||||
}
|
||||
|
||||
type param struct {
|
||||
GoVer string // 环境 go1.20.14
|
||||
GoOS string // 系统 linux
|
||||
GoArch string // 架构 amd64
|
||||
GoIns string // 指令 GOAMD64=v2
|
||||
Args []string // 参数 ldflags
|
||||
Tag string // 标志 go_json
|
||||
Cgos *list_cgos
|
||||
Venv string
|
||||
}
|
||||
|
||||
// 获取相对用户目录
|
||||
func home(str string) string {
|
||||
return homeDir + `/` + str
|
||||
}
|
||||
|
||||
// 检测环境是否存在
|
||||
func chkenv(s ...string) (err error) {
|
||||
for _, f := range s {
|
||||
if _, e := exec.LookPath(f); e != nil && !errors.Is(e, exec.ErrDot) {
|
||||
err = fmt.Errorf(`未找到指定环境: %s`, e)
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
var def_list = list_conf{
|
||||
`go`: {
|
||||
Args: def_args,
|
||||
GoOS: list_goos{
|
||||
`linux`: {
|
||||
Arch: list_arch{
|
||||
`amd64`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: `x86_64-linux-gnu-ar`,
|
||||
CC: `x86_64-linux-gnu-gcc`,
|
||||
CXX: `x86_64-linux-gnu-g++`,
|
||||
},
|
||||
Vers: list_vers{
|
||||
`v1`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`v2`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`v3`: {
|
||||
Tags: `sonic avx`,
|
||||
},
|
||||
`v4`: {
|
||||
Tags: `sonic avx`,
|
||||
},
|
||||
},
|
||||
},
|
||||
`arm`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: `arm-linux-gnueabihf-gcc-ar`,
|
||||
CC: `arm-linux-gnueabihf-gcc`,
|
||||
CXX: `arm-linux-gnueabihf-cpp`,
|
||||
},
|
||||
Vers: list_vers{
|
||||
`5`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`6`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`7`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
`arm64`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: `aarch64-linux-gnu-gcc-ar`,
|
||||
CC: `aarch64-linux-gnu-gcc`,
|
||||
CXX: `aarch64-linux-gnu-cpp`,
|
||||
},
|
||||
Vers: list_vers{
|
||||
``: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`windows`: {
|
||||
Arch: list_arch{
|
||||
`amd64`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: `x86_64-w64-mingw32-ar`,
|
||||
CC: `x86_64-w64-mingw32-gcc`,
|
||||
CXX: `x86_64-w64-mingw32-cpp`,
|
||||
},
|
||||
Vers: list_vers{
|
||||
`v2`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`v3`: {
|
||||
Tags: `sonic avx`,
|
||||
},
|
||||
`v4`: {
|
||||
Tags: `sonic avx`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`android`: {
|
||||
Arch: list_arch{
|
||||
`amd64`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar`),
|
||||
CC: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android24-clang`),
|
||||
CXX: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android24-clang++`),
|
||||
},
|
||||
Vers: list_vers{
|
||||
``: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
`arm64`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar`),
|
||||
CC: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang`),
|
||||
CXX: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang++`),
|
||||
},
|
||||
Vers: list_vers{
|
||||
``: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
`386`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar`),
|
||||
CC: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android24-clang`),
|
||||
CXX: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android24-clang++`),
|
||||
},
|
||||
Vers: list_vers{
|
||||
``: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
`arm`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar`),
|
||||
CC: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi24-clang`),
|
||||
CXX: home(`android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi24-clang++`),
|
||||
},
|
||||
Vers: list_vers{
|
||||
``: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
home(`go/bin/go1.20.14`): {
|
||||
Args: []string{
|
||||
`-trimpath`, `-buildvcs=false`,
|
||||
`-ldflags`, `-s -w -extldflags '-v -static'`,
|
||||
},
|
||||
GoOS: list_goos{
|
||||
`windows`: {
|
||||
Arch: list_arch{
|
||||
`amd64`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: `x86_64-w64-mingw32-ar`,
|
||||
CC: `x86_64-w64-mingw32-gcc`,
|
||||
CXX: `x86_64-w64-mingw32-cpp`,
|
||||
},
|
||||
Vers: list_vers{
|
||||
`v1`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`v2`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`v3`: {
|
||||
Tags: `sonic avx`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
`linux`: {
|
||||
Arch: list_arch{
|
||||
`arm`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: `arm-linux-gnueabihf-gcc-ar`,
|
||||
CC: `arm-linux-gnueabihf-gcc`,
|
||||
CXX: `arm-linux-gnueabihf-cpp`,
|
||||
},
|
||||
Vers: list_vers{
|
||||
`5`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`6`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`7`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
`arm64`: {
|
||||
Cgos: &list_cgos{
|
||||
AR: `aarch64-linux-gnu-gcc-ar`,
|
||||
CC: `aarch64-linux-gnu-gcc`,
|
||||
CXX: `aarch64-linux-gnu-cpp`,
|
||||
},
|
||||
Vers: list_vers{
|
||||
``: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
// 针对部分OpenWrt路由器系统 暂不支持开启CGO
|
||||
`mips`: {
|
||||
Vers: list_vers{
|
||||
`hardfloat`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`softfloat`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
`mipsle`: {
|
||||
Vers: list_vers{
|
||||
`hardfloat`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`softfloat`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
Venv: `MIPS`,
|
||||
},
|
||||
`mips64`: {
|
||||
Vers: list_vers{
|
||||
`hardfloat`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`softfloat`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
`mips64le`: {
|
||||
Vers: list_vers{
|
||||
`hardfloat`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`softfloat`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
Venv: `MIPS64`,
|
||||
},
|
||||
},
|
||||
},
|
||||
// Mac OS
|
||||
`darwin`: {
|
||||
Arch: list_arch{
|
||||
`amd64`: {
|
||||
Vers: list_vers{
|
||||
`v2`: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
`v3`: {
|
||||
Tags: `sonic avx`,
|
||||
},
|
||||
},
|
||||
},
|
||||
`arm64`: {
|
||||
Vers: list_vers{
|
||||
``: {
|
||||
Tags: `go_json`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
fmt.Printf(`
|
||||
================================
|
||||
| Action 一键编译脚本
|
||||
| 程序名称:%v
|
||||
| 输出目录:%v
|
||||
| 打包文件:%v
|
||||
================================
|
||||
`, args_name, args_path, args_zpak)
|
||||
// 解析配置文件
|
||||
for goVer, conf_list := range def_list {
|
||||
// 环境检测
|
||||
if err := chkenv(goVer); err != nil {
|
||||
fmt.Println(err, `跳过该环境`)
|
||||
continue
|
||||
}
|
||||
for goOS, goos_list := range conf_list.GoOS {
|
||||
for goArch, arch_list := range goos_list.Arch {
|
||||
// 工具链检测
|
||||
if arch_list.Cgos != nil {
|
||||
if err := chkenv(
|
||||
arch_list.Cgos.AR,
|
||||
arch_list.Cgos.CC,
|
||||
arch_list.Cgos.CXX,
|
||||
); err != nil {
|
||||
fmt.Println(err, `跳过该架构`)
|
||||
continue
|
||||
}
|
||||
}
|
||||
for goIns, vers_list := range arch_list.Vers {
|
||||
// 构建程序二进制
|
||||
if err := build(¶m{
|
||||
GoVer: goVer,
|
||||
GoOS: goOS,
|
||||
GoArch: goArch,
|
||||
GoIns: goIns,
|
||||
Args: conf_list.Args,
|
||||
Tag: vers_list.Tags,
|
||||
Cgos: arch_list.Cgos,
|
||||
Venv: arch_list.Venv,
|
||||
}); err != nil {
|
||||
fmt.Println(`err:`, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(`执行结束`)
|
||||
}
|
||||
|
||||
func build(p *param) (err error) {
|
||||
// 拼接程序名称
|
||||
var b strings.Builder
|
||||
b.WriteString(args_name) // lx-source
|
||||
b.WriteByte('-') // lx-source-
|
||||
b.WriteString(p.GoOS) // lx-source-linux
|
||||
b.WriteByte('-') // lx-source-linux-
|
||||
b.WriteString(p.GoArch) // lx-source-linux-amd64
|
||||
/*var digit byte
|
||||
if p.Venv != `` {
|
||||
digit = p.Venv[len(p.Venv)-1]
|
||||
} else {
|
||||
digit = p.GoArch[len(p.GoArch)-1]
|
||||
}
|
||||
if !unicode.IsDigit(rune(digit)) {
|
||||
// 架构名结尾不是数字的再加一个连字符
|
||||
b.WriteByte('-') // lx-source-linux-mipsle-softfloat
|
||||
}*/
|
||||
b.WriteString(p.GoIns) // lx-source-linux-amd64v2
|
||||
if biname := filepath.Base(p.GoVer); biname != `go` {
|
||||
b.WriteByte('-') // lx-source-linux-amd64v2-
|
||||
b.WriteString(biname) // lx-source-linux-amd64v2-go1.20.14
|
||||
}
|
||||
// 拼接输出名称
|
||||
oname := args_path + b.String() // dist/lx-source-linux-amd64v2
|
||||
if p.GoOS == `windows` {
|
||||
oname += `.exe` // dist/lx-source-linux-amd64v2.exe
|
||||
}
|
||||
fmt.Println(`开始编译:`, oname)
|
||||
fmt.Printf("编译参数: %+v\n", *p)
|
||||
// 填入参数并构建
|
||||
var args = []string{
|
||||
`build`, `-o`, oname,
|
||||
// `-asmflags=-trimpath="` + workDir + `"`,
|
||||
// `-gcflags=-trimpath="` + workDir + `"`,
|
||||
`-tags`, p.Tag,
|
||||
}
|
||||
cmd := exec.Command(
|
||||
p.GoVer,
|
||||
// append(append(args, p.Args...), args_repo)...,
|
||||
append(args, p.Args...)...,
|
||||
)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = cmd.Stdout
|
||||
cmd.Dir = workDir
|
||||
cmd.Env = append(os.Environ(), []string{
|
||||
`GOOS=` + p.GoOS,
|
||||
`GOARCH=` + p.GoArch,
|
||||
}...)
|
||||
if p.Cgos != nil {
|
||||
cmd.Env = append(cmd.Env, []string{
|
||||
`AR=` + p.Cgos.AR,
|
||||
`CC=` + p.Cgos.CC,
|
||||
`CXX=` + p.Cgos.CXX,
|
||||
`CGO_ENABLED=1`,
|
||||
}...)
|
||||
} /*else {
|
||||
cmd.Env = append(cmd.Env, `CGO_ENABLED=0`)
|
||||
}*/
|
||||
if p.GoIns != `` {
|
||||
if p.Venv != `` {
|
||||
cmd.Env = append(cmd.Env, `GO`+p.Venv+`=`+p.GoIns)
|
||||
} else {
|
||||
cmd.Env = append(cmd.Env, `GO`+strings.ToUpper(p.GoArch)+`=`+p.GoIns)
|
||||
}
|
||||
}
|
||||
|
||||
if err = cmd.Start(); err == nil {
|
||||
err = cmd.Wait()
|
||||
}
|
||||
if err != nil || !args_zpak {
|
||||
return
|
||||
}
|
||||
// 打包输出文件
|
||||
/*apath := filepath.Join(args_path, `archieve`)
|
||||
if _, e := os.Stat(apath); e != nil {
|
||||
if os.IsNotExist(e) {
|
||||
err = os.MkdirAll(apath, os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}*/
|
||||
zipname := filepath.Join(args_path, b.String()+`.zip`)
|
||||
fmt.Println(`打包文件:`, zipname)
|
||||
zipfile, err := os.Create(zipname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
archive := zip.NewWriter(zipfile)
|
||||
info, err := os.Lstat(oname)
|
||||
if err == nil {
|
||||
header, _ := zip.FileInfoHeader(info)
|
||||
header.Method = zip.Deflate
|
||||
header.Name = filepath.Base(oname)
|
||||
writer, err := archive.CreateHeader(header)
|
||||
if err == nil {
|
||||
file, err := os.Open(oname)
|
||||
if err == nil {
|
||||
_, err = io.Copy(writer, file)
|
||||
file.Close()
|
||||
if err == nil {
|
||||
err = os.Remove(oname)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
archive.Close()
|
||||
zipfile.Close()
|
||||
return err
|
||||
}
|
9
go.mod
9
go.mod
@ -1,11 +1,13 @@
|
||||
module lx-source
|
||||
|
||||
go 1.21
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/ZxwyWebSite/cr-go-sdk v0.0.2
|
||||
github.com/ZxwyWebSite/ztool v0.0.1
|
||||
github.com/gin-contrib/gzip v1.0.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
)
|
||||
|
||||
@ -43,4 +45,7 @@ require (
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/ZxwyWebSite/ztool v0.0.1 => ./pkg/ztool // ../ztool
|
||||
replace (
|
||||
github.com/ZxwyWebSite/cr-go-sdk v0.0.2 => ../cr-go-sdk
|
||||
github.com/ZxwyWebSite/ztool v0.0.1 => ../ztool // ./pkg/ztool
|
||||
)
|
||||
|
7
go.sum
7
go.sum
@ -24,7 +24,6 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU
|
||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
@ -34,8 +33,9 @@ github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaC
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
@ -43,7 +43,6 @@ github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuV
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
@ -63,7 +62,6 @@ github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@ -102,7 +100,6 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
43
init.go
43
init.go
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"encoding/base64"
|
||||
"lx-source/src/caches"
|
||||
"lx-source/src/caches/cloudcache"
|
||||
"lx-source/src/caches/localcache"
|
||||
"lx-source/src/env"
|
||||
|
||||
@ -12,6 +13,7 @@ import (
|
||||
stdurl "net/url"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ZxwyWebSite/cr-go-sdk"
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
"github.com/ZxwyWebSite/ztool/logs"
|
||||
"github.com/ZxwyWebSite/ztool/zcypt"
|
||||
@ -169,22 +171,31 @@ func initMain() {
|
||||
// }
|
||||
// icl.Info(`使用本地缓存,文件路径 %q,绑定地址 %v`, LocalCachePath, env.Config.Apis.BindAddr)
|
||||
case `2`, `cloudreve`:
|
||||
icl.Fatal(`Cloudreve驱动暂未完善,未兼容新版调用方式,当前版本禁用`)
|
||||
// icl.Warn(`Cloudreve驱动暂未完善,使用非本机存储时存在兼容性问题,请谨慎使用`)
|
||||
// cs, err := cloudreve.NewSite(&cloudreve.Config{
|
||||
// SiteUrl: env.Config.Cache.Cloud_Site,
|
||||
// Username: env.Config.Cache.Cloud_User,
|
||||
// Password: env.Config.Cache.Cloud_Pass,
|
||||
// Session: env.Config.Cache.Cloud_Sess,
|
||||
// })
|
||||
// if err != nil {
|
||||
// icl.Error(`驱动["cloudreve"]初始化失败: %v, 将禁用缓存功能`, err)
|
||||
// }
|
||||
// UseCache = &crcache.Cache{
|
||||
// Cs: cs,
|
||||
// Path: env.Config.Cache.Cloud_Path,
|
||||
// IsOk: err == nil,
|
||||
// }
|
||||
icl.Warn(`欢迎使用新版 Cloudreve 驱动, 由 cr-go-sdk 提供强力支持`)
|
||||
site := &cr.SiteObj{
|
||||
Addr: env.Config.Cache.Cloud_Site,
|
||||
ApiVer: cr.ApiV383,
|
||||
Users: &cr.UserObj{
|
||||
Mail: env.Config.Cache.Cloud_User,
|
||||
Pass: env.Config.Cache.Cloud_Pass,
|
||||
Cookie: cr.ParseCookie(env.Config.Cache.Cloud_Sess),
|
||||
},
|
||||
}
|
||||
cache, err := caches.New(&cloudcache.Cache{
|
||||
Site: site,
|
||||
Path: env.Config.Cache.Cloud_Path,
|
||||
})
|
||||
if err != nil {
|
||||
icl.Error(`驱动["cloudreve"]初始化失败: %v, 将禁用缓存功能`, err)
|
||||
} else {
|
||||
env.Tasker.Add(`cloud_sess`, func(l *logs.Logger, i int64) error {
|
||||
if sess := site.Users.Cookie.String(); sess != env.Config.Cache.Cloud_Sess {
|
||||
env.Config.Cache.Cloud_Sess = sess
|
||||
}
|
||||
return env.Cfg.Save(``)
|
||||
}, 3600, true)
|
||||
}
|
||||
caches.UseCache = cache
|
||||
default:
|
||||
icl.Error(`未定义的缓存模式,请检查配置 [Cache].Mode,本次启动禁用缓存`)
|
||||
}
|
||||
|
42
menu.go
42
menu.go
@ -1,8 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"lx-source/src/env"
|
||||
"lx-source/src/sources/custom/tx"
|
||||
wm "lx-source/src/sources/custom/wy/modules"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -22,6 +25,8 @@ func parseEtag(etag *string) {
|
||||
// menuMian()
|
||||
case `wyqr`:
|
||||
wyQrLogin()
|
||||
case `txqq`:
|
||||
txQqLogin()
|
||||
default:
|
||||
loger.Fatal(`未知参数:%q`, *etag)
|
||||
}
|
||||
@ -33,6 +38,17 @@ func wyQrLogin() {
|
||||
loger := env.Loger.NewGroup(`WyQrLogin`)
|
||||
defer loger.Free()
|
||||
loger.Info(`执行模块: 网易云扫码登录`)
|
||||
|
||||
if env.Config.Custom.Wy_Api_Cookie != `` {
|
||||
loger.Warn("已存在账号数据, 继续操作可能导致数据覆盖丢失!")
|
||||
fmt.Print(`输入'y'继续: `)
|
||||
var input string
|
||||
fmt.Scanln(&input)
|
||||
if input != `y` {
|
||||
loger.Fatal(`用户取消操作`)
|
||||
}
|
||||
}
|
||||
|
||||
res, err := wm.LoginQrKey()
|
||||
if err != nil {
|
||||
loger.Fatal(`无法创建请求: %s`, err)
|
||||
@ -80,6 +96,32 @@ func wyQrLogin() {
|
||||
}
|
||||
}
|
||||
|
||||
// QQ快速登录
|
||||
func txQqLogin() {
|
||||
loger := env.Loger.NewGroup(`TxQqLogin`)
|
||||
defer loger.Free()
|
||||
loger.Info(`执行模块: QQ快速登录`)
|
||||
|
||||
if runtime.GOOS != `windows` {
|
||||
loger.Fatal(`该模块仅支持在windows环境下使用`)
|
||||
return
|
||||
}
|
||||
|
||||
if env.Config.Custom.Tx_Ukey != `` {
|
||||
loger.Warn("已存在账号数据, 继续操作可能导致数据覆盖丢失!")
|
||||
fmt.Print(`输入'y'继续: `)
|
||||
var input string
|
||||
fmt.Scanln(&input)
|
||||
if input != `y` {
|
||||
loger.Fatal(`用户取消操作`)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Qlogin_graph(loger); err != nil {
|
||||
loger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// func menuMian() {
|
||||
// app := menu.NewApp(`Lx-Source`)
|
||||
// app.Data = menu.Data{
|
||||
|
107
release.go
Normal file
107
release.go
Normal file
@ -0,0 +1,107 @@
|
||||
//go:build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 获取版本号
|
||||
func version() string {
|
||||
fenv, _ := os.Open(`src/env/env.go`)
|
||||
benv := bufio.NewReader(fenv)
|
||||
var ever string
|
||||
for {
|
||||
line, _, _ := benv.ReadLine()
|
||||
length := len(line)
|
||||
if length == 0 {
|
||||
continue
|
||||
}
|
||||
sline := string(line)
|
||||
if strings.HasPrefix(sline, ` Version`) {
|
||||
ever = `v` + sline[12:length-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
fenv.Close()
|
||||
if ever == `` {
|
||||
panic(`No Version`)
|
||||
} else {
|
||||
return ever
|
||||
}
|
||||
}
|
||||
|
||||
// 生成更新日志
|
||||
func changelog(ever string) string {
|
||||
fupd, _ := os.Open(`update.md`)
|
||||
bupd := bufio.NewReader(fupd)
|
||||
var eupd strings.Builder
|
||||
eupd.WriteString(`### 更新内容:`)
|
||||
eupd.WriteByte('\n')
|
||||
for {
|
||||
line, _, _ := bupd.ReadLine()
|
||||
length := len(line)
|
||||
if length == 0 {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(string(line), ever) {
|
||||
for {
|
||||
lline, _, _ := bupd.ReadLine()
|
||||
length := len(lline)
|
||||
if length == 0 {
|
||||
break
|
||||
}
|
||||
eupd.WriteString(string(lline))
|
||||
eupd.WriteByte('\n')
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
fupd.Close()
|
||||
eupd.WriteByte('\n')
|
||||
eupd.WriteString(`### CDN加速下载:`)
|
||||
eupd.WriteByte('\n')
|
||||
for _, v := range []string{
|
||||
`lx-source-android-arm.zip`,
|
||||
`lx-source-android-arm64.zip`,
|
||||
`lx-source-linux-amd64v2.zip`,
|
||||
`lx-source-linux-amd64v3.zip`,
|
||||
`lx-source-linux-arm7.zip`,
|
||||
`lx-source-linux-arm64.zip`,
|
||||
`lx-source-windows-amd64v2.zip`,
|
||||
`lx-source-windows-amd64v2-go1.20.14.zip`,
|
||||
`lx-source-windows-amd64v3.zip`,
|
||||
} {
|
||||
eupd.WriteByte('+')
|
||||
eupd.WriteByte(' ')
|
||||
|
||||
eupd.WriteByte('[')
|
||||
eupd.WriteString(v)
|
||||
eupd.WriteByte(']')
|
||||
eupd.WriteByte('(')
|
||||
eupd.WriteString(`https://r2eu.zxwy.link/gh/lx-source/`)
|
||||
eupd.WriteString(ever)
|
||||
eupd.WriteByte('/')
|
||||
eupd.WriteString(v)
|
||||
eupd.WriteByte(')')
|
||||
|
||||
eupd.WriteByte('\n')
|
||||
}
|
||||
return eupd.String()
|
||||
}
|
||||
|
||||
func main() {
|
||||
ever := version()
|
||||
fmt.Println(ever)
|
||||
|
||||
eupd := changelog(ever)
|
||||
file, err := os.Create(`changelog.md`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
file.WriteString(eupd)
|
||||
file.Close()
|
||||
}
|
BIN
rsrc_windows_amd64.syso
Normal file
BIN
rsrc_windows_amd64.syso
Normal file
Binary file not shown.
@ -1 +1,121 @@
|
||||
package cloudcache
|
||||
|
||||
import (
|
||||
"lx-source/src/caches"
|
||||
"lx-source/src/env"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
cr "github.com/ZxwyWebSite/cr-go-sdk"
|
||||
"github.com/ZxwyWebSite/cr-go-sdk/service/explorer"
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
)
|
||||
|
||||
type Cache struct {
|
||||
Site *cr.SiteObj
|
||||
Path string
|
||||
state bool
|
||||
}
|
||||
|
||||
func (c *Cache) Get(q *caches.Query) string {
|
||||
var b strings.Builder
|
||||
b.WriteString(c.Path)
|
||||
b.WriteByte('/')
|
||||
b.WriteString(q.Source)
|
||||
b.WriteByte('/')
|
||||
b.WriteString(q.MusicID)
|
||||
list, err := c.Site.Directory(b.String())
|
||||
if err != nil {
|
||||
caches.Loger.Debug(`列出目录: %v`, err)
|
||||
return ``
|
||||
}
|
||||
name := q.Quality + `.` + q.Extname
|
||||
var id string
|
||||
for _, v := range list.Objects {
|
||||
if v.Name == name && v.Type == `file` {
|
||||
id = v.ID
|
||||
break
|
||||
}
|
||||
}
|
||||
if id == `` {
|
||||
caches.Loger.Debug(`文件不存在`)
|
||||
return ``
|
||||
}
|
||||
srcs, err := c.Site.FileSource(cr.GenerateSrc(false, id))
|
||||
if err != nil {
|
||||
caches.Loger.Debug(`生成外链: %v`, err)
|
||||
return ``
|
||||
}
|
||||
return (*srcs)[0].URL
|
||||
/*link, err := c.Site.FileDownload(id)
|
||||
if err != nil {
|
||||
caches.Loger.Debug(`下载文件: %v`, err)
|
||||
return ``
|
||||
}
|
||||
if (*link)[0] == '/' {
|
||||
return c.Site.Addr + (*link)[1:]
|
||||
}
|
||||
return *link*/
|
||||
}
|
||||
|
||||
func (c *Cache) Set(q *caches.Query, l string) string {
|
||||
var b strings.Builder
|
||||
b.WriteString(c.Path)
|
||||
b.WriteByte('/')
|
||||
b.WriteString(q.Source)
|
||||
b.WriteByte('/')
|
||||
b.WriteString(q.MusicID)
|
||||
dir := b.String()
|
||||
err := c.Site.DirectoryNew(&explorer.DirectoryService{
|
||||
Path: dir,
|
||||
})
|
||||
if err != nil {
|
||||
caches.Loger.Debug(`创建目录: %v`, err)
|
||||
return ``
|
||||
}
|
||||
/*var buf bytes.Buffer
|
||||
err = ztool.Net_Download(l, &buf, nil)
|
||||
if err != nil {
|
||||
caches.Loger.Debug(`下载文件: %v`, err)
|
||||
return ``
|
||||
}*/
|
||||
name := q.Quality + `.` + q.Extname
|
||||
err = ztool.Net_Request(
|
||||
http.MethodGet, l, nil,
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders()},
|
||||
[]ztool.Net_ResHandlerFunc{func(res *http.Response) error {
|
||||
return (&cr.UploadTask{
|
||||
Site: c.Site,
|
||||
File: res.Body,
|
||||
Size: uint64(res.ContentLength),
|
||||
Name: name,
|
||||
Mime: `audio/mpeg`,
|
||||
}).Do(dir)
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
caches.Loger.Debug(`上传文件: %v`, err)
|
||||
return ``
|
||||
}
|
||||
return c.Get(q)
|
||||
}
|
||||
|
||||
func (c *Cache) Stat() bool {
|
||||
return c.state
|
||||
}
|
||||
|
||||
func (c *Cache) Init() error {
|
||||
cr.Cr_Debug = env.Config.Main.Debug
|
||||
err := c.Site.SdkInit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Site.Users.Cookie == nil || c.Site.Config.User.Anonymous {
|
||||
err = c.Site.SdkLogin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.state = true
|
||||
return nil
|
||||
}
|
||||
|
62
src/env/env.go
vendored
62
src/env/env.go
vendored
@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
Version = `1.0.3.0430`
|
||||
Version = `1.0.3.0622`
|
||||
)
|
||||
|
||||
var (
|
||||
@ -36,10 +36,10 @@ type (
|
||||
Print bool `comment:"控制台输出 (影响io性能,后台使用建议关闭)"`
|
||||
SysLev bool `comment:"(实验性) 设置进程高优先级"`
|
||||
// FFConv bool `comment:"(实验性) 使用FFMpeg修复音频(本地缓存)"`
|
||||
NgProxy bool `comment:"兼容反向代理(beta)"`
|
||||
Timeout int64 `comment:"网络请求超时(单位:秒,海外服务器可适当调大)"`
|
||||
|
||||
Store string `comment:"内存缓存持久化文件地址"`
|
||||
NgProxy bool `comment:"兼容反向代理(beta)"`
|
||||
Timeout int64 `comment:"网络请求超时(单位:秒,海外服务器可适当调大)"`
|
||||
Store string `comment:"内存缓存持久化文件地址"`
|
||||
ErrMp3 string `comment:"获取失败默认音频"`
|
||||
}
|
||||
// 接口
|
||||
Conf_Apis struct {
|
||||
@ -124,6 +124,7 @@ type (
|
||||
Kw_Bd_DevId string `comment:"field user.device_id"`
|
||||
// kw kwdes
|
||||
Kw_Des_Type string `comment:"返回格式 0: text, 1: json"`
|
||||
Kw_Des_Source string `comment:"query source"`
|
||||
Kw_Des_Header string `comment:"请求头 User-Agent"`
|
||||
|
||||
// kg
|
||||
@ -158,12 +159,22 @@ type (
|
||||
// Lx_Enable bool `comment:"是否启用小洛源"`
|
||||
}
|
||||
// 脚本
|
||||
Conf_Script struct {
|
||||
Conf_Script_Update struct {
|
||||
Ver string `comment:"自定义脚本版本" json:"ver"`
|
||||
Log string `comment:"更新日志" json:"log"`
|
||||
Url string `comment:"脚本下载地址 (public目录内文件名)" json:"url"`
|
||||
Force bool `comment:"强制推送更新" json:"force"`
|
||||
Auto int `comment:"自动填写配置(beta) 0: 关闭, 1: 仅api地址, 2: 包含密钥" json:"-"`
|
||||
}
|
||||
Conf_Script struct {
|
||||
Name string `comment:"源的名字,建议不要过长,24个字符以内"`
|
||||
Descript string `comment:"源的描述,建议不要过长,36个字符以内,可不填"`
|
||||
Version string `comment:"源的版本号,可不填"`
|
||||
Author string `comment:"脚本作者名字,可不填"`
|
||||
Homepage string `comment:"脚本主页,可不填"`
|
||||
|
||||
Update Conf_Script_Update `ini:"Script"`
|
||||
|
||||
Auto int `comment:"自动填写配置(beta) 0: 关闭, 1: 仅api地址, 2: 包含密钥"`
|
||||
}
|
||||
// 缓存
|
||||
Conf_Cache struct {
|
||||
@ -174,11 +185,11 @@ type (
|
||||
Local_Bind string `comment:"本地缓存外部访问地址"`
|
||||
Local_Auto bool `comment:"自适应缓存访问地址(beta)"`
|
||||
// 云盘
|
||||
// Cloud_Site string `comment:"Cloudreve站点地址"`
|
||||
// Cloud_User string `comment:"Cloudreve用户名"`
|
||||
// Cloud_Pass string `comment:"Cloudreve密码"`
|
||||
// Cloud_Sess string `comment:"Cloudreve会话"`
|
||||
// Cloud_Path string `comment:"Cloudreve存储路径"`
|
||||
Cloud_Site string `comment:"Cloudreve站点地址"`
|
||||
Cloud_User string `comment:"Cloudreve用户名"`
|
||||
Cloud_Pass string `comment:"Cloudreve密码"`
|
||||
Cloud_Sess string `comment:"Cloudreve会话"`
|
||||
Cloud_Path string `comment:"Cloudreve存储路径"`
|
||||
}
|
||||
// 结构
|
||||
Conf struct {
|
||||
@ -204,6 +215,7 @@ var (
|
||||
SysLev: false,
|
||||
Timeout: 30,
|
||||
Store: `/data/memo.bin`,
|
||||
ErrMp3: `https://r2eu.zxwy.link/gh/lx-source/static/error.mp3`,
|
||||
},
|
||||
Apis: Conf_Apis{
|
||||
// BindAddr: `http://192.168.10.22:1011/`,
|
||||
@ -264,23 +276,31 @@ var (
|
||||
Tx_Refresh_Interval: 86000,
|
||||
},
|
||||
Script: Conf_Script{
|
||||
Log: `发布更新 (请删除旧源后重新导入):进行了部分优化,修复了部分Bug`, // 更新日志
|
||||
Name: `Lx-Source-Script`,
|
||||
Descript: `洛雪音乐自定义源脚本`,
|
||||
Version: `1.1.0`,
|
||||
Author: `Zxwy`,
|
||||
Homepage: `https://github.com/ZxwyWebSite/lx-script`,
|
||||
|
||||
Ver: `1.0.3`, // 自定义脚本版本
|
||||
Force: true, // 强制推送更新
|
||||
Update: Conf_Script_Update{
|
||||
Log: `发布更新 (请删除旧源后重新导入):进行了部分优化,修复了部分Bug`, // 更新日志
|
||||
|
||||
Url: `lx-custom-source.js`, // 脚本下载地址
|
||||
Ver: `1.0.3`, // 自定义脚本版本
|
||||
Force: true, // 强制推送更新
|
||||
|
||||
Url: `lx-custom-source.js`, // 脚本下载地址
|
||||
},
|
||||
},
|
||||
Cache: Conf_Cache{
|
||||
Mode: `local`, // 缓存模式
|
||||
LinkMode: `1`,
|
||||
Local_Path: `data/cache`,
|
||||
Local_Bind: `http://127.0.0.1:1011/`,
|
||||
// Cloud_Site: `https://cloudreveplus-demo.onrender.com/`,
|
||||
// Cloud_User: `admin@cloudreve.org`,
|
||||
// Cloud_Pass: `CloudrevePlusDemo`,
|
||||
// Cloud_Sess: ``,
|
||||
// Cloud_Path: `/Lx-Source/cache`,
|
||||
Cloud_Site: `https://cloudreveplus-demo.onrender.com/`,
|
||||
Cloud_User: `admin@cloudreve.org`,
|
||||
Cloud_Pass: `CloudrevePlusDemo`,
|
||||
Cloud_Sess: ``,
|
||||
Cloud_Path: `/Lx-Source/cache`,
|
||||
},
|
||||
}
|
||||
Config = DefCfg
|
||||
|
@ -2,6 +2,7 @@
|
||||
package resp
|
||||
|
||||
import (
|
||||
"lx-source/src/env"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@ -26,7 +27,7 @@ type Resp struct {
|
||||
}
|
||||
|
||||
// 获取失败默认音频
|
||||
var ErrMp3 = `https://r2eu.zxwy.link/gh/lx-source/static/error.mp3`
|
||||
// var ErrMp3 = `https://r2eu.zxwy.link/gh/lx-source/static/error.mp3`
|
||||
|
||||
// 返回请求
|
||||
/*
|
||||
@ -43,7 +44,7 @@ func (o *Resp) Execute(c *gin.Context) {
|
||||
case 2:
|
||||
status = http.StatusServiceUnavailable
|
||||
if o.Data == nil || o.Data == `` {
|
||||
o.Data = ErrMp3
|
||||
o.Data = env.Config.Main.ErrMp3 //ErrMp3
|
||||
}
|
||||
case 3:
|
||||
status = http.StatusUnauthorized
|
||||
|
@ -103,6 +103,7 @@ func musicHandler(c *gin.Context) {
|
||||
cstat = caches.UseCache.Stat()
|
||||
}
|
||||
uquery := caches.NewQuery(ps, pid, pq)
|
||||
uquery.Request = c.Request
|
||||
defer uquery.Free()
|
||||
if cstat {
|
||||
loger.Debug(`FileGet: %v`, uquery.Query())
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"lx-source/src/env"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
"github.com/ZxwyWebSite/ztool/x/bytesconv"
|
||||
@ -106,6 +107,63 @@ func loadPublic(r *gin.Engine) {
|
||||
} else {
|
||||
r.StaticFileFS(`/lx-custom-source.js`, `lx-custom-source.js`, httpFS)
|
||||
}
|
||||
// 新版源脚本
|
||||
{
|
||||
// 构建文件头
|
||||
var b strings.Builder
|
||||
b.Grow(75 +
|
||||
len(env.Config.Script.Name) +
|
||||
len(env.Config.Script.Descript) +
|
||||
len(env.Config.Script.Version) +
|
||||
len(env.Config.Script.Author) +
|
||||
len(env.Config.Script.Homepage),
|
||||
)
|
||||
b.WriteString("/*!\n * @name ")
|
||||
b.WriteString(env.Config.Script.Name)
|
||||
b.WriteString("\n * @description ")
|
||||
b.WriteString(env.Config.Script.Descript)
|
||||
b.WriteString("\n * @version v")
|
||||
b.WriteString(env.Config.Script.Version)
|
||||
b.WriteString("\n * @author ")
|
||||
b.WriteString(env.Config.Script.Author)
|
||||
b.WriteString("\n * @homepage ")
|
||||
b.WriteString(env.Config.Script.Homepage)
|
||||
b.WriteString("\n */\n")
|
||||
// 构建文件体
|
||||
file, _ := publicFS.Open(`lx-source-script.js`)
|
||||
data, _ := io.ReadAll(file)
|
||||
file.Close()
|
||||
r.GET(`/lx-source-script.js`, func(c *gin.Context) {
|
||||
var mime string
|
||||
if _, ok := c.GetQuery(`raw`); ok {
|
||||
mime = `application/octet-stream`
|
||||
} else {
|
||||
mime = `text/javascript; charset=utf-8`
|
||||
}
|
||||
// 构建文件尾
|
||||
var d strings.Builder
|
||||
d.WriteString(`globalThis.ls={api:{addr:'`)
|
||||
d.WriteString(env.Config.Cache.Local_Bind)
|
||||
d.WriteString(`',pass:'`)
|
||||
if env.Config.Auth.ApiKey_Enable {
|
||||
if env.Config.Script.Auto >= 2 {
|
||||
d.WriteString(env.Config.Auth.ApiKey_Value)
|
||||
} else {
|
||||
if key, ok := c.GetQuery(`key`); ok {
|
||||
d.WriteString(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
d.WriteString(`'}};`)
|
||||
d.WriteByte('\n')
|
||||
// Render
|
||||
c.Status(http.StatusOK)
|
||||
c.Writer.Header()[`Content-Type`] = []string{mime}
|
||||
c.Writer.WriteString(b.String())
|
||||
c.Writer.WriteString(d.String())
|
||||
c.Writer.Write(data)
|
||||
})
|
||||
}
|
||||
r.StaticFileFS(`/favicon.ico`, `lx-icon.ico`, httpFS)
|
||||
r.StaticFileFS(`/status`, `status.html`, httpFS)
|
||||
r.StaticFS(`/public`, httpFS)
|
||||
|
2
src/server/public/lx-source-script.js
Normal file
2
src/server/public/lx-source-script.js
Normal file
File diff suppressed because one or more lines are too long
@ -16,7 +16,7 @@
|
||||
const api = './';
|
||||
function l(s, id, q) {
|
||||
let url = `${api}link/${s}/${id[Math.floor(Math.random() * id.length)]}/${q}`;
|
||||
const key = localStorage.getItem('apipass'); if (key) url += `?key=${key}`;
|
||||
const key = localStorage.getItem('apipass'); if (key) url += `?key=${encodeURIComponent(key)}`;
|
||||
fetch(url)
|
||||
.then((response) => response.json())
|
||||
.then((res) => {
|
||||
|
@ -50,7 +50,7 @@ func InitRouter() *gin.Engine {
|
||||
sources.S_lx: qmap[sources.I_lx],
|
||||
},
|
||||
// 自定义源脚本更新
|
||||
`script`: env.DefCfg.Script, //env.Config.Script,
|
||||
`script`: env.Config.Script.Update, //env.Config.Script,
|
||||
// 数据统计
|
||||
`summary`: gin.H{
|
||||
`StartAt`: startime, // 启动时间
|
||||
|
@ -3,10 +3,10 @@ package kg
|
||||
import (
|
||||
"lx-source/src/env"
|
||||
"lx-source/src/sources"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
"github.com/ZxwyWebSite/ztool/x/slices"
|
||||
"github.com/ZxwyWebSite/ztool/zcypt"
|
||||
)
|
||||
|
||||
|
@ -1,15 +1,19 @@
|
||||
package kw
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"lx-source/src/env"
|
||||
"lx-source/src/sources"
|
||||
"lx-source/src/sources/custom/utils"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
"github.com/ZxwyWebSite/ztool/x/bytesconv"
|
||||
"github.com/ZxwyWebSite/ztool/zcypt"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -19,6 +23,7 @@ var (
|
||||
|
||||
parsemod bool
|
||||
convtype string
|
||||
desource string
|
||||
// desParse func([]byte, *playInfo) error
|
||||
// desParse func(any) ztool.Net_ResHandlerFunc
|
||||
)
|
||||
@ -36,11 +41,13 @@ func init() {
|
||||
) {
|
||||
loger.Fatal(`使用bdapi且验证参数为空`)
|
||||
}
|
||||
// bdheader[`token`] = env.Config.Custom.Kw_Bd_Token
|
||||
bdheader[`uid`] = env.Config.Custom.Kw_Bd_Uid
|
||||
bdheader[`devId`] = env.Config.Custom.Kw_Bd_DevId
|
||||
kw_pool = &sync.Pool{New: func() any { return new(kwApi_Song) }}
|
||||
Url = bdapi
|
||||
case `1`, `kwdes`:
|
||||
Url = kwdes
|
||||
switch env.Config.Custom.Kw_Des_Type {
|
||||
case `0`, `text`:
|
||||
loger.Debug(`use kwdes text`)
|
||||
@ -51,12 +58,20 @@ func init() {
|
||||
convtype = `convert_url_with_sign`
|
||||
// desParse = ztool.Net_ResToStruct
|
||||
parsemod = true
|
||||
case `2`, `anti`:
|
||||
loger.Debug(`use kwdes anti`)
|
||||
Url = manti
|
||||
default:
|
||||
loger.Fatal(`未定义的返回格式,请检查配置 [Custom].Kw_Des_Type`)
|
||||
}
|
||||
desheader[`User-Agent`] = env.Config.Custom.Kw_Des_Header
|
||||
kw_pool = &sync.Pool{New: func() any { return new(playInfo) }}
|
||||
Url = kwdes
|
||||
if env.Config.Custom.Kw_Des_Source != `` {
|
||||
desource = env.Config.Custom.Kw_Des_Source
|
||||
} else {
|
||||
dec, _ := zcypt.HexDecode([]byte{0x36, 0x62, 0x37, 0x37, 0x37, 0x30, 0x36, 0x63, 0x36, 0x31, 0x37, 0x39, 0x36, 0x35, 0x37, 0x32, 0x36, 0x38, 0x36, 0x34, 0x35, 0x66, 0x36, 0x31, 0x37, 0x32, 0x35, 0x66, 0x33, 0x35, 0x32, 0x65, 0x33, 0x31, 0x32, 0x65, 0x33, 0x30, 0x32, 0x65, 0x33, 0x30, 0x35, 0x66, 0x34, 0x32, 0x35, 0x66, 0x36, 0x61, 0x36, 0x39, 0x36, 0x31, 0x36, 0x62, 0x36, 0x66, 0x36, 0x65, 0x36, 0x37, 0x35, 0x66, 0x37, 0x36, 0x36, 0x38, 0x32, 0x65, 0x36, 0x31, 0x37, 0x30, 0x36, 0x62})
|
||||
desource = bytesconv.BytesToString(dec)
|
||||
}
|
||||
default:
|
||||
loger.Fatal(`未定义的接口模式,请检查配置 [Custom].Kw_Mode`)
|
||||
}
|
||||
@ -92,7 +107,7 @@ func bdapi(songMid, quality string) (ourl, msg string) {
|
||||
loger.Debug(`Resp: %+v`, resp)
|
||||
if resp.Code != 200 || resp.Data.AudioInfo.Bitrate == `1` {
|
||||
// jx.Debug(`Kw, Err: %#v`, resp)
|
||||
msg = ztool.Str_FastConcat(`failed: `, resp.Msg)
|
||||
msg = ztool.Str_FastConcat(strconv.Itoa(resp.Code), `: `, resp.Msg)
|
||||
return
|
||||
}
|
||||
ourl = utils.DelQuery(resp.Data.URL) //strings.Split(resp.Data.URL, `?`)[0]
|
||||
@ -110,12 +125,12 @@ func kwdes(songMid, quality string) (ourl, msg string) {
|
||||
target_url := ztool.Str_FastConcat(
|
||||
`https://mobi.kuwo.cn/mobi.s?f=kuwo&q=`,
|
||||
base64_encrypt(ztool.Str_FastConcat(
|
||||
`user=0&android_id=0&prod=kwplayer_ar_8.5.5.0&corp=kuwo&newver=3&vipver=8.5.5.0&source=kwplayer_ar_8.5.5.0_apk_keluze.apk&p2p=1¬race=0`,
|
||||
`corp=kuwo&p2p=1&sig=0¬race=0&priority=bitrate&network=WIFI&mode=down`,
|
||||
`&source=`, desource,
|
||||
`&type=`, convtype,
|
||||
`&br=`, infoFile.H, infoFile.E,
|
||||
`&format=`, infoFile.E,
|
||||
`&rid=`, songMid,
|
||||
`&priority=bitrate&loginUid=0&network=WIFI&loginSid=0&mode=down`,
|
||||
)),
|
||||
)
|
||||
if parsemod {
|
||||
@ -131,6 +146,7 @@ func kwdes(songMid, quality string) (ourl, msg string) {
|
||||
msg = sources.ErrHttpReq
|
||||
return
|
||||
}
|
||||
resp.Data.URL = utils.DelQuery(resp.Data.URL)
|
||||
loger.Debug(`Resp: %+v`, resp)
|
||||
if resp.Code != http.StatusOK {
|
||||
msg = ztool.Str_FastConcat(`failed: `, resp.Msg)
|
||||
@ -138,13 +154,13 @@ func kwdes(songMid, quality string) (ourl, msg string) {
|
||||
return
|
||||
}
|
||||
realQuality := strconv.Itoa(resp.Data.Bitrate)
|
||||
if realQuality != infoFile.H[:len(infoFile.H)-1] {
|
||||
if realQuality != infoFile.H[:len(infoFile.H)-1] /*&& resp.Data.Bitrate != 1*/ {
|
||||
msg = sources.E_QNotMatch
|
||||
if !env.Config.Source.ForceFallback {
|
||||
return
|
||||
}
|
||||
}
|
||||
ourl = utils.DelQuery(resp.Data.URL) //resp.Data.URL[:strings.Index(resp.Data.URL, `?`)]
|
||||
ourl = resp.Data.URL //resp.Data.URL[:strings.Index(resp.Data.URL, `?`)]
|
||||
return
|
||||
}
|
||||
ztool.Net_Request(http.MethodGet, target_url, nil,
|
||||
@ -179,3 +195,133 @@ func kwdes(songMid, quality string) (ourl, msg string) {
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 一种替代方案,仅在试听可用时获取cdn前缀,缺点是无法获取不能试听的歌曲
|
||||
func manti(songMid, quality string) (ourl, msg string) {
|
||||
loger := env.Loger.NewGroup(`Kw`)
|
||||
defer loger.Free()
|
||||
infoFile, ok := fileInfo[quality]
|
||||
if !ok {
|
||||
msg = sources.E_QNotSupport
|
||||
return
|
||||
}
|
||||
// 获取CDN地址
|
||||
// var out_a string
|
||||
/*var out_c struct {
|
||||
// Timestamp int `json:"timestamp"`
|
||||
Songs []struct {
|
||||
ID int `json:"id"`
|
||||
Duration int `json:"duration"`
|
||||
URL string `json:"url"`
|
||||
HTTPS string `json:"https"`
|
||||
CarURL string `json:"car_url"`
|
||||
CarURLHTTPS string `json:"car_url_https"`
|
||||
Format string `json:"format"`
|
||||
Br int `json:"br"`
|
||||
OverseasCopyright string `json:"overseas_copyright"`
|
||||
Start int `json:"start"`
|
||||
End int `json:"end"`
|
||||
Group string `json:"group"`
|
||||
} `json:"songs"`
|
||||
IP string `json:"ip"`
|
||||
Country string `json:"country"`
|
||||
Region string `json:"region"`
|
||||
Locationid int `json:"locationid"`
|
||||
Code int `json:"code"`
|
||||
Result string `json:"result"`
|
||||
}
|
||||
err := ztool.Net_Request(
|
||||
http.MethodGet,
|
||||
`https://musicpay30.kuwo.cn/audi.tion?op=query&ids=`+songMid,
|
||||
nil,
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders()},
|
||||
[]ztool.Net_ResHandlerFunc{ztool.Net_ResToStruct(&out_c)},
|
||||
)
|
||||
if err != nil {
|
||||
loger.Error(`Request: %s`, err)
|
||||
msg = sources.ErrHttpReq
|
||||
return
|
||||
}*/
|
||||
// 获取音频路径
|
||||
if quality != sources.Q_128k {
|
||||
ourl, msg = manti(songMid, sources.Q_128k)
|
||||
if msg != `` {
|
||||
return
|
||||
}
|
||||
if i := strings.LastIndexByte(ourl, '/'); i != -1 {
|
||||
if ourl[i+1:] == `2272659253.mp3` {
|
||||
msg = sources.ErrNoLink
|
||||
return
|
||||
}
|
||||
}
|
||||
target_url := ztool.Str_FastConcat(
|
||||
`https://mobi.kuwo.cn/mobi.s?f=web&type=convert_url`,
|
||||
`&br=`, infoFile.H, infoFile.E,
|
||||
`&format=`, infoFile.E,
|
||||
`&rid=`, songMid,
|
||||
)
|
||||
var out_u, realQuality string
|
||||
err := ztool.Net_Request(
|
||||
http.MethodGet, target_url, nil,
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders()},
|
||||
[]ztool.Net_ResHandlerFunc{func(res *http.Response) (err error) {
|
||||
var data []byte
|
||||
data, err = io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return errors.New(`failed: ` + res.Status)
|
||||
}
|
||||
infoData := mkMap(data)
|
||||
loger.Debug(`uData: %+v`, infoData)
|
||||
realQuality = infoData[`bitrate`]
|
||||
out_u = utils.DelQuery(infoData[`url`])
|
||||
return
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
loger.Error(`Request: %s`, err)
|
||||
msg = sources.ErrHttpReq
|
||||
return
|
||||
}
|
||||
if realQuality != infoFile.H[:len(infoFile.H)-1] {
|
||||
msg = sources.E_QNotMatch
|
||||
if !env.Config.Source.ForceFallback {
|
||||
return
|
||||
}
|
||||
}
|
||||
if ourl != `` && out_u != `` {
|
||||
ourl = ourl[:24] + out_u
|
||||
}
|
||||
return
|
||||
}
|
||||
resp := kw_pool.Get().(*playInfo)
|
||||
defer kw_pool.Put(resp)
|
||||
|
||||
err := ztool.Net_Request(
|
||||
http.MethodGet, `https://mobi.kuwo.cn/mobi.s?f=web&type=convert_url_with_sign&br=128kmp3&format=mp3&rid=`+songMid, nil,
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeader(desheader)},
|
||||
[]ztool.Net_ResHandlerFunc{ztool.Net_ResToStruct(&resp)},
|
||||
)
|
||||
if err != nil {
|
||||
loger.Error(`Request: %s`, err)
|
||||
msg = sources.ErrHttpReq
|
||||
return
|
||||
}
|
||||
loger.Debug(`tData: %+v`, resp)
|
||||
if resp.Code != http.StatusOK {
|
||||
msg = ztool.Str_FastConcat(`failed: `, resp.Msg)
|
||||
loger.Debug(msg)
|
||||
return
|
||||
}
|
||||
realQuality := strconv.Itoa(resp.Data.Bitrate)
|
||||
if realQuality != infoFile.H[:len(infoFile.H)-1] && resp.Data.Bitrate != 1 {
|
||||
msg = sources.E_QNotMatch
|
||||
if !env.Config.Source.ForceFallback {
|
||||
return
|
||||
}
|
||||
}
|
||||
ourl = utils.DelQuery(resp.Data.URL)
|
||||
return
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ type (
|
||||
Format string `json:"format"`
|
||||
P2PAudiosourceid string `json:"p2p_audiosourceid"`
|
||||
Rid int `json:"rid"`
|
||||
Source string `json:"source"`
|
||||
URL string `json:"url"`
|
||||
// Source string `json:"source"`
|
||||
URL string `json:"url"`
|
||||
} `json:"data"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
@ -40,25 +40,64 @@ var (
|
||||
// `User-Agent`: `okhttp/3.10.0`,
|
||||
}
|
||||
bdheader = map[string]string{
|
||||
`channel`: `qq`,
|
||||
`channel`: `guanfang`,
|
||||
`plat`: `ar`,
|
||||
`net`: `wifi`,
|
||||
`ver`: `3.1.2`,
|
||||
// `uid`: ``,
|
||||
// `devId`: `0`,
|
||||
`ver`: `3.1.4`,
|
||||
`api-ver`: `application/json`,
|
||||
|
||||
`user-agent`: `Dart/2.18 (dart:io)`, //`Dalvik/2.1.0 (Linux; U; Android 7.1.1; OPPO R9sk Build/NMF26F)`,
|
||||
}
|
||||
// bdsreg = regexp.MustCompile(`[^a-zA-Z0-9]`)
|
||||
)
|
||||
|
||||
func mkMap(data []byte) map[string]string {
|
||||
out := make(map[string]string)
|
||||
sep := bytes.Split(data, []byte{13, 10})
|
||||
for i, r := 0, len(sep); i < r; i++ {
|
||||
pat := bytes.Split(sep[i], []byte{61})
|
||||
if len(pat) == 2 {
|
||||
var s = sep[i]
|
||||
if p := bytes.IndexByte(s, '='); p != -1 {
|
||||
out[bytesconv.BytesToString(s[:p])] = bytesconv.BytesToString(s[p+1:])
|
||||
continue
|
||||
} else {
|
||||
out[`_`] += bytesconv.BytesToString(s) + `;`
|
||||
}
|
||||
/*pat := bytes.Split(sep[i], []byte{61})
|
||||
if len(pat) >= 2 {
|
||||
out[bytesconv.BytesToString(pat[0])] = bytesconv.BytesToString(pat[1])
|
||||
continue
|
||||
}
|
||||
out[`_`] += bytesconv.BytesToString(pat[0]) + `;`
|
||||
out[`_`] += bytesconv.BytesToString(pat[0]) + `;`*/
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// 波点签名算法
|
||||
/*func Bdsign(str string, m, m2 map[string]string) *strings.Builder {
|
||||
var b strings.Builder
|
||||
b.WriteString(`uid=`)
|
||||
b.WriteString(env.Config.Custom.Kw_Bd_Uid)
|
||||
b.WriteByte('&')
|
||||
b.WriteString(`token=`)
|
||||
b.WriteString(env.Config.Custom.Kw_Bd_Token)
|
||||
b.WriteByte('&')
|
||||
b.WriteString(`timestamp=`)
|
||||
b.WriteString(strconv.FormatInt(time.Now().UnixMilli(), 10))
|
||||
for k, v := range m2 {
|
||||
b.WriteByte('&')
|
||||
b.WriteString(k)
|
||||
b.WriteByte('=')
|
||||
b.WriteString(url.QueryEscape(v))
|
||||
}
|
||||
// 取 strings.Builder.buf []byte 地址
|
||||
pb := (*[]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&b)) + unsafe.Sizeof((*strings.Builder)(nil))))
|
||||
charArray := bdsreg.ReplaceAll(*pb, []byte{})
|
||||
slices.Sort(charArray)
|
||||
str3 := string(charArray)
|
||||
fmt.Println(str3)
|
||||
lowerCase := zcypt.MD5EncStr(`kuwotest` + str3 + `/api/play/music/v2/audioUrl`)
|
||||
b.WriteByte('&')
|
||||
b.WriteString(`sign=`)
|
||||
b.WriteString(lowerCase)
|
||||
return &b
|
||||
}*/
|
||||
|
355
src/sources/custom/tx/login.go
Normal file
355
src/sources/custom/tx/login.go
Normal file
@ -0,0 +1,355 @@
|
||||
package tx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"lx-source/src/env"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
"github.com/ZxwyWebSite/ztool/logs"
|
||||
"github.com/ZxwyWebSite/ztool/x/json"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
//go:linkname request github.com/ZxwyWebSite/ztool.request
|
||||
func request(client *http.Client, method, url string, body io.Reader, reqh []ztool.Net_ReqHandlerFunc, resh []ztool.Net_ResHandlerFunc) error
|
||||
|
||||
// QQ快速登录 - 直接使用本机已登录账号
|
||||
func Qlogin_graph(l *logs.Logger) error {
|
||||
// 参考文章: https://learnku.com/articles/33970
|
||||
|
||||
jar, _ := cookiejar.New(nil)
|
||||
client := &http.Client{
|
||||
Timeout: time.Second * 10,
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
Jar: jar,
|
||||
}
|
||||
|
||||
// Step0 - 获取本机QQ服务地址
|
||||
// (应该没有人会占用4301端口导致qq切换备用端口吧,先不写了...懒)
|
||||
err := request(
|
||||
client, http.MethodGet, `https://localhost.ptlogin2.qq.com:4301/pc_querystatus`, nil,
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders()},
|
||||
[]ztool.Net_ResHandlerFunc{func(res *http.Response) error {
|
||||
_, err := io.Copy(io.Discard, res.Body)
|
||||
return err
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
return errors.New(`step0: 无法连接本机QQ服务`)
|
||||
}
|
||||
|
||||
// Step1 - 获取 pt_local_token
|
||||
var pt_local_token string
|
||||
err = request(
|
||||
client, http.MethodGet,
|
||||
`https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=716027609&daid=383&style=33&login_text=%E7%99%BB%E5%BD%95&hide_title_bar=1&hide_border=1&target=self&s_url=https://graph.qq.com/oauth2.0/login_jump&pt_3rd_aid=100497308&pt_feedback_link=https://support.qq.com/products/77942?customInfo=.appid100497308&theme=2&verify_theme=`,
|
||||
nil,
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders(map[string]string{
|
||||
`Referer`: `https://graph.qq.com/`,
|
||||
})},
|
||||
[]ztool.Net_ResHandlerFunc{func(res *http.Response) error {
|
||||
for _, v := range res.Cookies() {
|
||||
if v.Name == `pt_local_token` {
|
||||
pt_local_token = v.Value
|
||||
break
|
||||
}
|
||||
}
|
||||
_, err := io.Copy(io.Discard, res.Body)
|
||||
return err
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.Info(`pt_local_token: %v`, pt_local_token)
|
||||
|
||||
// Step2 - 获取本机登录的 QQ 号
|
||||
var url2 strings.Builder
|
||||
url2.WriteString(`https://localhost.ptlogin2.qq.com:4301/pt_get_uins?callback=ptui_getuins_CB&r=`)
|
||||
url2.WriteString(strconv.FormatFloat(rand.Float64(), 'f', -1, 64))
|
||||
url2.WriteString(`&pt_local_tk=`)
|
||||
url2.WriteString(pt_local_token)
|
||||
var out2 []struct {
|
||||
Uin int `json:"uin"`
|
||||
// FaceIndex int `json:"face_index"`
|
||||
// Gender int `json:"gender"`
|
||||
Nickname string `json:"nickname"`
|
||||
// ClientType int `json:"client_type"`
|
||||
// UinFlag int `json:"uin_flag"`
|
||||
// Account int `json:"account"`
|
||||
}
|
||||
var header2 = map[string]string{
|
||||
`Referer`: `https://xui.ptlogin2.qq.com/`,
|
||||
// `Cookie`: `pt_local_token=` + pt_local_token,
|
||||
}
|
||||
err = request(
|
||||
client, http.MethodGet, url2.String(), nil,
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders(header2)},
|
||||
[]ztool.Net_ResHandlerFunc{func(res *http.Response) error {
|
||||
data, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sep_b := bytes.IndexByte(data, '[')
|
||||
sep_e := bytes.LastIndexByte(data, ']')
|
||||
if sep_b == -1 || sep_e == -1 {
|
||||
return errors.New(`step2: 无法解析返回数据`)
|
||||
}
|
||||
sep := data[sep_b : sep_e+1]
|
||||
return json.Unmarshal(sep, &out2)
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var uin string
|
||||
length := len(out2)
|
||||
switch length {
|
||||
case 0:
|
||||
return errors.New(`step2: 无可用账号`)
|
||||
case 1:
|
||||
uin = strconv.Itoa(out2[0].Uin)
|
||||
default:
|
||||
fmt.Println(`请选择要登录的账号:`)
|
||||
for i, v := range out2 {
|
||||
fmt.Println(i, v.Nickname, v.Uin)
|
||||
}
|
||||
for {
|
||||
fmt.Print(`输入序号: `)
|
||||
var input string
|
||||
fmt.Scanln(&input)
|
||||
i, err := strconv.Atoi(input)
|
||||
if err != nil {
|
||||
l.Error(`err: %v`, err)
|
||||
continue
|
||||
}
|
||||
if i >= length {
|
||||
l.Error(`err: 下标越界`)
|
||||
continue
|
||||
}
|
||||
uin = strconv.Itoa(out2[i].Uin)
|
||||
break
|
||||
}
|
||||
}
|
||||
l.Info(`uin: %v`, uin)
|
||||
|
||||
// Step3 - 获取 clientkey
|
||||
var url3 strings.Builder
|
||||
url3.WriteString(`https://localhost.ptlogin2.qq.com:4301/pt_get_st?clientuin=`)
|
||||
url3.WriteString(uin)
|
||||
url3.WriteString(`&r=`)
|
||||
url3.WriteString(strconv.FormatFloat(rand.Float64(), 'f', -1, 64))
|
||||
url3.WriteString(`&pt_local_tk=`)
|
||||
url3.WriteString(pt_local_token)
|
||||
url3.WriteString(`&callback=__jp0`)
|
||||
// var clientkey string
|
||||
err = request(
|
||||
client, http.MethodGet, url3.String(), nil,
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders(header2)},
|
||||
[]ztool.Net_ResHandlerFunc{func(res *http.Response) error {
|
||||
/*for _, v := range res.Cookies() {
|
||||
if v.Name == `clientkey` {
|
||||
clientkey = v.Value
|
||||
break
|
||||
}
|
||||
}*/
|
||||
_, err := io.Copy(io.Discard, res.Body)
|
||||
return err
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Step4 - 获取 skey
|
||||
var url4 strings.Builder
|
||||
url4.WriteString(`https://ssl.ptlogin2.qq.com/jump?clientuin=`)
|
||||
url4.WriteString(uin)
|
||||
url4.WriteString(`&keyindex=9&pt_aid=716027609&daid=383&u1=https://graph.qq.com/oauth2.0/login_jump&pt_local_tk=`)
|
||||
url4.WriteString(pt_local_token)
|
||||
url4.WriteString(`&pt_3rd_aid=100497308&ptopt=1&style=40`)
|
||||
/*var cookie4 strings.Builder
|
||||
cookie4.WriteString(`pt_local_token=`)
|
||||
cookie4.WriteString(pt_local_token)
|
||||
cookie4.WriteByte(';')
|
||||
cookie4.WriteString(`clientuin=`)
|
||||
cookie4.WriteString(uin)
|
||||
cookie4.WriteByte(';')
|
||||
cookie4.WriteString(`clientkey=`)
|
||||
cookie4.WriteString(clientkey)*/
|
||||
var jurl string
|
||||
err = request(
|
||||
client, http.MethodGet, url4.String(), nil,
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders( /*map[string]string{
|
||||
`Referer`: `https://xui.ptlogin2.qq.com/`,
|
||||
`Cookie`: cookie4.String(),
|
||||
}*/header2)},
|
||||
[]ztool.Net_ResHandlerFunc{func(res *http.Response) error {
|
||||
data, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sep_b := bytes.IndexByte(data, ',')
|
||||
sep_e := bytes.LastIndexByte(data, ' ')
|
||||
if sep_b == -1 || sep_e == -1 {
|
||||
return errors.New(`step4: 无法解析返回数据`)
|
||||
}
|
||||
jurl = string(data[sep_b+3 : sep_e-2])
|
||||
return nil
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Step5 - 获取 p_skey
|
||||
var p_skey string
|
||||
err = request(
|
||||
client, http.MethodGet, jurl, nil,
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders(header2)},
|
||||
[]ztool.Net_ResHandlerFunc{func(res *http.Response) error {
|
||||
for _, v := range res.Cookies() {
|
||||
if v.Name == `p_skey` && v.Value != `` {
|
||||
p_skey = v.Value
|
||||
break
|
||||
}
|
||||
}
|
||||
_, err := io.Copy(io.Discard, res.Body)
|
||||
return err
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Step6 - 登录账号
|
||||
getGtk := func(skey string) string {
|
||||
var hash = 5381
|
||||
for _, v := range skey {
|
||||
hash += (hash << 5) + int(v)
|
||||
}
|
||||
return strconv.Itoa(hash & 0x7fffffff)
|
||||
}
|
||||
now := time.Now()
|
||||
var authcode string
|
||||
err = request(
|
||||
client, http.MethodPost,
|
||||
`https://graph.qq.com/oauth2.0/authorize`,
|
||||
strings.NewReader(ztool.Str_FastConcat(
|
||||
`response_type=code&client_id=100497308&redirect_uri=https%3A%2F%2Fy.qq.com%2Fportal%2Fwx_redirect.html%3Flogin_type%3D1%26surl%3Dhttps%3A%2F%2Fy.qq.com%2F&scope=get_user_info%2Cget_app_friends&state=state&switch=&from_ptlogin=1&src=1&update_auth=1&openapi=1010_1030`,
|
||||
`&g_tk=`, getGtk(p_skey),
|
||||
`&auth_time=`, strconv.FormatInt(now.UnixMilli(), 10),
|
||||
`&ui=`, strings.ToUpper(uuid.NewString()),
|
||||
)),
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders(map[string]string{
|
||||
`Referer`: `https://graph.qq.com/oauth2.0/show?which=Login&display=pc&response_type=code&client_id=100497308&redirect_uri=https%3A%2F%2Fy.qq.com%2Fportal%2Fwx_redirect.html%3Flogin_type%3D1%26surl%3Dhttps%3A%2F%2Fy.qq.com%2F&state=state&display=pc&scope=get_user_info%2Cget_app_friends`,
|
||||
`Content-Type`: `application/x-www-form-urlencoded`,
|
||||
})},
|
||||
[]ztool.Net_ResHandlerFunc{func(res *http.Response) error {
|
||||
/*if res.StatusCode != 302 {
|
||||
return errors.New(`step6: not redirect`)
|
||||
}*/
|
||||
location := res.Header[`Location`][0]
|
||||
l.Info(`loc: %v`, location)
|
||||
loc, err := url.Parse(location)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authcode = loc.Query()[`code`][0]
|
||||
return nil
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.Info(`authcode: %v`, authcode)
|
||||
var out6 struct {
|
||||
Code int `json:"code"`
|
||||
// Ts int64 `json:"ts"`
|
||||
// StartTs int64 `json:"start_ts"`
|
||||
// Traceid string `json:"traceid"`
|
||||
Req struct {
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
// Openid string `json:"openid"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiredAt int `json:"expired_at"`
|
||||
// Musicid int `json:"musicid"`
|
||||
Musickey string `json:"musickey"`
|
||||
// MusickeyCreateTime int `json:"musickeyCreateTime"`
|
||||
// FirstLogin int `json:"first_login"`
|
||||
// ErrMsg string `json:"errMsg"`
|
||||
// SessionKey string `json:"sessionKey"`
|
||||
// Unionid string `json:"unionid"`
|
||||
StrMusicid string `json:"str_musicid"`
|
||||
// Errtip string `json:"errtip"`
|
||||
// Nick string `json:"nick"`
|
||||
// Logo string `json:"logo"`
|
||||
// FeedbackURL string `json:"feedbackURL"`
|
||||
// EncryptUin string `json:"encryptUin"`
|
||||
// Userip string `json:"userip"`
|
||||
// LastLoginTime int `json:"lastLoginTime"`
|
||||
// KeyExpiresIn int `json:"keyExpiresIn"`
|
||||
// RefreshKey string `json:"refresh_key"`
|
||||
// LoginType int `json:"loginType"`
|
||||
// Prompt2Bind int `json:"prompt2bind"`
|
||||
// LogoffStatus int `json:"logoffStatus"`
|
||||
// OtherAccounts []interface{} `json:"otherAccounts"`
|
||||
// OtherPhoneNo string `json:"otherPhoneNo"`
|
||||
// Token string `json:"token"`
|
||||
// IsPrized int `json:"isPrized"`
|
||||
// IsShowDevManage int `json:"isShowDevManage"`
|
||||
// ErrTip2 string `json:"errTip2"`
|
||||
// Tip3 string `json:"tip3"`
|
||||
// EncryptedPhoneNo string `json:"encryptedPhoneNo"`
|
||||
// PhoneNo string `json:"phoneNo"`
|
||||
// BindAccountType int `json:"bindAccountType"`
|
||||
// NeedRefreshKeyIn int `json:"needRefreshKeyIn"`
|
||||
} `json:"data"`
|
||||
} `json:"req"`
|
||||
}
|
||||
err = request(
|
||||
client, http.MethodPost,
|
||||
`https://u.y.qq.com/cgi-bin/musicu.fcg`,
|
||||
strings.NewReader(ztool.Str_FastConcat(
|
||||
`{"comm":{"g_tk":5381,"platform":"yqq","ct":24,"cv":0},"req":{"module":"QQConnectLogin.LoginServer","method":"QQLogin","param":{"code":"`, authcode, `"}}}`,
|
||||
)),
|
||||
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders(map[string]string{
|
||||
`Referer`: `https://y.qq.com/`,
|
||||
`Content-Type`: `application/x-www-form-urlencoded`,
|
||||
})},
|
||||
[]ztool.Net_ResHandlerFunc{ztool.Net_ResToStruct(&out6)},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.Info(`res: %+v`, out6)
|
||||
l.Info(`登录成功`)
|
||||
|
||||
env.Config.Custom.Tx_Enable = true
|
||||
env.Config.Custom.Tx_Uuin = out6.Req.Data.StrMusicid
|
||||
env.Config.Custom.Tx_Ukey = out6.Req.Data.Musickey
|
||||
env.Config.Custom.Tx_Refresh_Enable = false
|
||||
// env.Config.Custom.Tx_Refresh_Interval = time.Date(now.Year(), now.Month(), now.Day()+5, 0, 0, 0, 0, now.Location()).Unix()
|
||||
// env.Config.Custom.Tx_RefreshToken = out6.Req.Data.RefreshToken
|
||||
// env.Config.Custom.Tx_AccessToken = out6.Req.Data.AccessToken
|
||||
|
||||
return env.Cfg.Save(``)
|
||||
}
|
||||
|
||||
// QQ扫码登录(todo)
|
||||
// func qlogin_qr_()
|
@ -103,6 +103,7 @@ Loop:
|
||||
if quality != sources.Q_128k && infoBody.TrackInfo.Pay.PayPlay == 0 {
|
||||
msg = `Fallback to 128k`
|
||||
infoFile = fileInfo[sources.Q_128k]
|
||||
quality = sources.Q_128k
|
||||
} else {
|
||||
msg = `Fallbacked`
|
||||
tryLink = true
|
||||
|
@ -123,9 +123,18 @@ func refresh(loger *logs.Logger, now int64) error {
|
||||
// loger.Error(`请求Api失败: %s`, err)
|
||||
return errors.New(`请求Api失败: ` + err.Error())
|
||||
}
|
||||
loger.Debug(`Resp: %+v`, resp)
|
||||
if resp.Req1.Code != 0 {
|
||||
switch resp.Req1.Code {
|
||||
case 1000:
|
||||
return fmt.Errorf(`%v: Token无效或已过期`, resp.Req1.Code)
|
||||
case 2000:
|
||||
return fmt.Errorf(`%v: 该Token不支持刷新`, resp.Req1.Code)
|
||||
default:
|
||||
return fmt.Errorf(`%v: 刷新登录失败`, resp.Req1.Code)
|
||||
}
|
||||
// loger.Warn("刷新登录失败, code: %v\n响应体: %+v", resp.Req1.Code, resp)
|
||||
return fmt.Errorf("刷新登录失败, code: %v\n响应体: %+v", resp.Req1.Code, resp)
|
||||
// return fmt.Errorf("刷新登录失败, code: %v\n响应体: %+v", resp.Req1.Code, resp)
|
||||
}
|
||||
loger.Info(`刷新登录成功`)
|
||||
env.Config.Custom.Tx_Uuin = resp.Req1.Data.StrMusicId
|
||||
|
@ -20,7 +20,11 @@ import (
|
||||
|
||||
const anonymous_token = `1f5fa7b6a6a9f81a11886e5186fde7fb98e25cf0036d7afd055b980b2261f5464b7f5273fc3921d1262bfec66a19a30c41d8da00c3685f5ace96f0d5a48b6db334d974731083682e3324751bcc9aaf44c3061cd1`
|
||||
|
||||
var wapiReg = regexp.MustCompile(`\w*api`)
|
||||
var (
|
||||
wapiReg = regexp.MustCompile(`\w*api`)
|
||||
csrfReg = regexp.MustCompile(`_csrf=([^(;|$)]+)`)
|
||||
domaReg = regexp.MustCompile(`\s*Domain=[^(;|$)]+;*`)
|
||||
)
|
||||
|
||||
var userAgentMap = map[string]string{
|
||||
`mobile`: `Mozilla/5.0 (iPhone; CPU iPhone OS 17_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1`,
|
||||
@ -103,8 +107,7 @@ func createRequest(method, url string, data map[string]any, options reqOptions)
|
||||
switch options.Crypto {
|
||||
case `weapi`:
|
||||
options.Headers[`User-Agent`] = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69`
|
||||
reg := regexp.MustCompile(`_csrf=([^(;|$)]+)`)
|
||||
csrfToken := reg.FindStringSubmatch(options.Headers[`Cookie`])
|
||||
csrfToken := csrfReg.FindStringSubmatch(options.Headers[`Cookie`])
|
||||
if len(csrfToken) > 1 {
|
||||
data[`csrf_token`] = csrfToken[1]
|
||||
} else {
|
||||
@ -189,9 +192,8 @@ func createRequest(method, url string, data map[string]any, options reqOptions)
|
||||
}
|
||||
if err == nil {
|
||||
answer.Cookie = res.Header[`Set-Cookie`] //res.Header.Values(`set-cookie`)
|
||||
reg := regexp.MustCompile(`\s*Domain=[^(;|$)]+;*`)
|
||||
for i, v := range answer.Cookie {
|
||||
answer.Cookie[i] = reg.ReplaceAllString(v, ``)
|
||||
answer.Cookie[i] = domaReg.ReplaceAllString(v, ``)
|
||||
}
|
||||
if options.Crypto == `eapi` && body[0] != '{' {
|
||||
err = json.Unmarshal(decrypt(body), &answer.Body)
|
||||
|
@ -3,7 +3,6 @@ package wy
|
||||
import (
|
||||
"lx-source/src/env"
|
||||
wy "lx-source/src/sources/custom/wy/modules"
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
// "time"
|
||||
@ -48,7 +47,10 @@ func refresh(loger *logs.Logger, now int64) error {
|
||||
if out, ok := res.Body[`cookie`].(string); ok {
|
||||
loger.Info(`获取数据成功`)
|
||||
cmap := cookie.ToMap(cookie.Parse(out))
|
||||
maps.Copy(cookies, cmap)
|
||||
// inline call to maps.Copy
|
||||
for k, v := range cmap {
|
||||
cookies[k] = v
|
||||
}
|
||||
env.Config.Custom.Wy_Api_Cookie = cookie.Marshal(cookies)
|
||||
loger.Debug(`Cookie: %#v`, cookies)
|
||||
// if _, ok := cmap[`MUSIC_U`]; ok {
|
||||
|
32
update.md
32
update.md
@ -3,6 +3,38 @@
|
||||
<!-- #### \# 2024-02-14 v1.0.3-rel (release)
|
||||
+ **停止更新:感谢这三个月的陪伴,现因无力维护,停止后续更新,发布最后版本,大家有缘再见** -->
|
||||
|
||||
#### \# 2024-06-22 v1.0.3.0622 (dev)
|
||||
+ 临近期末,暂缓更新,计划假期重构服务端v1.1.0
|
||||
+ 更新源脚本,使用 WebPack 构建,支持自定义更多参数
|
||||
+ 体验地址 `/lx-source-script.js`,添加 `?key=请求密钥`
|
||||
+ 更新编译脚本,支持MuslLibC、静态构建,支持自动发布Release
|
||||
|
||||
#### \# 2024-06-14 v1.0.3.0614 (dev)
|
||||
+ 更新编译脚本,支持更多架构
|
||||
|
||||
#### \# 2024-05-31 v1.0.3.0531 (dev)
|
||||
+ Wy源优化模块,同步部分更改
|
||||
+ Kw源测试接口,无需白名单包名(二次甚至三次查询)
|
||||
+ Kw源允许自定义Des_Source参数
|
||||
|
||||
#### \# 2024-05-25 Special Ver (dev)
|
||||
+ 更新Action构建脚本,正式兼容Go1.20(windows7)
|
||||
|
||||
#### \# 2024-05-18 v1.0.3.0518 (dev)
|
||||
+ (据用户反馈,当前账号添加方式过于复杂,很多参数不知道怎么填,故增加部分平台简化登录方式)
|
||||
+ Tx源支持QQ快速登录(beta), 启动参数 `-e txqq`
|
||||
+ 支持自定义错误音频地址(不填禁用), 位置 [Main].ErrMp3
|
||||
+ ~~修复若干已知Bug~~
|
||||
|
||||
<!-- #### \# 2024-05-12 v1.0.3.0503 (dev)
|
||||
+ 支持对接Python版ApiServer(二次分销?)
|
||||
+ 同时开发了一套数据共享接口
|
||||
(太过逆天,先不发了,容易导致滥用问题) -->
|
||||
|
||||
#### \# 2024-05-03 v1.0.3.0503 (dev)
|
||||
+ 基于 cr-go-sdk 重新支持 Cloudreve 缓存
|
||||
+ 解决Tx源一处Fallback死循环问题
|
||||
|
||||
#### \# 2024-04-30 v1.0.3.0430 (beta)
|
||||
+ Tx源支持自定义CDN链接地址
|
||||
+ Wy源支持扫码登录(beta), 启动参数 `-e wyqr`
|
||||
|
Loading…
x
Reference in New Issue
Block a user