├── .gitignore ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── custom.md │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── x86_64-apple-darwin.yml │ ├── aarch64-apple-darwin.yml │ ├── x86_64-pc-windows-msvc.yml │ └── x86_64-unknown-linux-gnu.yml ├── .vscode └── settings.json ├── deno.json ├── deps.ts ├── combine.ts ├── index.html ├── extract.ts ├── mod.ts ├── check.ts ├── mirrorArticle.ts ├── util.ts ├── search.ts ├── index.xsl ├── README.md ├── get.ts ├── model.ts ├── LICENSE ├── mirror.ts └── serve.ts /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .env 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [abusenet] 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.lint": true, 4 | "deno.unstable": true 5 | } 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** A clear and 11 | concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** A clear and concise description of what you 14 | want to happen. 15 | 16 | **Describe alternatives you've considered** A clear and concise description of 17 | any alternative solutions or features you've considered. 18 | 19 | **Additional context** Add any other context or screenshots about the feature 20 | request here. 21 | -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "compile:": "deno task compile:x86_64-unknown-linux-gnu && deno task compile:x86_64-pc-windows-msvc && deno task compile:x86_64-apple-darwin && deno task compile:aarch64-apple-darwin", 4 | "compile:x86_64-unknown-linux-gnu": "deno compile --target x86_64-unknown-linux-gnu --output dist/nzb-x86_64-unknown-linux-gnu --allow-env --allow-read --allow-write --allow-net mod.ts", 5 | "compile:x86_64-pc-windows-msvc": "deno compile --target x86_64-pc-windows-msvc --output dist/nzb-x86_64-pc-windows-msvc.exe --allow-env --allow-read --allow-write --allow-net mod.ts", 6 | "compile:x86_64-apple-darwin": "deno compile --target x86_64-apple-darwin --output dist/nzb-x86_64-apple-darwin --allow-env --allow-read --allow-write --allow-net mod.ts", 7 | "compile:aarch64-apple-darwin": "deno compile --target aarch64-apple-darwin --output dist/nzb-aarch64-apple-darwin --allow-env --allow-read --allow-write --allow-net mod.ts" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** Steps to reproduce the behavior: 13 | 14 | 1. Go to '...' 15 | 2. Click on '....' 16 | 3. Scroll down to '....' 17 | 4. See error 18 | 19 | **Expected behavior** A clear and concise description of what you expected to 20 | happen. 21 | 22 | **Screenshots** If applicable, add screenshots to help explain your problem. 23 | 24 | **Desktop (please complete the following information):** 25 | 26 | - OS: [e.g. iOS] 27 | - Browser [e.g. chrome, safari] 28 | - Version [e.g. 22] 29 | 30 | **Smartphone (please complete the following information):** 31 | 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /deps.ts: -------------------------------------------------------------------------------- 1 | export { parseArgs } from "https://deno.land/std@0.208.0/cli/parse_args.ts"; 2 | export { DelimiterStream } from "https://deno.land/std@0.208.0/streams/mod.ts"; 3 | export { pooledMap } from "https://deno.land/std@0.208.0/async/pool.ts"; 4 | export { retry } from "https://deno.land/std@0.208.0/async/retry.ts"; 5 | export { 6 | STATUS_CODE, 7 | STATUS_TEXT, 8 | } from "https://deno.land/std@0.208.0/http/status.ts"; 9 | export { ifNoneMatch } from "https://deno.land/std@0.208.0/http/etag.ts"; 10 | export { 11 | basename, 12 | extname, 13 | globToRegExp, 14 | isGlob, 15 | } from "https://deno.land/std@0.208.0/path/mod.ts"; 16 | export { 17 | endsWith, 18 | startsWith, 19 | } from "https://deno.land/std@0.208.0/bytes/mod.ts"; 20 | export { format as prettyBytes } from "https://deno.land/std@0.208.0/fmt/bytes.ts"; 21 | 22 | export { contentType } from "https://deno.land/std@0.208.0/media_types/mod.ts"; 23 | export { encodeHex } from "https://deno.land/std@0.208.0/encoding/hex.ts"; 24 | 25 | export { Article, Client } from "https://deno.land/x/nntp@v0.6.1/mod.ts"; 26 | export { YEncDecoderStream } from "https://deno.land/x/yenc@v0.1.0/ystream.ts"; 27 | 28 | export { default as ProgressBar } from "https://deno.land/x/progress@v1.4.0/mod.ts"; 29 | -------------------------------------------------------------------------------- /combine.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S deno run --allow-read 2 | import { parseArgs } from "./deps.ts"; 3 | 4 | import { fetchNZB } from "./util.ts"; 5 | 6 | export function help() { 7 | return `NZB Combine 8 | Combines multiple NZB sources into a target NZB. 9 | 10 | INSTALL: 11 | deno install --allow-read -n nzb-combine https://deno.land/x/nzb/combine.ts 12 | 13 | USAGE: 14 | nzb-combine [...options] ...sources 15 | 16 | OPTIONS:`; 17 | } 18 | 19 | const parseOptions = {}; 20 | 21 | if (import.meta.main) { 22 | await combine(Deno.args, Deno.stdout.writable); 23 | } 24 | 25 | /** 26 | * Combines multiple NZB sources into a target NZB. 27 | * @param {string[]} args Argument list. 28 | * @param {WritableStream} [writable] Writable stream to output to. 29 | * @returns 30 | */ 31 | export async function combine( 32 | args = Deno.args, 33 | output = Deno.stdout.writable, 34 | ) { 35 | const { 36 | _: [target, ...sources], 37 | } = parseArgs(args, parseOptions); 38 | 39 | if (!target) { 40 | console.error("Missing input"); 41 | console.error(help()); 42 | return; 43 | } 44 | 45 | // The first NZB file is used as the result. 46 | const result = await fetchNZB(target as string); 47 | for await (const filename of sources) { 48 | const nzb = await fetchNZB(filename as string); 49 | // Appends source's files into the target's files. 50 | result.files.push(...nzb.files); 51 | } 52 | 53 | const writer = output.getWriter(); 54 | await writer.write(new TextEncoder().encode(result.toString())); 55 | writer.close(); 56 | } 57 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | NZB Server 8 | 9 | 10 | 11 | 12 |
13 |

