1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::fmt::{Display, Formatter};
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use reqwest::multipart::{Form, Part};
use serde::{Deserialize, Serialize};
/// Form data for uploading a torrent to a group
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct UploadForm {
/// Path to the torrent file to upload
pub path: PathBuf,
/// ID number of the category
///
/// *CAUTION: This index is inexplicably different to the [`Group`] `category_id`*
///
/// `Music`: 0,
/// `Applications`: 1,
/// `E-Books`: 2,
/// `Audiobooks`: 3,
/// `E-Learning Videos`: 4,
/// `Comedy`: 5,
/// `Comics`: 6
/// <https://github.com/OPSnet/Gazelle/blob/3e2f8f8ef99f654047d86ea75da166e270b85ba9/public/static/functions/upload.js#L702-L710>
pub category_id: u8,
/// Edition year
pub remaster_year: u16,
/// Edition title
pub remaster_title: String,
/// Edition record label
pub remaster_record_label: String,
/// Edition catalogue number
pub remaster_catalogue_number: String,
/// Format
///
/// 0: `MP3`
/// 1: `FLAC`
/// 2: `AAC`
/// 3: `AC3`
/// 4: `DTS`
///
/// *OPS may have others*
pub format: String,
/// Encoding
///
/// 0: `192`
/// 1: `APS (VBR)`
/// 2: `V2 (VBR)`
/// 3: `V1 (VBR)`
/// 4: `256`
/// 5: `APX (VBR)`
/// 6: `V0 (VBR)`
/// 7: `320`
/// 8: `Lossless`
/// 9: `24bit Lossless`
/// 10: `Other`
///
/// *OPS may have others*
pub bitrate: String,
/// Media
///
/// 0: `CD`
/// 1: `DVD`
/// 2: `Vinyl`
/// 3: `Soundboard`
/// 4: `SACD`
/// 5: `DAT`
/// 6: `Cassette`
/// 7: `WEB`
/// 8: `Blu-Ray` (Possibly `Blu-ray` on OPS)
pub media: String,
/// Description formatted as BB code
pub release_desc: String,
/// ID of the torrentgroup
pub group_id: u32,
}
impl UploadForm {
/// Convert to a multipart form for the upload API request
#[allow(clippy::wrong_self_convention, clippy::absolute_paths)]
pub fn to_form(self) -> Result<Form, std::io::Error> {
let mut file = File::open(&self.path)?;
let mut buffer = Vec::new();
let _size = file.read_to_end(&mut buffer)?;
let filename = self
.path
.file_name()
.expect("file should have a name")
.to_string_lossy()
.to_string();
let torrent_part = Part::bytes(buffer).file_name(filename);
let form = Form::new()
.part("file_input", torrent_part)
.text("type", self.category_id.to_string())
.text("remaster", "1") // required by OPS but not RED
.text("remaster_title", self.remaster_title)
.text("remaster_record_label", self.remaster_record_label)
.text("remaster_catalogue_number", self.remaster_catalogue_number)
.text("remaster_year", self.remaster_year.to_string())
.text("format", self.format)
.text("bitrate", self.bitrate)
.text("media", self.media)
.text("release_desc", self.release_desc)
.text("groupid", self.group_id.to_string());
Ok(form)
}
}
impl Display for UploadForm {
#[allow(clippy::absolute_paths)]
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
let output = if let Ok(yaml) = serde_yaml::to_string(self) {
yaml
} else {
format!("{self:?}")
};
output.fmt(formatter)
}
}