UrlCategorise 0.1.7 → 0.1.11

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.
data/bin/check_lists CHANGED
@@ -1,9 +1,112 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'bundler/setup'
4
+ require 'thread'
5
+ require 'optparse'
4
6
  require_relative '../lib/url_categorise'
5
7
 
8
+ # Default configuration
9
+ options = {
10
+ parallel_enabled: false,
11
+ max_threads: 8,
12
+ verbose: false
13
+ }
14
+
15
+ # Parse command-line options
16
+ OptionParser.new do |opts|
17
+ opts.banner = "Usage: #{$0} [options]"
18
+ opts.separator ''
19
+ opts.separator 'Check all URLs in constants for availability'
20
+ opts.separator ''
21
+
22
+ opts.on('-p', '--parallel', 'Enable parallel URL checking') do
23
+ options[:parallel_enabled] = true
24
+ end
25
+
26
+ opts.on('-t', '--threads NUM', Integer, "Number of threads to use (default: #{options[:max_threads]})") do |num|
27
+ options[:max_threads] = num
28
+ end
29
+
30
+ opts.on('-v', '--verbose', 'Verbose output') do
31
+ options[:verbose] = true
32
+ end
33
+
34
+ opts.on('-h', '--help', 'Show this help message') do
35
+ puts opts
36
+ exit
37
+ end
38
+ end.parse!
39
+
6
40
  puts '=== CHECKING ALL URLs IN CONSTANTS ==='
41
+ puts "šŸš€ Using parallel processing with #{options[:max_threads]} threads" if options[:parallel_enabled]
42
+
43
+ def check_url(url)
44
+ begin
45
+ response = HTTParty.head(url, timeout: 10)
46
+ case response.code
47
+ when 200
48
+ { url: url, status: 'āœ… OK', code: response.code }
49
+ when 404
50
+ { url: url, status: 'āŒ 404 Not Found', code: response.code }
51
+ when 403
52
+ { url: url, status: 'āŒ 403 Forbidden', code: response.code }
53
+ when 500..599
54
+ { url: url, status: "āŒ Server Error (#{response.code})", code: response.code }
55
+ else
56
+ { url: url, status: "āš ļø HTTP #{response.code}", code: response.code }
57
+ end
58
+ rescue Net::TimeoutError, HTTParty::TimeoutError
59
+ { url: url, status: 'āŒ Timeout', code: nil }
60
+ rescue SocketError, Errno::ECONNREFUSED
61
+ { url: url, status: 'āŒ DNS/Network Error', code: nil }
62
+ rescue StandardError => e
63
+ { url: url, status: "āŒ Error: #{e.class}", code: nil }
64
+ end
65
+ end
66
+
67
+ def check_urls_parallel(urls, max_threads)
68
+ results = []
69
+ results_mutex = Mutex.new
70
+
71
+ # Create work queue
72
+ queue = Queue.new
73
+ urls.each { |url| queue << url }
74
+
75
+ # Create worker threads
76
+ threads = []
77
+ max_threads.times do
78
+ threads << Thread.new do
79
+ while !queue.empty?
80
+ begin
81
+ url = queue.pop(true) # non-blocking pop
82
+ result = check_url(url)
83
+
84
+ results_mutex.synchronize do
85
+ results << result
86
+ end
87
+ rescue ThreadError
88
+ # Queue is empty, thread can exit
89
+ break
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ # Wait for all threads to complete
96
+ threads.each(&:join)
97
+
98
+ # Sort results to maintain original order
99
+ urls.map { |url| results.find { |r| r[:url] == url } }
100
+ end
101
+
102
+ def check_urls_sequential(urls)
103
+ urls.map do |url|
104
+ print " Testing #{url}... "
105
+ result = check_url(url)
106
+ puts result[:status]
107
+ result
108
+ end
109
+ end
7
110
 
8
111
  UrlCategorise::Constants::DEFAULT_HOST_URLS.each do |category, urls|
9
112
  puts "\n#{category.upcase}:"
@@ -20,28 +123,27 @@ UrlCategorise::Constants::DEFAULT_HOST_URLS.each do |category, urls|
20
123
  next
21
124
  end
22
125
 
