libsubconverter/utils/
node_manip.rs

1use log::{debug, info};
2use std::cmp::Ordering;
3
4use crate::models::{
5    extra_settings::ExtraSettings,
6    proxy::{Proxy, ProxyType},
7    regex_match_config::RegexMatchConfigs,
8};
9use crate::utils::{
10    matcher::{apply_matcher, reg_find},
11    reg_replace,
12    string::{remove_emoji, trim},
13};
14
15/// Applies a rename configuration to a node
16/// Similar to the C++ nodeRename function
17fn node_rename(node: &mut Proxy, rename_array: &RegexMatchConfigs, _extra: &ExtraSettings) {
18    let original_remark = node.remark.clone();
19
20    for pattern in rename_array {
21        // Skip script-based patterns since we're not implementing JavaScript support here
22        if !pattern._match.is_empty() {
23            let mut real_rule = String::new();
24            if apply_matcher(&pattern._match, &mut real_rule, node) && !real_rule.is_empty() {
25                node.remark = reg_replace(&node.remark, &real_rule, &pattern.replace, true, false);
26            }
27        }
28    }
29
30    // If the remark is empty after processing, restore the original
31    if node.remark.is_empty() {
32        node.remark = original_remark;
33    }
34}
35
36/// Adds emoji to node remark based on regex matching
37fn add_emoji(node: &Proxy, emoji_array: &RegexMatchConfigs, _extra: &ExtraSettings) -> String {
38    for pattern in emoji_array {
39        // Skip patterns with empty replace
40        if pattern.replace.is_empty() {
41            continue;
42        }
43
44        // Use apply_matcher to handle complex matching rules
45        let mut real_rule = String::new();
46        if apply_matcher(&pattern._match, &mut real_rule, node) {
47            if real_rule.is_empty() || reg_find(&node.remark, &real_rule) {
48                return format!("{} {}", pattern.replace, node.remark);
49            }
50        }
51    }
52
53    node.remark.clone()
54}
55
56/// Sorts nodes by a specified criterion
57fn sort_nodes(nodes: &mut Vec<Proxy>, _sort_script: &str) {
58    // Skip script-based sorting since we're not implementing JavaScript support
59    // Default sort by remark
60    nodes.sort_by(|a, b| {
61        if a.proxy_type == ProxyType::Unknown {
62            return Ordering::Greater;
63        }
64        if b.proxy_type == ProxyType::Unknown {
65            return Ordering::Less;
66        }
67        a.remark.cmp(&b.remark)
68    });
69}
70
71/// Preprocesses nodes before conversion
72/// Based on the C++ preprocessNodes function
73pub fn preprocess_nodes(
74    nodes: &mut Vec<Proxy>,
75    extra: &ExtraSettings,
76    rename_patterns: &RegexMatchConfigs,
77    emoji_patterns: &RegexMatchConfigs,
78) {
79    // Process each node
80    for node in nodes.iter_mut() {
81        // Remove emoji if needed
82        if extra.remove_emoji {
83            node.remark = trim(&remove_emoji(&node.remark)).to_string();
84        }
85
86        // Apply rename patterns
87        node_rename(node, rename_patterns, extra);
88
89        // Add emoji if needed
90        if extra.add_emoji {
91            node.remark = add_emoji(node, emoji_patterns, extra);
92        }
93    }
94
95    // Sort nodes if needed
96    if extra.sort_flag {
97        info!("Sorting {} nodes", nodes.len());
98        sort_nodes(nodes, &extra.sort_script);
99    }
100
101    debug!("Node preprocessing completed for {} nodes", nodes.len());
102}
103
104/// Appends proxy type to node remark
105pub fn append_type_to_remark(nodes: &mut Vec<Proxy>) {
106    for node in nodes.iter_mut() {
107        match node.proxy_type {
108            ProxyType::Unknown => {}
109            _ => {
110                let type_str = node.proxy_type.to_string();
111                node.remark = format!("{} ({})", node.remark, type_str);
112            }
113        }
114    }
115}