Initial commit
This commit is contained in:
commit
493d019352
9 changed files with 1798 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
1598
Cargo.lock
generated
Normal file
1598
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "torznab-toolkit"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rocket = "0.5.1"
|
21
README.md
Normal file
21
README.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Torznab Toolkit
|
||||||
|
|
||||||
|
A toolkit for adding Torznab APIs to programs.
|
||||||
|
|
||||||
|
## Functionality
|
||||||
|
|
||||||
|
| API call | Explanation | Compatibility |
|
||||||
|
| -------- | ------------------------------------------------------------ | -------------- |
|
||||||
|
| caps | Returns the capabilities of the api. | ❌ |
|
||||||
|
| search | Free text search query. | ❌ |
|
||||||
|
| tvsearch | Search query with tv specific query params and filtering. | ❌ |
|
||||||
|
| movie | Search query with movie specific query params and filtering. | ❌ |
|
||||||
|
| music | Search query with music specific query params and filtering. | ❌ |
|
||||||
|
| book | Search query with book specific query params and filtering. | ❌ |
|
||||||
|
|
||||||
|
<!-- for copy-pasting: ❌ ✅ -->
|
||||||
|
(copied from [torznab.github.io](https://torznab.github.io/spec-1.3-draft/torznab/Specification-v1.3.html))
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Thanks to [torznab.github.io](https://torznab.github.io), as it's my primary reference for this.
|
22
dev-notes.md
Normal file
22
dev-notes.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Dev notes
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- <https://torznab.github.io/spec-1.3-draft/index.html>
|
||||||
|
- <https://www.git.je/Mirrors/Sonarr/wiki/Implementing-a-Torznab-indexer>
|
||||||
|
- for testing: <https://fosstorrents.com/thankyou/?name=debian&cat=Installation%20-%20amd64&id=0&hybrid=0>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```rs
|
||||||
|
struct TorznabToolkitConfig {
|
||||||
|
auth_func: auth,
|
||||||
|
search_func: search,
|
||||||
|
whateverotherfunc: otherfunc,
|
||||||
|
port: 5309
|
||||||
|
}
|
||||||
|
|
||||||
|
fn launch() -> Result {
|
||||||
|
rocket::build().mount("/", routes![tt::search, tt:otherfunc])
|
||||||
|
}
|
||||||
|
```
|
4
src/api.rs
Normal file
4
src/api.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
use rocket::get;
|
||||||
|
|
||||||
|
#[get("/api?t=caps")]
|
||||||
|
pub(crate) fn caps() -> Result<String, String> {}
|
51
src/config.rs
Normal file
51
src/config.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
use crate::data::*;
|
||||||
|
|
||||||
|
type AuthFunc = fn(String) -> Result<String, String>;
|
||||||
|
type SearchFunc = fn(String, Vec<String>) -> Result<String, String>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Config {
|
||||||
|
/// A struct that holds configuration for torznab-toolkit
|
||||||
|
/// A search function (/api?t=search) and capabilities (/api?t=caps - struct Caps) required
|
||||||
|
/// Everything else is optional
|
||||||
|
pub search: SearchFunc,
|
||||||
|
pub auth: Option<AuthFunc>,
|
||||||
|
pub caps: Caps,
|
||||||
|
pub tvsearch: Option<SearchFunc>,
|
||||||
|
pub movie: Option<SearchFunc>,
|
||||||
|
pub music: Option<SearchFunc>,
|
||||||
|
pub book: Option<SearchFunc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Caps {
|
||||||
|
/// Holds the configuration for the capabilities of the Torznab server
|
||||||
|
///
|
||||||
|
/// - server_info: `ServerInfo`
|
||||||
|
/// - see: `ServerInfo` docs
|
||||||
|
/// - limits: `Limits`
|
||||||
|
/// - specifies the max and default items listed when searching
|
||||||
|
/// - see: `Limits` docs
|
||||||
|
/// - searching: `Vec<SearchInfo>`
|
||||||
|
/// - specifies the capabilities of each search mode
|
||||||
|
/// - see: `SearchInfo` docs
|
||||||
|
/// - categories: `Vec<Category>`
|
||||||
|
/// - lists known categories
|
||||||
|
/// - see: `Category` docs
|
||||||
|
/// - genres: `Option<Vec<Genre>>`
|
||||||
|
/// - lists known genres, optional
|
||||||
|
/// - see: `Genre` docs
|
||||||
|
///
|
||||||
|
/// <div class="warning">Note that this library might not support all the capabilities listed in yet, so check the README before listing capabilities, or just accept that unsupported capabilities will return error 404.
|
||||||
|
///
|
||||||
|
/// It's recommended to add any capabilities you want, and set `available` to `false` in the `Caps` struct for any currently unsupported search types.</div>
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// TODO: Add a way to partially generate search capabilities automatically from the Config
|
||||||
|
pub server_info: ServerInfo,
|
||||||
|
pub limits: Limits,
|
||||||
|
pub searching: Vec<SearchInfo>,
|
||||||
|
pub categories: Vec<Category>,
|
||||||
|
pub genres: Option<Vec<Genre>>,
|
||||||
|
pub tags: Option<Vec<Tag>>,
|
||||||
|
}
|
62
src/data.rs
Normal file
62
src/data.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ServerInfo {
|
||||||
|
/// Specify the ServerInfo to be listed in <server> for `/api?t=caps`
|
||||||
|
///
|
||||||
|
/// These fields are just those listed in the example on [torznab.github.io](https://torznab.github.io), there's no actual specification for thse fields.
|
||||||
|
/// TODO: Update this to have customizable fields instead
|
||||||
|
pub title: Option<String>,
|
||||||
|
pub email: Option<String>,
|
||||||
|
pub image: Option<String>,
|
||||||
|
pub version: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Limits {
|
||||||
|
/// The maximum and defaults for the `limit` parameter in queries
|
||||||
|
/// `max` is the maximum number of results the program can return
|
||||||
|
/// `default` is the default number of results the program will return
|
||||||
|
/*
|
||||||
|
I don't know why this would possibly need to be a u64, I can't imagine you'll be returning 18 quintillion results or whatever
|
||||||
|
In fact, I *really* hope you aren't - if you are, you're doing something extremely wrong
|
||||||
|
But hey, it's an option
|
||||||
|
*/
|
||||||
|
pub max: u64,
|
||||||
|
pub default: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SearchInfo {
|
||||||
|
/// A struct holding the info for a type of search
|
||||||
|
/// - `search_type` must be `search`, `tv-search`, `movie-search`, `audio-search`, or `book-search`
|
||||||
|
/// - `available`
|
||||||
|
pub search_type: String,
|
||||||
|
pub available: bool,
|
||||||
|
pub supported_params: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Subcategory {
|
||||||
|
pub id: String,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Category {
|
||||||
|
pub id: String,
|
||||||
|
pub name: String,
|
||||||
|
pub subcategories: Vec<Subcategory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Genre {
|
||||||
|
pub id: String,
|
||||||
|
pub category_id: String,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Tag {
|
||||||
|
pub id: String,
|
||||||
|
pub category_id: String,
|
||||||
|
pub name: String,
|
||||||
|
}
|
32
src/lib.rs
Normal file
32
src/lib.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
//! A toolkit for adding Torznab APIs to programs.
|
||||||
|
//!
|
||||||
|
//! Just fill in your own relevant functions and config, and
|
||||||
|
//! torznab-toolkit will run the API for you
|
||||||
|
//!
|
||||||
|
//! ```rs
|
||||||
|
//! use torznab_toolkit;
|
||||||
|
//! let config: torznab_toolkit::config::Config =
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The environment variables `ROCKET_ADDRESS` and `ROCKET_PORT` specify the address and port it will run on; these currently cannot be configured any other way. See the [relevant docs](https://rocket.rs/guide/v0.5/deploying/) for details.
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
|
//! This program is brought to you by: metaphorical *and* literal truckloads of structs!
|
||||||
|
//!
|
||||||
|
//! Note: I wrote the line above when I was tired. Don't ask me what *literal* truckloads of structs means, I don't know either.
|
||||||
|
|
||||||
|
mod api;
|
||||||
|
pub mod config;
|
||||||
|
pub mod data;
|
||||||
|
|
||||||
|
use config::{Caps, Config};
|
||||||
|
use rocket;
|
||||||
|
|
||||||
|
pub fn run(config: Config, caps: Caps) -> Result<bool, String> {
|
||||||
|
/// Runs the server
|
||||||
|
rocket::build().mount("/", rocket::routes![api::caps]);
|
||||||
|
return Ok(true);
|
||||||
|
}
|
Loading…
Reference in a new issue