crawlberg 1.2.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -0
- data/ext/crawlberg_rb/native/Cargo.lock +111 -142
- data/ext/crawlberg_rb/native/Cargo.toml +19 -2
- data/ext/crawlberg_rb/native/extconf.rb +5 -0
- data/ext/crawlberg_rb/src/lib.rs +223 -30
- data/lib/crawlberg/native.rb +48 -97
- data/lib/crawlberg/version.rb +3 -3
- data/lib/crawlberg.rb +2 -2
- data/sig/types.rbs +456 -449
- metadata +2 -3
- data/lib/crawlberg_rb.so +0 -0
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
# This file is auto-generated by alef — DO NOT EDIT.
|
|
2
|
+
# alef:hash:6d3e12955a76fb5c98a03dc656a5b76ae41ba095ad388a22cb35ce647d7159fc
|
|
3
|
+
# To regenerate: alef generate
|
|
4
|
+
# To verify freshness: alef verify
|
|
5
|
+
|
|
1
6
|
[package]
|
|
2
7
|
name = "crawlberg-rb"
|
|
3
|
-
version = "1.
|
|
8
|
+
version = "1.3.3"
|
|
4
9
|
edition = "2024"
|
|
5
10
|
license = "MIT"
|
|
6
11
|
description = "High-performance web crawling engine"
|
|
@@ -17,10 +22,22 @@ path = "../src/lib.rs"
|
|
|
17
22
|
crate-type = ["cdylib"]
|
|
18
23
|
|
|
19
24
|
[dependencies]
|
|
20
|
-
crawlberg = { version = "1.
|
|
25
|
+
crawlberg = { version = "1.3.3", features = ["interact", "browser-chromiumoxide"] }
|
|
21
26
|
futures = "0.3"
|
|
22
27
|
magnus = "0.8"
|
|
23
28
|
rb-sys = ">=0.9, <0.9.128"
|
|
24
29
|
serde = { version = "1", features = ["derive"] }
|
|
25
30
|
serde_json = "1"
|
|
26
31
|
tokio = { version = "1", features = ["rt-multi-thread"] }
|
|
32
|
+
|
|
33
|
+
# This crate deliberately does not use `[lints]` / `workspace = true`: its C-ABI /
|
|
34
|
+
# PyO3 / napi / ext-php-rs / NIF boundary requires `unsafe` code, and the workspace's
|
|
35
|
+
# `[workspace.lints.rust]` sets `unsafe_code = "deny"` -- an all-or-nothing table that
|
|
36
|
+
# would turn every such boundary into a compile error. The `[lints.clippy]` block below
|
|
37
|
+
# instead carries the subset of the workspace's deny-by-default lint policy this crate
|
|
38
|
+
# can actually satisfy. ~keep
|
|
39
|
+
[lints.clippy]
|
|
40
|
+
all = { level = "warn", priority = -1 }
|
|
41
|
+
dbg_macro = "deny"
|
|
42
|
+
print_stderr = "deny"
|
|
43
|
+
print_stdout = "deny"
|
data/ext/crawlberg_rb/src/lib.rs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// This file is auto-generated by alef. DO NOT EDIT.
|
|
2
|
-
// alef:hash:
|
|
2
|
+
// alef:hash:9312cb415995255492557432651036cfe6b0edf4ccd0b27a88d0cb3c5a7d1466
|
|
3
3
|
// Re-generate with: alef generate
|
|
4
4
|
#![allow(dead_code, unused_imports, unused_variables)]
|
|
5
5
|
#![allow(
|
|
@@ -316,7 +316,7 @@ impl ContentConfig {
|
|
|
316
316
|
exclude_selectors: kwargs
|
|
317
317
|
.get(ruby.to_symbol("exclude_selectors"))
|
|
318
318
|
.and_then(|v| <Vec<String>>::try_convert(v).ok())
|
|
319
|
-
.
|
|
319
|
+
.unwrap_or(vec!["noscript".to_string()]),
|
|
320
320
|
skip_images: kwargs
|
|
321
321
|
.get(ruby.to_symbol("skip_images"))
|
|
322
322
|
.and_then(|v| bool::try_convert(v).ok())
|
|
@@ -467,7 +467,7 @@ impl BrowserConfig {
|
|
|
467
467
|
wait: kwargs
|
|
468
468
|
.get(ruby.to_symbol("wait"))
|
|
469
469
|
.and_then(|v| BrowserWait::try_convert(v).ok())
|
|
470
|
-
.
|
|
470
|
+
.unwrap_or(BrowserWait::NetworkIdle),
|
|
471
471
|
wait_selector: kwargs
|
|
472
472
|
.get(ruby.to_symbol("wait_selector"))
|
|
473
473
|
.and_then(|v| String::try_convert(v).ok()),
|
|
@@ -559,6 +559,10 @@ pub struct CrawlConfig {
|
|
|
559
559
|
max_pages: Option<usize>,
|
|
560
560
|
max_links_per_page: Option<usize>,
|
|
561
561
|
max_concurrent: Option<usize>,
|
|
562
|
+
crawl_strategy: CrawlStrategyKind,
|
|
563
|
+
content_filter: Option<ContentFilterKind>,
|
|
564
|
+
bm25_query: Option<String>,
|
|
565
|
+
bm25_threshold: Option<f64>,
|
|
562
566
|
respect_robots_txt: bool,
|
|
563
567
|
soft_http_errors: bool,
|
|
564
568
|
user_agent: Option<String>,
|
|
@@ -654,6 +658,19 @@ impl CrawlConfig {
|
|
|
654
658
|
max_concurrent: kwargs
|
|
655
659
|
.get(ruby.to_symbol("max_concurrent"))
|
|
656
660
|
.and_then(|v| usize::try_convert(v).ok()),
|
|
661
|
+
crawl_strategy: kwargs
|
|
662
|
+
.get(ruby.to_symbol("crawl_strategy"))
|
|
663
|
+
.and_then(|v| CrawlStrategyKind::try_convert(v).ok())
|
|
664
|
+
.unwrap_or(CrawlStrategyKind::Bfs),
|
|
665
|
+
content_filter: kwargs
|
|
666
|
+
.get(ruby.to_symbol("content_filter"))
|
|
667
|
+
.and_then(|v| ContentFilterKind::try_convert(v).ok()),
|
|
668
|
+
bm25_query: kwargs
|
|
669
|
+
.get(ruby.to_symbol("bm25_query"))
|
|
670
|
+
.and_then(|v| String::try_convert(v).ok()),
|
|
671
|
+
bm25_threshold: kwargs
|
|
672
|
+
.get(ruby.to_symbol("bm25_threshold"))
|
|
673
|
+
.and_then(|v| f64::try_convert(v).ok()),
|
|
657
674
|
respect_robots_txt: kwargs
|
|
658
675
|
.get(ruby.to_symbol("respect_robots_txt"))
|
|
659
676
|
.and_then(|v| bool::try_convert(v).ok())
|
|
@@ -791,7 +808,7 @@ impl CrawlConfig {
|
|
|
791
808
|
ssrf: kwargs
|
|
792
809
|
.get(ruby.to_symbol("ssrf"))
|
|
793
810
|
.and_then(|v| SsrfPolicy::try_convert(v).ok())
|
|
794
|
-
.
|
|
811
|
+
.unwrap_or(crawlberg::SsrfPolicy::from_env().into()),
|
|
795
812
|
ssrf_deny_private_explicit: kwargs
|
|
796
813
|
.get(ruby.to_symbol("ssrf_deny_private_explicit"))
|
|
797
814
|
.and_then(|v| bool::try_convert(v).ok()),
|
|
@@ -814,6 +831,22 @@ impl CrawlConfig {
|
|
|
814
831
|
self.max_concurrent
|
|
815
832
|
}
|
|
816
833
|
|
|
834
|
+
fn crawl_strategy(&self) -> CrawlStrategyKind {
|
|
835
|
+
self.crawl_strategy.clone()
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
fn content_filter(&self) -> Option<ContentFilterKind> {
|
|
839
|
+
self.content_filter.clone()
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
fn bm25_query(&self) -> Option<String> {
|
|
843
|
+
self.bm25_query.clone()
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
fn bm25_threshold(&self) -> Option<f64> {
|
|
847
|
+
self.bm25_threshold
|
|
848
|
+
}
|
|
849
|
+
|
|
817
850
|
fn respect_robots_txt(&self) -> bool {
|
|
818
851
|
self.respect_robots_txt
|
|
819
852
|
}
|
|
@@ -981,6 +1014,14 @@ impl CrawlConfig {
|
|
|
981
1014
|
|
|
982
1015
|
max_concurrent: self.max_concurrent,
|
|
983
1016
|
|
|
1017
|
+
crawl_strategy: self.crawl_strategy.clone().into(),
|
|
1018
|
+
|
|
1019
|
+
content_filter: self.content_filter.clone().map(Into::into),
|
|
1020
|
+
|
|
1021
|
+
bm25_query: self.bm25_query.clone(),
|
|
1022
|
+
|
|
1023
|
+
bm25_threshold: self.bm25_threshold,
|
|
1024
|
+
|
|
984
1025
|
respect_robots_txt: self.respect_robots_txt,
|
|
985
1026
|
|
|
986
1027
|
soft_http_errors: self.soft_http_errors,
|
|
@@ -2460,7 +2501,7 @@ impl LinkInfo {
|
|
|
2460
2501
|
link_type: kwargs
|
|
2461
2502
|
.get(ruby.to_symbol("link_type"))
|
|
2462
2503
|
.and_then(|v| LinkType::try_convert(v).ok())
|
|
2463
|
-
.
|
|
2504
|
+
.unwrap_or(LinkType::Internal),
|
|
2464
2505
|
rel: kwargs
|
|
2465
2506
|
.get(ruby.to_symbol("rel"))
|
|
2466
2507
|
.and_then(|v| String::try_convert(v).ok()),
|
|
@@ -2560,7 +2601,7 @@ impl ImageInfo {
|
|
|
2560
2601
|
source: kwargs
|
|
2561
2602
|
.get(ruby.to_symbol("source"))
|
|
2562
2603
|
.and_then(|v| ImageSource::try_convert(v).ok())
|
|
2563
|
-
.
|
|
2604
|
+
.unwrap_or(ImageSource::Img),
|
|
2564
2605
|
})
|
|
2565
2606
|
}
|
|
2566
2607
|
|
|
@@ -2645,7 +2686,7 @@ impl FeedInfo {
|
|
|
2645
2686
|
feed_type: kwargs
|
|
2646
2687
|
.get(ruby.to_symbol("feed_type"))
|
|
2647
2688
|
.and_then(|v| FeedType::try_convert(v).ok())
|
|
2648
|
-
.
|
|
2689
|
+
.unwrap_or(FeedType::Rss),
|
|
2649
2690
|
})
|
|
2650
2691
|
}
|
|
2651
2692
|
|
|
@@ -2895,7 +2936,7 @@ impl DownloadedAsset {
|
|
|
2895
2936
|
asset_category: kwargs
|
|
2896
2937
|
.get(ruby.to_symbol("asset_category"))
|
|
2897
2938
|
.and_then(|v| AssetCategory::try_convert(v).ok())
|
|
2898
|
-
.
|
|
2939
|
+
.unwrap_or(AssetCategory::Image),
|
|
2899
2940
|
html_tag: kwargs
|
|
2900
2941
|
.get(ruby.to_symbol("html_tag"))
|
|
2901
2942
|
.and_then(|v| String::try_convert(v).ok()),
|
|
@@ -4542,8 +4583,9 @@ impl magnus::IntoValue for BrowserMode {
|
|
|
4542
4583
|
impl magnus::TryConvert for BrowserMode {
|
|
4543
4584
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
4544
4585
|
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
4545
|
-
// Accept the serde wire
|
|
4546
|
-
//
|
|
4586
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
4587
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
4588
|
+
// existing consumer code written in any of those styles keep working.
|
|
4547
4589
|
match s.as_str() {
|
|
4548
4590
|
"auto" | "Auto" => Ok(BrowserMode::Auto),
|
|
4549
4591
|
"always" | "Always" => Ok(BrowserMode::Always),
|
|
@@ -4588,8 +4630,9 @@ impl magnus::IntoValue for BrowserWait {
|
|
|
4588
4630
|
impl magnus::TryConvert for BrowserWait {
|
|
4589
4631
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
4590
4632
|
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
4591
|
-
// Accept the serde wire
|
|
4592
|
-
//
|
|
4633
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
4634
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
4635
|
+
// existing consumer code written in any of those styles keep working.
|
|
4593
4636
|
match s.as_str() {
|
|
4594
4637
|
"network_idle" | "NetworkIdle" => Ok(BrowserWait::NetworkIdle),
|
|
4595
4638
|
"selector" | "Selector" => Ok(BrowserWait::Selector),
|
|
@@ -4631,8 +4674,9 @@ impl magnus::IntoValue for BrowserBackend {
|
|
|
4631
4674
|
impl magnus::TryConvert for BrowserBackend {
|
|
4632
4675
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
4633
4676
|
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
4634
|
-
// Accept the serde wire
|
|
4635
|
-
//
|
|
4677
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
4678
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
4679
|
+
// existing consumer code written in any of those styles keep working.
|
|
4636
4680
|
match s.as_str() {
|
|
4637
4681
|
"chromiumoxide" | "Chromiumoxide" => Ok(BrowserBackend::Chromiumoxide),
|
|
4638
4682
|
"native" | "Native" => Ok(BrowserBackend::Native),
|
|
@@ -4671,8 +4715,9 @@ impl magnus::IntoValue for DocumentContentEncoding {
|
|
|
4671
4715
|
impl magnus::TryConvert for DocumentContentEncoding {
|
|
4672
4716
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
4673
4717
|
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
4674
|
-
// Accept the serde wire
|
|
4675
|
-
//
|
|
4718
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
4719
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
4720
|
+
// existing consumer code written in any of those styles keep working.
|
|
4676
4721
|
match s.as_str() {
|
|
4677
4722
|
"base64" | "Base64" => Ok(DocumentContentEncoding::Base64),
|
|
4678
4723
|
other => Err(magnus::Error::new(
|
|
@@ -4686,6 +4731,95 @@ impl magnus::TryConvert for DocumentContentEncoding {
|
|
|
4686
4731
|
unsafe impl IntoValueFromNative for DocumentContentEncoding {}
|
|
4687
4732
|
unsafe impl TryConvertOwned for DocumentContentEncoding {}
|
|
4688
4733
|
|
|
4734
|
+
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
4735
|
+
#[serde(rename_all = "snake_case")]
|
|
4736
|
+
pub enum CrawlStrategyKind {
|
|
4737
|
+
Bfs,
|
|
4738
|
+
Dfs,
|
|
4739
|
+
BestFirst,
|
|
4740
|
+
Adaptive,
|
|
4741
|
+
}
|
|
4742
|
+
|
|
4743
|
+
impl Default for CrawlStrategyKind {
|
|
4744
|
+
fn default() -> Self {
|
|
4745
|
+
Self::Bfs
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
|
|
4749
|
+
impl magnus::IntoValue for CrawlStrategyKind {
|
|
4750
|
+
fn into_value_with(self, handle: &Ruby) -> magnus::Value {
|
|
4751
|
+
let sym = match self {
|
|
4752
|
+
CrawlStrategyKind::Bfs => "bfs",
|
|
4753
|
+
CrawlStrategyKind::Dfs => "dfs",
|
|
4754
|
+
CrawlStrategyKind::BestFirst => "best_first",
|
|
4755
|
+
CrawlStrategyKind::Adaptive => "adaptive",
|
|
4756
|
+
};
|
|
4757
|
+
handle.to_symbol(sym).into_value_with(handle)
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4760
|
+
|
|
4761
|
+
impl magnus::TryConvert for CrawlStrategyKind {
|
|
4762
|
+
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
4763
|
+
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
4764
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
4765
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
4766
|
+
// existing consumer code written in any of those styles keep working.
|
|
4767
|
+
match s.as_str() {
|
|
4768
|
+
"bfs" | "Bfs" => Ok(CrawlStrategyKind::Bfs),
|
|
4769
|
+
"dfs" | "Dfs" => Ok(CrawlStrategyKind::Dfs),
|
|
4770
|
+
"best_first" | "BestFirst" => Ok(CrawlStrategyKind::BestFirst),
|
|
4771
|
+
"adaptive" | "Adaptive" => Ok(CrawlStrategyKind::Adaptive),
|
|
4772
|
+
other => Err(magnus::Error::new(
|
|
4773
|
+
unsafe { Ruby::get_unchecked() }.exception_arg_error(),
|
|
4774
|
+
format!("invalid CrawlStrategyKind value: {other}"),
|
|
4775
|
+
)),
|
|
4776
|
+
}
|
|
4777
|
+
}
|
|
4778
|
+
}
|
|
4779
|
+
|
|
4780
|
+
unsafe impl IntoValueFromNative for CrawlStrategyKind {}
|
|
4781
|
+
unsafe impl TryConvertOwned for CrawlStrategyKind {}
|
|
4782
|
+
|
|
4783
|
+
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
|
|
4784
|
+
#[serde(rename_all = "snake_case")]
|
|
4785
|
+
pub enum ContentFilterKind {
|
|
4786
|
+
Bm25,
|
|
4787
|
+
}
|
|
4788
|
+
|
|
4789
|
+
impl Default for ContentFilterKind {
|
|
4790
|
+
fn default() -> Self {
|
|
4791
|
+
Self::Bm25
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4794
|
+
|
|
4795
|
+
impl magnus::IntoValue for ContentFilterKind {
|
|
4796
|
+
fn into_value_with(self, handle: &Ruby) -> magnus::Value {
|
|
4797
|
+
let sym = match self {
|
|
4798
|
+
ContentFilterKind::Bm25 => "bm25",
|
|
4799
|
+
};
|
|
4800
|
+
handle.to_symbol(sym).into_value_with(handle)
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4804
|
+
impl magnus::TryConvert for ContentFilterKind {
|
|
4805
|
+
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
4806
|
+
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
4807
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
4808
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
4809
|
+
// existing consumer code written in any of those styles keep working.
|
|
4810
|
+
match s.as_str() {
|
|
4811
|
+
"bm25" | "Bm25" => Ok(ContentFilterKind::Bm25),
|
|
4812
|
+
other => Err(magnus::Error::new(
|
|
4813
|
+
unsafe { Ruby::get_unchecked() }.exception_arg_error(),
|
|
4814
|
+
format!("invalid ContentFilterKind value: {other}"),
|
|
4815
|
+
)),
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
|
|
4820
|
+
unsafe impl IntoValueFromNative for ContentFilterKind {}
|
|
4821
|
+
unsafe impl TryConvertOwned for ContentFilterKind {}
|
|
4822
|
+
|
|
4689
4823
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
|
4690
4824
|
#[serde(tag = "type")]
|
|
4691
4825
|
pub enum AuthConfig {
|
|
@@ -4781,8 +4915,9 @@ impl magnus::IntoValue for LinkType {
|
|
|
4781
4915
|
impl magnus::TryConvert for LinkType {
|
|
4782
4916
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
4783
4917
|
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
4784
|
-
// Accept the serde wire
|
|
4785
|
-
//
|
|
4918
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
4919
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
4920
|
+
// existing consumer code written in any of those styles keep working.
|
|
4786
4921
|
match s.as_str() {
|
|
4787
4922
|
"internal" | "Internal" => Ok(LinkType::Internal),
|
|
4788
4923
|
"external" | "External" => Ok(LinkType::External),
|
|
@@ -4821,8 +4956,8 @@ impl magnus::IntoValue for ImageSource {
|
|
|
4821
4956
|
let sym = match self {
|
|
4822
4957
|
ImageSource::Img => "img",
|
|
4823
4958
|
ImageSource::PictureSource => "picture_source",
|
|
4824
|
-
ImageSource::OgImage => "
|
|
4825
|
-
ImageSource::TwitterImage => "
|
|
4959
|
+
ImageSource::OgImage => "og:image",
|
|
4960
|
+
ImageSource::TwitterImage => "twitter:image",
|
|
4826
4961
|
};
|
|
4827
4962
|
handle.to_symbol(sym).into_value_with(handle)
|
|
4828
4963
|
}
|
|
@@ -4831,13 +4966,14 @@ impl magnus::IntoValue for ImageSource {
|
|
|
4831
4966
|
impl magnus::TryConvert for ImageSource {
|
|
4832
4967
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
4833
4968
|
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
4834
|
-
// Accept the serde wire
|
|
4835
|
-
//
|
|
4969
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
4970
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
4971
|
+
// existing consumer code written in any of those styles keep working.
|
|
4836
4972
|
match s.as_str() {
|
|
4837
4973
|
"img" | "Img" => Ok(ImageSource::Img),
|
|
4838
4974
|
"picture_source" | "PictureSource" => Ok(ImageSource::PictureSource),
|
|
4839
|
-
"og_image" | "OgImage" => Ok(ImageSource::OgImage),
|
|
4840
|
-
"twitter_image" | "TwitterImage" => Ok(ImageSource::TwitterImage),
|
|
4975
|
+
"og:image" | "og_image" | "OgImage" => Ok(ImageSource::OgImage),
|
|
4976
|
+
"twitter:image" | "twitter_image" | "TwitterImage" => Ok(ImageSource::TwitterImage),
|
|
4841
4977
|
other => Err(magnus::Error::new(
|
|
4842
4978
|
unsafe { Ruby::get_unchecked() }.exception_arg_error(),
|
|
4843
4979
|
format!("invalid ImageSource value: {other}"),
|
|
@@ -4877,8 +5013,9 @@ impl magnus::IntoValue for FeedType {
|
|
|
4877
5013
|
impl magnus::TryConvert for FeedType {
|
|
4878
5014
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
4879
5015
|
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
4880
|
-
// Accept the serde wire
|
|
4881
|
-
//
|
|
5016
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
5017
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
5018
|
+
// existing consumer code written in any of those styles keep working.
|
|
4882
5019
|
match s.as_str() {
|
|
4883
5020
|
"rss" | "Rss" => Ok(FeedType::Rss),
|
|
4884
5021
|
"atom" | "Atom" => Ok(FeedType::Atom),
|
|
@@ -4936,8 +5073,9 @@ impl magnus::IntoValue for AssetCategory {
|
|
|
4936
5073
|
impl magnus::TryConvert for AssetCategory {
|
|
4937
5074
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
4938
5075
|
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
4939
|
-
// Accept the serde wire
|
|
4940
|
-
//
|
|
5076
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
5077
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
5078
|
+
// existing consumer code written in any of those styles keep working.
|
|
4941
5079
|
match s.as_str() {
|
|
4942
5080
|
"document" | "Document" => Ok(AssetCategory::Document),
|
|
4943
5081
|
"image" | "Image" => Ok(AssetCategory::Image),
|
|
@@ -5133,8 +5271,9 @@ impl magnus::IntoValue for ScrollDirection {
|
|
|
5133
5271
|
impl magnus::TryConvert for ScrollDirection {
|
|
5134
5272
|
fn try_convert(val: magnus::Value) -> Result<Self, magnus::Error> {
|
|
5135
5273
|
let s: String = magnus::TryConvert::try_convert(val)?;
|
|
5136
|
-
// Accept the serde wire
|
|
5137
|
-
//
|
|
5274
|
+
// Accept the real serde wire value, the legacy always-snake_case symbol Magnus used to
|
|
5275
|
+
// emit unconditionally, and the verbatim PascalCase Rust variant name, so fixtures and
|
|
5276
|
+
// existing consumer code written in any of those styles keep working.
|
|
5138
5277
|
match s.as_str() {
|
|
5139
5278
|
"up" | "Up" => Ok(ScrollDirection::Up),
|
|
5140
5279
|
"down" | "Down" => Ok(ScrollDirection::Down),
|
|
@@ -5612,6 +5751,10 @@ impl From<CrawlConfig> for crawlberg::CrawlConfig {
|
|
|
5612
5751
|
max_pages: val.max_pages,
|
|
5613
5752
|
max_links_per_page: val.max_links_per_page,
|
|
5614
5753
|
max_concurrent: val.max_concurrent,
|
|
5754
|
+
crawl_strategy: val.crawl_strategy.into(),
|
|
5755
|
+
content_filter: val.content_filter.map(Into::into),
|
|
5756
|
+
bm25_query: val.bm25_query,
|
|
5757
|
+
bm25_threshold: val.bm25_threshold,
|
|
5615
5758
|
respect_robots_txt: val.respect_robots_txt,
|
|
5616
5759
|
soft_http_errors: val.soft_http_errors,
|
|
5617
5760
|
user_agent: val.user_agent,
|
|
@@ -5668,6 +5811,10 @@ impl From<crawlberg::CrawlConfig> for CrawlConfig {
|
|
|
5668
5811
|
max_pages: val.max_pages,
|
|
5669
5812
|
max_links_per_page: val.max_links_per_page,
|
|
5670
5813
|
max_concurrent: val.max_concurrent,
|
|
5814
|
+
crawl_strategy: val.crawl_strategy.into(),
|
|
5815
|
+
content_filter: val.content_filter.map(Into::into),
|
|
5816
|
+
bm25_query: val.bm25_query.map(|v| v.to_string()),
|
|
5817
|
+
bm25_threshold: val.bm25_threshold,
|
|
5671
5818
|
respect_robots_txt: val.respect_robots_txt,
|
|
5672
5819
|
soft_http_errors: val.soft_http_errors,
|
|
5673
5820
|
user_agent: val.user_agent.map(|v| v.to_string()),
|
|
@@ -6746,6 +6893,44 @@ impl From<crawlberg::DocumentContentEncoding> for DocumentContentEncoding {
|
|
|
6746
6893
|
}
|
|
6747
6894
|
}
|
|
6748
6895
|
|
|
6896
|
+
impl From<CrawlStrategyKind> for crawlberg::CrawlStrategyKind {
|
|
6897
|
+
fn from(val: CrawlStrategyKind) -> Self {
|
|
6898
|
+
match val {
|
|
6899
|
+
CrawlStrategyKind::Bfs => Self::Bfs,
|
|
6900
|
+
CrawlStrategyKind::Dfs => Self::Dfs,
|
|
6901
|
+
CrawlStrategyKind::BestFirst => Self::BestFirst,
|
|
6902
|
+
CrawlStrategyKind::Adaptive => Self::Adaptive,
|
|
6903
|
+
}
|
|
6904
|
+
}
|
|
6905
|
+
}
|
|
6906
|
+
|
|
6907
|
+
impl From<crawlberg::CrawlStrategyKind> for CrawlStrategyKind {
|
|
6908
|
+
fn from(val: crawlberg::CrawlStrategyKind) -> Self {
|
|
6909
|
+
match val {
|
|
6910
|
+
crawlberg::CrawlStrategyKind::Bfs => Self::Bfs,
|
|
6911
|
+
crawlberg::CrawlStrategyKind::Dfs => Self::Dfs,
|
|
6912
|
+
crawlberg::CrawlStrategyKind::BestFirst => Self::BestFirst,
|
|
6913
|
+
crawlberg::CrawlStrategyKind::Adaptive => Self::Adaptive,
|
|
6914
|
+
}
|
|
6915
|
+
}
|
|
6916
|
+
}
|
|
6917
|
+
|
|
6918
|
+
impl From<ContentFilterKind> for crawlberg::ContentFilterKind {
|
|
6919
|
+
fn from(val: ContentFilterKind) -> Self {
|
|
6920
|
+
match val {
|
|
6921
|
+
ContentFilterKind::Bm25 => Self::Bm25,
|
|
6922
|
+
}
|
|
6923
|
+
}
|
|
6924
|
+
}
|
|
6925
|
+
|
|
6926
|
+
impl From<crawlberg::ContentFilterKind> for ContentFilterKind {
|
|
6927
|
+
fn from(val: crawlberg::ContentFilterKind) -> Self {
|
|
6928
|
+
match val {
|
|
6929
|
+
crawlberg::ContentFilterKind::Bm25 => Self::Bm25,
|
|
6930
|
+
}
|
|
6931
|
+
}
|
|
6932
|
+
}
|
|
6933
|
+
|
|
6749
6934
|
impl From<AuthConfig> for crawlberg::AuthConfig {
|
|
6750
6935
|
fn from(val: AuthConfig) -> Self {
|
|
6751
6936
|
match val {
|
|
@@ -7286,6 +7471,14 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
7286
7471
|
|
|
7287
7472
|
class.define_method("max_concurrent", method!(CrawlConfig::max_concurrent, 0))?;
|
|
7288
7473
|
|
|
7474
|
+
class.define_method("crawl_strategy", method!(CrawlConfig::crawl_strategy, 0))?;
|
|
7475
|
+
|
|
7476
|
+
class.define_method("content_filter", method!(CrawlConfig::content_filter, 0))?;
|
|
7477
|
+
|
|
7478
|
+
class.define_method("bm25_query", method!(CrawlConfig::bm25_query, 0))?;
|
|
7479
|
+
|
|
7480
|
+
class.define_method("bm25_threshold", method!(CrawlConfig::bm25_threshold, 0))?;
|
|
7481
|
+
|
|
7289
7482
|
class.define_method("respect_robots_txt", method!(CrawlConfig::respect_robots_txt, 0))?;
|
|
7290
7483
|
|
|
7291
7484
|
class.define_method("soft_http_errors", method!(CrawlConfig::soft_http_errors, 0))?;
|