Skip to content

Commit ef8b78c

Browse files
authored
Merge pull request #22 from Sekkyo/main
- Fixes CBZ creation on macOS - Fixes page ordering on macOS - Resolves clippy warnings - Adds Windows ARM64 to automated release builds - Fixes typos - Improves code quality
2 parents 34a1e8b + f610f53 commit ef8b78c

10 files changed

Lines changed: 137 additions & 106 deletions

File tree

.github/workflows/release.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ jobs:
2626
target: i686-pc-windows-msvc
2727
bin: gbscraper.exe
2828
final: gbscraper-windows-i686.zip
29+
- os_name: Windows-aarch64
30+
os: windows-latest
31+
target: aarch64-pc-windows-msvc
32+
bin: gbscraper.exe
33+
final: gbscraper-windows-aarch64.zip
2934
- os_name: macOS-x86_64
3035
os: macOS-latest
3136
target: x86_64-apple-darwin

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ serde = { version = "1.0.24" , features = ["derive"] }
2626
serde_json = { version = "1.0.122" }
2727
clap = { version = "4.5.13", features = ["derive"] }
2828
bitflags = "2.6.0"
29-
zip = "2.1.6"
29+
zip = { version = "2.2.0", default-features = false, features = ["deflate-miniz"] }
3030
image = "0.25.2"
3131
sanitise-file-name = "1.0.0"
3232
time = "0.3.36"

src/lib/scraper/batching.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ pub fn download_period(url: &str, dest: &str, options: &mut ScraperOptions) -> i
1212
let url = sanitize_url(url)?;
1313

1414
if options.verbose {
15-
println!("Attemping download of period page with url: {url}");
15+
println!("Attempting download of period page with url: {url}");
1616
}
1717

