├── .github └── workflows │ └── docker-publish.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── client ├── assets │ ├── bitplay_logo.png │ ├── butterup.min.css │ ├── butterup.min.js │ ├── favicon.png │ ├── index.css │ ├── index.js │ ├── output.css │ └── videojs.hotkeys.min.js └── index.html ├── go.mod ├── go.sum ├── main.go ├── package-lock.json ├── package.json └── screenshots ├── bitplay_home.png ├── bitplay_jackett_integration.png ├── bitplay_prowlarr_integration.png ├── bitplay_proxy_settings.png └── bitplay_video_player.png /.github/workflows/docker-publish.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | on: 4 | schedule: 5 | - cron: '40 6 * * *' 6 | push: 7 | branches: [ "main" ] 8 | tags: [ 'v*.*.*' ] 9 | pull_request: 10 | branches: [ "main" ] 11 | env: 12 | REGISTRY: ghcr.io 13 | IMAGE_NAME: ${{ github.repository }} 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | permissions: 18 | contents: read 19 | packages: write 20 | id-token: write 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Install cosign 26 | if: github.event_name != 'pull_request' 27 | uses: sigstore/cosign-installer@v3.5.0 28 | with: 29 | cosign-release: 'v2.2.4' 30 | 31 | - name: Set up Docker Buildx 32 | uses: docker/setup-buildx-action@v3.0.0 33 | 34 | - name: Log into registry ${{ env.REGISTRY }} 35 | if: github.event_name != 'pull_request' 36 | uses: docker/login-action@v3.0.0 37 | with: 38 | registry: ${{ env.REGISTRY }} 39 | username: ${{ github.actor }} 40 | password: ${{ secrets.GIT_TOKEN }} 41 | 42 | - name: Extract Docker metadata 43 | id: meta 44 | uses: docker/metadata-action@v5.0.0 45 | with: 46 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 47 | 48 | - name: Build and push Docker image 49 | id: build-and-push 50 | uses: docker/build-push-action@v5.0.0 51 | with: 52 | context: . 53 | push: ${{ github.event_name != 'pull_request' }} 54 | tags: ${{ steps.meta.outputs.tags }} 55 | labels: ${{ steps.meta.outputs.labels }} 56 | platforms: linux/arm64,linux/amd64 57 | cache-from: type=gha 58 | cache-to: type=gha,mode=max 59 | 60 | - name: Sign the published Docker image 61 | if: ${{ github.event_name != 'pull_request' }} 62 | env: 63 | TAGS: ${{ steps.meta.outputs.tags }} 64 | DIGEST: ${{ steps.build-and-push.outputs.digest }} 65 | run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.DS_Store -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage 2 | FROM golang:1.24-alpine AS builder 3 | 4 | # Set working directory for the build 5 | WORKDIR /app 6 | 7 | # Copy module files first to leverage Docker cache 8 | COPY go.mod go.sum ./ 9 | RUN go mod download 10 | 11 | # Copy all source files including client directory 12 | COPY . . 13 | 14 | # Build the Go app with static linking 15 | RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o main . 16 | 17 | # Final stage 18 | FROM alpine:3.18 19 | RUN apk --no-cache add ca-certificates 20 | 21 | # Set working directory in final image 22 | WORKDIR /app 23 | 24 | # Copy the compiled binary from builder 25 | COPY --from=builder /app/main . 26 | 27 | # Copy client directory from builder 28 | COPY --from=builder /app/client ./client/ 29 | 30 | # Expose the port your app runs on 31 | EXPOSE 3347 32 | 33 | # Command to run the application 34 | CMD ["/app/main"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Aculix Technologies LLP. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BitPlay: Torrent Streaming Web App 2 | 3 | BitPlay is a web application built with Go that allows you to stream video content directly from torrents in your browser. It features a clean web UI, support for SOCKS5 proxies, and integration with Prowlarr and Jackett for seamless torrent searching. 4 | 5 | ![Bitplay Home](screenshots/bitplay_home.png) 6 | 7 | ## Features 8 | 9 | * **Direct Torrent Streaming:** Stream video files from magnet links or torrent files directly without needing to download them completely first. 10 | * **Web-Based UI:** Access and control BitPlay through a user-friendly web interface. 11 | * **Proxy Support:** Configure a SOCKS5 proxy for all torrent-related traffic (fetching metadata, peer connections). (Note: HTTP proxies are not currently supported). 12 | * **Prowlarr Integration:** Connect to your Prowlarr instance to search across your configured indexers directly within BitPlay. 13 | * **Jackett Integration:** Connect to your Jackett instance as an alternative search provider. 14 | * **On-the-fly Subtitle Conversion:** Converts SRT subtitles to VTT format for browser compatibility. 15 | * **Session Management:** Handles multiple torrent sessions and cleans up inactive ones. 16 | 17 | ## Getting Started 18 | 19 | You can run BitPlay either directly using Go or via Docker Compose. 20 | 21 | ### Prerequisites 22 | 23 | * **Go:** Requires Go 1.18 or later (if running locally). 24 | * **Docker & Docker Compose:** Required if running with Docker. 25 | 26 | ### Running Locally with Go 27 | 28 | 1. **Clone the repository:** 29 | ```bash 30 | git clone https://github.com/aculix/bitplay.git 31 | cd bitplay 32 | ``` 33 | 2. **Download dependencies:** 34 | ```bash 35 | go mod download 36 | ``` 37 | 3. **Run the application:** 38 | ```bash 39 | go run main.go 40 | ``` 41 | By default, the server will start on `http://localhost:3347`. 42 | 43 | ### Running with Docker Compose 44 | 45 | This is the recommended method for deployment. 46 | 47 | 1. **Create a `docker-compose.yml` file:** 48 | ```yaml 49 | services: 50 | bitplay: 51 | image: ghcr.io/aculix/bitplay:main 52 | container_name: bitplay 53 | ports: 54 | - 3347:3347 # Expose the web UI port 55 | volumes: 56 | # Mount the config directory for persistent settings (Optional) 57 | - ./config:/app/config 58 | restart: unless-stopped 59 | ``` 60 | * **Optional Persistence:** By default, settings (Proxy, Prowlarr/Jackett) are stored inside the container and will be lost if the container is restarted. To make settings persistent across restarts, you can mount a local directory from your host to `/app/config` inside the container using the `volumes` option above. 61 | * If you choose to mount the directory for persistence, you **must** create the directory on your host machine **before** starting the container for the first time: `mkdir -p ./config`. 62 | * If you don't mount this volume, the application will still function correctly, but you will need to re-configure your settings after each container restart. Torrent data itself is always ephemeral. 63 | 64 | 2. **Start the container:** 65 | ```bash 66 | docker-compose up -d 67 | ``` 68 | 3. **Access the application:** Open your browser to `http://:3347`. 69 | 70 | ### Running with Docker Run 71 | 72 | Alternatively, you can run the container directly using `docker run`: 73 | 74 | 1. **(Optional) Create the config directory for persistence:** If you want your settings (Proxy, Prowlarr/Jackett) to persist across container restarts, create the configuration directory on your host first: 75 | ```bash 76 | mkdir -p ./config 77 | ``` 78 | If you skip this step and the volume mount below, the application will still work, but settings will be lost on restart. 79 | 80 | 2. **Run the container:** 81 | ```bash 82 | docker run -d \ 83 | --name bitplay \ 84 | -p 3347:3347 \ 85 | # Add the volume mount below ONLY if you want persistent settings (and created ./config above) 86 | -v $(pwd)/config:/app/config \ 87 | --restart unless-stopped \ 88 | ghcr.io/aculix/bitplay:main 89 | ``` 90 | * `-d`: Run in detached mode (background). 91 | * `--name bitplay`: Assign a name to the container. 92 | * `-p 3347:3347`: Map port 3347 on the host to port 3347 in the container. 93 | * `-v $(pwd)/config:/app/config`: (Optional) Mount the local `./config` directory for persistent settings. 94 | * `--restart unless-stopped`: Configure the container to restart automatically unless manually stopped. 95 | * `ghcr.io/aculix/bitplay:main`: The Docker image to use. 96 | 97 | 3. **Access the application:** Open your browser to `http://:3347`. 98 | 99 | ## Configuration 100 | 101 | BitPlay is configured primarily through its web interface after starting the application. 102 | 103 | 1. **Access the Web UI:** Go to `http://localhost:3347` (or your server's address). 104 | 2. **Navigate to Settings:** Find the settings or configuration section within the UI. 105 | 3. **Configure:** 106 | * **Proxy:** Enable/disable proxy support and provide the full SOCKS5 proxy URL (e.g., `socks5://user:pass@host:port`). Test the connection using the provided button. 107 | * **Prowlarr:** Enable/disable Prowlarr, provide the Prowlarr Host URL (e.g., `http://prowlarr:9696`), and your Prowlarr API Key. Test the connection. 108 | * **Jackett:** Enable/disable Jackett, provide the Jackett Host URL (e.g., `http://jackett:9117`), and your Jackett API Key. Test the connection. 109 | 110 | Settings are saved automatically to `/app/config/settings.json` inside the Docker container, which maps to `./config/settings.json` on the host via the mounted volume in the example Docker Compose setup above. 111 | 112 | ## Usage 113 | 114 | 1. **Configure Settings:** Set up your proxy and search providers (Prowlarr/Jackett) as described above. 115 | 2. **Search:** Use the search bar to query Prowlarr or Jackett for torrents. 116 | 3. **Add Torrent:** Paste a magnet link directly or click a search result to add the torrent to BitPlay. 117 | 4. **Stream:** Once the torrent info is loaded, select the video file you want to watch. BitPlay will start downloading and streaming it directly in the built-in player. 118 | 119 | ## Contributing 120 | 121 | Contributions are welcome! Please feel free to submit pull requests or open issues. (You can add more details here if you have specific contribution guidelines). 122 | 123 | ## License 124 | 125 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. 126 | -------------------------------------------------------------------------------- /client/assets/bitplay_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aculix/bitplay/4f59c7d7731fb133f1fb80e70f11bf202a52ee5e/client/assets/bitplay_logo.png -------------------------------------------------------------------------------- /client/assets/butterup.min.css: -------------------------------------------------------------------------------- 1 | .toaster,ol.rack{list-style:none;margin:0}.toaster{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;box-sizing:border-box;padding:5px;outline:0;z-index:999999999;position:fixed}.butteruptoast,.butteruptoast.brutalist{font-size:13px;display:flex;padding:16px;width:325px}.toaster.bottom-right{bottom:20px;right:20px}.toaster.bottom-left{bottom:20px;left:20px}.toaster.top-right{top:20px;right:20px}.toaster.top-left{top:20px;left:20px}.toaster.bottom-center{bottom:20px;left:50%;transform:translateX(-50%)}.toaster.top-center{top:20px;left:50%;transform:translateX(-50%)}.toaster.top-center ol.rack,.toaster.top-left ol.rack,.toaster.top-right ol.rack{flex-direction:column-reverse}.toaster.bottom-center ol.rack,.toaster.bottom-left ol.rack,.toaster.bottom-right ol.rack{flex-direction:column}ol.rack{padding:0;display:flex}ol.rack li{margin-bottom:16px}ol.rack.upperstack li{margin-bottom:-35px;transition:.3s ease-in-out}ol.rack.upperstack li:hover{margin-bottom:16px;scale:1.03;transition:.3s ease-in-out}ol.rack.lowerstack li{margin-top:-35px}ol.rack.lowerstack{margin-bottom:0}.butteruptoast{border-radius:8px;box-shadow:0 4px 12px #0000001a;border:1px solid #ededed;background-color:#fff;gap:6px;color:#282828}.butteruptoast.dismissable{cursor:pointer}.butteruptoast .icon{display:flex;align-items:start;flex-direction:column}.butteruptoast .icon svg{width:20px;height:20px;fill:#282828}.notif .desc{display:flex;flex-direction:column;gap:2px}.notif .desc .title{font-weight:600;line-height:1.5}.notif .desc .message{font-weight:400;line-height:1.4}.butteruptoast.success{background-color:#ebfef2;color:#00892d;border:1px solid #d2fde4}.butteruptoast.success .icon svg{fill:hsl(140,100%,27%)}.butteruptoast.error .icon svg{fill:hsl(0,100%,27%)}.butteruptoast.warning .icon svg{fill:hsl(50,100%,27%)}.butteruptoast.info .icon svg{fill:hsl(210,100%,27%)}.butteruptoast.error{background-color:#fef0f0;color:#890000;border:1px solid #fdd2d2}.butteruptoast.warning{background-color:#fffdf0;color:#897200;border:1px solid #fdf6d2}.butteruptoast.info{background-color:#f0f8ff;color:#004489;border:1px solid #d2e8fd}.toast-buttons{display:flex;gap:8px;width:100%;align-items:center;flex-direction:row;margin-top:16px}.toast-buttons .toast-button.primary{background-color:#282828;color:#fff;padding:8px 16px;border-radius:4px;cursor:pointer;border:none;width:100%}.toast-buttons .toast-button.secondary{background-color:#f0f8ff;color:#004489;border:1px solid #d2e8fd;padding:8px 16px;border-radius:4px;cursor:pointer;width:100%}.butteruptoast.success .toast-button.primary{background-color:#27ae5f;color:#fff}.butteruptoast.success .toast-button.secondary{background-color:#daf0e3;color:#1e8549;border:1px solid #8ae4b0}.butteruptoast.error .toast-button.primary{background-color:#db3748;color:#fff}.butteruptoast.error .toast-button.secondary{background-color:#eddddf;color:#be2131;border:1px solid #eb8e97}.butteruptoast.warning .toast-button.primary{background-color:#ffc005;color:#4c3900}.butteruptoast.warning .toast-button.secondary{background-color:#fff9ea;color:#9e7600;border:1px solid #ffe084}.butteruptoast.info .toast-button.primary{background-color:#2094f3;color:#fff}.butteruptoast.info .toast-button.secondary{background-color:#e1f1fd;color:#085ea4;border:1px solid #81c2f8}.toastUp{animation:.5s ease-in-out forwards slideUp}.toastDown{animation:.5s ease-in-out forwards slideDown}@keyframes slideDown{0%{opacity:0;transform:translateY(-100%)}100%{opacity:1;transform:translateY(0)}}@keyframes slideUp{0%{opacity:0;transform:translateY(100%)}100%{opacity:1;transform:translateY(0)}}.fadeOutToast{animation:.3s ease-in-out forwards fadeOut}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}.butteruptoast.glass{background-color:rgba(255,255,255,.42)!important;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:none;box-shadow:0 4px 12px #0000001a;color:#282828}.butteruptoast.glass.success{background-color:rgba(235,254,242,.42)!important;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:none;box-shadow:0 4px 12px #0000001a;color:#00892d}.butteruptoast.glass.error,.butteruptoast.glass.warning{backdrop-filter:blur(10px);border:none;box-shadow:0 4px 12px #0000001a}.butteruptoast.glass.error{background-color:rgba(254,240,240,.42)!important;-webkit-backdrop-filter:blur(10px);color:#890000}.butteruptoast.glass.warning{background-color:rgba(255,253,240,.42)!important;-webkit-backdrop-filter:blur(10px);color:#897200}.butteruptoast.glass.info{background-color:rgba(240,248,255,.42)!important;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:none;box-shadow:0 4px 12px #0000001a;color:#004489}.butteruptoast.brutalist{border-radius:0;box-shadow:0 4px 12px #0000001a;border:2px solid #282828;align-items:center;background-color:#fff;gap:6px;color:#282828}.butteruptoast.brutalist.success{background-color:#ebfef2;color:#00892d;border:2px solid #00892d}.butteruptoast.brutalist.error{background-color:#fef0f0;color:#890000;border:2px solid #890000}.butteruptoast.brutalist.warning{background-color:#fffdf0;color:#897200;border:2px solid #897200}.butteruptoast.brutalist.info{background-color:#f0f8ff;color:#004489;border:2px solid #004489} -------------------------------------------------------------------------------- /client/assets/butterup.min.js: -------------------------------------------------------------------------------- 1 | /* butterup version 2.0.0 by Nathan Langer * https://github.com/dgtlss/butterup | https://butterup.nlanger.dev * Thankyou for using butterup! Please consider starring the project on GitHub. */ 2 | var butterup={options:{maxToasts:5,toastLife:5e3,currentToasts:0},toast:function({title:t,message:e,type:n,location:s,icon:o,theme:a,customIcon:l,dismissable:c,onClick:i,onRender:u,onTimeout:d,customHTML:r,primaryButton:m,secondaryButton:p}){if(null==document.getElementById("toaster")){const t=document.createElement("div");if(t.id="toaster",t.className=null==s?"toaster top-right":"toaster "+s,document.body.appendChild(t),null==document.getElementById("butterupRack")){const e=document.createElement("ol");e.id="butterupRack",e.className="rack",t.appendChild(e)}}else{const t=document.getElementById("toaster");t.classList.forEach((function(e){(e.includes("top-right")||e.includes("top-center")||e.includes("top-left")||e.includes("bottom-right")||e.includes("bottom-center")||e.includes("bottom-left"))&&t.classList.remove(e)})),t.className=null==s?"toaster top-right":"toaster "+s,document.getElementById("butterupRack")}if(butterup.options.currentToasts>=butterup.options.maxToasts){var v=document.getElementById("butterupRack").firstChild;document.getElementById("butterupRack").removeChild(v),butterup.options.currentToasts--}const f=document.createElement("li");if(butterup.options.currentToasts++,f.className="butteruptoast",(toaster.className.includes("top-right")||toaster.className.includes("top-center")||toaster.className.includes("top-left"))&&(f.className+=" toastDown"),(toaster.className.includes("bottom-right")||toaster.className.includes("bottom-center")||toaster.className.includes("bottom-left"))&&(f.className+=" toastUp"),f.id="butterupToast-"+butterup.options.currentToasts,null!=n&&(f.className+=" "+n),null!=a&&(f.className+=" "+a),document.getElementById("butterupRack").appendChild(f),null!=o&&1==o){const t=document.createElement("div");t.className="icon",f.appendChild(t),l&&(t.innerHTML=l),null!=n&&null==l&&(f.className+=" "+n,"success"==n&&(t.innerHTML=''),"error"==n&&(t.innerHTML=''),"warning"==n&&(t.innerHTML=''),"info"==n&&(t.innerHTML=''))}const g=document.createElement("div");g.className="notif",f.appendChild(g);const h=document.createElement("div");if(h.className="desc",g.appendChild(h),null!=t){const e=document.createElement("div");e.className="title",e.innerHTML=t,h.appendChild(e)}if(null!=r){const t=document.createElement("div");t.className="message",t.innerHTML=r,h.appendChild(t)}if(null!=e){const t=document.createElement("div");t.className="message",t.innerHTML=e,h.appendChild(t)}if(m||p){const t=document.createElement("div");if(t.className="toast-buttons",g.appendChild(t),m){const e=document.createElement("button");e.className="toast-button primary",e.textContent=m.text,e.onclick=function(t){t.stopPropagation(),m.onClick(t)},t.appendChild(e)}if(p){const e=document.createElement("button");e.className="toast-button secondary",e.textContent=p.text,e.onclick=function(t){t.stopPropagation(),p.onClick(t)},t.appendChild(e)}}i&&"function"==typeof i&&f.addEventListener("click",(function(t){t.stopPropagation(),i(t)})),u&&"function"==typeof u&&u(f),null!=c&&1==c&&(f.className+=" dismissable",f.addEventListener("click",(function(){butterup.despawnToast(f.id)}))),setTimeout((function(){f.className=f.className.replace(" toastDown",""),f.className=f.className.replace(" toastUp","")}),500),setTimeout((function(){d&&"function"==typeof d&&d(f),butterup.despawnToast(f.id)}),butterup.options.toastLife)},despawnToast(t,e){var n=document.getElementById(t);null!=n&&(n.className+=" fadeOutToast",setTimeout((function(){try{n.style.opacity="0",n.parentNode.removeChild(n),butterup.options.currentToasts--,e&&"function"==typeof e&&e(n)}catch(t){}if(0==butterup.options.currentToasts){var t=document.getElementById("toaster");t.parentNode.removeChild(t)}}),500))}}; -------------------------------------------------------------------------------- /client/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aculix/bitplay/4f59c7d7731fb133f1fb80e70f11bf202a52ee5e/client/assets/favicon.png -------------------------------------------------------------------------------- /client/assets/index.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | @custom-variant dark (&:is(.dark *)); 4 | 5 | @theme { 6 | --color-background: var(--background); 7 | --color-foreground: var(--foreground); 8 | --color-ring: var(--ring); 9 | --color-input: var(--input); 10 | --color-border: var(--border); 11 | --color-destructive: var(--destructive); 12 | --color-accent-foreground: var(--accent-foreground); 13 | --color-accent: var(--accent); 14 | --color-muted-foreground: var(--muted-foreground); 15 | --color-muted: var(--muted); 16 | --color-secondary-foreground: var(--secondary-foreground); 17 | --color-secondary: var(--secondary); 18 | --color-primary-foreground: var(--primary-foreground); 19 | --color-primary: var(--primary); 20 | --color-popover-foreground: var(--popover-foreground); 21 | --color-popover: var(--popover); 22 | --color-card-foreground: var(--card-foreground); 23 | --color-card: var(--card); 24 | --radius-sm: calc(var(--radius) - 4px); 25 | --radius-md: calc(var(--radius) - 2px); 26 | --radius-lg: var(--radius); 27 | --radius-xl: calc(var(--radius) + 4px); 28 | } 29 | 30 | :root { 31 | --radius: 0.625rem; 32 | --background: oklch(1 0 0); 33 | --foreground: oklch(0.141 0.005 285.823); 34 | --card: oklch(1 0 0); 35 | --card-foreground: oklch(0.141 0.005 285.823); 36 | --popover: oklch(1 0 0); 37 | --popover-foreground: oklch(0.141 0.005 285.823); 38 | --primary: oklch(65.24% 0.199188 160.1355); 39 | --primary-foreground: oklch(0.985 0 0); 40 | --secondary: oklch(0.967 0.001 286.375); 41 | --secondary-foreground: oklch(0.21 0.006 285.885); 42 | --muted: oklch(0.967 0.001 286.375); 43 | --muted-foreground: oklch(0.552 0.016 285.938); 44 | --accent: oklch(0.967 0.001 286.375); 45 | --accent-foreground: oklch(0.21 0.006 285.885); 46 | --destructive: oklch(0.577 0.245 27.325); 47 | --border: oklch(0.92 0.004 286.32); 48 | --input: oklch(0.92 0.004 286.32); 49 | --ring: oklch(0.705 0.015 286.067); 50 | } 51 | 52 | .dark { 53 | --background: oklch(0.191 0.005 285.823); 54 | --foreground: oklch(0.985 0 0); 55 | --card: oklch(0.21 0.006 285.885); 56 | --card-foreground: oklch(0.985 0 0); 57 | --popover: oklch(0.21 0.006 285.885); 58 | --popover-foreground: oklch(0.985 0 0); 59 | --primary: oklch(88.24% 0.199188 160.1355); 60 | --primary-foreground: oklch(0.21 0.006 285.885); 61 | --secondary: oklch(0.244 0.006 286.033); 62 | --secondary-foreground: oklch(0.985 0 0); 63 | --muted: oklch(0.274 0.006 286.033); 64 | --muted-foreground: oklch(0.705 0.015 286.067); 65 | --accent: oklch(0.274 0.006 286.033); 66 | --accent-foreground: oklch(0.985 0 0); 67 | --destructive: oklch(0.704 0.191 22.216); 68 | --border: oklch(1 0 0 / 10%); 69 | --input: oklch(1 0 0 / 15%); 70 | --ring: oklch(0.552 0.016 285.938); 71 | } 72 | 73 | @layer base { 74 | * { 75 | @apply border-border outline-ring/50; 76 | } 77 | body { 78 | @apply bg-background text-foreground; 79 | } 80 | } 81 | 82 | .btn { 83 | @apply flex gap-1.5 justify-center items-center min-w-[100px] bg-primary text-primary-foreground h-12 rounded-md px-2 py-2 font-semibold text-sm transition-all hover:bg-primary/90; 84 | } 85 | 86 | .btn.small{ 87 | @apply h-8 text-xs min-w-[70px]; 88 | } 89 | 90 | svg { 91 | display: inline; 92 | } 93 | 94 | #torrent_file_wrapper.drag-over { 95 | @apply border-primary; 96 | } 97 | 98 | #search-pagination { 99 | @apply flex items-center justify-center gap-2 my-4; 100 | } 101 | 102 | #search-pagination.hidden { 103 | display: none !important; 104 | } 105 | 106 | #search-pagination button { 107 | @apply min-w-[32px] h-[32px] border border-foreground/20 rounded-md p-1 flex items-center justify-center text-xs font-semibold text-sm transition-all hover:bg-accent; 108 | } 109 | 110 | #search-pagination button svg { 111 | font-size: 17px; 112 | } 113 | 114 | #search-pagination button.disabled { 115 | @apply cursor-not-allowed hover:bg-transparent; 116 | } 117 | 118 | #search-pagination button.active { 119 | @apply bg-primary text-primary-foreground; 120 | } 121 | 122 | #search-pagination button.active:hover { 123 | @apply bg-primary text-primary-foreground; 124 | } 125 | 126 | #video-player { 127 | @apply hidden; 128 | } 129 | 130 | .btn.loader:before { 131 | content: ""; 132 | display: block; 133 | width: 20px; 134 | height: 20px; 135 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBMaWNlbnNlOiBNSVQuIE1hZGUgYnkgTHVjaWRlIENvbnRyaWJ1dG9yczogaHR0cHM6Ly9sdWNpZGUuZGV2LyAtLT4KPHN2ZyAKICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgd2lkdGg9IjI0IgogIGhlaWdodD0iMjQiCiAgdmlld0JveD0iMCAwIDI0IDI0IgogIGZpbGw9Im5vbmUiCiAgc3Ryb2tlPSIjZmZmZmZmIgogIHN0cm9rZS13aWR0aD0iMiIKICBzdHJva2UtbGluZWNhcD0icm91bmQiCiAgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIKPgogIDxwYXRoIGQ9Ik0yMSAxMmE5IDkgMCAxMS02LjIxOS04LjU2IiAvPgo8L3N2Zz4=); 136 | background-size: 20px; 137 | background-repeat: no-repeat; 138 | background-position: center; 139 | animation: spin 0.5s linear infinite; 140 | } 141 | 142 | .dark .btn.loader:before { 143 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBMaWNlbnNlOiBNSVQuIE1hZGUgYnkgTHVjaWRlIENvbnRyaWJ1dG9yczogaHR0cHM6Ly9sdWNpZGUuZGV2LyAtLT4KPHN2ZyAKICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgd2lkdGg9IjI0IgogIGhlaWdodD0iMjQiCiAgdmlld0JveD0iMCAwIDI0IDI0IgogIGZpbGw9Im5vbmUiCiAgc3Ryb2tlPSIjMDAwMDAwIgogIHN0cm9rZS13aWR0aD0iMiIKICBzdHJva2UtbGluZWNhcD0icm91bmQiCiAgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIKPgogIDxwYXRoIGQ9Ik0yMSAxMmE5IDkgMCAxMS02LjIxOS04LjU2IiAvPgo8L3N2Zz4=); 144 | } 145 | 146 | @keyframes spin { 147 | 0% { 148 | transform: rotate(0deg); 149 | } 150 | 100% { 151 | transform: rotate(360deg); 152 | } 153 | } 154 | 155 | #toggle_theme { 156 | background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='1em' height='1em' fill='none' aria-hidden='true' focusable='false'%3E%3Cg%3E%3Cpath d='M21.0672 11.8568L20.4253 11.469L21.0672 11.8568ZM12.1432 2.93276L11.7553 2.29085V2.29085L12.1432 2.93276ZM21.25 12C21.25 17.1086 17.1086 21.25 12 21.25V22.75C17.9371 22.75 22.75 17.9371 22.75 12H21.25ZM12 21.25C6.89137 21.25 2.75 17.1086 2.75 12H1.25C1.25 17.9371 6.06294 22.75 12 22.75V21.25ZM2.75 12C2.75 6.89137 6.89137 2.75 12 2.75V1.25C6.06294 1.25 1.25 6.06294 1.25 12H2.75ZM15.5 14.25C12.3244 14.25 9.75 11.6756 9.75 8.5H8.25C8.25 12.5041 11.4959 15.75 15.5 15.75V14.25ZM20.4253 11.469C19.4172 13.1373 17.5882 14.25 15.5 14.25V15.75C18.1349 15.75 20.4407 14.3439 21.7092 12.2447L20.4253 11.469ZM9.75 8.5C9.75 6.41182 10.8627 4.5828 12.531 3.57467L11.7553 2.29085C9.65609 3.5593 8.25 5.86509 8.25 8.5H9.75ZM12 2.75C11.9115 2.75 11.8077 2.71008 11.7324 2.63168C11.6686 2.56527 11.6538 2.50244 11.6503 2.47703C11.6461 2.44587 11.6482 2.35557 11.7553 2.29085L12.531 3.57467C13.0342 3.27065 13.196 2.71398 13.1368 2.27627C13.0754 1.82126 12.7166 1.25 12 1.25V2.75ZM21.7092 12.2447C21.6444 12.3518 21.5541 12.3539 21.523 12.3497C21.4976 12.3462 21.4347 12.3314 21.3683 12.2676C21.2899 12.1923 21.25 12.0885 21.25 12H22.75C22.75 11.2834 22.1787 10.9246 21.7237 10.8632C21.286 10.804 20.7293 10.9658 20.4253 11.469L21.7092 12.2447Z' fill='%23000' stroke-width='1.5'%3E%3C/path%3E%3C/g%3E%3C/svg%3E") 157 | center no-repeat; 158 | } 159 | 160 | .dark #toggle_theme { 161 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='1em' height='1em' fill='none' aria-hidden='true' focusable='false'%3E%3Cg%3E%3Ccircle cx='12' cy='12' r='5' stroke='%23fff' stroke-width='1.5'%3E%3C/circle%3E%3Cpath d='M12 2V4' stroke='%23fff' stroke-width='1.5' stroke-linecap='round'%3E%3C/path%3E%3Cpath d='M12 20V22' stroke='%23fff' stroke-width='1.5' stroke-linecap='round'%3E%3C/path%3E%3Cpath d='M4 12L2 12' stroke='%23fff' stroke-width='1.5' stroke-linecap='round'%3E%3C/path%3E%3Cpath d='M22 12L20 12' stroke='%23fff' stroke-width='1.5' stroke-linecap='round'%3E%3C/path%3E%3Cpath d='M19.7778 4.22266L17.5558 6.25424' stroke='%23fff' stroke-width='1.5' stroke-linecap='round'%3E%3C/path%3E%3Cpath d='M4.22217 4.22266L6.44418 6.25424' stroke='%23fff' stroke-width='1.5' stroke-linecap='round'%3E%3C/path%3E%3Cpath d='M6.44434 17.5557L4.22211 19.7779' stroke='%23fff' stroke-width='1.5' stroke-linecap='round'%3E%3C/path%3E%3Cpath d='M19.7778 19.7773L17.5558 17.5551' stroke='%23fff' stroke-width='1.5' stroke-linecap='round'%3E%3C/path%3E%3C/g%3E%3C/svg%3E"); 162 | } 163 | 164 | button { 165 | cursor: pointer; 166 | transition: all 0.3s ease; 167 | } 168 | 169 | button:disabled { 170 | cursor: not-allowed; 171 | opacity: 0.6; 172 | } 173 | 174 | #video-player { 175 | min-height: 200px; 176 | } 177 | 178 | body .video-js .vjs-big-play-button { 179 | margin: 0; 180 | display: flex; 181 | width: 80px; 182 | height: 80px; 183 | transform: translate(-50%, -50%); 184 | align-items: center; 185 | justify-content: center; 186 | border-radius: 50%; 187 | border-color: var(--color-primary) !important; 188 | background-color: transparent !important; 189 | color: var(--color-primary); 190 | } 191 | 192 | body .vjs-has-started .vjs-big-play-button { 193 | display: none; 194 | } 195 | 196 | body .video-js .vjs-big-play-button .vjs-icon-placeholder { 197 | display: flex; 198 | } 199 | 200 | body .video-js .vjs-big-play-button .vjs-icon-placeholder:before { 201 | font-size: 47px; 202 | position: static; 203 | } 204 | 205 | .vjs-progress-control { 206 | position: absolute !important; 207 | bottom: 45px !important; 208 | width: calc(100% - 20px) !important; 209 | padding: 1px !important; 210 | height: 40px !important; 211 | } 212 | 213 | .video-js .vjs-progress-control .vjs-progress-holder, 214 | .video-js .vjs-play-progress, 215 | .video-js .vjs-load-progress div { 216 | border-radius: 50px; 217 | } 218 | 219 | .video-js .vjs-control-bar { 220 | background: transparent; 221 | padding: 0 10px 15px; 222 | height: auto; 223 | } 224 | 225 | .video-js .vjs-control-bar:before { 226 | content: ""; 227 | position: absolute; 228 | width: 100%; 229 | height: 200%; 230 | bottom: 0; 231 | left: 0; 232 | background: linear-gradient( 233 | 0deg, 234 | rgba(0, 0, 0, 0.84) 0%, 235 | rgba(0, 0, 0, 0.59) 50%, 236 | rgba(0, 0, 0, 0) 100% 237 | ); 238 | } 239 | 240 | .vjs-remaining-time { 241 | display: none; 242 | } 243 | 244 | .video-js .vjs-current-time, 245 | .video-js .vjs-duration, 246 | .vjs-live .vjs-time-control, 247 | .vjs-time-divider, 248 | .vjs-live .vjs-time-divider { 249 | display: block; 250 | } 251 | 252 | .video-js .vjs-time-control.vjs-duration { 253 | margin-right: auto; 254 | } 255 | 256 | .video-js .vjs-time-control { 257 | padding: 0 5px; 258 | font-size: 15px; 259 | line-height: 1.2; 260 | height: 33px; 261 | display: flex; 262 | align-items: center; 263 | } 264 | 265 | .video-js .vjs-time-control.vjs-time-divider { 266 | padding: 0; 267 | min-width: 0; 268 | font-size: 18px; 269 | line-height: 1; 270 | color: white; 271 | opacity: 1; 272 | z-index: 1; 273 | } 274 | 275 | .video-js .vjs-play-control { 276 | height: 33px; 277 | width: 33px; 278 | display: flex; 279 | align-items: center; 280 | justify-content: center; 281 | } 282 | 283 | .video-js .vjs-play-control .vjs-icon-placeholder { 284 | display: flex; 285 | align-items: center; 286 | justify-content: center; 287 | } 288 | 289 | .video-js .vjs-play-control .vjs-icon-placeholder:before { 290 | position: relative; 291 | line-height: 1; 292 | font-size: 30px; 293 | } 294 | 295 | .video-js .vjs-volume-panel .vjs-volume-control { 296 | opacity: 1; 297 | width: 60px !important; 298 | height: 33px; 299 | } 300 | 301 | .video-js .vjs-volume-panel { 302 | width: 110px !important; 303 | height: 33px; 304 | margin-left: 6px; 305 | } 306 | 307 | .video-js .vjs-mute-control { 308 | width: 33px; 309 | height: 33px; 310 | } 311 | 312 | .video-js .vjs-mute-control .vjs-icon-placeholder { 313 | display: flex; 314 | align-items: center; 315 | justify-content: center; 316 | } 317 | 318 | .video-js .vjs-mute-control .vjs-icon-placeholder:before { 319 | position: relative; 320 | line-height: 1; 321 | font-size: 25px; 322 | } 323 | 324 | .video-js .vjs-volume-bar { 325 | margin: 1.55em 0.45em; 326 | } 327 | 328 | .video-js .vjs-time-control.vjs-remaining-time { 329 | display: none; 330 | } 331 | 332 | .video-js .vjs-progress-control .vjs-progress-holder { 333 | margin: 0 6px; 334 | } 335 | 336 | .video-js .vjs-slider { 337 | background-color: rgb(255 255 255 / 27%); 338 | } 339 | 340 | .video-js .vjs-load-progress div { 341 | background: rgb(255 255 255 / 33%); 342 | } 343 | 344 | .video-js .vjs-fullscreen-control, 345 | .video-js .vjs-picture-in-picture-control, 346 | .video-js .vjs-subs-caps-button { 347 | height: 33px; 348 | width: 33px; 349 | display: flex; 350 | align-items: center; 351 | justify-content: center; 352 | } 353 | 354 | .video-js .vjs-fullscreen-control { 355 | margin-left: 6px; 356 | } 357 | 358 | .video-js .vjs-picture-in-picture-control { 359 | margin-left: 10px; 360 | } 361 | 362 | .video-js .vjs-fullscreen-control .vjs-icon-placeholder, 363 | .video-js .vjs-picture-in-picture-control .vjs-icon-placeholder, 364 | .video-js .vjs-subs-caps-button .vjs-icon-placeholder { 365 | display: flex; 366 | align-items: center; 367 | justify-content: center; 368 | } 369 | 370 | .video-js .vjs-fullscreen-control .vjs-icon-placeholder:before, 371 | .video-js .vjs-picture-in-picture-control .vjs-icon-placeholder:before, 372 | .video-js .vjs-subs-caps-button .vjs-icon-placeholder:before { 373 | position: relative; 374 | line-height: 1; 375 | font-size: 28px; 376 | } 377 | 378 | .video-js .vjs-picture-in-picture-control .vjs-icon-placeholder:before { 379 | font-size: 24px; 380 | } 381 | 382 | .video-js .vjs-subs-caps-button .vjs-icon-placeholder:before { 383 | font-size: 26px; 384 | } 385 | 386 | .video-select { 387 | position: absolute; 388 | top: 15px; 389 | left: 13px; 390 | background: transparent; 391 | display: none; 392 | font-size: 15px; 393 | max-width: calc(100% - 25px); 394 | overflow: hidden; 395 | text-overflow: ellipsis; 396 | } 397 | 398 | .vjs-has-started.vjs-controls-enabled .video-select { 399 | display: block; 400 | } 401 | 402 | .video-js .vjs-progress-holder { 403 | height: 6px; 404 | transition: 0.3s all; 405 | } 406 | 407 | .video-js .vjs-play-progress:before { 408 | font-size: 17px; 409 | transition: 0.3s all; 410 | } 411 | 412 | .video-js .vjs-progress-control:hover .vjs-progress-holder { 413 | height: 8px; 414 | } 415 | 416 | .vjs-progress-control:hover .vjs-play-progress:before { 417 | font-size: 22px; 418 | } 419 | 420 | @media (max-width: 768px) { 421 | .video-js .vjs-control-bar { 422 | padding: 0 4px 5px; 423 | } 424 | 425 | .vjs-progress-control { 426 | bottom: 31px !important; 427 | width: calc(100% - 6px) !important; 428 | padding: 0px !important; 429 | height: 30px !important; 430 | } 431 | 432 | .video-js .vjs-play-control .vjs-icon-placeholder:before { 433 | font-size: 25px; 434 | } 435 | 436 | .video-js .vjs-play-control { 437 | width: 26px; 438 | height: 26px; 439 | } 440 | 441 | .video-js .vjs-volume-bar { 442 | margin: 1.15em 0.45em; 443 | } 444 | 445 | .video-js .vjs-volume-panel .vjs-volume-control { 446 | width: 45px !important; 447 | height: 26px; 448 | } 449 | 450 | .video-js .vjs-mute-control { 451 | width: 26px; 452 | height: 26px; 453 | } 454 | 455 | .video-js .vjs-volume-panel { 456 | width: 80px !important; 457 | height: 26px; 458 | margin-left: 4px; 459 | } 460 | 461 | .video-js .vjs-time-control { 462 | padding: 0 4px; 463 | font-size: 12px; 464 | height: 26px; 465 | } 466 | 467 | .video-js .vjs-time-control.vjs-time-divider { 468 | font-size: 15px; 469 | } 470 | 471 | .video-js .vjs-fullscreen-control, 472 | .video-js .vjs-picture-in-picture-control, 473 | .video-js .vjs-subs-caps-button { 474 | height: 26px; 475 | width: 26px; 476 | } 477 | 478 | .video-js .vjs-fullscreen-control .vjs-icon-placeholder:before, 479 | .video-js .vjs-picture-in-picture-control .vjs-icon-placeholder:before, 480 | .video-js .vjs-subs-caps-button .vjs-icon-placeholder:before { 481 | font-size: 20px; 482 | } 483 | 484 | .video-js .vjs-picture-in-picture-control .vjs-icon-placeholder:before { 485 | font-size: 18px; 486 | } 487 | } 488 | -------------------------------------------------------------------------------- /client/assets/index.js: -------------------------------------------------------------------------------- 1 | const getLanguage = (code) => { 2 | const lang = new Intl.DisplayNames(["en"], { type: "language" }); 3 | return lang.of(code); 4 | }; 5 | 6 | let settings = { 7 | enableProxy: false, 8 | proxyUrl: "", 9 | enableProwlarr: false, 10 | prowlarrHost: "", 11 | prowlarrApiKey: "", 12 | enableJackett: false, 13 | jackettHost: "", 14 | jackettApiKey: "", 15 | }; 16 | 17 | const searchWrapper = document.querySelector("#search-wrapper"); 18 | var player = null; 19 | 20 | function doubleTapFF(options) { 21 | var videoElement = this 22 | var videoElementId = this.id(); 23 | document.getElementById(videoElementId).addEventListener("touchstart", tapHandler); 24 | var tapedTwice = false; 25 | function tapHandler(e) { 26 | if (!videoElement.paused()) { 27 | 28 | if (!tapedTwice) { 29 | tapedTwice = true; 30 | setTimeout(function () { 31 | tapedTwice = false; 32 | }, 300); 33 | return false; 34 | } 35 | e.preventDefault(); 36 | var br = document.getElementById(videoElementId).getBoundingClientRect(); 37 | 38 | 39 | var x = e.touches[0].clientX - br.left; 40 | var y = e.touches[0].clientY - br.top; 41 | 42 | if (x <= br.width / 2) { 43 | videoElement.currentTime(player.currentTime() - 10) 44 | } else { 45 | videoElement.currentTime(player.currentTime() + 10) 46 | 47 | } 48 | } 49 | 50 | 51 | } 52 | } 53 | videojs.registerPlugin('doubleTapFF', doubleTapFF); 54 | 55 | (async function ($) { 56 | // toggle dark mode button 57 | const toggleDarkMode = () => { 58 | const html = document.querySelector("html"); 59 | html.classList.toggle("dark"); 60 | localStorage.setItem( 61 | "theme", 62 | html.classList.contains("dark") ? "dark" : "light" 63 | ); 64 | }; 65 | const toggleDarkModeButton = document.querySelector("#toggle_theme"); 66 | toggleDarkModeButton.addEventListener("click", toggleDarkMode); 67 | 68 | // handle past button 69 | const pastButton = document.querySelector("#copy_magnet"); 70 | pastButton.addEventListener("click", async () => { 71 | navigator.clipboard.readText().then((text) => { 72 | document.getElementById("magnet").value = text; 73 | }); 74 | }); 75 | 76 | // handle demo button 77 | const demoButton = document.querySelector("#demo_torrent"); 78 | demoButton.addEventListener("click", async () => { 79 | document.getElementById("magnet").value = 80 | "magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent"; 81 | 82 | document 83 | .querySelector("#torrent-form") 84 | .dispatchEvent(new Event("submit")); 85 | }); 86 | 87 | const form = document.querySelector("#torrent-form"); 88 | form.addEventListener("submit", async (e) => { 89 | e.preventDefault(); 90 | const magnet = document.querySelector("#magnet").value; 91 | 92 | if (!magnet) { 93 | butterup.toast({ 94 | message: "Please enter a magnet link", 95 | location: "top-right", 96 | icon: true, 97 | dismissable: true, 98 | type: "error", 99 | }); 100 | return; 101 | } 102 | 103 | // clean up previous player 104 | if (player) { 105 | player.dispose(); 106 | player = null; 107 | const vidElm = document.createElement("video"); 108 | vidElm.setAttribute("id", "video-player"); 109 | vidElm.setAttribute("class", "video-js mt-10 w-full"); 110 | 111 | document.querySelector("main").appendChild(vidElm); 112 | } 113 | 114 | form 115 | .querySelector("button[type=submit]") 116 | .setAttribute("disabled", "disabled"); 117 | form.querySelector("button[type=submit]").innerHTML = ""; 118 | form.querySelector("button[type=submit]").classList.add("loader"); 119 | 120 | const res = await fetch("/api/v1/torrent/add", { 121 | method: "POST", 122 | headers: { "Content-Type": "application/json" }, 123 | body: JSON.stringify({ magnet }), 124 | }); 125 | 126 | if (!res.ok) { 127 | const err = await res.json(); 128 | butterup.toast({ 129 | message: err.error || "Something went wrong", 130 | location: "top-right", 131 | icon: true, 132 | dismissable: true, 133 | type: "error", 134 | }); 135 | form.querySelector("button[type=submit]").removeAttribute("disabled"); 136 | form.querySelector("button[type=submit]").innerHTML = "Play Now"; 137 | form.querySelector("button[type=submit]").classList.remove("loader"); 138 | searchResults.querySelectorAll("#play-torrent").forEach((el) => { 139 | el.removeAttribute("disabled"); 140 | el.innerHTML = "Watch"; 141 | el.classList.remove("loader"); 142 | }); 143 | return; 144 | } 145 | 146 | const { sessionId } = await res.json(); 147 | const filesRes = await fetch("/api/v1/torrent/" + sessionId); 148 | 149 | if (!filesRes.ok) { 150 | const err = await filesRes.json(); 151 | butterup.toast({ 152 | message: err.error || "Something went wrong", 153 | location: "top-right", 154 | icon: true, 155 | dismissable: true, 156 | type: "error", 157 | }); 158 | form.querySelector("button[type=submit]").removeAttribute("disabled"); 159 | form.querySelector("button[type=submit]").innerHTML = "Play Now"; 160 | form.querySelector("button[type=submit]").classList.remove("loader"); 161 | document.querySelectorAll("#play-torrent").forEach((el) => { 162 | el.removeAttribute("disabled"); 163 | el.innerHTML = "Watch"; 164 | el.classList.remove("loader"); 165 | }); 166 | return; 167 | } 168 | 169 | const files = await filesRes.json(); 170 | 171 | // Find video file 172 | const videoFiles = files.filter((f) => 173 | f.name.match(/\.(mp4|mkv|webm|avi)$/i) 174 | ); 175 | 176 | if (!videoFiles.length) { 177 | butterup.toast({ 178 | message: "No video file found", 179 | location: "top-right", 180 | icon: true, 181 | dismissable: true, 182 | type: "error", 183 | }); 184 | form.querySelector("button[type=submit]").removeAttribute("disabled"); 185 | form.querySelector("button[type=submit]").innerHTML = "Play Now"; 186 | form.querySelector("button[type=submit]").classList.remove("loader"); 187 | document.querySelectorAll("#play-torrent").forEach((el) => { 188 | el.removeAttribute("disabled"); 189 | el.innerHTML = "Watch"; 190 | el.classList.remove("loader"); 191 | }); 192 | return; 193 | } 194 | 195 | const subtitleFiles = files.filter((f) => 196 | f.name.match(/\.(srt|vtt|sub)$/i) 197 | ); 198 | 199 | const videoUrls = videoFiles.map((file) => { 200 | return { 201 | src: "/api/v1/torrent/" + sessionId + "/stream/" + file.index, 202 | title: file.name, 203 | type: "video/mp4", 204 | }; 205 | }); 206 | 207 | let subtitles = []; 208 | if (subtitleFiles.length) { 209 | subtitles = subtitleFiles.map((subFile) => { 210 | let language = "en"; 211 | let langName = "English"; 212 | 213 | // Try to extract language code from filename 214 | console.log(subFile.name); 215 | const langMatch = subFile.name.match(/\.([a-z]{2,3})\.(srt|vtt|sub)$/i); 216 | if (langMatch) { 217 | language = langMatch[1]; 218 | langName = getLanguage(language); 219 | } 220 | 221 | return { 222 | src: 223 | "/api/v1/torrent/" + 224 | sessionId + 225 | "/stream/" + 226 | subFile.index + 227 | ".vtt?format=vtt", 228 | srclang: language, 229 | label: langName, 230 | kind: "subtitles", 231 | type: "vtt", 232 | }; 233 | }); 234 | } 235 | player = videojs( 236 | "video-player", 237 | { 238 | fluid: true, 239 | controls: true, 240 | autoplay: true, 241 | preload: "auto", 242 | sources: [{ 243 | src: videoUrls[0].src, 244 | type: videoUrls[0].type, 245 | label: videoUrls[0].title, 246 | }], 247 | tracks: subtitles, 248 | html5: { 249 | nativeTextTracks: false 250 | }, 251 | plugins: { 252 | hotkeys: { 253 | volumeStep: 0.1, 254 | seekStep: 5, 255 | enableModifiersForNumbers: false, 256 | enableVolumeScroll: false, 257 | }, 258 | }, 259 | }, 260 | function () { 261 | player = this; 262 | player.on("error", (e) => { 263 | console.error(e); 264 | butterup.toast({ 265 | message: "Something went wrong", 266 | location: "top-right", 267 | icon: true, 268 | dismissable: true, 269 | type: "error", 270 | }); 271 | }); 272 | } 273 | ); 274 | player.doubleTapFF(); 275 | 276 | document.querySelector("#video-player").style.display = "block"; 277 | // scroll to video player 278 | setTimeout(() => { 279 | window.scrollTo({ 280 | top: document.body.scrollHeight, 281 | behavior: "smooth", 282 | }); 283 | 284 | if (videoUrls.length > 1) { 285 | const videoSelect = document.createElement("select"); 286 | videoSelect.setAttribute("id", "video-select"); 287 | videoSelect.setAttribute("class", "video-select"); 288 | videoSelect.setAttribute("aria-label", "Select video"); 289 | videoUrls.forEach((video) => { 290 | const option = document.createElement("option"); 291 | option.setAttribute("value", video.src); 292 | option.innerHTML = video.title; 293 | videoSelect.appendChild(option); 294 | }); 295 | videoSelect.addEventListener("change", (e) => { 296 | const selectedSrc = e.target.value; 297 | player.src({ 298 | src: selectedSrc, 299 | type: "video/mp4", 300 | }); 301 | player.play(); 302 | }); 303 | document.querySelector("#video-player").appendChild(videoSelect); 304 | } 305 | player.play() 306 | }, 300); 307 | 308 | form.querySelector("button[type=submit]").removeAttribute("disabled"); 309 | form.querySelector("button[type=submit]").innerHTML = "Play Now"; 310 | form.querySelector("button[type=submit]").classList.remove("loader"); 311 | document.querySelectorAll("#play-torrent").forEach((el) => { 312 | el.removeAttribute("disabled"); 313 | el.innerHTML = "Watch"; 314 | el.classList.remove("loader"); 315 | }); 316 | }); 317 | 318 | // create switch button 319 | const switchInputs = document.querySelectorAll("#switchInput"); 320 | switchInputs.forEach((input) => { 321 | input.querySelector("input").addEventListener("change", (e) => { 322 | const dot = e.target.parentElement.querySelector(".dot"); 323 | const wrapper = e.target.parentElement.querySelector(".switch-wrapper"); 324 | if (e.target.checked) { 325 | dot.classList.add("translate-x-full", "!bg-muted"); 326 | wrapper.classList.add("bg-primary"); 327 | } else { 328 | dot.classList.remove("translate-x-full", "!bg-muted"); 329 | wrapper.classList.remove("bg-primary"); 330 | } 331 | }); 332 | }); 333 | 334 | document.querySelector("#settings-btn").addEventListener("click", () => { 335 | document.querySelector("#settings-model").classList.toggle("hidden"); 336 | }); 337 | 338 | document.querySelectorAll("#close-settings").forEach((el) => { 339 | el.addEventListener("click", () => { 340 | document.querySelector("#settings-model").classList.toggle("hidden"); 341 | document.querySelector("#proxy-result").classList.remove("flex"); 342 | document.querySelector("#proxy-result").classList.add("hidden"); 343 | }); 344 | }); 345 | 346 | document.querySelectorAll(".tab-btn").forEach((el) => { 347 | el.addEventListener("click", () => { 348 | const tabIndex = el.getAttribute("data-index"); 349 | document.querySelectorAll(".tab").forEach((tab) => { 350 | const index = tab.getAttribute("data-tab"); 351 | if (index === tabIndex) { 352 | tab.classList.remove("hidden"); 353 | document.querySelectorAll(".tab-btn").forEach((el) => { 354 | el.classList.remove("bg-primary", "text-primary-foreground"); 355 | el.classList.add("bg-muted"); 356 | }); 357 | el.classList.add("bg-primary", "text-primary-foreground"); 358 | } else { 359 | tab.classList.add("hidden"); 360 | } 361 | }); 362 | }); 363 | }); 364 | 365 | function generatePagination(currentPage, pageSize, total, target) { 366 | const pagination = document.querySelector(target); 367 | if (!pagination) return; 368 | pagination.classList.remove("hidden"); 369 | pagination.innerHTML = ""; 370 | const totalPages = Math.ceil(total / pageSize); 371 | const startPage = Math.max(1, currentPage - 2); 372 | const endPage = Math.min(totalPages, currentPage + 2); 373 | 374 | for (let i = startPage; i <= endPage; i++) { 375 | const pageButton = document.createElement("button"); 376 | pageButton.textContent = i; 377 | pageButton.classList.add("page-button"); 378 | if (i === currentPage) { 379 | pageButton.classList.add("active"); 380 | } 381 | pageButton.addEventListener("click", () => { 382 | searchPage = i; 383 | updateSearchResults(); 384 | }); 385 | pagination.appendChild(pageButton); 386 | } 387 | const prevButton = document.createElement("button"); 388 | prevButton.innerHTML = ``; 389 | prevButton.classList.add("page-button"); 390 | prevButton.disabled = currentPage === 1; 391 | prevButton.addEventListener("click", () => { 392 | if (currentPage > 1) { 393 | searchPage--; 394 | updateSearchResults(); 395 | } 396 | }); 397 | pagination.prepend(prevButton); 398 | const nextButton = document.createElement("button"); 399 | nextButton.innerHTML = ``; 400 | nextButton.classList.add("page-button"); 401 | nextButton.disabled = currentPage === totalPages; 402 | nextButton.addEventListener("click", () => { 403 | if (currentPage < totalPages) { 404 | searchPage++; 405 | updateSearchResults(); 406 | } 407 | }); 408 | pagination.appendChild(nextButton); 409 | } 410 | 411 | let searchData = []; 412 | let searchPage = 1; 413 | let searchPageSize = 5; 414 | 415 | const updateSearchResults = () => { 416 | const searchPagination = document.querySelector("#search-pagination"); 417 | const searchResults = document.querySelector("#search-result"); 418 | searchResults.classList.remove("hidden"); 419 | searchResults.querySelector("tbody").innerHTML = ""; 420 | searchResults.querySelector("tfoot").classList.add("hidden"); 421 | if (searchData.length === 0) { 422 | searchResults.querySelector("tfoot").classList.remove("hidden"); 423 | return; 424 | } 425 | 426 | const start = (searchPage - 1) * searchPageSize; 427 | const end = start + searchPageSize; 428 | const results = searchData.slice(start, end); 429 | results.forEach((result) => { 430 | const resultDiv = document.createElement("tr"); 431 | resultDiv.innerHTML = ` 432 | ${result.title} 433 | ${result.indexer} 434 | ${result.size} 435 | ${result.leechers}/${result.seeders} 436 | 439 | `; 440 | searchResults.querySelector("tbody").appendChild(resultDiv); 441 | }); 442 | 443 | // Generate pagination 444 | const totalResults = searchData.length; 445 | const totalPages = Math.ceil(totalResults / searchPageSize); 446 | generatePagination( 447 | searchPage, 448 | searchPageSize, 449 | totalResults, 450 | "#search-pagination" 451 | ); 452 | 453 | // Add event listener to each play button 454 | searchResults.querySelectorAll("#play-torrent").forEach((el) => { 455 | el.addEventListener("click", async (e) => { 456 | const magnet = e.target.getAttribute("data-magnet"); 457 | document.querySelector("#magnet").value = magnet; 458 | document 459 | .querySelector("#torrent-form") 460 | .dispatchEvent(new Event("submit")); 461 | e.target.setAttribute("disabled", "disabled"); 462 | e.target.innerHTML = ""; 463 | e.target.classList.add("loader"); 464 | }); 465 | }); 466 | }; 467 | 468 | document.querySelector("#search-form").addEventListener("submit", (e) => { 469 | e.preventDefault(); 470 | const query = e.target.querySelector("#search").value; 471 | if (!query) { 472 | butterup.toast({ 473 | message: "Please enter a search query", 474 | location: "top-right", 475 | icon: true, 476 | dismissable: true, 477 | type: "error", 478 | }); 479 | return; 480 | } 481 | 482 | searchData = []; 483 | searchPage = 1; 484 | 485 | e.target 486 | .querySelector("button[type=submit]") 487 | .setAttribute("disabled", "disabled"); 488 | e.target.querySelector("button[type=submit]").classList.add("loader"); 489 | e.target.querySelector("button[type=submit]").innerHTML = ""; 490 | const searchResults = document.querySelector("#search-result"); 491 | 492 | searchResults.classList.add("hidden"); 493 | document.querySelector("#search-pagination").classList.add("hidden"); 494 | 495 | let apiUrl = "/api/v1/prowlarr/search"; 496 | 497 | if ( 498 | (!settings.prowlarrHost || !settings.prowlarrApiKey) && 499 | settings.jackettHost && 500 | settings.jackettApiKey 501 | ) { 502 | apiUrl = "/api/v1/jackett/search"; 503 | } 504 | 505 | fetch(`${apiUrl}?q=${query}`, { 506 | method: "POST", 507 | headers: { "Content-Type": "application/json" }, 508 | }) 509 | .then(async (res) => { 510 | if (!res.ok) { 511 | const err = await res.json(); 512 | throw new Error(res.error || "Failed to fetch search results"); 513 | } 514 | return res.json(); 515 | }) 516 | .then((data) => { 517 | if (data && typeof data === "object") { 518 | searchData = data; 519 | } else { 520 | searchData = []; 521 | } 522 | 523 | updateSearchResults(); 524 | }) 525 | .catch((error) => { 526 | console.error("There was a problem with the fetch operation:", error); 527 | butterup.toast({ 528 | message: error.message || "Failed to fetch search results", 529 | location: "top-right", 530 | icon: true, 531 | dismissable: true, 532 | type: "error", 533 | }); 534 | }) 535 | .finally(() => { 536 | e.target 537 | .querySelector("button[type=submit]") 538 | .removeAttribute("disabled"); 539 | e.target 540 | .querySelector("button[type=submit]") 541 | .classList.remove("loader"); 542 | e.target.querySelector("button[type=submit]").innerHTML = "Search"; 543 | }); 544 | }); 545 | 546 | const testProwlarrConfig = async () => { 547 | const prowlarrHost = document.querySelector("#prowlarrHost").value; 548 | const prowlarrApiKey = document.querySelector("#prowlarrApiKey").value; 549 | const prowlarrTestBtn = document.querySelector("#test-prowlarr"); 550 | 551 | if (!prowlarrHost || !prowlarrApiKey) { 552 | butterup.toast({ 553 | message: "Please enter Prowlarr host and API key", 554 | location: "top-right", 555 | icon: true, 556 | dismissable: true, 557 | type: "error", 558 | }); 559 | return false; 560 | } 561 | 562 | prowlarrTestBtn.setAttribute("disabled", "disabled"); 563 | prowlarrTestBtn.querySelector("span").innerHTML = "Testing..."; 564 | 565 | const response = await fetch("/api/v1/prowlarr/test", { 566 | method: "POST", 567 | headers: { "Content-Type": "application/json" }, 568 | body: JSON.stringify({ prowlarrHost, prowlarrApiKey }), 569 | }); 570 | 571 | const data = await response.json(); 572 | if (!response.ok) { 573 | butterup.toast({ 574 | message: data.error || "Failed to test Prowlarr connection", 575 | location: "top-right", 576 | icon: true, 577 | dismissable: true, 578 | type: "error", 579 | }); 580 | prowlarrTestBtn.removeAttribute("disabled"); 581 | prowlarrTestBtn.querySelector("span").innerHTML = "Test Connection"; 582 | return false; 583 | } 584 | 585 | butterup.toast({ 586 | message: "Prowlarr settings are valid", 587 | location: "top-right", 588 | icon: true, 589 | dismissable: true, 590 | type: "success", 591 | }); 592 | 593 | prowlarrTestBtn.removeAttribute("disabled"); 594 | prowlarrTestBtn.querySelector("span").innerHTML = "Test Connection"; 595 | 596 | return true; 597 | } 598 | 599 | document.querySelector("#test-prowlarr").addEventListener("click", (e) => { 600 | testProwlarrConfig(); 601 | }); 602 | 603 | const testJackettConfig = async () => { 604 | const jackettHost = document.querySelector("#jackettHost").value; 605 | const jackettApiKey = document.querySelector("#jackettApiKey").value; 606 | const jackettTestBtn = document.querySelector("#test-jackett"); 607 | 608 | if (!jackettHost || !jackettApiKey) { 609 | butterup.toast({ 610 | message: "Please enter Jackett host and API key", 611 | location: "top-right", 612 | icon: true, 613 | dismissable: true, 614 | type: "error", 615 | }); 616 | return false; 617 | } 618 | 619 | jackettTestBtn.setAttribute("disabled", "disabled"); 620 | jackettTestBtn.querySelector("span").innerHTML = "Testing..."; 621 | 622 | const response = await fetch("/api/v1/jackett/test", { 623 | method: "POST", 624 | headers: { "Content-Type": "application/json" }, 625 | body: JSON.stringify({ jackettHost, jackettApiKey }), 626 | }); 627 | 628 | const data = await response.json(); 629 | if (!response.ok) { 630 | butterup.toast({ 631 | message: data.error || "Failed to test Jackett connection", 632 | location: "top-right", 633 | icon: true, 634 | dismissable: true, 635 | type: "error", 636 | }); 637 | jackettTestBtn.removeAttribute("disabled"); 638 | jackettTestBtn.querySelector("span").innerHTML = "Test Connection"; 639 | return false; 640 | } 641 | 642 | butterup.toast({ 643 | message: "Jackett settings are valid", 644 | location: "top-right", 645 | icon: true, 646 | dismissable: true, 647 | type: "success", 648 | }); 649 | 650 | jackettTestBtn.removeAttribute("disabled"); 651 | jackettTestBtn.querySelector("span").innerHTML = "Test Connection"; 652 | 653 | return true; 654 | } 655 | 656 | document.querySelector("#test-jackett").addEventListener("click", (e) => { 657 | testJackettConfig(); 658 | }); 659 | 660 | const testProxy = async () => { 661 | const proxyUrl = document.querySelector("#proxyUrl").value; 662 | const proxyBtn = document.querySelector("#test-proxy"); 663 | 664 | if (!proxyUrl) { 665 | butterup.toast({ 666 | message: "Please enter a proxy URL", 667 | location: "top-right", 668 | icon: true, 669 | dismissable: true, 670 | type: "error", 671 | }); 672 | return false; 673 | } 674 | 675 | proxyBtn.setAttribute("disabled", "disabled"); 676 | proxyBtn.querySelector("span").innerHTML = "Testing..."; 677 | 678 | const response = await fetch("/api/v1/proxy/test", { 679 | method: "POST", 680 | headers: { "Content-Type": "application/json" }, 681 | body: JSON.stringify({ proxyUrl }), 682 | }); 683 | 684 | const data = await response.json(); 685 | 686 | if (!response.ok) { 687 | butterup.toast({ 688 | message: data.error || "Failed to test Proxy connection", 689 | location: "top-right", 690 | icon: true, 691 | dismissable: true, 692 | type: "error", 693 | }); 694 | proxyBtn.removeAttribute("disabled"); 695 | proxyBtn.querySelector("span").innerHTML = "Test Proxy"; 696 | return false; 697 | } 698 | 699 | butterup.toast({ 700 | message: "Proxy url is valid", 701 | location: "top-right", 702 | icon: true, 703 | dismissable: true, 704 | type: "success", 705 | }); 706 | 707 | proxyBtn.removeAttribute("disabled"); 708 | proxyBtn.querySelector("span").innerHTML = "Test Proxy"; 709 | 710 | if (data?.origin) { 711 | document.querySelector("#proxy-result").classList.remove("hidden"); 712 | document.querySelector("#proxy-result").classList.add("flex"); 713 | document.querySelector("#proxy-result .output-ip").innerHTML = data?.origin 714 | } 715 | 716 | return true; 717 | } 718 | 719 | document.querySelector("#test-proxy").addEventListener("click", () => { 720 | testProxy(); 721 | }); 722 | 723 | document 724 | .querySelector("#proxy-settings-form") 725 | .addEventListener("submit", async (e) => { 726 | e.preventDefault(); 727 | const enableProxy = e.target.querySelector("#enableProxy").checked; 728 | const proxyUrl = e.target.querySelector("#proxyUrl").value; 729 | const submitButton = e.target.querySelector("button[type=submit]"); 730 | 731 | submitButton.setAttribute("disabled", "disabled"); 732 | 733 | if (enableProxy) { 734 | const isValid = await testProxy(); 735 | if (!isValid) { 736 | submitButton.removeAttribute("disabled"); 737 | return; 738 | } 739 | } 740 | 741 | submitButton.classList.add("loader"); 742 | submitButton.innerHTML = "Saving..."; 743 | 744 | const body = { 745 | enableProxy, 746 | proxyUrl, 747 | }; 748 | 749 | const response = await fetch("/api/v1/settings/proxy", { 750 | method: "POST", 751 | headers: { "Content-Type": "application/json" }, 752 | body: JSON.stringify(body), 753 | }) 754 | 755 | const data = await response.json(); 756 | 757 | if (!response.ok) { 758 | butterup.toast({ 759 | message: data.error || "Failed to save settings", 760 | location: "top-right", 761 | icon: true, 762 | dismissable: true, 763 | type: "error", 764 | }); 765 | } else { 766 | butterup.toast({ 767 | message: "Proxy settings saved successfully", 768 | location: "top-right", 769 | icon: true, 770 | dismissable: true, 771 | type: "success", 772 | }); 773 | 774 | settings = { 775 | ...settings, 776 | enableProxy: body.enableProxy, 777 | proxyUrl: body.proxyUrl, 778 | }; 779 | } 780 | 781 | submitButton.removeAttribute("disabled"); 782 | submitButton.classList.remove("loader"); 783 | submitButton.innerHTML = "Save Settings"; 784 | }); 785 | 786 | document 787 | .querySelector("#prowlarr-settings-form") 788 | .addEventListener("submit", async (e) => { 789 | e.preventDefault(); 790 | const enableProwlarr = e.target.querySelector("#enableProwlarr").checked; 791 | const prowlarrHost = e.target.querySelector("#prowlarrHost").value; 792 | const prowlarrApiKey = e.target.querySelector("#prowlarrApiKey").value; 793 | const submitButton = e.target.querySelector("button[type=submit]"); 794 | 795 | submitButton.setAttribute("disabled", "disabled"); 796 | 797 | if (enableProwlarr) { 798 | const isValid = await testProwlarrConfig(); 799 | if (!isValid) { 800 | submitButton.removeAttribute("disabled"); 801 | return; 802 | } 803 | } 804 | 805 | submitButton.classList.add("loader"); 806 | submitButton.innerHTML = "Saving..."; 807 | 808 | const body = { 809 | enableProwlarr, 810 | prowlarrHost, 811 | prowlarrApiKey, 812 | }; 813 | 814 | const response = await fetch("/api/v1/settings/prowlarr", { 815 | method: "POST", 816 | headers: { "Content-Type": "application/json" }, 817 | body: JSON.stringify(body), 818 | }) 819 | 820 | const data = await response.json(); 821 | if (!response.ok) { 822 | butterup.toast({ 823 | message: data.error || "Failed to save settings", 824 | location: "top-right", 825 | icon: true, 826 | dismissable: true, 827 | type: "error", 828 | }); 829 | } else { 830 | butterup.toast({ 831 | message: "Prowlarr settings saved successfully", 832 | location: "top-right", 833 | icon: true, 834 | dismissable: true, 835 | type: "success", 836 | }); 837 | 838 | settings = { 839 | ...settings, 840 | enableProwlarr: body.enableProwlarr, 841 | prowlarrHost: body.prowlarrHost, 842 | prowlarrApiKey: body.prowlarrApiKey, 843 | }; 844 | 845 | // Check if Prowlarr or Jackett is enabled 846 | if (body?.enableProwlarr || settings?.enableJackett) { 847 | searchWrapper.classList.remove("hidden"); 848 | } else { 849 | searchWrapper.classList.add("hidden"); 850 | } 851 | } 852 | 853 | submitButton.removeAttribute("disabled"); 854 | submitButton.classList.remove("loader"); 855 | submitButton.innerHTML = "Save Settings"; 856 | }); 857 | 858 | document 859 | .querySelector("#jackett-settings-form") 860 | .addEventListener("submit", async (e) => { 861 | e.preventDefault(); 862 | const enableJackett = e.target.querySelector("#enableJackett").checked; 863 | const jackettHost = e.target.querySelector("#jackettHost").value; 864 | const jackettApiKey = e.target.querySelector("#jackettApiKey").value; 865 | const submitButton = e.target.querySelector("button[type=submit]"); 866 | 867 | submitButton.setAttribute("disabled", "disabled"); 868 | 869 | if (enableJackett) { 870 | const isValid = await testJackettConfig(); 871 | if (!isValid) { 872 | submitButton.removeAttribute("disabled"); 873 | return; 874 | } 875 | } 876 | 877 | submitButton.classList.add("loader"); 878 | submitButton.innerHTML = "Saving..."; 879 | 880 | const body = { 881 | enableJackett, 882 | jackettHost, 883 | jackettApiKey, 884 | }; 885 | 886 | const response = await fetch("/api/v1/settings/jackett", { 887 | method: "POST", 888 | headers: { "Content-Type": "application/json" }, 889 | body: JSON.stringify(body), 890 | }) 891 | 892 | const data = await response.json(); 893 | if (!response.ok) { 894 | butterup.toast({ 895 | message: data.error || "Failed to save settings", 896 | location: "top-right", 897 | icon: true, 898 | dismissable: true, 899 | type: "error", 900 | }); 901 | } else { 902 | butterup.toast({ 903 | message: "Jackett settings saved successfully", 904 | location: "top-right", 905 | icon: true, 906 | dismissable: true, 907 | type: "success", 908 | }); 909 | 910 | settings = { 911 | ...settings, 912 | enableJackett: body.enableJackett, 913 | jackettHost: body.jackettHost, 914 | jackettApiKey: body.jackettApiKey, 915 | }; 916 | 917 | // Check if Jackett or Jackett is enabled 918 | if (body?.enableJackett || settings?.enableJackett) { 919 | searchWrapper.classList.remove("hidden"); 920 | } else { 921 | searchWrapper.classList.add("hidden"); 922 | } 923 | } 924 | 925 | submitButton.removeAttribute("disabled"); 926 | submitButton.classList.remove("loader"); 927 | submitButton.innerHTML = "Save Settings"; 928 | }); 929 | 930 | document.querySelector("#torrent_file").addEventListener("change", (e) => { 931 | const file = e.target.files[0]; 932 | if (file) { 933 | const formData = new FormData(); 934 | formData.append("torrent", file); 935 | 936 | fetch("/api/v1/torrent/convert", { 937 | method: "POST", 938 | body: formData, 939 | }) 940 | .then(async (res) => { 941 | if (!res.ok) { 942 | const err = await res.json(); 943 | throw new Error(err.error || "Failed to upload torrent file"); 944 | } 945 | return res.json(); 946 | }) 947 | .then((data) => { 948 | document.querySelector("#magnet").value = data.magnet; 949 | document 950 | .querySelector("#torrent-form") 951 | .dispatchEvent(new Event("submit")); 952 | }) 953 | .catch((error) => { 954 | console.error("There was a problem with the fetch operation:", error); 955 | butterup.toast({ 956 | message: error.message || "Failed to upload torrent file", 957 | location: "top-right", 958 | icon: true, 959 | dismissable: true, 960 | type: "error", 961 | }); 962 | }); 963 | } 964 | }); 965 | 966 | const torrentFileWrapper = document.querySelector("#torrent_file_wrapper"); 967 | torrentFileWrapper.addEventListener("dragenter", (e) => { 968 | e.preventDefault(); 969 | e.stopPropagation(); 970 | torrentFileWrapper.classList.add("drag-over"); 971 | }); 972 | torrentFileWrapper.addEventListener("dragover", (e) => { 973 | e.preventDefault(); 974 | e.stopPropagation(); 975 | }); 976 | torrentFileWrapper.addEventListener("dragleave", (e) => { 977 | e.preventDefault(); 978 | e.stopPropagation(); 979 | torrentFileWrapper.classList.remove("drag-over"); 980 | }); 981 | torrentFileWrapper.addEventListener("drop", (e) => { 982 | e.preventDefault(); 983 | e.stopPropagation(); 984 | torrentFileWrapper.classList.remove("drag-over"); 985 | const files = e.dataTransfer.files; 986 | if (files.length > 0) { 987 | const file = files[0]; 988 | if (file.name.endsWith(".torrent")) { 989 | const formData = new FormData(); 990 | formData.append("torrent", file); 991 | 992 | fetch("/api/v1/torrent/convert", { 993 | method: "POST", 994 | body: formData, 995 | }) 996 | .then(async (res) => { 997 | if (!res.ok) { 998 | const err = await res.json(); 999 | throw new Error(err.error || "Failed to upload torrent file"); 1000 | } 1001 | return res.json(); 1002 | }) 1003 | .then((data) => { 1004 | document.querySelector("#magnet").value = data.magnet; 1005 | document 1006 | .querySelector("#torrent-form") 1007 | .dispatchEvent(new Event("submit")); 1008 | }) 1009 | .catch((error) => { 1010 | console.error( 1011 | "There was a problem with the fetch operation:", 1012 | error 1013 | ); 1014 | butterup.toast({ 1015 | message: error.message || "Failed to upload torrent file", 1016 | location: "top-right", 1017 | icon: true, 1018 | dismissable: true, 1019 | type: "error", 1020 | }); 1021 | }); 1022 | } else { 1023 | butterup.toast({ 1024 | message: "Please drop a valid torrent file", 1025 | location: "top-right", 1026 | icon: true, 1027 | dismissable: true, 1028 | type: "error", 1029 | }); 1030 | } 1031 | } 1032 | }); 1033 | 1034 | // fetch settings 1035 | fetch("/api/v1/settings") 1036 | .then((res) => { 1037 | if (!res.ok) { 1038 | throw new Error("Network response was not ok"); 1039 | } 1040 | return res.json(); 1041 | }) 1042 | .then((data) => { 1043 | settings = data; 1044 | document.querySelector("#enableProxy").checked = data.enableProxy; 1045 | document.querySelector("#proxyUrl").value = data.proxyUrl || ""; 1046 | document.querySelector("#enableProwlarr").checked = 1047 | data.enableProwlarr || false; 1048 | document.querySelector("#prowlarrHost").value = data.prowlarrHost || ""; 1049 | document.querySelector("#prowlarrApiKey").value = 1050 | data.prowlarrApiKey || ""; 1051 | document.querySelector("#enableJackett").checked = 1052 | data.enableJackett || false; 1053 | document.querySelector("#jackettHost").value = data.jackettHost || ""; 1054 | document.querySelector("#jackettApiKey").value = data.jackettApiKey || ""; 1055 | 1056 | // Set switch button state 1057 | const switchInputs = document.querySelectorAll("#switchInput"); 1058 | switchInputs.forEach((input) => { 1059 | const dot = input.querySelector(".dot"); 1060 | const wrapper = input.querySelector(".switch-wrapper"); 1061 | if (input.querySelector("input").checked) { 1062 | dot.classList.add("translate-x-full", "!bg-muted"); 1063 | wrapper.classList.add("bg-primary"); 1064 | } else { 1065 | dot.classList.remove("translate-x-full", "!bg-muted"); 1066 | wrapper.classList.remove("bg-primary"); 1067 | } 1068 | }); 1069 | 1070 | // Check if Prowlarr or Jackett is enabled 1071 | if (data?.enableProwlarr || data?.enableJackett) { 1072 | searchWrapper.classList.remove("hidden"); 1073 | } else { 1074 | searchWrapper.classList.add("hidden"); 1075 | } 1076 | }) 1077 | .catch((error) => { 1078 | console.error("There was a problem with the fetch operation:", error); 1079 | }); 1080 | })(); 1081 | -------------------------------------------------------------------------------- /client/assets/videojs.hotkeys.min.js: -------------------------------------------------------------------------------- 1 | /* videojs-hotkeys v0.2.30 - https://github.com/ctd1500/videojs-hotkeys */ 2 | (t=>{var e;"undefined"!=typeof window&&window.videojs?t(window.videojs):"function"==typeof define&&define.amd?define("videojs-hotkeys",["video.js"],function(e){return t(e.default||e)}):"undefined"!=typeof module&&module.exports&&(e=require("video.js"),module.exports=t(e.default||e))})(function(I){"undefined"!=typeof window&&(window.videojs_hotkeys={version:"0.2.30"});(I.registerPlugin||I.plugin)("hotkeys",function(a){function e(e){var t;t=u?0:y.activeElement,s.controls()&&(q||t==m||t==m.querySelector(".vjs-tech")||t==m.querySelector(".iframeblocker")||t==m.querySelector(".vjs-control-bar")||x)&&r&&(e=window.event||e,t=Math.max(-1,Math.min(1,e.wheelDelta||-e.detail)),e.preventDefault(),1==t?s.volume(s.volume()+k):-1==t&&s.volume(s.volume()-k))}var t,s=this,m=s.el(),y=document,d=1,v=2,f=3,p=4,b=5,h=6,w=7,n=I.obj?.merge||I.mergeOptions||I.util.mergeOptions,k=(a=n({volumeStep:.1,seekStep:5,enableMute:!0,enableVolumeScroll:!0,enableHoverScroll:!1,enableFullscreen:!0,enableNumbers:!0,enableJogStyle:!1,alwaysCaptureHotkeys:!1,captureDocumentHotkeys:!1,documentHotkeysFocusElementFilter:()=>!1,enableModifiersForNumbers:!0,enableInactiveFocus:!0,skipInitialFocus:!1,playPauseKey:function(e){return 32===e.which||179===e.which},rewindKey:function(e){return 37===e.which||177===e.which},forwardKey:function(e){return 39===e.which||176===e.which},volumeUpKey:function(e){return 38===e.which},volumeDownKey:function(e){return 40===e.which},muteKey:function(e){return 77===e.which},fullscreenKey:function(e){return 70===e.which},customKeys:{}},a||{})).volumeStep,o=a.seekStep,S=a.enableMute,r=a.enableVolumeScroll,u=a.enableHoverScroll,K=a.enableFullscreen,F=a.enableNumbers,j=a.enableJogStyle,q=a.alwaysCaptureHotkeys,E=a.captureDocumentHotkeys,T=a.documentHotkeysFocusElementFilter,g=a.enableModifiersForNumbers,n=a.enableInactiveFocus,l=a.skipInitialFocus,i=I.VERSION,c=(m.hasAttribute("tabIndex")||m.setAttribute("tabIndex","-1"),m.style.outline="none",!q&&s.autoplay()||l||s.one("play",()=>{m.focus()}),n&&s.on("userinactive",()=>{var o=()=>{clearTimeout(e)},e=setTimeout(()=>{s.off("useractive",o);var e=y.activeElement,t=e.parentElement,n=m.querySelector(".vjs-control-bar");!e||n!=t&&n!=t.parentElement||m.focus()},10);s.one("useractive",o)}),s.on("play",()=>{var e=m.querySelector(".iframeblocker");e&&""===e.style.display&&(e.style.display="block",e.style.bottom="39px")}),function(e){var t=e.which,n=e.preventDefault.bind(e),o=s.duration();if(s.controls()){var r,u,l,i=y.activeElement;if(q||E&&T(i)||i==m||i==m.querySelector(".vjs-tech")||i==m.querySelector(".vjs-control-bar")||i==m.querySelector(".iframeblocker"))switch(D(e,s)){case d:n(),(q||E)&&e.stopPropagation(),s.paused()?M(s.play()):s.pause();break;case v:r=!s.paused(),n(),r&&s.pause(),u=s.currentTime()-H(e),s.currentTime(u=u<=0?0:u),r&&M(s.play());break;case f:r=!s.paused(),n(),r&&s.pause(),u=s.currentTime()+H(e),s.currentTime(u=o<=u?r?o-.001:o:u),r&&M(s.play());break;case b:n(),j?(u=s.currentTime()-1,s.currentTime()<=1&&(u=0),s.currentTime(u)):s.volume(s.volume()-k);break;case p:n(),j?(u=s.currentTime()+1,s.currentTime(u=o<=u?o:u)):s.volume(s.volume()+k);break;case h:S&&s.muted(!s.muted());break;case w:K&&(s.isFullscreen()?s.exitFullscreen():s.requestFullscreen());break;default:for(l in!(47{x=!0}),l.addEventListener("mouseout",()=>{x=!1})),function(e,t){return a.playPauseKey(e,t)?d:a.rewindKey(e,t)?v:a.forwardKey(e,t)?f:a.volumeUpKey(e,t)?p:a.volumeDownKey(e,t)?b:a.muteKey(e,t)?h:a.fullscreenKey(e,t)?w:void 0});function H(e){return"function"==typeof o?o(e):o}function M(e){null!=e&&"function"==typeof e.then&&e.then(null,function(e){})}return E?(t=function(e){c(e)},document.addEventListener("keydown",t),this.dispose=()=>{document.removeEventListener("keydown",t)}):s.on("keydown",c),s.on("dblclick",function(e){null!=i&&i<="7.1.0"&&(!s.controls()||(e=e.relatedTarget||e.toElement||y.activeElement)!=m&&e!=m.querySelector(".vjs-tech")&&e!=m.querySelector(".iframeblocker")||K&&(s.isFullscreen()?s.exitFullscreen():s.requestFullscreen()))}),s.on("mousewheel",e),s.on("DOMMouseScroll",e),this})}); -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BitPlay - Stream Torrents Inside the Browser 7 | 11 | 12 | 16 | 17 | 18 | 26 | 27 | 28 | 29 |
32 |
33 |
34 | logo 35 | bitplay 36 |
37 |
38 | 43 | 67 |
68 |
69 |

