torznab_toolkit/data.rs
1//! Contains tons of structs used by the library
2//!
3//! All examples here are based off the [Torznab spec](https://torznab.github.io/spec-1.3-draft/torznab/Specification-v1.3.html)'s `/api?caps` example.
4use std::collections::HashMap;
5pub(crate) type AuthFunc = fn(String) -> Result<bool, String>;
6pub(crate) type SearchFunc = fn(SearchParameters) -> Result<Vec<Torrent>, String>;
7
8// TODO: Redo this all so that is uses builders with `AsRef<str>` arguments instead
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11/// The maximum and defaults for the `limit` parameter in queries
12/// `max` is the maximum number of results the program can return
13/// `default` is the default number of results the program will return
14///
15/// Example:
16/// ```
17/// let query_limits = Limits {
18/// max: 100, // maximum of 100 results per search query
19/// default: 50, // default of 50
20/// };
21/// ```
22pub struct Limits {
23 /*
24 I don't know why this would possibly need to be a u32, I can't imagine you'll be returning 4 billion results or whatever
25 In fact, I *really* hope you aren't - if you are, you're doing something extremely wrong
26 But hey, it's an option
27 */
28 /// The maximum number of entries that can be listed in a search query
29 pub max: u32,
30 /// The default number of entries to be listed in a search query
31 pub default: u32,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq)]
35/// A struct holding the info for a type of search
36///
37/// Example:
38/// ```
39/// let tv_query_search_info = SearchInfo {
40/// search_type: "tv-search".to_string(),
41/// available: true,
42/// supported_params: vec!["q", "rid", "tvdbid", "season", "ep"]
43/// .into_iter().map(|i| i.to_string()).collect::<String>(), // this bit's just to make all the `str`s to `String`s
44/// };
45/// ```
46pub struct SearchInfo {
47 /// What type of search this is - must be `search`, `tv-search`, `movie-search`, `audio-search`, or `book-search`
48 pub search_type: String,
49 /// Whether this search type is available
50 pub available: bool,
51 /// The supported parameters for this search type
52 ///
53 /// Highly recommended: `q` (free text query)
54 pub supported_params: Vec<String>,
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
58/// Contains subcategories, for use in [`Category`]
59///
60/// Example:
61/// ```
62/// let subcat = Subcategory {
63/// id: 2010,
64/// name: "Foreign".to_string(),
65/// };
66/// ```
67pub struct Subcategory {
68 /// The numeric ID of a subcategory
69 ///
70 /// The (de facto?) standard is `xxyy`, xx being the first two digits of the category, and the last two digits specifying the subcategory; see also: Category
71 pub id: u32,
72 /// The name of the subcategory, e.g. "Anime" under the "TV" cateogyr
73 pub name: String,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
77/// Contains a category, for use in [`Caps`] and searches as a query parameter
78///
79/// Example, using `subcat` from the [`Subcategory`] example:
80/// ```
81/// let category = Category {
82/// id: 2000,
83/// name: "Movies".to_string(),
84/// subcategory: vec![subcat],
85/// };
86/// ```
87pub struct Category {
88 /// The numeric ID of a category
89 ///
90 /// The (de facto?) standard is `xxyy`, xx being the first two digits of the category, and the last two digits specifying the subcategory; see also: Subcategory
91 pub id: u32,
92 /// The name of the category, e.g. "Movies"
93 pub name: String,
94 /// A vector of all the subcategory in this category
95 pub subcategories: Vec<Subcategory>,
96}
97
98#[derive(Debug, Clone, PartialEq, Eq)]
99/// Contains a genre, for use in [`Caps`] and searches as a query parameter
100///
101/// Example:
102/// ```
103/// let genre = Genre {
104/// id: 1,
105/// category_id: 5000,
106/// name: "Kids".to_string(),
107/// };
108/// ```
109pub struct Genre {
110 /// The numeric ID of a genre
111 ///
112 /// I'm not aware of any standard for numbering this; the specification for Torznab shows an example with an ID of 1.
113 pub id: u32,
114 /// The numeric ID of the category this genre is for.
115 pub category_id: u32,
116 /// The name of the genre
117 pub name: String,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq)]
121/// Contains a tag, for use in [`Caps`] and searches as a query parameter
122///
123/// Example:
124///
125/// ```
126/// let tag = Tag {
127/// name: "trusted".to_string(),
128/// description: "Uploader has high reputation".to_string(),
129/// };
130/// ```
131pub struct Tag {
132 /// The name of a tag for a torrent
133 pub name: String,
134 /// The description of the tag
135 pub description: String,
136}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
139/// Holds the configuration for the capabilities of the Torznab server (used in `/api?t=caps`)
140///
141/// <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 501.
142///
143/// 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>
144///
145/// Example, using other examples:
146/// ```
147/// let mut info: HashMap<String, String> = HashMap::new();
148/// info.insert("version".to_string(), "1.1".to_string());
149///
150/// let caps_data = Caps {
151/// server_info: Some(info),
152/// limits: query_limits,
153/// searching: vec![tv_query_search_info],
154/// categories: vec![category],
155/// genres: Some(vec![genre]),
156/// tags: Some(vec![tag]),
157/// };
158/// ```
159pub struct Caps {
160 /// The server info, like title - optional
161 ///
162 /// Examples: `version`, `title`, `email`, `url`, `image`
163 pub server_info: Option<HashMap<String, String>>,
164 /// The max and default number of items to be returned by queries
165 pub limits: Limits,
166 /// Info about each type of search
167 pub searching: Vec<SearchInfo>,
168 /// What categories the server has
169 pub categories: Vec<Category>,
170 /// What genres the server has (optional)
171 pub genres: Option<Vec<Genre>>,
172 /// What torrents can be tagged with (optional)
173 pub tags: Option<Vec<Tag>>,
174}
175
176#[derive(Debug, Clone, PartialEq, Eq)]
177/// A struct that holds configuration for torznab-toolkit
178/// The search function (`/api?t=search`) and capabilities (`/api?t=caps` - struct [`Caps`]) are required
179/// Everything else is optional
180///
181/// Example, using other examples:
182/// ```
183/// fn search_func(parameters: SearchParameters) -> Result<Vec<Torrent>, String> {
184/// let torrent = /* see `Torrent` example */
185/// return torrent;
186/// }
187///
188/// fn auth_func(apikey: String) -> Result<bool, String> {
189/// if apikey == "letmein".to_string() {
190/// return Ok(true);
191/// }
192/// return Ok(false);
193/// }
194///
195/// let conf = Config {
196/// search: search,
197/// auth: Some(auth),
198/// caps: caps_data,
199/// }
200/// ```
201pub struct Config {
202 /// The function to use for all search types
203 ///
204 /// What search types are available is dependent on what's marked as available in the `searching` field of `caps` ([`Caps`])
205 ///
206 /// Search types: `search`, `tv-search`, `movie-search`, `audio-search`, `book-search`
207 pub search: SearchFunc,
208 /// The auth function - if not specified, then no authorization is needed.
209 pub auth: Option<AuthFunc>,
210 /// The capabilities of the indexer
211 pub caps: Caps,
212}
213
214#[derive(Debug, Clone, PartialEq, Eq)]
215/// Holds the parameters for a search query
216pub struct SearchParameters {
217 /// What type of search this is
218 ///
219 /// Search types: `search`, `tv-search`, `movie-search`, `audio-search`, `book-search`
220 pub search_type: String,
221 /// The text query for the search
222 pub q: Option<String>,
223 /// The apikey, for authentication
224 pub apikey: Option<String>,
225 /// A [`Vec`] containing the numeric category IDs to be included in the search results
226 pub categories: Option<Vec<u32>>,
227 /// A [`Vec`] containing the extended attribute names to be included in the search results
228 pub attributes: Option<Vec<String>>,
229 /// Whether *all* extended attributes should be included in the search results; overrules `attributes`
230 pub extended_attrs: Option<bool>,
231 /// How many items to skip/offset by in the results.
232 pub offset: Option<u32>,
233 /// The maximum number of items to return - also limited to whatever `limits` is in [`Caps`]
234 pub limit: u32,
235}
236
237#[derive(Debug, Clone, PartialEq, Eq)]
238/// Holds the info for a torrent
239///
240/// Any attributes not listed here are optional, and can be put in `other_attributes`; **however**, the following are recommended:
241/// - `seeders`
242/// - `leechers`
243/// - `peers`
244/// - `infohash`
245/// - `link` (link to a webpage; if not specified, will fallback to `torrent_file_url`, then `magnet_uri`)
246///
247/// <div class="warning">One of either `torrent_file_url` or `magnet_uri` are required.</div>
248/// Example:
249/// ```
250/// let torrent = Torrent {
251/// title: "totally normal torrent".to_string(),
252/// description: None,
253/// size: 2484345508,
254/// category_ids: vec![1010],
255/// torrent_file_url: Some("http://localhost/totally-normal.torrent".to_string()),
256/// magnet_uri: Some("magnet:?xt=urn:btih:blahblahblahdothechachacha".to_string()),
257/// other_attributes: None,
258/// };
259/// ```
260pub struct Torrent {
261 /// The title of the torrent
262 pub title: String,
263 /// The description of the torrent - optional
264 pub description: Option<String>,
265 /// The size of the torrent, **in bytes**
266 pub size: u64,
267 /// A vector of (sub)category IDs
268 pub category_ids: Vec<u32>,
269 /// The URL of the `.torrent` file
270 pub torrent_file_url: Option<String>,
271 /// The magnet URI o the torrent
272 pub magnet_uri: Option<String>,
273 /// Any other attributes
274 pub other_attributes: Option<HashMap<String, String>>,
275}