18-
for issue_url in get_issue_urls_in_period(&url, &options)? {
18+
for issue_url in get_issue_urls_in_period(&url, options)? {
1919
if let Err(x) = download_issue(&issue_url, dest, options) {
2020
eprintln!("Error downloading issue {issue_url}: {}", x);
2121
}
@@ -28,10 +28,10 @@ pub fn download_all(url: &str, dest: &str, options: &mut ScraperOptions) -> io::
2828
let url = sanitize_url(url)?;
2929

3030
if options.verbose {
31-
println!("Attemping download of base page with url: {url}");
31+
println!("Attempting download of base page with url: {url}");
3232
}
3333

34-
for period_url in get_period_urls(&url, &options)? {
34+
for period_url in get_period_urls(&url, options)? {
3535
if let Err(x) = download_period(&period_url, dest, options) {
3636
eprintln!("Error downloading period {period_url}: {}", x);
3737
}
@@ -43,7 +43,7 @@ pub fn download_all(url: &str, dest: &str, options: &mut ScraperOptions) -> io::
4343
pub fn get_period_urls(url: &str, options: &ScraperOptions) -> io::Result<Vec<String>> {
4444
let mut ret = Vec::new();
4545

46-
let res = try_download(&url, options.download_attempts)?;
46+
let res = try_download(url, options.download_attempts)?;
4747
let body = res.text().to_result()?;
4848

4949
let doc = Html::parse_document(&body);
@@ -72,7 +72,7 @@ pub fn get_period_urls(url: &str, options: &ScraperOptions) -> io::Result<Vec<St
7272
pub fn get_issue_urls_in_period(url: &str, options: &ScraperOptions) -> io::Result<Vec<String>> {
7373
let mut ret = Vec::new();
7474

75-
let res = try_download(&url, options.download_attempts)?;
75+
let res = try_download(url, options.download_attempts)?;
7676
let body = res.text().to_result()?;
7777
let doc = Html::parse_document(&body);
7878

src/lib/scraper/helpers.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub(crate) fn id_from_url(url: &str) -> io::Result<String> {
1414
None => url_obj
1515
.path_segments()
1616
.to_result(INVALID_URL)?
17-
.last()
17+
.next_back()
1818
.to_result(INVALID_URL)?
1919
.to_string(),
2020
})
@@ -41,49 +41,42 @@ pub(crate) fn sanitize_url(url: &str) -> io::Result<String> {
4141
const PERIOD_TAG: &str = "atm_aiy";
4242
let url_obj = Url::try_from(url).to_result()?;
4343
match url_obj.query_pairs().find(|x| x.0 == PERIOD_TAG) {
44-
Some(x) => Ok(std::format!("{base_url}&{PERIOD_TAG}={}", x.1.to_string())),
44+
Some(x) => Ok(std::format!("{base_url}&{PERIOD_TAG}={}", x.1)),
4545
None => Ok(base_url),
4646
}
4747
}
4848

49-
// Methods to convert between option/result types for error propogation.
49+
// Methods to convert between option/result types for error propagation.
5050

5151
pub(crate) trait ToResult<T> {
52-
///
5352
fn to_result(self) -> std::io::Result<T>;
5453
}
5554

5655
impl<T, E: Display> ToResult<T> for std::result::Result<T, E> {
5756
fn to_result(self) -> std::io::Result<T> {
5857
match self {
5958
Ok(x) => Ok(x),
60-
Err(x) => Err(std::io::Error::new(io::ErrorKind::Other, x.to_string())),
59+
Err(x) => Err(std::io::Error::other(x.to_string())),
6160
}
6261
}
6362
}
6463

6564
pub(crate) trait ToResultErrorMessage<T> {
66-
///
6765
fn to_result(self, msg: &str) -> std::io::Result<T>;
6866
}
6967

7068
impl<T> ToResultErrorMessage<T> for Option<T> {
7169
fn to_result(self, msg: &str) -> std::io::Result<T> {
7270
match self {
7371
Some(x) => Ok(x),
74-
None => Err(std::io::Error::new(io::ErrorKind::Other, msg)),
72+
None => Err(std::io::Error::other(msg.to_string())),
7573
}
7674
}
7775
}
7876

7977
/// Generate filename for image.
8078
pub(crate) fn generate_image_filename(page_number: &usize, page_id: &str, ext: &str) -> String {
81-
std::format!(
82-
"{0}-{1}.{2}",
83-
std::format!("{:0>5}", page_number),
84-
page_id,
85-
ext
86-
)
79+
std::format!("{:0>5}-{page_id}.{ext}", page_number)
8780
}
8881

8982
/// Determine image extension by the content header.
@@ -109,7 +102,7 @@ pub(crate) fn get_image_ext(res: &reqwest::blocking::Response) -> io::Result<Str
109102
/// Determine image extension by the content header.
110103
pub(crate) fn try_download(url: &str, mut attempts: u32) -> io::Result<reqwest::blocking::Response> {
111104
let indefinite = attempts == 0;
112-
let mut res: io::Result<reqwest::blocking::Response> = Err(io::Error::new(io::ErrorKind::Other, ""));
105+
let mut res: io::Result<reqwest::blocking::Response> = Err(io::Error::other(""));
113106
while indefinite || attempts > 0 {
114107
res = reqwest::blocking::get(url).to_result();
115108
if let Ok(res) = res {

src/lib/scraper/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod batching;
22
mod helpers;
3+
#[allow(clippy::module_inception)]
34
pub mod scraper;
45
pub mod types;
56

src/lib/scraper/scraper.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pub fn download_issue(
129129
let mut first_page = "1".to_string();
130130
let mut i_page = 1;
131131
for page in issue.page {
132-
if let None = page.src {
132+
if page.src.is_none() {
133133
page_number_lookup.insert(page.pid.clone(), i_page);
134134
pages_to_download.push_back(page.pid.clone());
135135
if i_page == 1 {
@@ -172,12 +172,8 @@ pub fn download_issue(
172172
// Download images linked in JSON.
173173
// Note: JSON will contain an entry for every page in book. Requested page should have accompanying source URL, and adjacent pages may as well.
174174
for page in &issue.page {
175-
// Skip if already downloaded.
176-
if let None = &page.src {
177-
continue;
178-
}
179-
// Skip if no download link.
180-
else if pages_downloaded.contains(&page.pid) {
175+
// Skip if no download link or already downloaded.
176+
if page.src.is_none() || pages_downloaded.contains(&page.pid) {
181177
continue;
182178
}
183179

@@ -209,8 +205,8 @@ pub fn download_issue(
209205

210206
let mut any_png = false;
211207
let mut canvas = image::DynamicImage::new(
212-
size_info.width.into(),
213-
size_info.height.into(),
208+
size_info.width,
209+
size_info.height,
214210
image::ColorType::Rgb8,
215211
);
216212

src/lib/scraper/types.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ pub enum ContentType {
139139
}
140140

141141
#[derive(Debug, PartialEq, Eq)]
142+
#[allow(clippy::large_enum_variant)]
142143
pub enum DownloadStatus {
143144
Skipped,
144145
Complete(BookMetadata),
@@ -176,9 +177,9 @@ impl BookMetadata {
176177
}
177178

178179
fn parse_length(text: &str) -> io::Result<u32> {
179-
Ok(Self::remove_and_extract(text, Self::SUFFIX_PAGES)
180+
Self::remove_and_extract(text, Self::SUFFIX_PAGES)
180181
.parse::<u32>()
181-
.to_result()?)
182+
.to_result()
182183
}
183184

184185
fn remove_and_extract(source: &str, to_remove: &str) -> String {
@@ -225,8 +226,7 @@ impl BookMetadata {
225226
.select(&Selector::parse("#metadata").to_result()?)
226227
.next()
227228
{
228-
let mut i: u32 = 0;
229-
for child in e.text() {
229+
for (i, child) in e.text().enumerate() {
230230
if i == 0 {
231231
publish_date = child.to_string();
232232
} else if child.starts_with(Self::PREFIX_PUBLISHER) {
@@ -238,8 +238,6 @@ impl BookMetadata {
238238
} else {
239239
volume = child.to_string();
240240
}
241-
242-
i += 1;
243241
}
244242
};
245243

src/lib/writer/cbz.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,29 @@ use zip::write::SimpleFileOptions;
1212
/// * `target_filename` - Path to save CBZ to, including filename and extension.
1313
pub fn create_cbz(image_dir: &str, target_filename: &str) -> io::Result<()> {
1414
let dir_entry = std::path::Path::new(target_filename);
15-
let file = std::fs::File::create(dir_entry).unwrap();
15+
let file = std::fs::File::create(dir_entry)?;
1616

1717
let mut zip = zip::ZipWriter::new(file);
1818
let options = SimpleFileOptions::default().compression_method(zip::CompressionMethod::Deflated);
1919

20-
let read_dir = fs::read_dir(image_dir)?;
21-
for dir_entry in read_dir {
22-
if let Ok(dir_entry) = dir_entry {
23-
if let Ok(mut file) = std::fs::File::open(dir_entry.path()) {
24-
let filename = dir_entry.file_name().into_string().unwrap();
25-
let _ = file.seek(io::SeekFrom::Start(0));
20+
let mut entries: Vec<_> = fs::read_dir(image_dir)?
21+
.collect::<io::Result<_>>()?;
22+
entries.sort_by_key(|e| e.file_name());
23+
for dir_entry in entries {
24+
let mut file = std::fs::File::open(dir_entry.path())?;
25+
let filename = dir_entry.file_name().into_string().map_err(|file_name| {
26+
io::Error::new(
27+
io::ErrorKind::InvalidData,
28+
format!("image filename is not valid UTF-8: {:?}", file_name),
29+
)
30+
})?;
31+
file.seek(io::SeekFrom::Start(0))?;
2632

27-
zip.start_file(filename, options)?;
33+
zip.start_file(filename, options)?;
2834

29-
let mut buffer = Vec::new();
30-
let _ = file.read_to_end(&mut buffer)?;
31-
zip.write_all(&buffer)?;
32-
}
33-
}
35+
let mut buffer = Vec::new();
36+
file.read_to_end(&mut buffer)?;
37+
zip.write_all(&buffer)?;
3438
}
3539

3640
zip.finish()?;

0 commit comments

Comments
 (0)