72 | Stream torrents with ease 73 |

74 | 125 |
126 |
127 | 133 | 159 |
160 | 161 |
162 |
166 | 178 | 181 | 182 | 183 | Try Demo with Sintel (CC Movie) 184 |
185 |
189 | 201 | 202 | 203 | 204 | 205 | Drag and drop your torrent file here, or 207 | Browse 208 | 209 | 215 |
216 | 217 |
218 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module torrent-stream 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/anacrolix/torrent v1.58.1 7 | golang.org/x/net v0.38.0 8 | ) 9 | 10 | require ( 11 | github.com/RoaringBitmap/roaring v1.2.3 // indirect 12 | github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect 13 | github.com/alecthomas/atomic v0.1.0-alpha2 // indirect 14 | github.com/anacrolix/chansync v0.4.1-0.20240627045151-1aa1ac392fe8 // indirect 15 | github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444 // indirect 16 | github.com/anacrolix/envpprof v1.3.0 // indirect 17 | github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca // indirect 18 | github.com/anacrolix/go-libutp v1.3.2 // indirect 19 | github.com/anacrolix/log v0.15.3-0.20240627045001-cd912c641d83 // indirect 20 | github.com/anacrolix/missinggo v1.3.0 // indirect 21 | github.com/anacrolix/missinggo/perf v1.0.0 // indirect 22 | github.com/anacrolix/missinggo/v2 v2.7.4 // indirect 23 | github.com/anacrolix/mmsg v1.0.1 // indirect 24 | github.com/anacrolix/multiless v0.4.0 // indirect 25 | github.com/anacrolix/stm v0.4.0 // indirect 26 | github.com/anacrolix/sync v0.5.1 // indirect 27 | github.com/anacrolix/upnp v0.1.4 // indirect 28 | github.com/anacrolix/utp v0.1.0 // indirect 29 | github.com/bahlo/generic-list-go v0.2.0 // indirect 30 | github.com/benbjohnson/immutable v0.3.0 // indirect 31 | github.com/bits-and-blooms/bitset v1.2.2 // indirect 32 | github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect 33 | github.com/cespare/xxhash v1.1.0 // indirect 34 | github.com/davecgh/go-spew v1.1.1 // indirect 35 | github.com/dustin/go-humanize v1.0.0 // indirect 36 | github.com/edsrzf/mmap-go v1.1.0 // indirect 37 | github.com/go-llsqlite/adapter v0.0.0-20230927005056-7f5ce7f0c916 // indirect 38 | github.com/go-llsqlite/crawshaw v0.5.2-0.20240425034140-f30eb7704568 // indirect 39 | github.com/go-logr/logr v1.2.3 // indirect 40 | github.com/go-logr/stdr v1.2.2 // indirect 41 | github.com/google/btree v1.1.2 // indirect 42 | github.com/google/uuid v1.6.0 // indirect 43 | github.com/gorilla/websocket v1.5.0 // indirect 44 | github.com/huandu/xstrings v1.3.2 // indirect 45 | github.com/klauspost/cpuid/v2 v2.2.3 // indirect 46 | github.com/mattn/go-isatty v0.0.16 // indirect 47 | github.com/minio/sha256-simd v1.0.0 // indirect 48 | github.com/mr-tron/base58 v1.2.0 // indirect 49 | github.com/mschoch/smat v0.2.0 // indirect 50 | github.com/multiformats/go-multihash v0.2.3 // indirect 51 | github.com/multiformats/go-varint v0.0.6 // indirect 52 | github.com/pion/datachannel v1.5.9 // indirect 53 | github.com/pion/dtls/v3 v3.0.3 // indirect 54 | github.com/pion/ice/v4 v4.0.2 // indirect 55 | github.com/pion/interceptor v0.1.37 // indirect 56 | github.com/pion/logging v0.2.2 // indirect 57 | github.com/pion/mdns/v2 v2.0.7 // indirect 58 | github.com/pion/randutil v0.1.0 // indirect 59 | github.com/pion/rtcp v1.2.14 // indirect 60 | github.com/pion/rtp v1.8.9 // indirect 61 | github.com/pion/sctp v1.8.33 // indirect 62 | github.com/pion/sdp/v3 v3.0.9 // indirect 63 | github.com/pion/srtp/v3 v3.0.4 // indirect 64 | github.com/pion/stun/v3 v3.0.0 // indirect 65 | github.com/pion/transport/v3 v3.0.7 // indirect 66 | github.com/pion/turn/v4 v4.0.0 // indirect 67 | github.com/pion/webrtc/v4 v4.0.0 // indirect 68 | github.com/pkg/errors v0.9.1 // indirect 69 | github.com/protolambda/ctxlock v0.1.0 // indirect 70 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect 71 | github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 // indirect 72 | github.com/spaolacci/murmur3 v1.1.0 // indirect 73 | github.com/tidwall/btree v1.6.0 // indirect 74 | github.com/wlynxg/anet v0.0.3 // indirect 75 | go.etcd.io/bbolt v1.3.6 // indirect 76 | go.opentelemetry.io/otel v1.11.1 // indirect 77 | go.opentelemetry.io/otel/trace v1.11.1 // indirect 78 | golang.org/x/crypto v0.36.0 // indirect 79 | golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect 80 | golang.org/x/sync v0.8.0 // indirect 81 | golang.org/x/sys v0.31.0 // indirect 82 | golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect 83 | lukechampine.com/blake3 v1.1.6 // indirect 84 | modernc.org/libc v1.22.3 // indirect 85 | modernc.org/mathutil v1.5.0 // indirect 86 | modernc.org/memory v1.5.0 // indirect 87 | modernc.org/sqlite v1.21.1 // indirect 88 | zombiezen.com/go/sqlite v0.13.1 // indirect 89 | ) 90 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk= 4 | crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4= 5 | filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= 6 | filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= 7 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 8 | github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= 9 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 10 | github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= 11 | github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI= 12 | github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= 13 | github.com/RoaringBitmap/roaring v1.2.3 h1:yqreLINqIrX22ErkKI0vY47/ivtJr6n+kMhVOVmhWBY= 14 | github.com/RoaringBitmap/roaring v1.2.3/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE= 15 | github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= 16 | github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= 17 | github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 h1:byYvvbfSo3+9efR4IeReh77gVs4PnNDR3AMOE9NJ7a0= 18 | github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0/go.mod h1:q37NoqncT41qKc048STsifIt69LfUJ8SrWWcz/yam5k= 19 | github.com/alecthomas/assert/v2 v2.0.0-alpha3 h1:pcHeMvQ3OMstAWgaeaXIAL8uzB9xMm2zlxt+/4ml8lk= 20 | github.com/alecthomas/assert/v2 v2.0.0-alpha3/go.mod h1:+zD0lmDXTeQj7TgDgCt0ePWxb0hMC1G+PGTsTCv1B9o= 21 | github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= 22 | github.com/alecthomas/atomic v0.1.0-alpha2/go.mod h1:zD6QGEyw49HIq19caJDc2NMXAy8rNi9ROrxtMXATfyI= 23 | github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142 h1:8Uy0oSf5co/NZXje7U1z8Mpep++QJOldL2hs/sBQf48= 24 | github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= 25 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 26 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 27 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 28 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 29 | github.com/anacrolix/chansync v0.4.1-0.20240627045151-1aa1ac392fe8 h1:eyb0bBaQKMOh5Se/Qg54shijc8K4zpQiOjEhKFADkQM= 30 | github.com/anacrolix/chansync v0.4.1-0.20240627045151-1aa1ac392fe8/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k= 31 | github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444 h1:8V0K09lrGoeT2KRJNOtspA7q+OMxGwQqK/Ug0IiaaRE= 32 | github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444/go.mod h1:MctKM1HS5YYDb3F30NGJxLE+QPuqWoT5ReW/4jt8xew= 33 | github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= 34 | github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= 35 | github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4= 36 | github.com/anacrolix/envpprof v1.3.0 h1:WJt9bpuT7A/CDCxPOv/eeZqHWlle/Y0keJUvc6tcJDk= 37 | github.com/anacrolix/envpprof v1.3.0/go.mod h1:7QIG4CaX1uexQ3tqd5+BRa/9e2D02Wcertl6Yh0jCB0= 38 | github.com/anacrolix/generics v0.0.0-20230113004304-d6428d516633/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8= 39 | github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca h1:aiiGqSQWjtVNdi8zUMfA//IrM8fPkv2bWwZVPbDe0wg= 40 | github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca/go.mod h1:MN3ve08Z3zSV/rTuX/ouI4lNdlfTxgdafQJiLzyNRB8= 41 | github.com/anacrolix/go-libutp v1.3.2 h1:WswiaxTIogchbkzNgGHuHRfbrYLpv4o290mlvcx+++M= 42 | github.com/anacrolix/go-libutp v1.3.2/go.mod h1:fCUiEnXJSe3jsPG554A200Qv+45ZzIIyGEvE56SHmyA= 43 | github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU= 44 | github.com/anacrolix/log v0.6.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU= 45 | github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68= 46 | github.com/anacrolix/log v0.14.2/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY= 47 | github.com/anacrolix/log v0.15.3-0.20240627045001-cd912c641d83 h1:9o/yVzzLzYaBDFx8B27yhkvBLhNnRAuSTK7Y+yZKVtU= 48 | github.com/anacrolix/log v0.15.3-0.20240627045001-cd912c641d83/go.mod h1:xvHjsYWWP7yO8PZwtuIp/k0DBlu07pSJqH4SEC78Vwc= 49 | github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62 h1:P04VG6Td13FHMgS5ZBcJX23NPC/fiC4cp9bXwYujdYM= 50 | github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM= 51 | github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s= 52 | github.com/anacrolix/missinggo v1.1.0/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo= 53 | github.com/anacrolix/missinggo v1.1.2-0.20190815015349-b888af804467/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo= 54 | github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikzMt+uUjeM21Y= 55 | github.com/anacrolix/missinggo v1.3.0 h1:06HlMsudotL7BAELRZs0yDZ4yVXsHXGi323QBjAVASw= 56 | github.com/anacrolix/missinggo v1.3.0/go.mod h1:bqHm8cE8xr+15uVfMG3BFui/TxyB6//H5fwlq/TeqMc= 57 | github.com/anacrolix/missinggo/perf v1.0.0 h1:7ZOGYziGEBytW49+KmYGTaNfnwUqP1HBsy6BqESAJVw= 58 | github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ= 59 | github.com/anacrolix/missinggo/v2 v2.2.0/go.mod h1:o0jgJoYOyaoYQ4E2ZMISVa9c88BbUBVQQW4QeRkNCGY= 60 | github.com/anacrolix/missinggo/v2 v2.5.1/go.mod h1:WEjqh2rmKECd0t1VhQkLGTdIWXO6f6NLjp5GlMZ+6FA= 61 | github.com/anacrolix/missinggo/v2 v2.7.4 h1:47h5OXoPV8JbA/ACA+FLwKdYbAinuDO8osc2Cu9xkxg= 62 | github.com/anacrolix/missinggo/v2 v2.7.4/go.mod h1:vVO5FEziQm+NFmJesc7StpkquZk+WJFCaL0Wp//2sa0= 63 | github.com/anacrolix/mmsg v1.0.1 h1:TxfpV7kX70m3f/O7ielL/2I3OFkMPjrRCPo7+4X5AWw= 64 | github.com/anacrolix/mmsg v1.0.1/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc= 65 | github.com/anacrolix/multiless v0.4.0 h1:lqSszHkliMsZd2hsyrDvHOw4AbYWa+ijQ66LzbjqWjM= 66 | github.com/anacrolix/multiless v0.4.0/go.mod h1:zJv1JF9AqdZiHwxqPgjuOZDGWER6nyE48WBCi/OOrMM= 67 | github.com/anacrolix/stm v0.2.0/go.mod h1:zoVQRvSiGjGoTmbM0vSLIiaKjWtNPeTvXUSdJQA4hsg= 68 | github.com/anacrolix/stm v0.4.0 h1:tOGvuFwaBjeu1u9X1eIh9TX8OEedEiEQ1se1FjhFnXY= 69 | github.com/anacrolix/stm v0.4.0/go.mod h1:GCkwqWoAsP7RfLW+jw+Z0ovrt2OO7wRzcTtFYMYY5t8= 70 | github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk= 71 | github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g= 72 | github.com/anacrolix/sync v0.5.1 h1:FbGju6GqSjzVoTgcXTUKkF041lnZkG5P0C3T5RL3SGc= 73 | github.com/anacrolix/sync v0.5.1/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g= 74 | github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= 75 | github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= 76 | github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8= 77 | github.com/anacrolix/torrent v1.58.1 h1:6FP+KH57b1gyT2CpVL9fEqf9MGJEgh3xw1VA8rI0pW8= 78 | github.com/anacrolix/torrent v1.58.1/go.mod h1:/7ZdLuHNKgtCE1gjYJCfbtG9JodBcDaF5ip5EUWRtk8= 79 | github.com/anacrolix/upnp v0.1.4 h1:+2t2KA6QOhm/49zeNyeVwDu1ZYS9dB9wfxyVvh/wk7U= 80 | github.com/anacrolix/upnp v0.1.4/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic= 81 | github.com/anacrolix/utp v0.1.0 h1:FOpQOmIwYsnENnz7tAGohA+r6iXpRjrq8ssKSre2Cp4= 82 | github.com/anacrolix/utp v0.1.0/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk= 83 | github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 84 | github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= 85 | github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= 86 | github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI= 87 | github.com/benbjohnson/immutable v0.3.0 h1:TVRhuZx2wG9SZ0LRdqlbs9S5BZ6Y24hJEHTCgWHZEIw= 88 | github.com/benbjohnson/immutable v0.3.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI= 89 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 90 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 91 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 92 | github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= 93 | github.com/bits-and-blooms/bitset v1.2.2 h1:J5gbX05GpMdBjCvQ9MteIg2KKDExr7DrgK+Yc15FvIk= 94 | github.com/bits-and-blooms/bitset v1.2.2/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= 95 | github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= 96 | github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= 97 | github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8= 98 | github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og= 99 | github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 100 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 101 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 102 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 103 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 104 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 105 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 106 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 107 | github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= 108 | github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 109 | github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= 110 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 111 | github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= 112 | github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= 113 | github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= 114 | github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= 115 | github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= 116 | github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= 117 | github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 118 | github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= 119 | github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 120 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 121 | github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= 122 | github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= 123 | github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= 124 | github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= 125 | github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= 126 | github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= 127 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 128 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 129 | github.com/go-llsqlite/adapter v0.0.0-20230927005056-7f5ce7f0c916 h1:OyQmpAN302wAopDgwVjgs2HkFawP9ahIEqkUYz7V7CA= 130 | github.com/go-llsqlite/adapter v0.0.0-20230927005056-7f5ce7f0c916/go.mod h1:DADrR88ONKPPeSGjFp5iEN55Arx3fi2qXZeKCYDpbmU= 131 | github.com/go-llsqlite/crawshaw v0.5.2-0.20240425034140-f30eb7704568 h1:3EpZo8LxIzF4q3BT+vttQQlRfA6uTtTb/cxVisWa5HM= 132 | github.com/go-llsqlite/crawshaw v0.5.2-0.20240425034140-f30eb7704568/go.mod h1:/YJdV7uBQaYDE0fwe4z3wwJIZBJxdYzd38ICggWqtaE= 133 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 134 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 135 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 136 | github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= 137 | github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 138 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 139 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 140 | github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= 141 | github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= 142 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 143 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 144 | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 145 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 146 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 147 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 148 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 149 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 150 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 151 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 152 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 153 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 154 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 155 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 156 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 157 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 158 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 159 | github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 160 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 161 | github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= 162 | github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= 163 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 164 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 165 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 166 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 167 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 168 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 169 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 170 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 171 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 172 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 173 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 174 | github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 175 | github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 176 | github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 177 | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= 178 | github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 179 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= 180 | github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 181 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 182 | github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= 183 | github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= 184 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 185 | github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= 186 | github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= 187 | github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 188 | github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 189 | github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= 190 | github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 191 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 192 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 193 | github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 194 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 195 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 196 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 197 | github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 198 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 199 | github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= 200 | github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 201 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 202 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 203 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 204 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 205 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 206 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 207 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 208 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 209 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 210 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 211 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 212 | github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= 213 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 214 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 215 | github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= 216 | github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= 217 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 218 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 219 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 220 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 221 | github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 222 | github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 223 | github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= 224 | github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= 225 | github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= 226 | github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= 227 | github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= 228 | github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= 229 | github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= 230 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 231 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 232 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 233 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 234 | github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= 235 | github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= 236 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 237 | github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA= 238 | github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE= 239 | github.com/pion/dtls/v3 v3.0.3 h1:j5ajZbQwff7Z8k3pE3S+rQ4STvKvXUdKsi/07ka+OWM= 240 | github.com/pion/dtls/v3 v3.0.3/go.mod h1:weOTUyIV4z0bQaVzKe8kpaP17+us3yAuiQsEAG1STMU= 241 | github.com/pion/ice/v4 v4.0.2 h1:1JhBRX8iQLi0+TfcavTjPjI6GO41MFn4CeTBX+Y9h5s= 242 | github.com/pion/ice/v4 v4.0.2/go.mod h1:DCdqyzgtsDNYN6/3U8044j3U7qsJ9KFJC92VnOWHvXg= 243 | github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= 244 | github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= 245 | github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= 246 | github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= 247 | github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= 248 | github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= 249 | github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= 250 | github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= 251 | github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= 252 | github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= 253 | github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk= 254 | github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= 255 | github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw= 256 | github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM= 257 | github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= 258 | github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= 259 | github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= 260 | github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ= 261 | github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= 262 | github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= 263 | github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= 264 | github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= 265 | github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= 266 | github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= 267 | github.com/pion/webrtc/v4 v4.0.0 h1:x8ec7uJQPP3D1iI8ojPAiTOylPI7Fa7QgqZrhpLyqZ8= 268 | github.com/pion/webrtc/v4 v4.0.0/go.mod h1:SfNn8CcFxR6OUVjLXVslAQ3a3994JhyE3Hw1jAuqEto= 269 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 270 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 271 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 272 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 273 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 274 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 275 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 276 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 277 | github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= 278 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 279 | github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= 280 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 281 | github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 282 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 283 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 284 | github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 285 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 286 | github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= 287 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 288 | github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 289 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 290 | github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= 291 | github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 292 | github.com/protolambda/ctxlock v0.1.0 h1:rCUY3+vRdcdZXqT07iXgyr744J2DU2LCBIXowYAjBCE= 293 | github.com/protolambda/ctxlock v0.1.0/go.mod h1:vefhX6rIZH8rsg5ZpOJfEDYQOppZi19SfPiGOFrNnwM= 294 | github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 295 | github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 296 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= 297 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 298 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 299 | github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= 300 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 301 | github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= 302 | github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= 303 | github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 h1:Lt9DzQALzHoDwMBGJ6v8ObDPR0dzr2a6sXTB1Fq7IHs= 304 | github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA= 305 | github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8= 306 | github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= 307 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 308 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 309 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 310 | github.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 311 | github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= 312 | github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= 313 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 314 | github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= 315 | github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 316 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 317 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 318 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 319 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 320 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 321 | github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 322 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 323 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 324 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 325 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 326 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 327 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 328 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 329 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 330 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 331 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 332 | github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= 333 | github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= 334 | github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= 335 | github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= 336 | github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= 337 | github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= 338 | github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= 339 | github.com/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg= 340 | github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= 341 | github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 342 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 343 | go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= 344 | go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= 345 | go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 346 | go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 347 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 348 | go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= 349 | go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= 350 | go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= 351 | go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= 352 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 353 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 354 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 355 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 356 | golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 357 | golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= 358 | golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= 359 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 360 | golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= 361 | golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= 362 | golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= 363 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 364 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 365 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 366 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 367 | golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= 368 | golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= 369 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 370 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 371 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 372 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 373 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 374 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 375 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 376 | golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 377 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 378 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 379 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 380 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 381 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 382 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 383 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 384 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 385 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 386 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 387 | golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 388 | golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= 389 | golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= 390 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 391 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 392 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 393 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 394 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 395 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 396 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 397 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 398 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 399 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 400 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 401 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= 402 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 403 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 404 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 405 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 406 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 407 | golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 408 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 409 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 410 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 411 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 412 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 413 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 414 | golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 415 | golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 416 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 417 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 418 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 419 | golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 420 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 421 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 422 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 423 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 424 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 425 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 426 | golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 427 | golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= 428 | golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 429 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 430 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 431 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 432 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 433 | golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= 434 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 435 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 436 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 437 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 438 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 439 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 440 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 441 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 442 | golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= 443 | golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 444 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 445 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 446 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 447 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 448 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 449 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 450 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 451 | golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= 452 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 453 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 454 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 455 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 456 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 457 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 458 | google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= 459 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 460 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 461 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 462 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 463 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 464 | google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 465 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 466 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 467 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 468 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 469 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 470 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 471 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 472 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 473 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 474 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 475 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 476 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 477 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 478 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 479 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 480 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 481 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 482 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 483 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 484 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 485 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 486 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 487 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 488 | lukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c= 489 | lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= 490 | modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY= 491 | modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw= 492 | modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= 493 | modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= 494 | modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= 495 | modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= 496 | modernc.org/sqlite v1.21.1 h1:GyDFqNnESLOhwwDRaHGdp2jKLDzpyT/rNLglX3ZkMSU= 497 | modernc.org/sqlite v1.21.1/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI= 498 | zombiezen.com/go/sqlite v0.13.1 h1:qDzxyWWmMtSSEH5qxamqBFmqA2BLSSbtODi3ojaE02o= 499 | zombiezen.com/go/sqlite v0.13.1/go.mod h1:Ht/5Rg3Ae2hoyh1I7gbWtWAl89CNocfqeb/aAMTkJr4= 500 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "torr-stream", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "@tailwindcss/cli": "^4.1.4", 9 | "tailwindcss": "^4.1.4" 10 | } 11 | }, 12 | "node_modules/@parcel/watcher": { 13 | "version": "2.5.1", 14 | "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", 15 | "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", 16 | "hasInstallScript": true, 17 | "license": "MIT", 18 | "dependencies": { 19 | "detect-libc": "^1.0.3", 20 | "is-glob": "^4.0.3", 21 | "micromatch": "^4.0.5", 22 | "node-addon-api": "^7.0.0" 23 | }, 24 | "engines": { 25 | "node": ">= 10.0.0" 26 | }, 27 | "funding": { 28 | "type": "opencollective", 29 | "url": "https://opencollective.com/parcel" 30 | }, 31 | "optionalDependencies": { 32 | "@parcel/watcher-android-arm64": "2.5.1", 33 | "@parcel/watcher-darwin-arm64": "2.5.1", 34 | "@parcel/watcher-darwin-x64": "2.5.1", 35 | "@parcel/watcher-freebsd-x64": "2.5.1", 36 | "@parcel/watcher-linux-arm-glibc": "2.5.1", 37 | "@parcel/watcher-linux-arm-musl": "2.5.1", 38 | "@parcel/watcher-linux-arm64-glibc": "2.5.1", 39 | "@parcel/watcher-linux-arm64-musl": "2.5.1", 40 | "@parcel/watcher-linux-x64-glibc": "2.5.1", 41 | "@parcel/watcher-linux-x64-musl": "2.5.1", 42 | "@parcel/watcher-win32-arm64": "2.5.1", 43 | "@parcel/watcher-win32-ia32": "2.5.1", 44 | "@parcel/watcher-win32-x64": "2.5.1" 45 | } 46 | }, 47 | "node_modules/@parcel/watcher-android-arm64": { 48 | "version": "2.5.1", 49 | "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", 50 | "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", 51 | "cpu": [ 52 | "arm64" 53 | ], 54 | "license": "MIT", 55 | "optional": true, 56 | "os": [ 57 | "android" 58 | ], 59 | "engines": { 60 | "node": ">= 10.0.0" 61 | }, 62 | "funding": { 63 | "type": "opencollective", 64 | "url": "https://opencollective.com/parcel" 65 | } 66 | }, 67 | "node_modules/@parcel/watcher-darwin-arm64": { 68 | "version": "2.5.1", 69 | "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", 70 | "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", 71 | "cpu": [ 72 | "arm64" 73 | ], 74 | "license": "MIT", 75 | "optional": true, 76 | "os": [ 77 | "darwin" 78 | ], 79 | "engines": { 80 | "node": ">= 10.0.0" 81 | }, 82 | "funding": { 83 | "type": "opencollective", 84 | "url": "https://opencollective.com/parcel" 85 | } 86 | }, 87 | "node_modules/@parcel/watcher-darwin-x64": { 88 | "version": "2.5.1", 89 | "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", 90 | "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", 91 | "cpu": [ 92 | "x64" 93 | ], 94 | "license": "MIT", 95 | "optional": true, 96 | "os": [ 97 | "darwin" 98 | ], 99 | "engines": { 100 | "node": ">= 10.0.0" 101 | }, 102 | "funding": { 103 | "type": "opencollective", 104 | "url": "https://opencollective.com/parcel" 105 | } 106 | }, 107 | "node_modules/@parcel/watcher-freebsd-x64": { 108 | "version": "2.5.1", 109 | "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", 110 | "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", 111 | "cpu": [ 112 | "x64" 113 | ], 114 | "license": "MIT", 115 | "optional": true, 116 | "os": [ 117 | "freebsd" 118 | ], 119 | "engines": { 120 | "node": ">= 10.0.0" 121 | }, 122 | "funding": { 123 | "type": "opencollective", 124 | "url": "https://opencollective.com/parcel" 125 | } 126 | }, 127 | "node_modules/@parcel/watcher-linux-arm-glibc": { 128 | "version": "2.5.1", 129 | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", 130 | "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", 131 | "cpu": [ 132 | "arm" 133 | ], 134 | "license": "MIT", 135 | "optional": true, 136 | "os": [ 137 | "linux" 138 | ], 139 | "engines": { 140 | "node": ">= 10.0.0" 141 | }, 142 | "funding": { 143 | "type": "opencollective", 144 | "url": "https://opencollective.com/parcel" 145 | } 146 | }, 147 | "node_modules/@parcel/watcher-linux-arm-musl": { 148 | "version": "2.5.1", 149 | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", 150 | "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", 151 | "cpu": [ 152 | "arm" 153 | ], 154 | "license": "MIT", 155 | "optional": true, 156 | "os": [ 157 | "linux" 158 | ], 159 | "engines": { 160 | "node": ">= 10.0.0" 161 | }, 162 | "funding": { 163 | "type": "opencollective", 164 | "url": "https://opencollective.com/parcel" 165 | } 166 | }, 167 | "node_modules/@parcel/watcher-linux-arm64-glibc": { 168 | "version": "2.5.1", 169 | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", 170 | "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", 171 | "cpu": [ 172 | "arm64" 173 | ], 174 | "license": "MIT", 175 | "optional": true, 176 | "os": [ 177 | "linux" 178 | ], 179 | "engines": { 180 | "node": ">= 10.0.0" 181 | }, 182 | "funding": { 183 | "type": "opencollective", 184 | "url": "https://opencollective.com/parcel" 185 | } 186 | }, 187 | "node_modules/@parcel/watcher-linux-arm64-musl": { 188 | "version": "2.5.1", 189 | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", 190 | "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", 191 | "cpu": [ 192 | "arm64" 193 | ], 194 | "license": "MIT", 195 | "optional": true, 196 | "os": [ 197 | "linux" 198 | ], 199 | "engines": { 200 | "node": ">= 10.0.0" 201 | }, 202 | "funding": { 203 | "type": "opencollective", 204 | "url": "https://opencollective.com/parcel" 205 | } 206 | }, 207 | "node_modules/@parcel/watcher-linux-x64-glibc": { 208 | "version": "2.5.1", 209 | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", 210 | "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", 211 | "cpu": [ 212 | "x64" 213 | ], 214 | "license": "MIT", 215 | "optional": true, 216 | "os": [ 217 | "linux" 218 | ], 219 | "engines": { 220 | "node": ">= 10.0.0" 221 | }, 222 | "funding": { 223 | "type": "opencollective", 224 | "url": "https://opencollective.com/parcel" 225 | } 226 | }, 227 | "node_modules/@parcel/watcher-linux-x64-musl": { 228 | "version": "2.5.1", 229 | "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", 230 | "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", 231 | "cpu": [ 232 | "x64" 233 | ], 234 | "license": "MIT", 235 | "optional": true, 236 | "os": [ 237 | "linux" 238 | ], 239 | "engines": { 240 | "node": ">= 10.0.0" 241 | }, 242 | "funding": { 243 | "type": "opencollective", 244 | "url": "https://opencollective.com/parcel" 245 | } 246 | }, 247 | "node_modules/@parcel/watcher-win32-arm64": { 248 | "version": "2.5.1", 249 | "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", 250 | "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", 251 | "cpu": [ 252 | "arm64" 253 | ], 254 | "license": "MIT", 255 | "optional": true, 256 | "os": [ 257 | "win32" 258 | ], 259 | "engines": { 260 | "node": ">= 10.0.0" 261 | }, 262 | "funding": { 263 | "type": "opencollective", 264 | "url": "https://opencollective.com/parcel" 265 | } 266 | }, 267 | "node_modules/@parcel/watcher-win32-ia32": { 268 | "version": "2.5.1", 269 | "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", 270 | "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", 271 | "cpu": [ 272 | "ia32" 273 | ], 274 | "license": "MIT", 275 | "optional": true, 276 | "os": [ 277 | "win32" 278 | ], 279 | "engines": { 280 | "node": ">= 10.0.0" 281 | }, 282 | "funding": { 283 | "type": "opencollective", 284 | "url": "https://opencollective.com/parcel" 285 | } 286 | }, 287 | "node_modules/@parcel/watcher-win32-x64": { 288 | "version": "2.5.1", 289 | "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", 290 | "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", 291 | "cpu": [ 292 | "x64" 293 | ], 294 | "license": "MIT", 295 | "optional": true, 296 | "os": [ 297 | "win32" 298 | ], 299 | "engines": { 300 | "node": ">= 10.0.0" 301 | }, 302 | "funding": { 303 | "type": "opencollective", 304 | "url": "https://opencollective.com/parcel" 305 | } 306 | }, 307 | "node_modules/@tailwindcss/cli": { 308 | "version": "4.1.4", 309 | "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.4.tgz", 310 | "integrity": "sha512-gP05Qihh+cZ2FqD5fa0WJXx3KEk2YWUYv/RBKAyiOg0V4vYVDr/xlLc0sacpnVEXM45BVUR9U2hsESufYs6YTA==", 311 | "license": "MIT", 312 | "dependencies": { 313 | "@parcel/watcher": "^2.5.1", 314 | "@tailwindcss/node": "4.1.4", 315 | "@tailwindcss/oxide": "4.1.4", 316 | "enhanced-resolve": "^5.18.1", 317 | "mri": "^1.2.0", 318 | "picocolors": "^1.1.1", 319 | "tailwindcss": "4.1.4" 320 | }, 321 | "bin": { 322 | "tailwindcss": "dist/index.mjs" 323 | } 324 | }, 325 | "node_modules/@tailwindcss/node": { 326 | "version": "4.1.4", 327 | "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.4.tgz", 328 | "integrity": "sha512-MT5118zaiO6x6hNA04OWInuAiP1YISXql8Z+/Y8iisV5nuhM8VXlyhRuqc2PEviPszcXI66W44bCIk500Oolhw==", 329 | "license": "MIT", 330 | "dependencies": { 331 | "enhanced-resolve": "^5.18.1", 332 | "jiti": "^2.4.2", 333 | "lightningcss": "1.29.2", 334 | "tailwindcss": "4.1.4" 335 | } 336 | }, 337 | "node_modules/@tailwindcss/oxide": { 338 | "version": "4.1.4", 339 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.4.tgz", 340 | "integrity": "sha512-p5wOpXyOJx7mKh5MXh5oKk+kqcz8T+bA3z/5VWWeQwFrmuBItGwz8Y2CHk/sJ+dNb9B0nYFfn0rj/cKHZyjahQ==", 341 | "license": "MIT", 342 | "engines": { 343 | "node": ">= 10" 344 | }, 345 | "optionalDependencies": { 346 | "@tailwindcss/oxide-android-arm64": "4.1.4", 347 | "@tailwindcss/oxide-darwin-arm64": "4.1.4", 348 | "@tailwindcss/oxide-darwin-x64": "4.1.4", 349 | "@tailwindcss/oxide-freebsd-x64": "4.1.4", 350 | "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.4", 351 | "@tailwindcss/oxide-linux-arm64-gnu": "4.1.4", 352 | "@tailwindcss/oxide-linux-arm64-musl": "4.1.4", 353 | "@tailwindcss/oxide-linux-x64-gnu": "4.1.4", 354 | "@tailwindcss/oxide-linux-x64-musl": "4.1.4", 355 | "@tailwindcss/oxide-wasm32-wasi": "4.1.4", 356 | "@tailwindcss/oxide-win32-arm64-msvc": "4.1.4", 357 | "@tailwindcss/oxide-win32-x64-msvc": "4.1.4" 358 | } 359 | }, 360 | "node_modules/@tailwindcss/oxide-android-arm64": { 361 | "version": "4.1.4", 362 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.4.tgz", 363 | "integrity": "sha512-xMMAe/SaCN/vHfQYui3fqaBDEXMu22BVwQ33veLc8ep+DNy7CWN52L+TTG9y1K397w9nkzv+Mw+mZWISiqhmlA==", 364 | "cpu": [ 365 | "arm64" 366 | ], 367 | "license": "MIT", 368 | "optional": true, 369 | "os": [ 370 | "android" 371 | ], 372 | "engines": { 373 | "node": ">= 10" 374 | } 375 | }, 376 | "node_modules/@tailwindcss/oxide-darwin-arm64": { 377 | "version": "4.1.4", 378 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.4.tgz", 379 | "integrity": "sha512-JGRj0SYFuDuAGilWFBlshcexev2hOKfNkoX+0QTksKYq2zgF9VY/vVMq9m8IObYnLna0Xlg+ytCi2FN2rOL0Sg==", 380 | "cpu": [ 381 | "arm64" 382 | ], 383 | "license": "MIT", 384 | "optional": true, 385 | "os": [ 386 | "darwin" 387 | ], 388 | "engines": { 389 | "node": ">= 10" 390 | } 391 | }, 392 | "node_modules/@tailwindcss/oxide-darwin-x64": { 393 | "version": "4.1.4", 394 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.4.tgz", 395 | "integrity": "sha512-sdDeLNvs3cYeWsEJ4H1DvjOzaGios4QbBTNLVLVs0XQ0V95bffT3+scptzYGPMjm7xv4+qMhCDrkHwhnUySEzA==", 396 | "cpu": [ 397 | "x64" 398 | ], 399 | "license": "MIT", 400 | "optional": true, 401 | "os": [ 402 | "darwin" 403 | ], 404 | "engines": { 405 | "node": ">= 10" 406 | } 407 | }, 408 | "node_modules/@tailwindcss/oxide-freebsd-x64": { 409 | "version": "4.1.4", 410 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.4.tgz", 411 | "integrity": "sha512-VHxAqxqdghM83HslPhRsNhHo91McsxRJaEnShJOMu8mHmEj9Ig7ToHJtDukkuLWLzLboh2XSjq/0zO6wgvykNA==", 412 | "cpu": [ 413 | "x64" 414 | ], 415 | "license": "MIT", 416 | "optional": true, 417 | "os": [ 418 | "freebsd" 419 | ], 420 | "engines": { 421 | "node": ">= 10" 422 | } 423 | }, 424 | "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { 425 | "version": "4.1.4", 426 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.4.tgz", 427 | "integrity": "sha512-OTU/m/eV4gQKxy9r5acuesqaymyeSCnsx1cFto/I1WhPmi5HDxX1nkzb8KYBiwkHIGg7CTfo/AcGzoXAJBxLfg==", 428 | "cpu": [ 429 | "arm" 430 | ], 431 | "license": "MIT", 432 | "optional": true, 433 | "os": [ 434 | "linux" 435 | ], 436 | "engines": { 437 | "node": ">= 10" 438 | } 439 | }, 440 | "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { 441 | "version": "4.1.4", 442 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.4.tgz", 443 | "integrity": "sha512-hKlLNvbmUC6z5g/J4H+Zx7f7w15whSVImokLPmP6ff1QqTVE+TxUM9PGuNsjHvkvlHUtGTdDnOvGNSEUiXI1Ww==", 444 | "cpu": [ 445 | "arm64" 446 | ], 447 | "license": "MIT", 448 | "optional": true, 449 | "os": [ 450 | "linux" 451 | ], 452 | "engines": { 453 | "node": ">= 10" 454 | } 455 | }, 456 | "node_modules/@tailwindcss/oxide-linux-arm64-musl": { 457 | "version": "4.1.4", 458 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.4.tgz", 459 | "integrity": "sha512-X3As2xhtgPTY/m5edUtddmZ8rCruvBvtxYLMw9OsZdH01L2gS2icsHRwxdU0dMItNfVmrBezueXZCHxVeeb7Aw==", 460 | "cpu": [ 461 | "arm64" 462 | ], 463 | "license": "MIT", 464 | "optional": true, 465 | "os": [ 466 | "linux" 467 | ], 468 | "engines": { 469 | "node": ">= 10" 470 | } 471 | }, 472 | "node_modules/@tailwindcss/oxide-linux-x64-gnu": { 473 | "version": "4.1.4", 474 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.4.tgz", 475 | "integrity": "sha512-2VG4DqhGaDSmYIu6C4ua2vSLXnJsb/C9liej7TuSO04NK+JJJgJucDUgmX6sn7Gw3Cs5ZJ9ZLrnI0QRDOjLfNQ==", 476 | "cpu": [ 477 | "x64" 478 | ], 479 | "license": "MIT", 480 | "optional": true, 481 | "os": [ 482 | "linux" 483 | ], 484 | "engines": { 485 | "node": ">= 10" 486 | } 487 | }, 488 | "node_modules/@tailwindcss/oxide-linux-x64-musl": { 489 | "version": "4.1.4", 490 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.4.tgz", 491 | "integrity": "sha512-v+mxVgH2kmur/X5Mdrz9m7TsoVjbdYQT0b4Z+dr+I4RvreCNXyCFELZL/DO0M1RsidZTrm6O1eMnV6zlgEzTMQ==", 492 | "cpu": [ 493 | "x64" 494 | ], 495 | "license": "MIT", 496 | "optional": true, 497 | "os": [ 498 | "linux" 499 | ], 500 | "engines": { 501 | "node": ">= 10" 502 | } 503 | }, 504 | "node_modules/@tailwindcss/oxide-wasm32-wasi": { 505 | "version": "4.1.4", 506 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.4.tgz", 507 | "integrity": "sha512-2TLe9ir+9esCf6Wm+lLWTMbgklIjiF0pbmDnwmhR9MksVOq+e8aP3TSsXySnBDDvTTVd/vKu1aNttEGj3P6l8Q==", 508 | "bundleDependencies": [ 509 | "@napi-rs/wasm-runtime", 510 | "@emnapi/core", 511 | "@emnapi/runtime", 512 | "@tybys/wasm-util", 513 | "@emnapi/wasi-threads", 514 | "tslib" 515 | ], 516 | "cpu": [ 517 | "wasm32" 518 | ], 519 | "license": "MIT", 520 | "optional": true, 521 | "dependencies": { 522 | "@emnapi/core": "^1.4.0", 523 | "@emnapi/runtime": "^1.4.0", 524 | "@emnapi/wasi-threads": "^1.0.1", 525 | "@napi-rs/wasm-runtime": "^0.2.8", 526 | "@tybys/wasm-util": "^0.9.0", 527 | "tslib": "^2.8.0" 528 | }, 529 | "engines": { 530 | "node": ">=14.0.0" 531 | } 532 | }, 533 | "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { 534 | "version": "4.1.4", 535 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.4.tgz", 536 | "integrity": "sha512-VlnhfilPlO0ltxW9/BgfLI5547PYzqBMPIzRrk4W7uupgCt8z6Trw/tAj6QUtF2om+1MH281Pg+HHUJoLesmng==", 537 | "cpu": [ 538 | "arm64" 539 | ], 540 | "license": "MIT", 541 | "optional": true, 542 | "os": [ 543 | "win32" 544 | ], 545 | "engines": { 546 | "node": ">= 10" 547 | } 548 | }, 549 | "node_modules/@tailwindcss/oxide-win32-x64-msvc": { 550 | "version": "4.1.4", 551 | "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.4.tgz", 552 | "integrity": "sha512-+7S63t5zhYjslUGb8NcgLpFXD+Kq1F/zt5Xv5qTv7HaFTG/DHyHD9GA6ieNAxhgyA4IcKa/zy7Xx4Oad2/wuhw==", 553 | "cpu": [ 554 | "x64" 555 | ], 556 | "license": "MIT", 557 | "optional": true, 558 | "os": [ 559 | "win32" 560 | ], 561 | "engines": { 562 | "node": ">= 10" 563 | } 564 | }, 565 | "node_modules/braces": { 566 | "version": "3.0.3", 567 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 568 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 569 | "license": "MIT", 570 | "dependencies": { 571 | "fill-range": "^7.1.1" 572 | }, 573 | "engines": { 574 | "node": ">=8" 575 | } 576 | }, 577 | "node_modules/detect-libc": { 578 | "version": "1.0.3", 579 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", 580 | "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", 581 | "license": "Apache-2.0", 582 | "bin": { 583 | "detect-libc": "bin/detect-libc.js" 584 | }, 585 | "engines": { 586 | "node": ">=0.10" 587 | } 588 | }, 589 | "node_modules/enhanced-resolve": { 590 | "version": "5.18.1", 591 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", 592 | "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", 593 | "license": "MIT", 594 | "dependencies": { 595 | "graceful-fs": "^4.2.4", 596 | "tapable": "^2.2.0" 597 | }, 598 | "engines": { 599 | "node": ">=10.13.0" 600 | } 601 | }, 602 | "node_modules/fill-range": { 603 | "version": "7.1.1", 604 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 605 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 606 | "license": "MIT", 607 | "dependencies": { 608 | "to-regex-range": "^5.0.1" 609 | }, 610 | "engines": { 611 | "node": ">=8" 612 | } 613 | }, 614 | "node_modules/graceful-fs": { 615 | "version": "4.2.11", 616 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 617 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 618 | "license": "ISC" 619 | }, 620 | "node_modules/is-extglob": { 621 | "version": "2.1.1", 622 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 623 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 624 | "license": "MIT", 625 | "engines": { 626 | "node": ">=0.10.0" 627 | } 628 | }, 629 | "node_modules/is-glob": { 630 | "version": "4.0.3", 631 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 632 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 633 | "license": "MIT", 634 | "dependencies": { 635 | "is-extglob": "^2.1.1" 636 | }, 637 | "engines": { 638 | "node": ">=0.10.0" 639 | } 640 | }, 641 | "node_modules/is-number": { 642 | "version": "7.0.0", 643 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 644 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 645 | "license": "MIT", 646 | "engines": { 647 | "node": ">=0.12.0" 648 | } 649 | }, 650 | "node_modules/jiti": { 651 | "version": "2.4.2", 652 | "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", 653 | "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", 654 | "license": "MIT", 655 | "bin": { 656 | "jiti": "lib/jiti-cli.mjs" 657 | } 658 | }, 659 | "node_modules/lightningcss": { 660 | "version": "1.29.2", 661 | "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", 662 | "integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==", 663 | "license": "MPL-2.0", 664 | "dependencies": { 665 | "detect-libc": "^2.0.3" 666 | }, 667 | "engines": { 668 | "node": ">= 12.0.0" 669 | }, 670 | "funding": { 671 | "type": "opencollective", 672 | "url": "https://opencollective.com/parcel" 673 | }, 674 | "optionalDependencies": { 675 | "lightningcss-darwin-arm64": "1.29.2", 676 | "lightningcss-darwin-x64": "1.29.2", 677 | "lightningcss-freebsd-x64": "1.29.2", 678 | "lightningcss-linux-arm-gnueabihf": "1.29.2", 679 | "lightningcss-linux-arm64-gnu": "1.29.2", 680 | "lightningcss-linux-arm64-musl": "1.29.2", 681 | "lightningcss-linux-x64-gnu": "1.29.2", 682 | "lightningcss-linux-x64-musl": "1.29.2", 683 | "lightningcss-win32-arm64-msvc": "1.29.2", 684 | "lightningcss-win32-x64-msvc": "1.29.2" 685 | } 686 | }, 687 | "node_modules/lightningcss-darwin-arm64": { 688 | "version": "1.29.2", 689 | "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz", 690 | "integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==", 691 | "cpu": [ 692 | "arm64" 693 | ], 694 | "license": "MPL-2.0", 695 | "optional": true, 696 | "os": [ 697 | "darwin" 698 | ], 699 | "engines": { 700 | "node": ">= 12.0.0" 701 | }, 702 | "funding": { 703 | "type": "opencollective", 704 | "url": "https://opencollective.com/parcel" 705 | } 706 | }, 707 | "node_modules/lightningcss-darwin-x64": { 708 | "version": "1.29.2", 709 | "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz", 710 | "integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==", 711 | "cpu": [ 712 | "x64" 713 | ], 714 | "license": "MPL-2.0", 715 | "optional": true, 716 | "os": [ 717 | "darwin" 718 | ], 719 | "engines": { 720 | "node": ">= 12.0.0" 721 | }, 722 | "funding": { 723 | "type": "opencollective", 724 | "url": "https://opencollective.com/parcel" 725 | } 726 | }, 727 | "node_modules/lightningcss-freebsd-x64": { 728 | "version": "1.29.2", 729 | "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz", 730 | "integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==", 731 | "cpu": [ 732 | "x64" 733 | ], 734 | "license": "MPL-2.0", 735 | "optional": true, 736 | "os": [ 737 | "freebsd" 738 | ], 739 | "engines": { 740 | "node": ">= 12.0.0" 741 | }, 742 | "funding": { 743 | "type": "opencollective", 744 | "url": "https://opencollective.com/parcel" 745 | } 746 | }, 747 | "node_modules/lightningcss-linux-arm-gnueabihf": { 748 | "version": "1.29.2", 749 | "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz", 750 | "integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==", 751 | "cpu": [ 752 | "arm" 753 | ], 754 | "license": "MPL-2.0", 755 | "optional": true, 756 | "os": [ 757 | "linux" 758 | ], 759 | "engines": { 760 | "node": ">= 12.0.0" 761 | }, 762 | "funding": { 763 | "type": "opencollective", 764 | "url": "https://opencollective.com/parcel" 765 | } 766 | }, 767 | "node_modules/lightningcss-linux-arm64-gnu": { 768 | "version": "1.29.2", 769 | "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz", 770 | "integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==", 771 | "cpu": [ 772 | "arm64" 773 | ], 774 | "license": "MPL-2.0", 775 | "optional": true, 776 | "os": [ 777 | "linux" 778 | ], 779 | "engines": { 780 | "node": ">= 12.0.0" 781 | }, 782 | "funding": { 783 | "type": "opencollective", 784 | "url": "https://opencollective.com/parcel" 785 | } 786 | }, 787 | "node_modules/lightningcss-linux-arm64-musl": { 788 | "version": "1.29.2", 789 | "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz", 790 | "integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==", 791 | "cpu": [ 792 | "arm64" 793 | ], 794 | "license": "MPL-2.0", 795 | "optional": true, 796 | "os": [ 797 | "linux" 798 | ], 799 | "engines": { 800 | "node": ">= 12.0.0" 801 | }, 802 | "funding": { 803 | "type": "opencollective", 804 | "url": "https://opencollective.com/parcel" 805 | } 806 | }, 807 | "node_modules/lightningcss-linux-x64-gnu": { 808 | "version": "1.29.2", 809 | "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz", 810 | "integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==", 811 | "cpu": [ 812 | "x64" 813 | ], 814 | "license": "MPL-2.0", 815 | "optional": true, 816 | "os": [ 817 | "linux" 818 | ], 819 | "engines": { 820 | "node": ">= 12.0.0" 821 | }, 822 | "funding": { 823 | "type": "opencollective", 824 | "url": "https://opencollective.com/parcel" 825 | } 826 | }, 827 | "node_modules/lightningcss-linux-x64-musl": { 828 | "version": "1.29.2", 829 | "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz", 830 | "integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==", 831 | "cpu": [ 832 | "x64" 833 | ], 834 | "license": "MPL-2.0", 835 | "optional": true, 836 | "os": [ 837 | "linux" 838 | ], 839 | "engines": { 840 | "node": ">= 12.0.0" 841 | }, 842 | "funding": { 843 | "type": "opencollective", 844 | "url": "https://opencollective.com/parcel" 845 | } 846 | }, 847 | "node_modules/lightningcss-win32-arm64-msvc": { 848 | "version": "1.29.2", 849 | "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz", 850 | "integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==", 851 | "cpu": [ 852 | "arm64" 853 | ], 854 | "license": "MPL-2.0", 855 | "optional": true, 856 | "os": [ 857 | "win32" 858 | ], 859 | "engines": { 860 | "node": ">= 12.0.0" 861 | }, 862 | "funding": { 863 | "type": "opencollective", 864 | "url": "https://opencollective.com/parcel" 865 | } 866 | }, 867 | "node_modules/lightningcss-win32-x64-msvc": { 868 | "version": "1.29.2", 869 | "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz", 870 | "integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==", 871 | "cpu": [ 872 | "x64" 873 | ], 874 | "license": "MPL-2.0", 875 | "optional": true, 876 | "os": [ 877 | "win32" 878 | ], 879 | "engines": { 880 | "node": ">= 12.0.0" 881 | }, 882 | "funding": { 883 | "type": "opencollective", 884 | "url": "https://opencollective.com/parcel" 885 | } 886 | }, 887 | "node_modules/lightningcss/node_modules/detect-libc": { 888 | "version": "2.0.3", 889 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", 890 | "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", 891 | "license": "Apache-2.0", 892 | "engines": { 893 | "node": ">=8" 894 | } 895 | }, 896 | "node_modules/micromatch": { 897 | "version": "4.0.8", 898 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 899 | "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 900 | "license": "MIT", 901 | "dependencies": { 902 | "braces": "^3.0.3", 903 | "picomatch": "^2.3.1" 904 | }, 905 | "engines": { 906 | "node": ">=8.6" 907 | } 908 | }, 909 | "node_modules/mri": { 910 | "version": "1.2.0", 911 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", 912 | "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", 913 | "license": "MIT", 914 | "engines": { 915 | "node": ">=4" 916 | } 917 | }, 918 | "node_modules/node-addon-api": { 919 | "version": "7.1.1", 920 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", 921 | "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", 922 | "license": "MIT" 923 | }, 924 | "node_modules/picocolors": { 925 | "version": "1.1.1", 926 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 927 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 928 | "license": "ISC" 929 | }, 930 | "node_modules/picomatch": { 931 | "version": "2.3.1", 932 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 933 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 934 | "license": "MIT", 935 | "engines": { 936 | "node": ">=8.6" 937 | }, 938 | "funding": { 939 | "url": "https://github.com/sponsors/jonschlinkert" 940 | } 941 | }, 942 | "node_modules/tailwindcss": { 943 | "version": "4.1.4", 944 | "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.4.tgz", 945 | "integrity": "sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==", 946 | "license": "MIT" 947 | }, 948 | "node_modules/tapable": { 949 | "version": "2.2.1", 950 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", 951 | "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", 952 | "license": "MIT", 953 | "engines": { 954 | "node": ">=6" 955 | } 956 | }, 957 | "node_modules/to-regex-range": { 958 | "version": "5.0.1", 959 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 960 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 961 | "license": "MIT", 962 | "dependencies": { 963 | "is-number": "^7.0.0" 964 | }, 965 | "engines": { 966 | "node": ">=8.0" 967 | } 968 | } 969 | } 970 | } 971 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "build": "tailwindcss -i ./client/assets/index.css -o ./client/assets/output.css --minify", 4 | "watch": "tailwindcss -i ./client/assets/index.css -o ./client/assets/output.css --watch" 5 | }, 6 | "dependencies": { 7 | "@tailwindcss/cli": "^4.1.4", 8 | "tailwindcss": "^4.1.4" 9 | }, 10 | "packageManager": "pnpm@10.8.0+sha512.0e82714d1b5b43c74610193cb20734897c1d00de89d0e18420aebc5977fa13d780a9cb05734624e81ebd81cc876cd464794850641c48b9544326b5622ca29971" 11 | } 12 | -------------------------------------------------------------------------------- /screenshots/bitplay_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aculix/bitplay/4f59c7d7731fb133f1fb80e70f11bf202a52ee5e/screenshots/bitplay_home.png -------------------------------------------------------------------------------- /screenshots/bitplay_jackett_integration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aculix/bitplay/4f59c7d7731fb133f1fb80e70f11bf202a52ee5e/screenshots/bitplay_jackett_integration.png -------------------------------------------------------------------------------- /screenshots/bitplay_prowlarr_integration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aculix/bitplay/4f59c7d7731fb133f1fb80e70f11bf202a52ee5e/screenshots/bitplay_prowlarr_integration.png -------------------------------------------------------------------------------- /screenshots/bitplay_proxy_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aculix/bitplay/4f59c7d7731fb133f1fb80e70f11bf202a52ee5e/screenshots/bitplay_proxy_settings.png -------------------------------------------------------------------------------- /screenshots/bitplay_video_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aculix/bitplay/4f59c7d7731fb133f1fb80e70f11bf202a52ee5e/screenshots/bitplay_video_player.png --------------------------------------------------------------------------------