From c100c2da4d14b924cccdf1869f20a1bf1846ecf8 Mon Sep 17 00:00:00 2001 From: 0xrsydn Date: Fri, 19 Jun 2026 19:42:16 +0700 Subject: [PATCH] fix: restore live IDX ownership import --- src/curl_impersonate.rs | 2 +- src/ownership/parser.rs | 39 +++++++++++++++++++++++++++++++++++---- src/ownership/remote.rs | 3 --- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/curl_impersonate.rs b/src/curl_impersonate.rs index 3735feb..6189ed0 100644 --- a/src/curl_impersonate.rs +++ b/src/curl_impersonate.rs @@ -3,9 +3,9 @@ use std::process::{Command, Output}; use crate::error::IdxError; const CANDIDATES: &[&str] = &[ - "curl_chrome142", "curl_chrome136", "curl_chrome133a", + "curl_chrome142", "curl_chrome131", "curl_chrome124", "curl_chrome120", diff --git a/src/ownership/parser.rs b/src/ownership/parser.rs index 4239247..db87814 100644 --- a/src/ownership/parser.rs +++ b/src/ownership/parser.rs @@ -29,10 +29,15 @@ const HEADER_LABELS: &[&str] = &[ const HOLDER_REGISTER_SCHEMA_MARKERS: &[&str] = &[ "TEXT=\"DATE\"", "TEXT=\"SHARE_CODE\"", + "TEXT=\"SHARE CODE\"", "TEXT=\"INVESTOR_NAME\"", + "TEXT=\"INVESTOR NAME\"", "TEXT=\"INVESTOR_TYPE\"", + "TEXT=\"INVESTOR CLASSIFICATION\"", "TEXT=\"LOCAL_FOREIGN\"", + "TEXT=\"LOCAL/FOREIGN\"", "TEXT=\"TOTAL_HOLDING_SHARES\"", + "TEXT=\"TOTAL HOLDING SHARES\"", "TEXT=\"PERCENTAGE\"", ]; const ANNOUNCEMENT_WRAPPER_SCHEMA_MARKERS: &[&str] = @@ -40,8 +45,9 @@ const ANNOUNCEMENT_WRAPPER_SCHEMA_MARKERS: &[&str] = const ABOVE_FIVE_SCHEMA_MARKERS: &[&str] = &["TEXT=\"INVS\"", "REKENING TAMPUNGAN KSEI", "CLOSED MEMBER-"]; const INVESTOR_TYPE_SCHEMA_MARKERS: &[&str] = &[ - "TEXT=\"STOCK_CODE\"", - "TEXT=\"NUMBER_OF_SHARES\"", + "STOCK_CODE", + "NUMBER_OF_SHARES", + "TEXT=\"DOMESTIC\"", "TEXT=\"FOREIGN\"", ]; @@ -460,8 +466,33 @@ fn is_id_number_like(value: &str) -> bool { } fn is_investor_type_marker(value: &str) -> bool { - let trimmed = value.trim(); - !trimmed.is_empty() && trimmed.len() <= 4 && trimmed.chars().all(|ch| ch.is_ascii_uppercase()) + let trimmed = value.trim().to_ascii_uppercase(); + if trimmed.is_empty() { + return false; + } + + if trimmed.len() <= 4 && trimmed.chars().all(|ch| ch.is_ascii_uppercase()) { + return true; + } + + matches!( + trimmed.as_str(), + "CORPORATE" + | "INDIVIDUAL" + | "MUTUAL FUND" + | "PENSION FUND" + | "INSURANCE" + | "FOUNDATION" + | "SECURITIES COMPANY" + | "PRIVATE BANK" + | "PRIVATE EQUITY" + | "SOVEREIGN WEALTH FUND" + | "STATE OWNED ENTERPRISES" + | "BANK" + | "FIRM" + | "BROKER" + | "OTHER" + ) } fn is_locality_marker(value: &str) -> bool { diff --git a/src/ownership/remote.rs b/src/ownership/remote.rs index c8b18f6..2b74a77 100644 --- a/src/ownership/remote.rs +++ b/src/ownership/remote.rs @@ -12,7 +12,6 @@ const DEFAULT_IDX_ANNOUNCEMENT_API_URL: &str = const IDX_ANNOUNCEMENT_API_ENV: &str = "IDX_OWNERSHIP_ANNOUNCEMENT_API_URL"; const IDX_ANNOUNCEMENT_LISTING_ENV: &str = "IDX_OWNERSHIP_ANNOUNCEMENT_PAGE_URL"; const IDX_ANNOUNCEMENT_PAGE_SIZE: usize = 10; -const USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"; #[derive(Debug, Clone, Deserialize)] pub struct AnnouncementPage { @@ -383,7 +382,6 @@ fn fetch_bytes(stage: &str, url: &str, headers: &[(String, String)]) -> Result Vec<(String, String)> { vec![ - ("User-Agent".to_string(), USER_AGENT.to_string()), ( "Accept".to_string(), "application/json,text/plain,*/*".to_string(), @@ -398,7 +396,6 @@ fn json_headers() -> Vec<(String, String)> { fn pdf_headers() -> Vec<(String, String)> { vec![ - ("User-Agent".to_string(), USER_AGENT.to_string()), ( "Accept".to_string(), "application/pdf,application/octet-stream,*/*;q=0.8".to_string(),