[
  {
    "path": ".cross_compile.sh",
    "content": "\n###\n # @Author: Vincent Young\n # @Date: 2022-10-20 02:19:06\n # @LastEditors: Vincent Yang\n # @LastEditTime: 2024-03-20 16:52:40\n # @FilePath: /DeepLX/.cross_compile.sh\n # @Telegram: https://t.me/missuo\n # \n # Copyright © 2022 by Vincent, All Rights Reserved. \n### \nset -e\n\nDIST_PREFIX=\"deeplx\"\nDEBUG_MODE=${2}\nTARGET_DIR=\"dist\"\nPLATFORMS=\"darwin/amd64 darwin/arm64 linux/386 linux/amd64 linux/arm64 linux/mips openbsd/amd64 openbsd/arm64 freebsd/amd64 freebsd/arm64 windows/386 windows/amd64\"\n\nrm -rf ${TARGET_DIR}\nmkdir ${TARGET_DIR}\n\nfor pl in ${PLATFORMS}; do\n    export GOOS=$(echo ${pl} | cut -d'/' -f1)\n    export GOARCH=$(echo ${pl} | cut -d'/' -f2)\n    export TARGET=${TARGET_DIR}/${DIST_PREFIX}_${GOOS}_${GOARCH}\n    if [ \"${GOOS}\" == \"windows\" ]; then\n        export TARGET=${TARGET_DIR}/${DIST_PREFIX}_${GOOS}_${GOARCH}.exe\n    fi\n\n    echo \"build => ${TARGET}\"\n    if [ \"${DEBUG_MODE}\" == \"debug\" ]; then\n        CGO_ENABLED=0 go build -trimpath -gcflags \"all=-N -l\" -o ${TARGET} \\\n            -ldflags \"-w -s\" .\n    else\n        CGO_ENABLED=0 go build -trimpath -o ${TARGET} \\\n            -ldflags \"-w -s\" .\n    fi\ndone\n"
  },
  {
    "path": ".github/FUNDING.yaml",
    "content": "github: [missuo]\n"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "content": "on:\n  push:\n  pull_request:\n\nname: CI\n\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@v3\n\n      - name: Set up Go\n        uses: actions/setup-go@v4\n        with:\n          go-version: '1.24.2'\n\n      - name: Install golint\n        run: go install golang.org/x/lint/golint@latest\n\n      - name: Build\n        run: go build ./...\n\n      - name: Test\n        run: go test ./...\n"
  },
  {
    "path": ".github/workflows/docker.yaml",
    "content": "name: Docker Image CI\n\non:\n  push:\n    branches:\n      - dev\n    tags:\n      - 'v*'\n\nenv:\n  DOCKER_IMAGE_NAME: missuo/deeplx\n  GHCR_IMAGE_NAME: ${{ github.repository }}\n  DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}\n  DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}\n  GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n  GHCR_USERNAME: ${{ github.repository_owner }}\n\njobs:\n  docker_build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n        with:\n          fetch-depth: 0\n\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v2\n        with:\n          platforms: all\n\n      - name: Set up docker buildx\n        id: buildx\n        uses: docker/setup-buildx-action@v2\n        with:\n          version: latest\n\n      - name: Login to DockerHub\n        uses: docker/login-action@v2\n        with:\n          registry: docker.io\n          username: ${{ env.DOCKER_USERNAME }}\n          password: ${{ env.DOCKER_PASSWORD }}\n\n      - name: Login to GHCR\n        uses: docker/login-action@v2\n        with:\n          registry: ghcr.io\n          username: ${{ env.GHCR_USERNAME }}\n          password: ${{ env.GHCR_TOKEN }}\n\n      - name: Docker meta\n        id: meta\n        uses: docker/metadata-action@v4\n        with:\n          # list of Docker images to use as base name for tags\n          images: |\n            docker.io/${{ env.DOCKER_IMAGE_NAME }}\n            ghcr.io/${{ env.GHCR_IMAGE_NAME }}\n          # generate Docker tags based on the following events/attributes\n          tags: |\n            type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}\n            type=pep440,pattern={{raw}},enable=${{ startsWith(github.ref, 'refs/tags/') }}\n            type=raw,value=dev,enable=${{ github.ref == 'refs/heads/dev' }}\n\n      - name: Build and push\n        uses: docker/build-push-action@v3\n        with:\n          context: .\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: ${{ steps.meta.outputs.tags }}\n          labels: ${{ steps.meta.outputs.labels }}\n          cache-from: type=gha\n          cache-to: type=gha,mode=max\n"
  },
  {
    "path": ".github/workflows/release.yaml",
    "content": "on:\n  push:\n    tags:\n      - 'v*'\n  pull_request:\n\nname: Release\njobs:\n        \n  Build:\n    if: startsWith(github.ref, 'refs/tags/v')\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: actions/setup-go@v4\n        with:\n          go-version: \"1.24.2\"\n\n      - run: bash .cross_compile.sh\n\n      - name: Release\n        uses: softprops/action-gh-release@v1\n        with:\n          draft: false\n          generate_release_notes: true\n          files: |\n            dist/*\n"
  },
  {
    "path": ".gitignore",
    "content": "DeepLX"
  },
  {
    "path": "Dockerfile",
    "content": "FROM golang:1.25 AS builder\nWORKDIR /go/src/github.com/OwO-Network/DeepLX\nCOPY . .\nRUN go get -d -v ./\nRUN CGO_ENABLED=0 go build -a -installsuffix cgo -o deeplx .\n\nFROM alpine:latest\nWORKDIR /app\nCOPY --from=builder /go/src/github.com/OwO-Network/DeepLX/deeplx /app/deeplx\nCMD [\"/app/deeplx\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022 OwO Network Limited\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<!--\n * @Author: Vincent Young\n * @Date: 2022-10-18 07:32:29\n * @LastEditors: Vincent Yang\n * @LastEditTime: 2024-11-30 19:48:00\n * @FilePath: /DeepLX/README.md\n * @Telegram: https://t.me/missuo\n * \n * Copyright © 2022 by Vincent, All Rights Reserved. \n-->\n\n[![GitHub Workflow][1]](https://github.com/OwO-Network/DeepLX/actions)\n[![Go Version][2]](https://github.com/OwO-Network/DeepLX/blob/main/go.mod)\n[![Go Report][3]](https://goreportcard.com/badge/github.com/OwO-Network/DeepLX)\n[![GitHub License][4]](https://github.com/OwO-Network/DeepLX/blob/main/LICENSE)\n[![Docker Pulls][5]](https://hub.docker.com/r/missuo/deeplx)\n[![Releases][6]](https://github.com/OwO-Network/DeepLX/releases)\n\n[1]: https://img.shields.io/github/actions/workflow/status/OwO-Network/DeepLX/release.yaml?logo=github\n[2]: https://img.shields.io/github/go-mod/go-version/OwO-Network/DeepLX?logo=go\n[3]: https://goreportcard.com/badge/github.com/OwO-Network/DeepLX\n[4]: https://img.shields.io/github/license/OwO-Network/DeepLX\n[5]: https://img.shields.io/docker/pulls/missuo/deeplx?logo=docker\n[6]: https://img.shields.io/github/v/release/OwO-Network/DeepLX?logo=smartthings\n\n## How to use\n\n> \\[!TIP]\n>\n> Learn more about [📘 Using DeepLX](https://deeplx.owo.network) by checking it out.\n\n## Discussion Group\n[Telegram Group](https://t.me/+8KDGHKJCxEVkNzll)\n\n## Acknowledgements\n\n### Contributors\n\n<a href=\"https://github.com/OwO-Network/DeepLX/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=OwO-Network/DeepLX&anon=0\" />\n</a>\n\n## Activity\n![Alt](https://repobeats.axiom.co/api/embed/5f473f85db27cb30028a2f3db7a560f3577a4860.svg \"Repobeats analytics image\")\n\n## License\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FOwO-Network%2FDeepLX.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FOwO-Network%2FDeepLX?ref=badge_large)\n"
  },
  {
    "path": "compose.yaml",
    "content": "services:\n  deeplx:\n    image: ghcr.io/owo-network/deeplx:latest\n    restart: always\n    ports:\n      - \"1188:1188\"\n    # environment:\n      # - TOKEN=helloworld\n      # - DL_SESSION=xxxxxx\n"
  },
  {
    "path": "deeplx.service",
    "content": "[Unit]\nDescription=DeepLX Service\nAfter=network.target\n\n[Service]\nType=simple\nRestart=always\nWorkingDirectory=/usr/bin/\nExecStart=/usr/bin/deeplx\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/OwO-Network/DeepLX\n\ngo 1.25.0\n\nrequire (\n\tgithub.com/abadojack/whatlanggo v1.0.1\n\tgithub.com/andybalholm/brotli v1.2.0\n\tgithub.com/gin-contrib/cors v1.7.6\n\tgithub.com/gin-gonic/gin v1.11.0\n\tgithub.com/imroc/req/v3 v3.57.0\n\tgithub.com/tidwall/gjson v1.18.0\n)\n\nrequire (\n\tgithub.com/bytedance/gopkg v0.1.3 // indirect\n\tgithub.com/bytedance/sonic v1.15.0 // indirect\n\tgithub.com/bytedance/sonic/loader v0.5.0 // indirect\n\tgithub.com/cloudwego/base64x v0.1.6 // indirect\n\tgithub.com/gabriel-vasile/mimetype v1.4.13 // indirect\n\tgithub.com/gin-contrib/sse v1.1.0 // indirect\n\tgithub.com/go-playground/locales v0.14.1 // indirect\n\tgithub.com/go-playground/universal-translator v0.18.1 // indirect\n\tgithub.com/go-playground/validator/v10 v10.30.1 // indirect\n\tgithub.com/goccy/go-json v0.10.5 // indirect\n\tgithub.com/goccy/go-yaml v1.19.2 // indirect\n\tgithub.com/google/go-querystring v1.2.0 // indirect\n\tgithub.com/icholy/digest v1.1.0 // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/klauspost/compress v1.18.4 // indirect\n\tgithub.com/klauspost/cpuid/v2 v2.3.0 // indirect\n\tgithub.com/leodido/go-urn v1.4.0 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/pelletier/go-toml/v2 v2.2.4 // indirect\n\tgithub.com/quic-go/qpack v0.6.0 // indirect\n\tgithub.com/quic-go/quic-go v0.57.1 // indirect\n\tgithub.com/refraction-networking/utls v1.8.2 // indirect\n\tgithub.com/tidwall/match v1.2.0 // indirect\n\tgithub.com/tidwall/pretty v1.2.1 // indirect\n\tgithub.com/twitchyliquid64/golang-asm v0.15.1 // indirect\n\tgithub.com/ugorji/go/codec v1.3.1 // indirect\n\tgolang.org/x/arch v0.24.0 // indirect\n\tgolang.org/x/crypto v0.48.0 // indirect\n\tgolang.org/x/net v0.51.0 // indirect\n\tgolang.org/x/sys v0.41.0 // indirect\n\tgolang.org/x/text v0.34.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.11 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/abadojack/whatlanggo v1.0.1 h1:19N6YogDnf71CTHm3Mp2qhYfkRdyvbgwWdd2EPxJRG4=\ngithub.com/abadojack/whatlanggo v1.0.1/go.mod h1:66WiQbSbJBIlOZMsvbKe5m6pzQovxCH9B/K8tQB2uoc=\ngithub.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=\ngithub.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=\ngithub.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=\ngithub.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=\ngithub.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=\ngithub.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=\ngithub.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE=\ngithub.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=\ngithub.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=\ngithub.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=\ngithub.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=\ngithub.com/gin-contrib/cors v1.7.6 h1:3gQ8GMzs1Ylpf70y8bMw4fVpycXIeX1ZemuSQIsnQQY=\ngithub.com/gin-contrib/cors v1.7.6/go.mod h1:Ulcl+xN4jel9t1Ry8vqph23a60FwH9xVLd+3ykmTjOk=\ngithub.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=\ngithub.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=\ngithub.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=\ngithub.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=\ngithub.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=\ngithub.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=\ngithub.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=\ngithub.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=\ngithub.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=\ngithub.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=\ngithub.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=\ngithub.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=\ngithub.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=\ngithub.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=\ngithub.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=\ngithub.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0=\ngithub.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=\ngithub.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=\ngithub.com/imroc/req/v3 v3.57.0 h1:LMTUjNRUybUkTPn8oJDq8Kg3JRBOBTcnDhKu7mzupKI=\ngithub.com/imroc/req/v3 v3.57.0/go.mod h1:JL62ey1nvSLq81HORNcosvlf7SxZStONNqOprg0Pz00=\ngithub.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=\ngithub.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=\ngithub.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=\ngithub.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=\ngithub.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=\ngithub.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=\ngithub.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=\ngithub.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=\ngithub.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10=\ngithub.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s=\ngithub.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo=\ngithub.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=\ngithub.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=\ngithub.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=\ngithub.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM=\ngithub.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=\ngithub.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=\ngithub.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=\ngithub.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=\ngithub.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=\ngithub.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=\ngithub.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=\ngithub.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=\ngithub.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=\ngithub.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=\ngo.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=\ngo.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=\ngolang.org/x/arch v0.24.0 h1:qlJ3M9upxvFfwRM51tTg3Yl+8CP9vCC1E7vlFpgv99Y=\ngolang.org/x/arch v0.24.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=\ngolang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=\ngolang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=\ngolang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=\ngolang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=\ngolang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngolang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=\ngolang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=\ngolang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=\ngolang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=\ngotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=\n"
  },
  {
    "path": "install.sh",
    "content": "###\n # @Author: Vincent Young\n # @Date: 2023-02-12 09:53:21\n # @LastEditors: Vincent Young\n # @LastEditTime: 2023-02-12 10:01:57\n # @FilePath: /DeepLX/install.sh\n # @Telegram: https://t.me/missuo\n # \n # Copyright © 2023 by Vincent, All Rights Reserved. \n### \n\ninstall_deeplx(){\n    last_version=$(curl -Ls \"https://api.github.com/repos/OwO-Network/DeepLX/releases/latest\" | grep '\"tag_name\":' | sed -E 's/.*\"([^\"]+)\".*/\\1/')\n    if [[ ! -n \"$last_version\" ]]; then\n        echo -e \"${red}Failed to detect DeepLX version, probably due to exceeding Github API limitations.${plain}\"\n        exit 1\n    fi\n    echo -e \"DeepLX latest version: ${last_version}, Start install...\"\n    wget -q -N --no-check-certificate -O /usr/bin/deeplx https://github.com/OwO-Network/DeepLX/releases/download/${last_version}/deeplx_linux_amd64\n\n    chmod +x /usr/bin/deeplx\n    wget -q -N --no-check-certificate -O /etc/systemd/system/deeplx.service https://raw.githubusercontent.com/OwO-Network/DeepLX/main/deeplx.service\n    systemctl daemon-reload\n    systemctl enable deeplx\n    systemctl start deeplx\n    echo -e \"Installed successfully, listening at 0.0.0.0:1188\"\n}\ninstall_deeplx\n"
  },
  {
    "path": "main.go",
    "content": "/*\n * @Author: Vincent Yang\n * @Date: 2023-07-01 21:45:34\n * @LastEditors: Jason Lyu\n * @LastEditTime: 2025-04-08 13:45:00\n * @FilePath: /DeepLX/main.go\n * @Telegram: https://t.me/missuo\n * @GitHub: https://github.com/missuo\n *\n * Copyright © 2024 by Vincent, All Rights Reserved.\n */\n\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/OwO-Network/DeepLX/service\"\n)\n\nfunc main() {\n\tcfg := service.InitConfig()\n\n\tfmt.Printf(\"DeepL X has been successfully launched! Listening on %v:%v\\n\", cfg.IP, cfg.Port)\n\tfmt.Println(\"Developed by sjlleo <i@leo.moe> and missuo <me@missuo.me>.\")\n\n\t// Setting the application to release mode\n\tgin.SetMode(gin.ReleaseMode)\n\n\tapp := service.Router(cfg)\n\tapp.Run(fmt.Sprintf(\"%v:%v\", cfg.IP, cfg.Port))\n}\n"
  },
  {
    "path": "me.missuo.deeplx.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Label</key>\n\t<string>me.missuo.deeplx</string>\n\t<key>KeepAlive</key>\n\t<true/>\n\t<key>ProgramArguments</key>\n\t<array>\n\t\t<string>/usr/local/bin/deeplx</string>\n\t</array>\n\t<key>RunAtLoad</key>\n\t<true/>\n\t<key>OnDemand</key>\n\t<false/>\n\t<key>LaunchOnlyOnce</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "service/config.go",
    "content": "/*\n * @Author: Vincent Yang\n * @Date: 2024-04-23 00:39:03\n * @LastEditors: Jason Lyu\n * @LastEditTime: 2025-04-08 13:45:00\n * @FilePath: /DeepLX/config.go\n * @Telegram: https://t.me/missuo\n * @GitHub: https://github.com/missuo\n *\n * Copyright © 2024 by Vincent, All Rights Reserved.\n */\n\npackage service\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n)\n\ntype Config struct {\n\tIP        string\n\tPort      int\n\tToken     string\n\tDlSession string\n\tProxy     string\n}\n\nfunc InitConfig() *Config {\n\tcfg := &Config{\n\t\tIP:   \"0.0.0.0\",\n\t\tPort: 1188,\n\t}\n\n\t// IP flag\n\tif ip, ok := os.LookupEnv(\"IP\"); ok && ip != \"\" {\n\t\tcfg.IP = ip\n\t}\n\tflag.StringVar(&cfg.IP, \"ip\", cfg.IP, \"set up the IP address to bind to\")\n\tflag.StringVar(&cfg.IP, \"i\", cfg.IP, \"set up the IP address to bind to\")\n\n\t// Port flag\n\tif port, ok := os.LookupEnv(\"PORT\"); ok && port != \"\" {\n\t\tfmt.Sscanf(port, \"%d\", &cfg.Port)\n\t}\n\tflag.IntVar(&cfg.Port, \"port\", cfg.Port, \"set up the port to listen on\")\n\tflag.IntVar(&cfg.Port, \"p\", cfg.Port, \"set up the port to listen on\")\n\n\t// DL Session flag\n\tflag.StringVar(&cfg.DlSession, \"s\", \"\", \"set the dl-session for /v1/translate endpoint\")\n\tif cfg.DlSession == \"\" {\n\t\tif dlSession, ok := os.LookupEnv(\"DL_SESSION\"); ok {\n\t\t\tcfg.DlSession = dlSession\n\t\t}\n\t}\n\n\t// Access token flag\n\tflag.StringVar(&cfg.Token, \"token\", \"\", \"set the access token for /translate endpoint\")\n\tif cfg.Token == \"\" {\n\t\tif token, ok := os.LookupEnv(\"TOKEN\"); ok {\n\t\t\tcfg.Token = token\n\t\t}\n\t}\n\n\t// HTTP Proxy flag\n\tflag.StringVar(&cfg.Proxy, \"proxy\", \"\", \"set the proxy URL for HTTP requests\")\n\tif cfg.Proxy == \"\" {\n\t\tif proxy, ok := os.LookupEnv(\"PROXY\"); ok {\n\t\t\tcfg.Proxy = proxy\n\t\t}\n\t}\n\n\tflag.Parse()\n\treturn cfg\n}\n"
  },
  {
    "path": "service/service.go",
    "content": "/*\n * @Author: Vincent Yang\n * @Date: 2023-07-01 21:45:34\n * @LastEditors: Jason Lyu\n * @LastEditTime: 2025-04-08 13:45:00\n * @FilePath: /DeepLX/main.go\n * @Telegram: https://t.me/missuo\n * @GitHub: https://github.com/missuo\n *\n * Copyright © 2024 by Vincent, All Rights Reserved.\n */\n\npackage service\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/gin-contrib/cors\"\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/OwO-Network/DeepLX/translate\"\n)\n\nfunc authMiddleware(cfg *Config) gin.HandlerFunc {\n\treturn func(c *gin.Context) {\n\t\tif cfg.Token != \"\" {\n\t\t\tprovidedTokenInQuery := c.Query(\"token\")\n\t\t\tprovidedTokenInHeader := c.GetHeader(\"Authorization\")\n\n\t\t\t// Compatability with the Bearer token format\n\t\t\tif providedTokenInHeader != \"\" {\n\t\t\t\tparts := strings.Split(providedTokenInHeader, \" \")\n\t\t\t\tif len(parts) == 2 {\n\t\t\t\t\tif parts[0] == \"Bearer\" || parts[0] == \"DeepL-Auth-Key\" {\n\t\t\t\t\t\tprovidedTokenInHeader = parts[1]\n\t\t\t\t\t} else {\n\t\t\t\t\t\tprovidedTokenInHeader = \"\"\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tprovidedTokenInHeader = \"\"\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif providedTokenInHeader != cfg.Token && providedTokenInQuery != cfg.Token {\n\t\t\t\tc.JSON(http.StatusUnauthorized, gin.H{\n\t\t\t\t\t\"code\":    http.StatusUnauthorized,\n\t\t\t\t\t\"message\": \"Invalid access token\",\n\t\t\t\t})\n\t\t\t\tc.Abort()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tc.Next()\n\t}\n}\n\ntype PayloadFree struct {\n\tTransText   string `json:\"text\"`\n\tSourceLang  string `json:\"source_lang\"`\n\tTargetLang  string `json:\"target_lang\"`\n\tTagHandling string `json:\"tag_handling\"`\n}\n\ntype PayloadAPI struct {\n\tText        []string `json:\"text\"`\n\tTargetLang  string   `json:\"target_lang\"`\n\tSourceLang  string   `json:\"source_lang\"`\n\tTagHandling string   `json:\"tag_handling\"`\n}\n\nfunc Router(cfg *Config) *gin.Engine {\n\t// Set Proxy\n\tproxyURL := os.Getenv(\"PROXY\")\n\tif proxyURL == \"\" {\n\t\tproxyURL = cfg.Proxy\n\t}\n\tif proxyURL != \"\" {\n\t\tproxy, err := url.Parse(proxyURL)\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"Failed to parse proxy URL: %v\", err)\n\t\t}\n\t\thttp.DefaultTransport = &http.Transport{\n\t\t\tProxy: http.ProxyURL(proxy),\n\t\t}\n\t}\n\n\tif cfg.Token != \"\" {\n\t\tfmt.Println(\"Access token is set.\")\n\t}\n\n\tr := gin.Default()\n\tr.Use(cors.Default())\n\n\t// Defining the root endpoint which returns the project details\n\tr.GET(\"/\", func(c *gin.Context) {\n\t\tc.JSON(http.StatusOK, gin.H{\n\t\t\t\"code\":    http.StatusOK,\n\t\t\t\"message\": \"DeepL Free API, Developed by sjlleo and missuo. Go to /translate with POST. http://github.com/OwO-Network/DeepLX\",\n\t\t})\n\t})\n\n\t// Free API endpoint, No Pro Account required\n\tr.POST(\"/translate\", authMiddleware(cfg), func(c *gin.Context) {\n\t\treq := PayloadFree{}\n\t\tc.BindJSON(&req)\n\n\t\tsourceLang := req.SourceLang\n\t\ttargetLang := req.TargetLang\n\t\ttranslateText := req.TransText\n\t\ttagHandling := req.TagHandling\n\n\t\tproxyURL := cfg.Proxy\n\n\t\tif tagHandling != \"\" && tagHandling != \"html\" && tagHandling != \"xml\" {\n\t\t\tc.JSON(http.StatusBadRequest, gin.H{\n\t\t\t\t\"code\":    http.StatusBadRequest,\n\t\t\t\t\"message\": \"Invalid tag_handling value. Allowed values are 'html' and 'xml'.\",\n\t\t\t})\n\t\t\treturn\n\t\t}\n\n\t\tresult, err := translate.TranslateByDeepLX(sourceLang, targetLang, translateText, tagHandling, proxyURL, \"\")\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"Translation failed: %s\", err)\n\t\t}\n\n\t\tif result.Code == http.StatusOK {\n\t\t\tc.JSON(http.StatusOK, gin.H{\n\t\t\t\t\"code\":         http.StatusOK,\n\t\t\t\t\"id\":           result.ID,\n\t\t\t\t\"data\":         result.Data,\n\t\t\t\t\"alternatives\": result.Alternatives,\n\t\t\t\t\"source_lang\":  result.SourceLang,\n\t\t\t\t\"target_lang\":  result.TargetLang,\n\t\t\t\t\"method\":       result.Method,\n\t\t\t})\n\t\t} else {\n\t\t\tc.JSON(result.Code, gin.H{\n\t\t\t\t\"code\":    result.Code,\n\t\t\t\t\"message\": result.Message,\n\t\t\t})\n\n\t\t}\n\t})\n\n\t// Pro API endpoint, Pro Account required\n\tr.POST(\"/v1/translate\", authMiddleware(cfg), func(c *gin.Context) {\n\t\treq := PayloadFree{}\n\t\tc.BindJSON(&req)\n\n\t\tsourceLang := req.SourceLang\n\t\ttargetLang := req.TargetLang\n\t\ttranslateText := req.TransText\n\t\ttagHandling := req.TagHandling\n\t\tproxyURL := cfg.Proxy\n\n\t\tdlSession := cfg.DlSession\n\n\t\tif tagHandling != \"\" && tagHandling != \"html\" && tagHandling != \"xml\" {\n\t\t\tc.JSON(http.StatusBadRequest, gin.H{\n\t\t\t\t\"code\":    http.StatusBadRequest,\n\t\t\t\t\"message\": \"Invalid tag_handling value. Allowed values are 'html' and 'xml'.\",\n\t\t\t})\n\t\t\treturn\n\t\t}\n\n\t\tcookie := c.GetHeader(\"Cookie\")\n\t\tif cookie != \"\" {\n\t\t\tdlSession = strings.Replace(cookie, \"dl_session=\", \"\", -1)\n\t\t}\n\n\t\tif dlSession == \"\" {\n\t\t\tc.JSON(http.StatusUnauthorized, gin.H{\n\t\t\t\t\"code\":    http.StatusUnauthorized,\n\t\t\t\t\"message\": \"No dl_session Found\",\n\t\t\t})\n\t\t\treturn\n\t\t} else if strings.Contains(dlSession, \".\") {\n\t\t\tc.JSON(http.StatusUnauthorized, gin.H{\n\t\t\t\t\"code\":    http.StatusUnauthorized,\n\t\t\t\t\"message\": \"Your account is not a Pro account. Please upgrade your account or switch to a different account.\",\n\t\t\t})\n\t\t\treturn\n\t\t}\n\n\t\tresult, err := translate.TranslateByDeepLX(sourceLang, targetLang, translateText, tagHandling, proxyURL, dlSession)\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"Translation failed: %s\", err)\n\t\t}\n\n\t\tif result.Code == http.StatusOK {\n\t\t\tc.JSON(http.StatusOK, gin.H{\n\t\t\t\t\"code\":         http.StatusOK,\n\t\t\t\t\"id\":           result.ID,\n\t\t\t\t\"data\":         result.Data,\n\t\t\t\t\"alternatives\": result.Alternatives,\n\t\t\t\t\"source_lang\":  result.SourceLang,\n\t\t\t\t\"target_lang\":  result.TargetLang,\n\t\t\t\t\"method\":       result.Method,\n\t\t\t})\n\t\t} else {\n\t\t\tc.JSON(result.Code, gin.H{\n\t\t\t\t\"code\":    result.Code,\n\t\t\t\t\"message\": result.Message,\n\t\t\t})\n\n\t\t}\n\t})\n\n\t// Free API endpoint, Consistent with the official API format\n\tr.POST(\"/v2/translate\", authMiddleware(cfg), func(c *gin.Context) {\n\t\tproxyURL := cfg.Proxy\n\n\t\tvar translateText string\n\t\tvar targetLang string\n\n\t\ttranslateText = c.PostForm(\"text\")\n\t\ttargetLang = c.PostForm(\"target_lang\")\n\n\t\tif translateText == \"\" || targetLang == \"\" {\n\t\t\tvar jsonData struct {\n\t\t\t\tText       []string `json:\"text\"`\n\t\t\t\tTargetLang string   `json:\"target_lang\"`\n\t\t\t}\n\n\t\t\tif err := c.BindJSON(&jsonData); err != nil {\n\t\t\t\tc.JSON(http.StatusBadRequest, gin.H{\n\t\t\t\t\t\"code\":    http.StatusBadRequest,\n\t\t\t\t\t\"message\": \"Invalid request payload\",\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttranslateText = strings.Join(jsonData.Text, \"\\n\")\n\t\t\ttargetLang = jsonData.TargetLang\n\t\t}\n\n\t\tresult, err := translate.TranslateByDeepLX(\"\", targetLang, translateText, \"\", proxyURL, \"\")\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"Translation failed: %s\", err)\n\t\t}\n\n\t\tif result.Code == http.StatusOK {\n\t\t\tc.JSON(http.StatusOK, gin.H{\n\t\t\t\t\"translations\": []map[string]interface{}{\n\t\t\t\t\t{\n\t\t\t\t\t\t\"detected_source_language\": result.SourceLang,\n\t\t\t\t\t\t\"text\":                     result.Data,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t} else {\n\t\t\tc.JSON(result.Code, gin.H{\n\t\t\t\t\"code\":    result.Code,\n\t\t\t\t\"message\": result.Message,\n\t\t\t})\n\t\t}\n\t})\n\n\t// Catch-all route to handle undefined paths\n\tr.NoRoute(func(c *gin.Context) {\n\t\tc.JSON(http.StatusNotFound, gin.H{\n\t\t\t\"code\":    http.StatusNotFound,\n\t\t\t\"message\": \"Path not found\",\n\t\t})\n\t})\n\n\treturn r\n}\n"
  },
  {
    "path": "translate/translate.go",
    "content": "/*\n * @Author: Vincent Young\n * @Date: 2024-09-16 11:59:24\n * @LastEditors: Vincent Yang\n * @LastEditTime: 2025-07-13 23:09:49\n * @FilePath: /DeepLX/translate/translate.go\n * @Telegram: https://t.me/missuo\n * @GitHub: https://github.com/missuo\n *\n * Copyright © 2024 by Vincent, All Rights Reserved.\n */\n\npackage translate\n\nimport (\n\t\"bytes\"\n\t\"compress/flate\"\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/abadojack/whatlanggo\"\n\t\"github.com/imroc/req/v3\"\n\n\t\"github.com/andybalholm/brotli\"\n\t\"github.com/tidwall/gjson\"\n)\n\n// makeRequestWithBody makes an HTTP request with pre-formatted body using minimal headers\nfunc makeRequestWithBody(postStr string, proxyURL string, dlSession string) (gjson.Result, error) {\n\turlFull := \"https://www2.deepl.com/jsonrpc\"\n\n\t// Create a new req client\n\tclient := req.C().SetTLSFingerprintRandomized()\n\n\t// Set headers to simulate browser request\n\theaders := http.Header{\n\t\t\"Content-Type\":    []string{\"application/json\"},\n\t\t\"Accept\":          []string{\"*/*\"},\n\t\t\"Accept-Language\": []string{\"en-US,en;q=0.9\"},\n\t\t\"Accept-Encoding\": []string{\"gzip, deflate, br, zstd\"},\n\t\t\"Origin\":          []string{\"https://www.deepl.com\"},\n\t\t\"Referer\":         []string{\"https://www.deepl.com/\"},\n\t\t\"Sec-Fetch-Dest\":  []string{\"empty\"},\n\t\t\"Sec-Fetch-Mode\":  []string{\"cors\"},\n\t\t\"Sec-Fetch-Site\":  []string{\"same-site\"},\n\t\t\"User-Agent\":      []string{\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0\"},\n\t}\n\n\tif dlSession != \"\" {\n\t\theaders.Set(\"Cookie\", \"dl_session=\"+dlSession)\n\t}\n\n\t// Set proxy if provided\n\tif proxyURL != \"\" {\n\t\tproxy, err := url.Parse(proxyURL)\n\t\tif err != nil {\n\t\t\treturn gjson.Result{}, err\n\t\t}\n\t\tclient.SetProxyURL(proxy.String())\n\t}\n\n\t// Make the request\n\tr := client.R()\n\tr.Headers = headers\n\tresp, err := r.\n\t\tSetBody(bytes.NewReader([]byte(postStr))).\n\t\tPost(urlFull)\n\n\tif err != nil {\n\t\treturn gjson.Result{}, err\n\t}\n\n\t// Check for blocked status like TypeScript version\n\tif resp.StatusCode == 429 {\n\t\treturn gjson.Result{}, fmt.Errorf(\"too many requests, your IP has been blocked by DeepL temporarily, please don't request it frequently in a short time\")\n\t}\n\n\t// Check for other error status codes\n\tif resp.StatusCode != 200 {\n\t\treturn gjson.Result{}, fmt.Errorf(\"request failed with status code: %d\", resp.StatusCode)\n\t}\n\n\tvar bodyReader io.Reader\n\tcontentEncoding := resp.Header.Get(\"Content-Encoding\")\n\tswitch contentEncoding {\n\tcase \"br\":\n\t\tbodyReader = brotli.NewReader(resp.Body)\n\tcase \"gzip\":\n\t\tbodyReader, err = gzip.NewReader(resp.Body)\n\t\tif err != nil {\n\t\t\treturn gjson.Result{}, fmt.Errorf(\"failed to create gzip reader: %w\", err)\n\t\t}\n\tcase \"deflate\":\n\t\tbodyReader = flate.NewReader(resp.Body)\n\tdefault:\n\t\tbodyReader = resp.Body\n\t}\n\n\tbody, err := io.ReadAll(bodyReader)\n\tif err != nil {\n\t\treturn gjson.Result{}, fmt.Errorf(\"failed to read response body: %w\", err)\n\t}\n\treturn gjson.ParseBytes(body), nil\n}\n\n// TranslateByDeepLX performs translation using DeepL API\nfunc TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string, proxyURL string, dlSession string) (DeepLXTranslationResult, error) {\n\tif text == \"\" {\n\t\treturn DeepLXTranslationResult{\n\t\t\tCode:    http.StatusNotFound,\n\t\t\tMessage: \"No text to translate\",\n\t\t}, nil\n\t}\n\n\t// Get detected language if source language is auto\n\tif sourceLang == \"auto\" || sourceLang == \"\" {\n\t\tsourceLang = strings.ToUpper(whatlanggo.DetectLang(text).Iso6391())\n\t}\n\n\t// Prepare translation request using new LMT_handle_texts method\n\tid := getRandomNumber()\n\tiCount := getICount(text)\n\ttimestamp := getTimeStamp(iCount)\n\n\tpostData := &PostData{\n\t\tJsonrpc: \"2.0\",\n\t\tMethod:  \"LMT_handle_texts\",\n\t\tID:      id,\n\t\tParams: Params{\n\t\t\tSplitting: \"newlines\",\n\t\t\tLang: Lang{\n\t\t\t\tSourceLangUserSelected: sourceLang,\n\t\t\t\tTargetLang:             targetLang,\n\t\t\t},\n\t\t\tTexts: []TextItem{{\n\t\t\t\tText:                text,\n\t\t\t\tRequestAlternatives: 3,\n\t\t\t}},\n\t\t\tTimestamp: timestamp,\n\t\t},\n\t}\n\n\t// Format and apply body manipulation method like TypeScript\n\tpostStr := formatPostString(postData)\n\tpostStr = handlerBodyMethod(id, postStr)\n\n\t// Make translation request\n\tresult, err := makeRequestWithBody(postStr, proxyURL, dlSession)\n\tif err != nil {\n\t\treturn DeepLXTranslationResult{\n\t\t\tCode:    http.StatusServiceUnavailable,\n\t\t\tMessage: err.Error(),\n\t\t}, nil\n\t}\n\n\t// Process translation results using new format\n\ttextsArray := result.Get(\"result.texts\").Array()\n\tif len(textsArray) == 0 {\n\t\treturn DeepLXTranslationResult{\n\t\t\tCode:    http.StatusServiceUnavailable,\n\t\t\tMessage: \"Translation failed\",\n\t\t}, nil\n\t}\n\n\t// Get main translation\n\tmainText := textsArray[0].Get(\"text\").String()\n\tif mainText == \"\" {\n\t\treturn DeepLXTranslationResult{\n\t\t\tCode:    http.StatusServiceUnavailable,\n\t\t\tMessage: \"Translation failed\",\n\t\t}, nil\n\t}\n\n\t// Get alternatives\n\tvar alternatives []string\n\talternativesArray := textsArray[0].Get(\"alternatives\").Array()\n\tfor _, alt := range alternativesArray {\n\t\taltText := alt.Get(\"text\").String()\n\t\tif altText != \"\" {\n\t\t\talternatives = append(alternatives, altText)\n\t\t}\n\t}\n\n\t// Get detected source language from response\n\tdetectedLang := result.Get(\"result.lang\").String()\n\tif detectedLang != \"\" {\n\t\tsourceLang = detectedLang\n\t}\n\n\treturn DeepLXTranslationResult{\n\t\tCode:         http.StatusOK,\n\t\tID:           id,\n\t\tData:         mainText,\n\t\tAlternatives: alternatives,\n\t\tSourceLang:   sourceLang,\n\t\tTargetLang:   targetLang,\n\t\tMethod:       map[bool]string{true: \"Pro\", false: \"Free\"}[dlSession != \"\"],\n\t}, nil\n}\n"
  },
  {
    "path": "translate/types.go",
    "content": "/*\n * @Author: Vincent Young\n * @Date: 2024-09-16 11:59:24\n * @LastEditors: Vincent Yang\n * @LastEditTime: 2025-03-01 04:16:07\n * @FilePath: /DeepLX/translate/types.go\n * @Telegram: https://t.me/missuo\n * @GitHub: https://github.com/missuo\n *\n * Copyright © 2024 by Vincent, All Rights Reserved.\n */\n\npackage translate\n\n// Lang represents the language settings for translation\ntype Lang struct {\n\tSourceLangUserSelected string `json:\"source_lang_user_selected\"` // Can be \"auto\"\n\tTargetLang             string `json:\"target_lang\"`\n\tSourceLangComputed     string `json:\"source_lang_computed,omitempty\"`\n}\n\n// CommonJobParams represents common parameters for translation jobs\ntype CommonJobParams struct {\n\tFormality       string `json:\"formality\"` // Can be \"undefined\"\n\tTranscribeAs    string `json:\"transcribe_as\"`\n\tMode            string `json:\"mode\"`\n\tWasSpoken       bool   `json:\"wasSpoken\"`\n\tAdvancedMode    bool   `json:\"advancedMode\"`\n\tTextType        string `json:\"textType\"`\n\tRegionalVariant string `json:\"regionalVariant,omitempty\"`\n}\n\n// Sentence represents a sentence in the translation request\ntype Sentence struct {\n\tPrefix string `json:\"prefix\"`\n\tText   string `json:\"text\"`\n\tID     int    `json:\"id\"`\n}\n\n// Job represents a translation job\ntype Job struct {\n\tKind               string     `json:\"kind\"`\n\tPreferredNumBeams  int        `json:\"preferred_num_beams\"`\n\tRawEnContextBefore []string   `json:\"raw_en_context_before\"`\n\tRawEnContextAfter  []string   `json:\"raw_en_context_after\"`\n\tSentences          []Sentence `json:\"sentences\"`\n}\n\n// TextItem represents a text item for translation\ntype TextItem struct {\n\tText                string `json:\"text\"`\n\tRequestAlternatives int    `json:\"requestAlternatives\"`\n}\n\n// Params represents parameters for translation requests\ntype Params struct {\n\tSplitting string     `json:\"splitting\"`\n\tLang      Lang       `json:\"lang\"`\n\tTexts     []TextItem `json:\"texts\"`\n\tTimestamp int64      `json:\"timestamp\"`\n}\n\n// LegacyParams represents the old parameters structure for jobs (kept for compatibility)\ntype LegacyParams struct {\n\tCommonJobParams CommonJobParams `json:\"commonJobParams\"`\n\tLang            Lang            `json:\"lang\"`\n\tJobs            []Job           `json:\"jobs\"`\n\tTimestamp       int64           `json:\"timestamp\"`\n}\n\n// PostData represents the complete translation request\ntype PostData struct {\n\tJsonrpc string `json:\"jsonrpc\"`\n\tMethod  string `json:\"method\"`\n\tID      int64  `json:\"id\"`\n\tParams  Params `json:\"params\"`\n}\n\n// TextResponse represents a single text response\ntype TextResponse struct {\n\tText         string   `json:\"text\"`\n\tAlternatives []struct {\n\t\tText string `json:\"text\"`\n\t} `json:\"alternatives\"`\n}\n\n// TranslationResponse represents the response from LMT_handle_texts\ntype TranslationResponse struct {\n\tJsonrpc string `json:\"jsonrpc\"`\n\tID      int64  `json:\"id\"`\n\tResult  struct {\n\t\tLang  string          `json:\"lang\"`\n\t\tTexts []TextResponse  `json:\"texts\"`\n\t} `json:\"result\"`\n}\n\n// LegacyTranslationResponse represents the old response format (kept for compatibility)\ntype LegacyTranslationResponse struct {\n\tJsonrpc string `json:\"jsonrpc\"`\n\tID      int64  `json:\"id\"`\n\tResult  struct {\n\t\tTranslations []struct {\n\t\t\tBeams []struct {\n\t\t\t\tSentences       []SentenceResponse `json:\"sentences\"`\n\t\t\t\tNumSymbols      int                `json:\"num_symbols\"`\n\t\t\t\tRephraseVariant struct {           // Added rephrase_variant\n\t\t\t\t\tName string `json:\"name\"`\n\t\t\t\t} `json:\"rephrase_variant\"`\n\t\t\t} `json:\"beams\"`\n\t\t\tQuality string `json:\"quality\"` // Added quality\n\t\t} `json:\"translations\"`\n\t\tTargetLang            string                 `json:\"target_lang\"`\n\t\tSourceLang            string                 `json:\"source_lang\"`\n\t\tSourceLangIsConfident bool                   `json:\"source_lang_is_confident\"`\n\t\tDetectedLanguages     map[string]interface{} `json:\"detectedLanguages\"` // Use interface{} for now\n\t} `json:\"result\"`\n}\n\n// SentenceResponse is a helper struct for the response sentences\ntype SentenceResponse struct {\n\tText string `json:\"text\"`\n\tIDS  []int  `json:\"ids\"` // Added IDS\n}\n\n// DeepLXTranslationResult represents the final translation result\ntype DeepLXTranslationResult struct {\n\tCode         int      `json:\"code\"`\n\tID           int64    `json:\"id\"`\n\tMessage      string   `json:\"message,omitempty\"`\n\tData         string   `json:\"data\"`         // The primary translated text\n\tAlternatives []string `json:\"alternatives\"` // Other possible translations\n\tSourceLang   string   `json:\"source_lang\"`\n\tTargetLang   string   `json:\"target_lang\"`\n\tMethod       string   `json:\"method\"`\n}\n"
  },
  {
    "path": "translate/utils.go",
    "content": "/*\n * @Author: Vincent Young\n * @Date: 2024-09-16 11:59:24\n * @LastEditors: Vincent Yang\n * @LastEditTime: 2025-04-08 14:27:21\n * @FilePath: /DeepLX/translate/utils.go\n * @Telegram: https://t.me/missuo\n * @GitHub: https://github.com/missuo\n *\n * Copyright © 2024 by Vincent, All Rights Reserved.\n */\n\npackage translate\n\nimport (\n\t\"encoding/json\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"time\"\n)\n\n// getICount returns the number of 'i' characters in the text\nfunc getICount(translateText string) int64 {\n\treturn int64(strings.Count(translateText, \"i\"))\n}\n\n// getRandomNumber generates a random number for request ID\nfunc getRandomNumber() int64 {\n\tsrc := rand.NewSource(time.Now().UnixNano())\n\trng := rand.New(src)\n\tnum := rng.Int63n(99999) + 100000\n\treturn num * 1000\n}\n\n// getTimeStamp generates timestamp for request based on i count\nfunc getTimeStamp(iCount int64) int64 {\n\tts := time.Now().UnixMilli()\n\tif iCount != 0 {\n\t\tiCount = iCount + 1\n\t\treturn ts - (ts % iCount) + iCount\n\t}\n\treturn ts\n}\n\n// formatPostString formats the request JSON string with specific spacing rules\nfunc formatPostString(postData *PostData) string {\n\tpostBytes, _ := json.Marshal(postData)\n\tpostStr := string(postBytes)\n\treturn postStr\n}\n\n// handlerBodyMethod manipulates the request body based on random number calculation\nfunc handlerBodyMethod(random int64, body string) string {\n\tcalc := (random+5)%29 == 0 || (random+3)%13 == 0\n\tif calc {\n\t\treturn strings.Replace(body, `\"method\":\"`, `\"method\" : \"`, 1)\n\t}\n\treturn strings.Replace(body, `\"method\":\"`, `\"method\": \"`, 1)\n}\n"
  },
  {
    "path": "uninstall.sh",
    "content": "#!/bin/bash\n\n# Colors\nred='\\033[0;31m'\ngreen='\\033[0;32m'\nyellow='\\033[0;33m'\nplain='\\033[0m'\n\n# Check for root privileges\nif [[ $EUID -ne 0 ]]; then\n    echo -e \"${red}This script must be run as root.${plain}\"\n    exit 1\nfi\n\nuninstall_deeplx() {\n    echo -e \"${green}Starting DeepLX uninstallation...${plain}\"\n\n    # 1. Stop and disable the DeepLX service\n    if systemctl is-active --quiet deeplx; then\n        echo -e \"${yellow}Stopping DeepLX service...${plain}\"\n        systemctl stop deeplx\n    else\n        echo -e \"${yellow}DeepLX service is not running or not found.${plain}\"\n    fi\n\n    if systemctl is-enabled --quiet deeplx; then\n        echo -e \"${yellow}Disabling DeepLX service from starting on boot...${plain}\"\n        systemctl disable deeplx\n    else\n        echo -e \"${yellow}DeepLX service is not enabled.${plain}\"\n    fi\n\n    # 2. Remove the systemd service file\n    if [ -f /etc/systemd/system/deeplx.service ]; then\n        echo -e \"${yellow}Removing DeepLX systemd service file (/etc/systemd/system/deeplx.service)...${plain}\"\n        rm -f /etc/systemd/system/deeplx.service\n        systemctl daemon-reload\n        echo -e \"${green}Systemd daemon reloaded.${plain}\"\n    else\n        echo -e \"${yellow}DeepLX systemd service file not found, skipping removal.${plain}\"\n    fi\n\n    # 3. Remove the DeepLX executable\n    if [ -f /usr/bin/deeplx ]; then\n        echo -e \"${yellow}Removing DeepLX executable (/usr/bin/deeplx)...${plain}\"\n        rm -f /usr/bin/deeplx\n    else\n        echo -e \"${yellow}DeepLX executable not found, skipping removal.${plain}\"\n    fi\n\n    echo -e \"${green}DeepLX uninstallation complete.${plain}\"\n    echo -e \"${green}If you wish to reinstall, please run the install script again.${plain}\"\n}\n\nuninstall_deeplx\n"
  }
]