23
- actual_urls.each do |url|
24
- print " Testing #{url}... "
25
- begin
26
- response = HTTParty.head(url, timeout: 10)
27
- case response.code
28
- when 200
29
- puts 'āœ… OK'
30
- when 404
31
- puts 'āŒ 404 Not Found'
32
- when 403
33
- puts 'āŒ 403 Forbidden'
34
- when 500..599
35
- puts "āŒ Server Error (#{response.code})"
36
- else
37
- puts "āš ļø HTTP #{response.code}"
38
- end
39
- rescue Net::TimeoutError, HTTParty::TimeoutError
40
- puts 'āŒ Timeout'
41
- rescue SocketError, Errno::ECONNREFUSED
42
- puts 'āŒ DNS/Network Error'
43
- rescue StandardError => e
44
- puts "āŒ Error: #{e.class}"
126
+ if options[:parallel_enabled] && actual_urls.length > 1
127
+ puts " ⚔ Checking #{actual_urls.length} URLs in parallel..."
128
+ start_time = Time.now
129
+ results = check_urls_parallel(actual_urls, [options[:max_threads], actual_urls.length].min)
130
+ end_time = Time.now
131
+
132
+ # Display results
133
+ results.each do |result|
134
+ puts " #{result[:url]} → #{result[:status]}"
45
135
  end
136
+
137
+ puts " ā±ļø Completed in #{'%.2f' % ((end_time - start_time) * 1000)}ms"
138
+ else
139
+ results = check_urls_sequential(actual_urls)
46
140
  end
141
+
142
+ # Summary for this category
143
+ ok_count = results.count { |r| r[:status].include?('āœ…') }
144
+ error_count = results.length - ok_count
145
+ puts " šŸ“Š Summary: #{ok_count} OK, #{error_count} errors" if results.length > 1
47
146
  end
147
+
148
+ puts "\nšŸŽÆ Health check completed!"
149
+ puts "šŸ’” Tip: Use --parallel (-p) for faster checking and --threads (-t) NUM to control thread count"
data/bin/export_csv CHANGED
@@ -7,55 +7,64 @@ require_relative '../lib/url_categorise'
7
7
  options = {
8
8
  output_path: nil,
9
9
  cache_dir: nil,
10
- verbose: false,
10
+ verbose: true, # Verbose by default as requested
11
11
  iab_compliance: false,
12
12
  smart_categorization: false,
13
13
  auto_load_datasets: false,
14
- kaggle_credentials_file: nil
14
+ kaggle_credentials_file: nil,
15
+ parallel_loading: true # Enable by default for better performance
15
16
  }
16
17
 
17
18
  OptionParser.new do |opts|
18
19
  opts.banner = "Usage: #{$0} [options]"
19
- opts.separator ""
20
- opts.separator "Export all categorized domains and dataset content as a single CSV file for AI training"
21
- opts.separator ""
22
-
23
- opts.on("-o", "--output PATH", "Output directory path (default: cache_dir/exports/csv or ./exports/csv)") do |path|
20
+ opts.separator ''
21
+ opts.separator 'Export all categorized domains and dataset content as a single CSV file for AI training'
22
+ opts.separator ''
23
+
24
+ opts.on('-o', '--output PATH', 'Output directory path (default: cache_dir/exports/csv or ./exports/csv)') do |path|
24
25
  options[:output_path] = path
25
26
  end
26
-
27
- opts.on("-c", "--cache-dir PATH", "Cache directory path for client initialization") do |path|
27
+
28
+ opts.on('-c', '--cache-dir PATH', 'Cache directory path for client initialization') do |path|
28
29
  options[:cache_dir] = path
29
30
  end
30
-
31
- opts.on("--iab-compliance", "Enable IAB compliance for category mapping") do
31
+
32
+ opts.on('--iab-compliance', 'Enable IAB compliance for category mapping') do
32
33
  options[:iab_compliance] = true
33
34
  end
34
-
35
- opts.on("--smart-categorization", "Enable smart categorization") do
35
+
36
+ opts.on('--smart-categorization', 'Enable smart categorization') do
36
37
  options[:smart_categorization] = true
37
38
  end
38
-
39
- opts.on("--auto-load-datasets", "Auto-load datasets from constants for rich content export") do
39
+
40
+ opts.on('--auto-load-datasets', 'Auto-load datasets from constants for rich content export') do
40
41
  options[:auto_load_datasets] = true
41
42
  end