Index of {{ name | basename }}

14 | 15 |
16 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | {% for file in files %} 35 | 36 | 39 | 42 | 45 | 48 | 51 | 52 | {% endfor %} 53 | 54 | 55 | 56 | 61 | 62 | 63 |
NameSizePosterLast Modified Date
37 | 38 | 40 | {{ file.name }} 41 | 43 | {{ file.size | prettyBytes }} 44 | 46 | {{ file.poster }} 47 | 49 | {{ file.lastModified | UTCString }} 50 |
57 |
58 | 59 |
60 |
64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /extract.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S deno run --allow-read 2 | import { globToRegExp, isGlob, parseArgs } from "./deps.ts"; 3 | import { File, NZB } from "./model.ts"; 4 | import { fetchNZB } from "./util.ts"; 5 | 6 | export function help() { 7 | return `NZB Extract 8 | Extract files in an NZB into a new NZB using glob/regex. 9 | 10 | INSTALL: 11 | deno install --allow-read -n nzb-extract https://deno.land/x/nzb/extract.ts 12 | 13 | USAGE: 14 | nzb-extract [...options] 15 | 16 | OPTIONS:`; 17 | } 18 | 19 | const parseOptions = {}; 20 | 21 | if (import.meta.main) { 22 | await extract(Deno.args, Deno.stdout.writable); 23 | } 24 | 25 | /** 26 | * Extracts files from input NZB based on Glob or RegExp. 27 | * 28 | * If `out` flag is specified with a path to a file, writes resulting 29 | * to that file; otherwise, to `stdout`. 30 | * 31 | * A second parameter can be used to provide non-string arguments, 32 | * such as `out` with a `Writer`. 33 | */ 34 | export async function extract( 35 | args: unknown[] = Deno.args, 36 | output = Deno.stdout.writable, 37 | ) { 38 | const { 39 | _: [input, pattern], 40 | } = parseArgs(args as string[], parseOptions); 41 | 42 | if (!input) { 43 | console.error("Missing input"); 44 | console.error(help()); 45 | return; 46 | } 47 | 48 | const nzb = typeof input === "string" 49 | ? await fetchNZB(input) 50 | : input as unknown as NZB; 51 | 52 | let regex: RegExp; 53 | 54 | if (isGlob(pattern as string)) { 55 | regex = globToRegExp(pattern as string); 56 | } else { 57 | regex = new RegExp(pattern as string); 58 | } 59 | 60 | // Filters out files that do not matchthe regex. 61 | filter(nzb.files, regex); 62 | 63 | const writer = output.getWriter(); 64 | await writer.write(new TextEncoder().encode(nzb.toString())); 65 | writer.close(); 66 | } 67 | 68 | /** Filter an array based on a regex inline. */ 69 | function filter(files: File[], regex: RegExp) { 70 | let length = files.length; 71 | while (length--) { 72 | if (!regex.test(files[length].name)) { 73 | files.splice(length, 1); 74 | } 75 | } 76 | 77 | return files; 78 | } 79 | -------------------------------------------------------------------------------- /.github/workflows/x86_64-apple-darwin.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow will install Deno then run Deno lint and test. 7 | # For more information see: https://github.com/denoland/setup-deno 8 | 9 | name: x86_64-apple-darwin 10 | 11 | on: 12 | push: 13 | branches: [main] 14 | pull_request: 15 | branches: [main] 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | build: 22 | runs-on: ubuntu-latest 23 | strategy: 24 | matrix: 25 | target: [ x86_64-apple-darwin ] 26 | 27 | # Set DENO_DIR to an absolute or relative path on the runner. 28 | env: 29 | DENO_DIR: .cache 30 | 31 | steps: 32 | - name: Set git to use LF 33 | run: | 34 | git config --global core.autocrlf false 35 | git config --global core.eol lf 36 | 37 | - name: Cache Deno dependencies 38 | uses: actions/cache@v2 39 | with: 40 | path: ${{ env.DENO_DIR }} 41 | key: ${{ secrets.CACHE_VERSION }}-${{ hashFiles('lock.json') }} 42 | 43 | - name: Setup repo 44 | uses: actions/checkout@v3 45 | 46 | - name: Setup Deno 47 | uses: denoland/setup-deno@v1 48 | with: 49 | deno-version: v1.38 50 | 51 | # Check if the code is formatted according to Deno's default 52 | # formatting conventions. 53 | - name: Verify formatting 54 | run: deno fmt --check 55 | 56 | # Scan the code for syntax errors and style issues. 57 | - name: Run linter 58 | run: deno lint 59 | 60 | # Run all test files in the repository and collect code coverage. The example 61 | # runs with all permissions, but it is recommended to run with the minimal permissions your program needs (for example --allow-read). 62 | # - name: Run tests 63 | # run: deno test -A --unstable 64 | 65 | - name: Compile 66 | run: deno task compile:${{ matrix.target }} 67 | 68 | - name: Upload artifacts 69 | uses: actions/upload-artifact@v3 70 | with: 71 | name: nzb-${{ matrix.target }} 72 | path: dist 73 | -------------------------------------------------------------------------------- /.github/workflows/aarch64-apple-darwin.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow will install Deno then run Deno lint and test. 7 | # For more information see: https://github.com/denoland/setup-deno 8 | 9 | name: aarch64-apple-darwin 10 | 11 | on: 12 | push: 13 | branches: [main] 14 | pull_request: 15 | branches: [main] 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | build: 22 | runs-on: ubuntu-latest 23 | strategy: 24 | matrix: 25 | target: [ aarch64-apple-darwin ] 26 | 27 | # Set DENO_DIR to an absolute or relative path on the runner. 28 | env: 29 | DENO_DIR: .cache 30 | 31 | steps: 32 | - name: Set git to use LF 33 | run: | 34 | git config --global core.autocrlf false 35 | git config --global core.eol lf 36 | 37 | - name: Cache Deno dependencies 38 | uses: actions/cache@v2 39 | with: 40 | path: ${{ env.DENO_DIR }} 41 | key: ${{ secrets.CACHE_VERSION }}-${{ hashFiles('lock.json') }} 42 | 43 | - name: Setup repo 44 | uses: actions/checkout@v3 45 | 46 | - name: Setup Deno 47 | uses: denoland/setup-deno@v1 48 | with: 49 | deno-version: v1.38 50 | 51 | # Check if the code is formatted according to Deno's default 52 | # formatting conventions. 53 | - name: Verify formatting 54 | run: deno fmt --check 55 | 56 | # Scan the code for syntax errors and style issues. 57 | - name: Run linter 58 | run: deno lint 59 | 60 | # Run all test files in the repository and collect code coverage. The example 61 | # runs with all permissions, but it is recommended to run with the minimal permissions your program needs (for example --allow-read). 62 | # - name: Run tests 63 | # run: deno test -A --unstable 64 | 65 | - name: Compile 66 | run: deno task compile:${{ matrix.target }} 67 | 68 | - name: Upload artifacts 69 | uses: actions/upload-artifact@v3 70 | with: 71 | name: nzb-${{ matrix.target }} 72 | path: dist 73 | -------------------------------------------------------------------------------- /.github/workflows/x86_64-pc-windows-msvc.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow will install Deno then run Deno lint and test. 7 | # For more information see: https://github.com/denoland/setup-deno 8 | 9 | name: x86_64-pc-windows-msvc 10 | 11 | on: 12 | push: 13 | branches: [main] 14 | pull_request: 15 | branches: [main] 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | build: 22 | runs-on: ubuntu-latest 23 | strategy: 24 | matrix: 25 | target: [ x86_64-pc-windows-msvc ] 26 | 27 | # Set DENO_DIR to an absolute or relative path on the runner. 28 | env: 29 | DENO_DIR: .cache 30 | 31 | steps: 32 | - name: Set git to use LF 33 | run: | 34 | git config --global core.autocrlf false 35 | git config --global core.eol lf 36 | 37 | - name: Cache Deno dependencies 38 | uses: actions/cache@v2 39 | with: 40 | path: ${{ env.DENO_DIR }} 41 | key: ${{ secrets.CACHE_VERSION }}-${{ hashFiles('lock.json') }} 42 | 43 | - name: Setup repo 44 | uses: actions/checkout@v3 45 | 46 | - name: Setup Deno 47 | uses: denoland/setup-deno@v1 48 | with: 49 | deno-version: v1.38 50 | 51 | # Check if the code is formatted according to Deno's default 52 | # formatting conventions. 53 | - name: Verify formatting 54 | run: deno fmt --check 55 | 56 | # Scan the code for syntax errors and style issues. 57 | - name: Run linter 58 | run: deno lint 59 | 60 | # Run all test files in the repository and collect code coverage. The example 61 | # runs with all permissions, but it is recommended to run with the minimal permissions your program needs (for example --allow-read). 62 | # - name: Run tests 63 | # run: deno test -A --unstable 64 | 65 | - name: Compile 66 | run: deno task compile:${{ matrix.target }} 67 | 68 | - name: Upload artifacts 69 | uses: actions/upload-artifact@v3 70 | with: 71 | name: nzb-${{ matrix.target }}.exe 72 | path: dist 73 | -------------------------------------------------------------------------------- /.github/workflows/x86_64-unknown-linux-gnu.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow will install Deno then run Deno lint and test. 7 | # For more information see: https://github.com/denoland/setup-deno 8 | 9 | name: x86_64-unknown-linux-gnu 10 | 11 | on: 12 | push: 13 | branches: [main] 14 | pull_request: 15 | branches: [main] 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | build: 22 | runs-on: ubuntu-latest 23 | strategy: 24 | matrix: 25 | target: [ x86_64-unknown-linux-gnu ] 26 | 27 | # Set DENO_DIR to an absolute or relative path on the runner. 28 | env: 29 | DENO_DIR: .cache 30 | 31 | steps: 32 | - name: Set git to use LF 33 | run: | 34 | git config --global core.autocrlf false 35 | git config --global core.eol lf 36 | 37 | - name: Cache Deno dependencies 38 | uses: actions/cache@v2 39 | with: 40 | path: ${{ env.DENO_DIR }} 41 | key: ${{ secrets.CACHE_VERSION }}-${{ hashFiles('lock.json') }} 42 | 43 | - name: Setup repo 44 | uses: actions/checkout@v3 45 | 46 | - name: Setup Deno 47 | uses: denoland/setup-deno@v1 48 | with: 49 | deno-version: v1.38 50 | 51 | # Check if the code is formatted according to Deno's default 52 | # formatting conventions. 53 | - name: Verify formatting 54 | run: deno fmt --check 55 | 56 | # Scan the code for syntax errors and style issues. 57 | - name: Run linter 58 | run: deno lint 59 | 60 | # Run all test files in the repository and collect code coverage. The example 61 | # runs with all permissions, but it is recommended to run with the minimal permissions your program needs (for example --allow-read). 62 | # - name: Run tests 63 | # run: deno test -A --unstable 64 | 65 | - name: Compile 66 | run: deno task compile:${{ matrix.target }} 67 | 68 | - name: Upload artifacts 69 | uses: actions/upload-artifact@v3 70 | with: 71 | name: nzb-${{ matrix.target }} 72 | path: dist 73 | -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S deno run --allow-net --allow-env --allow-read --allow-write 2 | import { check } from "./check.ts"; 3 | import { combine } from "./combine.ts"; 4 | import { extract } from "./extract.ts"; 5 | import { get } from "./get.ts"; 6 | import { mirror } from "./mirror.ts"; 7 | import { search } from "./search.ts"; 8 | import { serve } from "./serve.ts"; 9 | 10 | export function help() { 11 | return `NZB Toolkit 12 | Various tools for handling NZB files 13 | 14 | INSTALL: 15 | deno install --allow-net --allow-env --allow-read --allow-write -n nzb https://deno.land/x/nzb/mod.ts 16 | 17 | USAGE: 18 | nzb [...options] 19 | 20 | COMMANDS: 21 | check [--method] [...options] 22 | combine [...options] ...sources 23 | extract [...options] 24 | get [...options] 25 | mirror [...options] 26 | search [...options] 27 | serve [...options] 28 | 29 | OPTIONS: 30 | --address, -addr
IPaddress:Port or :Port to bind server to (default "127.0.0.1:8000") 31 | --template, -t