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.
- checksums.yaml +4 -4
- data/.claude/settings.local.json +9 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +56 -0
- data/.sublime-project +14 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +89 -41
- data/README.md +167 -9
- data/Rakefile +1 -1
- data/bin/check_lists +124 -22
- data/bin/export_csv +45 -36
- data/bin/export_hosts +34 -24
- data/bin/generate_categorised_lists +533 -0
- data/bin/generate_social_media_lists +398 -0
- data/bin/generate_video_lists +303 -124
- data/bin/generate_video_lists_focused +381 -0
- data/correct_usage_example.rb +18 -18
- data/lib/url_categorise/active_record_client.rb +11 -11
- data/lib/url_categorise/client.rb +856 -226
- data/lib/url_categorise/constants.rb +148 -70
- data/lib/url_categorise/dataset_processor.rb +68 -64
- data/lib/url_categorise/iab_compliance.rb +111 -99
- data/lib/url_categorise/models.rb +15 -15
- data/lib/url_categorise/version.rb +1 -1
- data/lib/url_categorise.rb +14 -14
- data/lists/blogging_domains.hosts +62 -0
- data/lists/crypto_domains.hosts +46 -0
- data/lists/developer_domains.hosts +108 -0
- data/lists/forum_domains.hosts +65 -0
- data/lists/gaming_domains.hosts +99 -0
- data/lists/messaging_domains.hosts +96 -0
- data/lists/music_domains.hosts +62 -0
- data/lists/security_domains.hosts +48 -0
- data/lists/social_media_domains.hosts +443 -0
- data/lists/streaming_domains.hosts +41 -0
- data/lists/video_hosting_domains.hosts +203 -175
- data/lists/video_url_patterns.txt +15 -15
- data/url_categorise.gemspec +11 -9
- metadata +69 -20
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.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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:
|
|
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
|
|
21
|
-
opts.separator
|
|
22
|
-
|
|
23
|
-
opts.on(
|
|
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(
|
|
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(
|
|
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(
|
|
35
|
+
|
|
36
|
+
opts.on('--smart-categorization', 'Enable smart categorization') do
|
|
36
37
|
options[:smart_categorization] = true
|
|
37
38
|
end
|
|
38
|
-
|
|
39
|
-
opts.on(
|
|
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(
|
|
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(
|
|
47
|
+
|
|
48
|
+
opts.on('-v', '--verbose', 'Force verbose output (default behavior)') do
|
|
48
49
|
options[:verbose] = true
|
|
49
50
|
end
|
|
50
|
-
|
|
51
|
-
opts.on(
|
|
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
|
|
58
|
-
puts
|
|
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
|
|
87
|
-
puts
|
|
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
|
|
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:
|
|
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
|
|
17
|
-
opts.separator
|
|
18
|
-
|
|
19
|
-
opts.on(
|
|
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(
|
|
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(
|
|
28
|
+
|
|
29
|
+
opts.on('-v', '--verbose', 'Force verbose output (default behavior)') do
|
|
28
30
|
options[:verbose] = true
|
|
29
31
|
end
|
|
30
|
-
|
|
31
|
-
opts.on(
|
|
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
|
|
38
|
-
puts
|
|
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
|
|
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 |
|
|
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
|