42
-
43
- opts.on("--kaggle-credentials FILE", "Path to Kaggle credentials file (default: ~/.kaggle/kaggle.json)") do |file|
43
+
44
+ opts.on('--kaggle-credentials FILE', 'Path to Kaggle credentials file (default: ~/.kaggle/kaggle.json)') do |file|
44
45
  options[:kaggle_credentials_file] = file
45
46
  end
46
-
47
- opts.on("-v", "--verbose", "Verbose output") do
47
+
48
+ opts.on('-v', '--verbose', 'Force verbose output (default behavior)') do
48
49
  options[:verbose] = true
49
50
  end
50
-
51
- opts.on("-h", "--help", "Show this help message") do
51
+
52
+ opts.on('-q', '--quiet', '--silence', 'Disable verbose output') do
53
+ options[:verbose] = false
54
+ end
55
+
56
+ opts.on('--no-parallel', 'Disable parallel loading (use for debugging or reduced memory usage)') do
57
+ options[:parallel_loading] = false
58
+ end
59
+
60
+ opts.on('-h', '--help', 'Show this help message') do
52
61
  puts opts
53
62
  exit
54
63
  end
55
64
  end.parse!
56
65
 
57
- puts "=== UrlCategorise CSV Data Export ===" if options[:verbose]
58
- puts "Initializing client..." if options[:verbose]
66
+ puts '=== UrlCategorise CSV Data Export ===' if options[:verbose]
67
+ puts 'Initializing client...' if options[:verbose]
59
68
 
60
69
  begin
61
70
  # Build dataset config if datasets should be loaded
@@ -65,7 +74,7 @@ begin
65
74
  cache_path: options[:cache_dir] ? File.join(options[:cache_dir], 'datasets') : './url_cache/datasets',
66
75
  download_path: options[:cache_dir] ? File.join(options[:cache_dir], 'downloads') : './url_cache/downloads'
67
76
  }
68
-
77
+
69
78
  # Add Kaggle credentials if provided
70
79
  if options[:kaggle_credentials_file]
71
80
  dataset_config[:kaggle] = { credentials_file: options[:kaggle_credentials_file] }
@@ -79,42 +88,42 @@ begin
79
88
  iab_compliance: options[:iab_compliance],
80
89
  smart_categorization: options[:smart_categorization],
81
90
  auto_load_datasets: options[:auto_load_datasets],
82
- dataset_config: dataset_config
91
+ dataset_config: dataset_config,
92
+ parallel_loading: options[:parallel_loading]
83
93
  )
84
-
94
+
85
95
  if options[:verbose] && options[:auto_load_datasets]
86
- puts "Client initialized with dataset loading enabled"
87
- puts "Dataset statistics:"
96
+ puts 'Client initialized with dataset loading enabled'
97
+ puts 'Dataset statistics:'
88
98
  puts " Dataset categories: #{client.count_of_dataset_categories}"
89
99
  puts " Dataset hosts: #{client.count_of_dataset_hosts.to_s.reverse.gsub(/(\\d{3})(?=\\d)/, '\\1,').reverse}"
90
100
  puts " Dataset data size: #{client.size_of_dataset_data.round(2)} MB" if client.respond_to?(:size_of_dataset_data)
91
101
  end
92
-
93
- puts "Exporting CSV data..." if options[:verbose]
94
-
102
+
103
+ puts 'Exporting CSV data...' if options[:verbose]
104
+
95
105
  result = client.export_csv_data(options[:output_path])
96
-
106
+
97
107
  puts "\nāœ… Export completed successfully!"
98
108
  puts "šŸ“ Export directory: #{result[:export_directory]}"
99
109
  puts "šŸ“„ CSV file: #{result[:csv_file]}"
100
110
  puts "šŸ“„ Summary file: #{result[:summary_file]}"
101
-
111
+
102
112
  puts "\nšŸ“Š Data Summary:"
103
113
  puts " Total entries: #{result[:total_entries]}"
104
114
  puts " Domain categorizations: #{result[:summary][:domain_categorization_entries]}"
105
115
  puts " Dataset content entries: #{result[:summary][:dataset_content_entries]}"
106
116
  puts " Total categories: #{result[:summary][:total_categories]}"
107
117
  puts " Has dataset content: #{result[:summary][:has_dataset_content]}"
108
-
118
+
109
119
  if options[:verbose]
110
120
  puts "\nšŸ·ļø Categories included:"
111
121
  result[:summary][:categories].each do |category|
112
122
  puts " - #{category}"
113
123
  end
114
124
  end
115
-
116
125
  rescue StandardError => e
117
126
  puts "āŒ Error: #{e.message}"
118
127
  puts e.backtrace if options[:verbose]
119
128
  exit 1
120
- end
129
+ end
data/bin/export_hosts CHANGED
@@ -7,62 +7,72 @@ require_relative '../lib/url_categorise'
7
7
  options = {
8
8
  output_path: nil,
9
9
  cache_dir: nil,
10
- verbose: false
10
+ verbose: true, # Verbose by default as requested
11
+ parallel_loading: true # Enable by default for better performance
11
12
  }
12
13
 
13
14
  OptionParser.new do |opts|
14
15
  opts.banner = "Usage: #{$0} [options]"
15
- opts.separator ""
16
- opts.separator "Export all categorized domains as separate hosts files per category"
17
- opts.separator ""
18
-
19
- opts.on("-o", "--output PATH", "Output directory path (default: cache_dir/exports/hosts or ./exports/hosts)") do |path|
16
+ opts.separator ''
17
+ opts.separator 'Export all categorized domains as separate hosts files per category'
18
+ opts.separator ''
19
+
20
+ opts.on('-o', '--output PATH',
21
+ 'Output directory path (default: cache_dir/exports/hosts or ./exports/hosts)') do |path|
20
22
  options[:output_path] = path
21
23
  end
22
-
23
- opts.on("-c", "--cache-dir PATH", "Cache directory path for client initialization") do |path|
24
+
25
+ opts.on('-c', '--cache-dir PATH', 'Cache directory path for client initialization') do |path|
24
26
  options[:cache_dir] = path
25
27
  end
26
-
27
- opts.on("-v", "--verbose", "Verbose output") do
28
+
29
+ opts.on('-v', '--verbose', 'Force verbose output (default behavior)') do
28
30
  options[:verbose] = true
29
31
  end
30
-
31
- opts.on("-h", "--help", "Show this help message") do
32
+
33
+ opts.on('-q', '--quiet', '--silence', 'Disable verbose output') do
34
+ options[:verbose] = false
35
+ end
36
+
37
+ opts.on('--no-parallel', 'Disable parallel loading (use for debugging or reduced memory usage)') do
38
+ options[:parallel_loading] = false
39
+ end
40
+
41
+ opts.on('-h', '--help', 'Show this help message') do
32
42
  puts opts
33
43
  exit
34
44
  end
35
45
  end.parse!
36
46
 
37
- puts "=== UrlCategorise Hosts Export ===" if options[:verbose]
38
- puts "Initializing client..." if options[:verbose]
47
+ puts '=== UrlCategorise Hosts Export ===' if options[:verbose]
48
+ puts 'Initializing client...' if options[:verbose]
39
49
 
40
50
  begin
41
51
  client = UrlCategorise::Client.new(
42
- cache_dir: options[:cache_dir]
52
+ cache_dir: options[:cache_dir],
53
+ parallel_loading: options[:parallel_loading]
43
54
  )
44
-
45
- puts "Exporting hosts files..." if options[:verbose]
46
-
55
+
56
+ puts 'Exporting hosts files...' if options[:verbose]
57
+
47
58
  result = client.export_hosts_files(options[:output_path])
48
-
59
+
49
60
  summary = result.delete(:_summary)
50
-
61
+
51
62
  puts "\nāœ… Export completed successfully!"
52
63
  puts "šŸ“ Export directory: #{summary[:export_directory]}"
53
64
  puts "šŸ“Š Total categories exported: #{summary[:total_categories]}"
54
65
  puts "🌐 Total domains exported: #{summary[:total_domains]}"
55
66
  puts "šŸ“„ Summary file: #{summary[:path]}"
56
-
67
+
57
68
  if options[:verbose]
58
69
  puts "\nšŸ“‹ Files created:"
59
- result.each do |category, info|
70
+ result.each do |_category, info|
60
71
  puts " #{info[:filename]} - #{info[:count]} domains"
61
72
  end
62
73
  end
63
-
64
74
  rescue StandardError => e
65
75
  puts "āŒ Error: #{e.message}"
66
76
  puts e.backtrace if options[:verbose]
67
77
  exit 1
68
- end
78
+ end