UrlCategorise 0.1.9 → 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/Gemfile.lock +31 -32
- data/bin/generate_video_lists_focused +381 -0
- data/lib/url_categorise/client.rb +17 -5
- data/lib/url_categorise/dataset_processor.rb +7 -1
- data/lib/url_categorise/version.rb +1 -1
- data/lists/blogging_domains.hosts +1 -1
- data/lists/crypto_domains.hosts +1 -1
- data/lists/developer_domains.hosts +1 -1
- data/lists/forum_domains.hosts +1 -1
- data/lists/gaming_domains.hosts +1 -1
- data/lists/messaging_domains.hosts +1 -1
- data/lists/music_domains.hosts +1 -1
- data/lists/security_domains.hosts +1 -1
- data/lists/social_media_domains.hosts +1 -1
- data/lists/streaming_domains.hosts +1 -1
- data/lists/video_hosting_domains.hosts +15 -9
- data/lists/video_url_patterns.txt +10 -10
- data/url_categorise.gemspec +2 -2
- metadata +8 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6ed2176041a871f6fae72dc1b7c1f266910f6233879e1359d02eead164f8f6ff
|
|
4
|
+
data.tar.gz: 5ff46c4dd9faaa22218a86d7b40f54bedaa6f91e9914b8e9671b14ba55ec6495
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 71aa116bb3de0c269ccaf18a3f159f78c722ab010589a2118c411f826f1ff4de48b9e5ed8c9936a67a6eac3cb17b3f52d71e41bac552e73a91c67edee804f9c4
|
|
7
|
+
data.tar.gz: 4c2d8f50a9cad1b1f32c56ddc51b44e8ca28f49af5718970bb0bea02a12e934cb2c8075589fa9ca8db56437e3a377a5e0cc1afe7a30e44aab5b393cb94a70f3a
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
UrlCategorise (0.1.
|
|
4
|
+
UrlCategorise (0.1.10)
|
|
5
5
|
active_attr (>= 0.17.1, < 1.0)
|
|
6
6
|
api_pattern (>= 0.0.6, < 1.0)
|
|
7
7
|
csv (>= 3.3.0, < 4.0)
|
|
@@ -18,9 +18,9 @@ PATH
|
|
|
18
18
|
GEM
|
|
19
19
|
remote: https://rubygems.org/
|
|
20
20
|
specs:
|
|
21
|
-
actionpack (8.
|
|
22
|
-
actionview (= 8.
|
|
23
|
-
activesupport (= 8.
|
|
21
|
+
actionpack (8.1.3)
|
|
22
|
+
actionview (= 8.1.3)
|
|
23
|
+
activesupport (= 8.1.3)
|
|
24
24
|
nokogiri (>= 1.8.5)
|
|
25
25
|
rack (>= 2.2.4)
|
|
26
26
|
rack-session (>= 1.0.1)
|
|
@@ -28,37 +28,37 @@ GEM
|
|
|
28
28
|
rails-dom-testing (~> 2.2)
|
|
29
29
|
rails-html-sanitizer (~> 1.6)
|
|
30
30
|
useragent (~> 0.16)
|
|
31
|
-
actionview (8.
|
|
32
|
-
activesupport (= 8.
|
|
31
|
+
actionview (8.1.3)
|
|
32
|
+
activesupport (= 8.1.3)
|
|
33
33
|
builder (~> 3.1)
|
|
34
34
|
erubi (~> 1.11)
|
|
35
35
|
rails-dom-testing (~> 2.2)
|
|
36
36
|
rails-html-sanitizer (~> 1.6)
|
|
37
|
-
active_attr (0.17.
|
|
38
|
-
actionpack (>= 3.0.2, < 8.
|
|
39
|
-
activemodel (>= 3.0.2, < 8.
|
|
40
|
-
activesupport (>= 3.0.2, < 8.
|
|
41
|
-
activemodel (8.
|
|
42
|
-
activesupport (= 8.
|
|
43
|
-
activerecord (8.
|
|
44
|
-
activemodel (= 8.
|
|
45
|
-
activesupport (= 8.
|
|
37
|
+
active_attr (0.17.2)
|
|
38
|
+
actionpack (>= 3.0.2, < 8.2)
|
|
39
|
+
activemodel (>= 3.0.2, < 8.2)
|
|
40
|
+
activesupport (>= 3.0.2, < 8.2)
|
|
41
|
+
activemodel (8.1.3)
|
|
42
|
+
activesupport (= 8.1.3)
|
|
43
|
+
activerecord (8.1.3)
|
|
44
|
+
activemodel (= 8.1.3)
|
|
45
|
+
activesupport (= 8.1.3)
|
|
46
46
|
timeout (>= 0.4.0)
|
|
47
|
-
activesupport (8.
|
|
47
|
+
activesupport (8.1.3)
|
|
48
48
|
base64
|
|
49
|
-
benchmark (>= 0.3)
|
|
50
49
|
bigdecimal
|
|
51
50
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
52
51
|
connection_pool (>= 2.2.5)
|
|
53
52
|
drb
|
|
54
53
|
i18n (>= 1.6, < 2)
|
|
54
|
+
json
|
|
55
55
|
logger (>= 1.4.2)
|
|
56
56
|
minitest (>= 5.1)
|
|
57
57
|
securerandom (>= 0.3)
|
|
58
58
|
tzinfo (~> 2.0, >= 2.0.5)
|
|
59
59
|
uri (>= 0.13.1)
|
|
60
|
-
addressable (2.
|
|
61
|
-
public_suffix (>= 2.0.2, <
|
|
60
|
+
addressable (2.9.0)
|
|
61
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
62
62
|
ansi (1.5.0)
|
|
63
63
|
api_pattern (0.0.6)
|
|
64
64
|
active_attr (>= 0.15.4)
|
|
@@ -67,15 +67,14 @@ GEM
|
|
|
67
67
|
nokogiri (>= 1.16.0)
|
|
68
68
|
ast (2.4.3)
|
|
69
69
|
base64 (0.3.0)
|
|
70
|
-
|
|
71
|
-
bigdecimal (4.1.0)
|
|
70
|
+
bigdecimal (4.1.2)
|
|
72
71
|
builder (3.3.0)
|
|
73
72
|
bundler-audit (0.9.3)
|
|
74
73
|
bundler (>= 1.2.0)
|
|
75
74
|
thor (~> 1.0)
|
|
76
75
|
coderay (1.1.3)
|
|
77
|
-
concurrent-ruby (1.3.
|
|
78
|
-
connection_pool (
|
|
76
|
+
concurrent-ruby (1.3.6)
|
|
77
|
+
connection_pool (3.0.2)
|
|
79
78
|
crack (1.0.0)
|
|
80
79
|
bigdecimal
|
|
81
80
|
rexml
|
|
@@ -91,10 +90,10 @@ GEM
|
|
|
91
90
|
csv
|
|
92
91
|
mini_mime (>= 1.0.0)
|
|
93
92
|
multi_xml (>= 0.5.2)
|
|
94
|
-
i18n (1.14.
|
|
93
|
+
i18n (1.14.8)
|
|
95
94
|
concurrent-ruby (~> 1.0)
|
|
96
95
|
io-console (0.8.1)
|
|
97
|
-
json (2.
|
|
96
|
+
json (2.19.5)
|
|
98
97
|
kaggle (0.0.3)
|
|
99
98
|
csv (>= 3.3)
|
|
100
99
|
fileutils (>= 1.7)
|
|
@@ -104,7 +103,7 @@ GEM
|
|
|
104
103
|
language_server-protocol (3.17.0.5)
|
|
105
104
|
lint_roller (1.1.0)
|
|
106
105
|
logger (1.7.0)
|
|
107
|
-
loofah (2.
|
|
106
|
+
loofah (2.25.1)
|
|
108
107
|
crass (~> 1.0.2)
|
|
109
108
|
nokogiri (>= 1.12.0)
|
|
110
109
|
method_source (1.1.0)
|
|
@@ -121,7 +120,7 @@ GEM
|
|
|
121
120
|
ruby2_keywords (>= 0.0.5)
|
|
122
121
|
multi_xml (0.8.1)
|
|
123
122
|
bigdecimal (>= 3.1, < 5)
|
|
124
|
-
nokogiri (1.19.
|
|
123
|
+
nokogiri (1.19.3-arm64-darwin)
|
|
125
124
|
racc (~> 1.4)
|
|
126
125
|
oj (3.16.11)
|
|
127
126
|
bigdecimal (>= 3.0)
|
|
@@ -135,10 +134,10 @@ GEM
|
|
|
135
134
|
pry (0.15.2)
|
|
136
135
|
coderay (~> 1.1)
|
|
137
136
|
method_source (~> 1.0)
|
|
138
|
-
public_suffix (
|
|
137
|
+
public_suffix (7.0.5)
|
|
139
138
|
racc (1.8.1)
|
|
140
|
-
rack (3.2.
|
|
141
|
-
rack-session (2.1.
|
|
139
|
+
rack (3.2.6)
|
|
140
|
+
rack-session (2.1.2)
|
|
142
141
|
base64 (>= 0.1.0)
|
|
143
142
|
rack (>= 3.0.0)
|
|
144
143
|
rack-test (2.2.0)
|
|
@@ -147,8 +146,8 @@ GEM
|
|
|
147
146
|
activesupport (>= 5.0.0)
|
|
148
147
|
minitest
|
|
149
148
|
nokogiri (>= 1.6)
|
|
150
|
-
rails-html-sanitizer (1.
|
|
151
|
-
loofah (~> 2.
|
|
149
|
+
rails-html-sanitizer (1.7.0)
|
|
150
|
+
loofah (~> 2.25)
|
|
152
151
|
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
|
153
152
|
rainbow (3.1.1)
|
|
154
153
|
rake (13.3.0)
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'net/http'
|
|
5
|
+
require 'uri'
|
|
6
|
+
require 'json'
|
|
7
|
+
require 'fileutils'
|
|
8
|
+
require 'time'
|
|
9
|
+
require 'set'
|
|
10
|
+
|
|
11
|
+
module VideoListGenerator
|
|
12
|
+
class FocusedExtractorParser
|
|
13
|
+
# Focus on the most popular video hosting platforms first
|
|
14
|
+
PRIORITY_EXTRACTORS = [
|
|
15
|
+
'youtube.py',
|
|
16
|
+
'vimeo.py',
|
|
17
|
+
'dailymotion.py',
|
|
18
|
+
'twitch.py',
|
|
19
|
+
'tiktok.py',
|
|
20
|
+
'instagram.py',
|
|
21
|
+
'facebook.py',
|
|
22
|
+
'twitter.py',
|
|
23
|
+
'reddit.py',
|
|
24
|
+
'streamable.py',
|
|
25
|
+
'wistia.py',
|
|
26
|
+
'brightcove.py',
|
|
27
|
+
'jwplatform.py',
|
|
28
|
+
'kaltura.py',
|
|
29
|
+
'vidyard.py',
|
|
30
|
+
'vzaar.py',
|
|
31
|
+
'soundcloud.py',
|
|
32
|
+
'mixcloud.py',
|
|
33
|
+
'bandcamp.py',
|
|
34
|
+
'peertube.py',
|
|
35
|
+
'rumble.py',
|
|
36
|
+
'odysee.py',
|
|
37
|
+
'bitchute.py'
|
|
38
|
+
].freeze
|
|
39
|
+
|
|
40
|
+
YT_DLP_API_URL = 'https://api.github.com/repos/yt-dlp/yt-dlp/contents/yt_dlp/extractor'
|
|
41
|
+
|
|
42
|
+
def initialize
|
|
43
|
+
@video_domains = Set.new
|
|
44
|
+
@video_regexes = []
|
|
45
|
+
@manual_domains = get_manual_video_domains
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def generate_lists
|
|
49
|
+
puts "🎬 Generating focused video hosting lists..."
|
|
50
|
+
|
|
51
|
+
puts "📝 Adding manually curated video hosting domains..."
|
|
52
|
+
@manual_domains.each { |domain| @video_domains.add(domain) }
|
|
53
|
+
|
|
54
|
+
puts "📡 Fetching priority yt-dlp extractors..."
|
|
55
|
+
fetch_priority_extractors
|
|
56
|
+
|
|
57
|
+
create_lists_directory
|
|
58
|
+
generate_hosts_file
|
|
59
|
+
generate_regex_file
|
|
60
|
+
|
|
61
|
+
puts "✅ Video hosting lists generated successfully!"
|
|
62
|
+
puts "📁 Files created in lists/ directory:"
|
|
63
|
+
puts " - video_hosting_domains.hosts (PiHole compatible)"
|
|
64
|
+
puts " - video_url_patterns.txt (Regex patterns for video detection)"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def get_manual_video_domains
|
|
70
|
+
# Manually curated list of major video hosting domains
|
|
71
|
+
[
|
|
72
|
+
'youtube.com', 'youtu.be', 'youtube-nocookie.com',
|
|
73
|
+
'vimeo.com', 'player.vimeo.com',
|
|
74
|
+
'dailymotion.com', 'dai.ly',
|
|
75
|
+
'twitch.tv', 'clips.twitch.tv',
|
|
76
|
+
'tiktok.com', 'vm.tiktok.com',
|
|
77
|
+
'instagram.com', 'instagr.am',
|
|
78
|
+
'facebook.com', 'fb.com', 'fb.watch',
|
|
79
|
+
'twitter.com', 'x.com', 't.co',
|
|
80
|
+
'reddit.com', 'redd.it', 'v.redd.it',
|
|
81
|
+
'streamable.com',
|
|
82
|
+
'wistia.com', 'fast.wistia.com', 'fast.wistia.net',
|
|
83
|
+
'brightcove.com', 'bcove.video',
|
|
84
|
+
'jwplatform.com', 'jwpcdn.com',
|
|
85
|
+
'kaltura.com',
|
|
86
|
+
'vidyard.com',
|
|
87
|
+
'vzaar.com',
|
|
88
|
+
'soundcloud.com', 'snd.sc',
|
|
89
|
+
'mixcloud.com',
|
|
90
|
+
'bandcamp.com',
|
|
91
|
+
'rumble.com',
|
|
92
|
+
'odysee.com', 'lbry.tv',
|
|
93
|
+
'bitchute.com',
|
|
94
|
+
'peertube.tv',
|
|
95
|
+
'archive.org',
|
|
96
|
+
'vevo.com',
|
|
97
|
+
'liveleak.com',
|
|
98
|
+
'metacafe.com',
|
|
99
|
+
'veoh.com',
|
|
100
|
+
'break.com',
|
|
101
|
+
'crunchyroll.com',
|
|
102
|
+
'funimation.com',
|
|
103
|
+
'vrv.co',
|
|
104
|
+
'roosterteeth.com',
|
|
105
|
+
'newgrounds.com',
|
|
106
|
+
'coub.com',
|
|
107
|
+
'vidme.com',
|
|
108
|
+
'vid.me',
|
|
109
|
+
'gfycat.com',
|
|
110
|
+
'imgur.com',
|
|
111
|
+
'giphy.com',
|
|
112
|
+
'tenor.com'
|
|
113
|
+
]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def fetch_priority_extractors
|
|
117
|
+
uri = URI(YT_DLP_API_URL)
|
|
118
|
+
response = Net::HTTP.get_response(uri)
|
|
119
|
+
|
|
120
|
+
unless response.code == '200'
|
|
121
|
+
puts "⚠️ Failed to fetch extractor list from GitHub API, using manual domains only"
|
|
122
|
+
return
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
files = JSON.parse(response.body)
|
|
126
|
+
|
|
127
|
+
# Filter to priority extractor files
|
|
128
|
+
priority_files = files.select { |file| PRIORITY_EXTRACTORS.include?(file['name']) }
|
|
129
|
+
|
|
130
|
+
puts "📝 Processing #{priority_files.length} priority extractor files..."
|
|
131
|
+
|
|
132
|
+
priority_files.each_with_index do |file, index|
|
|
133
|
+
puts "Processing #{index + 1}/#{priority_files.length}: #{file['name']}"
|
|
134
|
+
process_extractor_file(file)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
puts "🎯 Found #{@video_domains.size} unique video hosting domains"
|
|
138
|
+
puts "🔍 Extracted #{@video_regexes.size} URL pattern regexes"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def process_extractor_file(file_info)
|
|
142
|
+
begin
|
|
143
|
+
response = Net::HTTP.get_response(URI(file_info['download_url']))
|
|
144
|
+
return unless response.code == '200'
|
|
145
|
+
|
|
146
|
+
content = response.body
|
|
147
|
+
|
|
148
|
+
extract_domains_from_content(content, file_info['name'])
|
|
149
|
+
extract_regexes_from_content(content, file_info['name'])
|
|
150
|
+
rescue StandardError => e
|
|
151
|
+
puts "⚠️ Error processing #{file_info['name']}: #{e.message}"
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def extract_domains_from_content(content, filename)
|
|
156
|
+
# Look for _VALID_URL patterns
|
|
157
|
+
valid_url_patterns = content.scan(/_VALID_URL\s*=\s*r?['"]([^'"]+)['"]/m)
|
|
158
|
+
|
|
159
|
+
valid_url_patterns.each do |pattern|
|
|
160
|
+
pattern = pattern[0] if pattern.is_a?(Array)
|
|
161
|
+
|
|
162
|
+
domains = extract_domains_from_regex(pattern)
|
|
163
|
+
domains.each { |domain| @video_domains.add(domain) }
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Also look for explicit domain lists or IE_NAME patterns
|
|
167
|
+
ie_name_patterns = content.scan(/IE_NAME\s*=\s*['"]([^'"]+)['"]/m)
|
|
168
|
+
ie_name_patterns.each do |name|
|
|
169
|
+
name = name[0] if name.is_a?(Array)
|
|
170
|
+
next unless name
|
|
171
|
+
|
|
172
|
+
# Many IE_NAME values correspond to domain names
|
|
173
|
+
if name.include?('.') && valid_domain?(name)
|
|
174
|
+
@video_domains.add(name.downcase)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def extract_regexes_from_content(content, filename)
|
|
180
|
+
# Extract _VALID_URL patterns for video detection
|
|
181
|
+
valid_url_patterns = content.scan(/_VALID_URL\s*=\s*r?['"]([^'"]+)['"]/m)
|
|
182
|
+
|
|
183
|
+
valid_url_patterns.each do |pattern|
|
|
184
|
+
pattern = pattern[0] if pattern.is_a?(Array)
|
|
185
|
+
|
|
186
|
+
cleaned_pattern = clean_regex_pattern(pattern)
|
|
187
|
+
if cleaned_pattern && !cleaned_pattern.empty?
|
|
188
|
+
@video_regexes << {
|
|
189
|
+
source: filename.gsub('.py', ''),
|
|
190
|
+
pattern: cleaned_pattern,
|
|
191
|
+
original: pattern,
|
|
192
|
+
description: generate_pattern_description(pattern, filename)
|
|
193
|
+
}
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def extract_domains_from_regex(pattern)
|
|
199
|
+
domains = Set.new
|
|
200
|
+
|
|
201
|
+
# Various patterns to extract domains from regex
|
|
202
|
+
# Pattern: https?://(?:www\.)?domain\.com
|
|
203
|
+
domain_matches = pattern.scan(/https?:\/\/[^\/]*?([a-zA-Z0-9-]+\.[a-zA-Z]{2,})/i)
|
|
204
|
+
domain_matches.each do |match|
|
|
205
|
+
domain = match[0] if match.is_a?(Array)
|
|
206
|
+
domain = clean_domain(domain) if domain
|
|
207
|
+
domains.add(domain.downcase) if domain && valid_domain?(domain)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Pattern: (?:www\.)?domain\.com
|
|
211
|
+
simple_matches = pattern.scan(/(?:\(\?\:www\\\.\)\?)?([a-zA-Z0-9-]+\.[a-zA-Z]{2,})/i)
|
|
212
|
+
simple_matches.each do |match|
|
|
213
|
+
domain = match[0] if match.is_a?(Array)
|
|
214
|
+
domain = clean_domain(domain) if domain
|
|
215
|
+
domains.add(domain.downcase) if domain && valid_domain?(domain)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
domains.to_a
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def clean_domain(domain)
|
|
222
|
+
return nil unless domain
|
|
223
|
+
|
|
224
|
+
# Remove common regex escapes
|
|
225
|
+
cleaned = domain.gsub(/\\\./, '.').gsub(/[\(\)\?\:\|\\]/, '')
|
|
226
|
+
cleaned = cleaned.strip
|
|
227
|
+
|
|
228
|
+
# Remove any trailing regex syntax
|
|
229
|
+
cleaned = cleaned.split(/[\(\)\[\]]/)[0] if cleaned.include?('(') || cleaned.include?('[')
|
|
230
|
+
|
|
231
|
+
cleaned
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def clean_regex_pattern(pattern)
|
|
235
|
+
return nil unless pattern
|
|
236
|
+
|
|
237
|
+
# Simplify common patterns for practical use
|
|
238
|
+
cleaned = pattern.dup
|
|
239
|
+
|
|
240
|
+
# Remove complex lookaheads/lookbehinds
|
|
241
|
+
cleaned = cleaned.gsub(/\(\?\![^)]*\)/, '')
|
|
242
|
+
cleaned = cleaned.gsub(/\(\?\<\![^)]*\)/, '')
|
|
243
|
+
|
|
244
|
+
# Simplify common patterns
|
|
245
|
+
cleaned = cleaned.gsub(/\(\?\:www\\\.\)\?/, '(?:www\.)?')
|
|
246
|
+
cleaned = cleaned.gsub(/\\\./, '\.')
|
|
247
|
+
|
|
248
|
+
# Validate that it's a reasonable regex
|
|
249
|
+
begin
|
|
250
|
+
Regexp.new(cleaned)
|
|
251
|
+
cleaned
|
|
252
|
+
rescue RegexpError
|
|
253
|
+
# Return a simplified version if the complex regex fails
|
|
254
|
+
extract_simple_pattern(pattern)
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def extract_simple_pattern(pattern)
|
|
259
|
+
# Extract a simple domain pattern from complex regex
|
|
260
|
+
if pattern.include?('https?://')
|
|
261
|
+
# Extract the basic domain part
|
|
262
|
+
match = pattern.match(/https?:\/\/[^\/]*?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/i)
|
|
263
|
+
if match
|
|
264
|
+
return "https?://[^/]*#{Regexp.escape(match[1])}"
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
nil
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def generate_pattern_description(pattern, filename)
|
|
272
|
+
service = filename.gsub('.py', '').capitalize
|
|
273
|
+
|
|
274
|
+
case filename
|
|
275
|
+
when 'youtube.py'
|
|
276
|
+
'YouTube video, playlist, and channel URLs'
|
|
277
|
+
when 'vimeo.py'
|
|
278
|
+
'Vimeo video and album URLs'
|
|
279
|
+
when 'twitch.py'
|
|
280
|
+
'Twitch streams, clips, and VODs'
|
|
281
|
+
when 'tiktok.py'
|
|
282
|
+
'TikTok video URLs'
|
|
283
|
+
else
|
|
284
|
+
"#{service} video content URLs"
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def valid_domain?(domain)
|
|
289
|
+
return false unless domain
|
|
290
|
+
return false if domain.length < 4
|
|
291
|
+
return false unless domain.match?(/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)
|
|
292
|
+
return false if domain.include?('example.') || domain.include?('test.')
|
|
293
|
+
return false if domain.include?('localhost')
|
|
294
|
+
true
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def create_lists_directory
|
|
298
|
+
FileUtils.mkdir_p('lists')
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def generate_hosts_file
|
|
302
|
+
hosts_file_path = 'lists/video_hosting_domains.hosts'
|
|
303
|
+
|
|
304
|
+
File.open(hosts_file_path, 'w') do |file|
|
|
305
|
+
write_hosts_header(file)
|
|
306
|
+
|
|
307
|
+
@video_domains.sort.each do |domain|
|
|
308
|
+
file.puts "0.0.0.0 #{domain}"
|
|
309
|
+
file.puts "0.0.0.0 www.#{domain}" unless domain.start_with?('www.')
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
puts "📝 Generated hosts file: #{hosts_file_path} (#{@video_domains.size} domains)"
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def generate_regex_file
|
|
317
|
+
regex_file_path = 'lists/video_url_patterns.txt'
|
|
318
|
+
|
|
319
|
+
File.open(regex_file_path, 'w') do |file|
|
|
320
|
+
write_regex_header(file)
|
|
321
|
+
|
|
322
|
+
@video_regexes.each do |regex_info|
|
|
323
|
+
file.puts "# Source: #{regex_info[:source]}"
|
|
324
|
+
file.puts "# Description: #{regex_info[:description]}"
|
|
325
|
+
file.puts "# Pattern: #{regex_info[:pattern]}"
|
|
326
|
+
file.puts "# Original: #{regex_info[:original]}"
|
|
327
|
+
file.puts regex_info[:pattern]
|
|
328
|
+
file.puts ""
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
puts "📝 Generated regex file: #{regex_file_path} (#{@video_regexes.size} patterns)"
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def write_hosts_header(file)
|
|
336
|
+
file.puts "# Video Hosting Domains - PiHole Compatible Hosts File"
|
|
337
|
+
file.puts "# Generated on: #{Time.now.strftime('%Y-%m-%d %H:%M:%S UTC')}"
|
|
338
|
+
file.puts "# Source: yt-dlp extractors + manual curation"
|
|
339
|
+
file.puts "# Purpose: Block or categorize video hosting websites"
|
|
340
|
+
file.puts "# Format: 0.0.0.0 domain.com"
|
|
341
|
+
file.puts "#"
|
|
342
|
+
file.puts "# This file contains domains from popular video hosting platforms"
|
|
343
|
+
file.puts "# extracted from yt-dlp video extractors and manually curated lists."
|
|
344
|
+
file.puts "# Use this for URL categorization or content filtering."
|
|
345
|
+
file.puts "#"
|
|
346
|
+
file.puts "# Generated by UrlCategorise gem: https://github.com/trex22/url_categorise"
|
|
347
|
+
file.puts "#"
|
|
348
|
+
file.puts ""
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def write_regex_header(file)
|
|
352
|
+
file.puts "# Video URL Detection Patterns"
|
|
353
|
+
file.puts "# Generated on: #{Time.now.strftime('%Y-%m-%d %H:%M:%S UTC')}"
|
|
354
|
+
file.puts "# Source: yt-dlp extractors + manual curation"
|
|
355
|
+
file.puts "# Purpose: Regex patterns to detect video URLs vs other content"
|
|
356
|
+
file.puts "#"
|
|
357
|
+
file.puts "# These patterns help distinguish between:"
|
|
358
|
+
file.puts "# - Direct video content URLs (matches these patterns)"
|
|
359
|
+
file.puts "# - Homepage, playlist, user profile, community content URLs"
|
|
360
|
+
file.puts "#"
|
|
361
|
+
file.puts "# Usage: Use these patterns to categorize URLs from video hosting domains"
|
|
362
|
+
file.puts "# to determine if they contain actual video content or other resources"
|
|
363
|
+
file.puts "#"
|
|
364
|
+
file.puts "# Each pattern includes:"
|
|
365
|
+
file.puts "# - Source extractor name"
|
|
366
|
+
file.puts "# - Human-readable description"
|
|
367
|
+
file.puts "# - Simplified regex pattern"
|
|
368
|
+
file.puts "# - Original complex pattern (for reference)"
|
|
369
|
+
file.puts "#"
|
|
370
|
+
file.puts "# Generated by UrlCategorise gem: https://github.com/trex22/url_categorise"
|
|
371
|
+
file.puts "#"
|
|
372
|
+
file.puts ""
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Run the generator if this file is executed directly
|
|
378
|
+
if __FILE__ == $0
|
|
379
|
+
generator = VideoListGenerator::FocusedExtractorParser.new
|
|
380
|
+
generator.generate_lists
|
|
381
|
+
end
|
|
@@ -101,10 +101,16 @@ module UrlCategorise
|
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
def categorise(url)
|
|
104
|
+
return [] if url.nil? || (url.respond_to?(:strip) && url.strip.empty?)
|
|
105
|
+
|
|
104
106
|
debug_time("Categorizing '#{url}'") do
|
|
105
107
|
debug_log("🔍 Starting categorization for URL: #{url}")
|
|
106
108
|
|
|
107
|
-
host =
|
|
109
|
+
host = begin
|
|
110
|
+
(URI.parse(url).host || url).downcase
|
|
111
|
+
rescue URI::InvalidURIError
|
|
112
|
+
url.to_s.downcase
|
|
113
|
+
end
|
|
108
114
|
host = host.gsub("www.", "")
|
|
109
115
|
debug_log("📌 Extracted host: #{host}")
|
|
110
116
|
|
|
@@ -1318,7 +1324,7 @@ module UrlCategorise
|
|
|
1318
1324
|
# Phase 2: Process content in parallel using Ractors (if available) or threads
|
|
1319
1325
|
debug_log("⚡ Phase 2: Processing content in parallel")
|
|
1320
1326
|
|
|
1321
|
-
if self.class.ractor_available?
|
|
1327
|
+
if self.class.ractor_available? && !test_environment?
|
|
1322
1328
|
process_content_with_ractors(downloaded_content)
|
|
1323
1329
|
else
|
|
1324
1330
|
process_content_with_threads(downloaded_content)
|
|
@@ -1332,9 +1338,10 @@ module UrlCategorise
|
|
|
1332
1338
|
original_verbose = $VERBOSE
|
|
1333
1339
|
$VERBOSE = nil
|
|
1334
1340
|
work_queue = Ractor.new do
|
|
1341
|
+
# :nocov:
|
|
1335
1342
|
tasks = []
|
|
1336
1343
|
no_more_tasks = false
|
|
1337
|
-
|
|
1344
|
+
|
|
1338
1345
|
while (task = Ractor.receive) != :done
|
|
1339
1346
|
if task == :get_task
|
|
1340
1347
|
if tasks.empty? && no_more_tasks
|
|
@@ -1348,6 +1355,7 @@ module UrlCategorise
|
|
|
1348
1355
|
tasks << task
|
|
1349
1356
|
end
|
|
1350
1357
|
end
|
|
1358
|
+
# :nocov:
|
|
1351
1359
|
end
|
|
1352
1360
|
|
|
1353
1361
|
# Add all tasks to queue
|
|
@@ -1364,6 +1372,7 @@ module UrlCategorise
|
|
|
1364
1372
|
|
|
1365
1373
|
workers = num_workers.times.map do
|
|
1366
1374
|
Ractor.new(work_queue, cache_dir) do |queue, cache_path|
|
|
1375
|
+
# :nocov:
|
|
1367
1376
|
require "digest"
|
|
1368
1377
|
require "fileutils"
|
|
1369
1378
|
|
|
@@ -1433,6 +1442,7 @@ module UrlCategorise
|
|
|
1433
1442
|
end
|
|
1434
1443
|
|
|
1435
1444
|
results
|
|
1445
|
+
# :nocov:
|
|
1436
1446
|
end
|
|
1437
1447
|
end
|
|
1438
1448
|
|
|
@@ -1585,9 +1595,11 @@ module UrlCategorise
|
|
|
1585
1595
|
end
|
|
1586
1596
|
|
|
1587
1597
|
def extract_host(url)
|
|
1598
|
+
return nil if url.nil? || (url.respond_to?(:strip) && url.strip.empty?)
|
|
1599
|
+
|
|
1588
1600
|
(URI.parse(url).host || url).downcase.gsub("www.", "")
|
|
1589
1601
|
rescue URI::InvalidURIError
|
|
1590
|
-
url.downcase.gsub("www.", "")
|
|
1602
|
+
url.to_s.downcase.gsub("www.", "")
|
|
1591
1603
|
end
|
|
1592
1604
|
|
|
1593
1605
|
def build_host_data(urls)
|
|
@@ -1803,7 +1815,7 @@ module UrlCategorise
|
|
|
1803
1815
|
return true if url.start_with?("file://")
|
|
1804
1816
|
|
|
1805
1817
|
uri = URI.parse(url)
|
|
1806
|
-
uri.is_a?(URI::HTTP) && !uri.host.nil?
|
|
1818
|
+
uri.is_a?(URI::HTTP) && !uri.host.nil? && !uri.host.empty?
|
|
1807
1819
|
rescue URI::InvalidURIError
|
|
1808
1820
|
false
|
|
1809
1821
|
end
|
|
@@ -262,10 +262,16 @@ module UrlCategorise
|
|
|
262
262
|
|
|
263
263
|
def extract_zip_file(zip_file_path, extract_to_dir)
|
|
264
264
|
FileUtils.mkdir_p(extract_to_dir)
|
|
265
|
+
base_dir = File.expand_path(extract_to_dir)
|
|
265
266
|
|
|
266
267
|
Zip::File.open(zip_file_path) do |zip_file|
|
|
267
268
|
zip_file.each do |entry|
|
|
268
|
-
extract_path = File.join(
|
|
269
|
+
extract_path = File.expand_path(File.join(base_dir, entry.name))
|
|
270
|
+
|
|
271
|
+
# Reject entries that would be written outside the extraction directory (zip-slip)
|
|
272
|
+
unless extract_path.start_with?("#{base_dir}#{File::SEPARATOR}")
|
|
273
|
+
raise Error, "Unsafe path in zip file: #{entry.name}"
|
|
274
|
+
end
|
|
269
275
|
|
|
270
276
|
if entry.directory?
|
|
271
277
|
FileUtils.mkdir_p(extract_path)
|
data/lists/crypto_domains.hosts
CHANGED
data/lists/forum_domains.hosts
CHANGED
data/lists/gaming_domains.hosts
CHANGED
data/lists/music_domains.hosts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Video Hosting Domains - PiHole Compatible Hosts File
|
|
2
|
-
# Generated on: 2026-
|
|
2
|
+
# Generated on: 2026-05-22 11:05:43 UTC
|
|
3
3
|
# Source: yt-dlp extractors (https://github.com/yt-dlp/yt-dlp)
|
|
4
4
|
# Purpose: Block access to video hosting websites
|
|
5
5
|
# Format: 0.0.0.0 domain.com
|
|
@@ -618,6 +618,8 @@
|
|
|
618
618
|
0.0.0.0 www.api.vkplay
|
|
619
619
|
0.0.0.0 api.vmh
|
|
620
620
|
0.0.0.0 www.api.vmh
|
|
621
|
+
0.0.0.0 api.watch
|
|
622
|
+
0.0.0.0 www.api.watch
|
|
621
623
|
0.0.0.0 api.whowatch
|
|
622
624
|
0.0.0.0 www.api.whowatch
|
|
623
625
|
0.0.0.0 api.zype
|
|
@@ -704,6 +706,8 @@
|
|
|
704
706
|
0.0.0.0 www.ardaudiothek.de
|
|
705
707
|
0.0.0.0 ardmediathek.de
|
|
706
708
|
0.0.0.0 www.ardmediathek.de
|
|
709
|
+
0.0.0.0 ardsounds.de
|
|
710
|
+
0.0.0.0 www.ardsounds.de
|
|
707
711
|
0.0.0.0 arhiiv.err
|
|
708
712
|
0.0.0.0 www.arhiiv.err
|
|
709
713
|
0.0.0.0 armed-f.akamaihd
|
|
@@ -1168,6 +1172,8 @@
|
|
|
1168
1172
|
0.0.0.0 www.capitaltv.cy
|
|
1169
1173
|
0.0.0.0 caracoltv.com
|
|
1170
1174
|
0.0.0.0 www.caracoltv.com
|
|
1175
|
+
0.0.0.0 cas.global
|
|
1176
|
+
0.0.0.0 www.cas.global
|
|
1171
1177
|
0.0.0.0 catalogue.pr
|
|
1172
1178
|
0.0.0.0 www.catalogue.pr
|
|
1173
1179
|
0.0.0.0 cbc.ca
|
|
@@ -1258,6 +1264,8 @@
|
|
|
1258
1264
|
0.0.0.0 www.cdn.syndication
|
|
1259
1265
|
0.0.0.0 cdn.teamcococdn
|
|
1260
1266
|
0.0.0.0 www.cdn.teamcococdn
|
|
1267
|
+
0.0.0.0 cdn.thechosen
|
|
1268
|
+
0.0.0.0 www.cdn.thechosen
|
|
1261
1269
|
0.0.0.0 cdn.vidyard
|
|
1262
1270
|
0.0.0.0 www.cdn.vidyard
|
|
1263
1271
|
0.0.0.0 cdn.viqeo
|
|
@@ -1304,8 +1312,6 @@
|
|
|
1304
1312
|
0.0.0.0 www.cgtn.com
|
|
1305
1313
|
0.0.0.0 ch.nicovideo
|
|
1306
1314
|
0.0.0.0 www.ch.nicovideo
|
|
1307
|
-
0.0.0.0 ch.sooplive
|
|
1308
|
-
0.0.0.0 www.ch.sooplive
|
|
1309
1315
|
0.0.0.0 channel.microcms
|
|
1310
1316
|
0.0.0.0 www.channel.microcms
|
|
1311
1317
|
0.0.0.0 channel4.com
|
|
@@ -2204,8 +2210,6 @@
|
|
|
2204
2210
|
0.0.0.0 www.feeds.cbsn
|
|
2205
2211
|
0.0.0.0 feeds.rasset
|
|
2206
2212
|
0.0.0.0 www.feeds.rasset
|
|
2207
|
-
0.0.0.0 feeds.video
|
|
2208
|
-
0.0.0.0 www.feeds.video
|
|
2209
2213
|
0.0.0.0 felixcosm.tumblr
|
|
2210
2214
|
0.0.0.0 www.felixcosm.tumblr
|
|
2211
2215
|
0.0.0.0 fem.com
|
|
@@ -3754,8 +3758,6 @@
|
|
|
3754
3758
|
0.0.0.0 www.music.amazon
|
|
3755
3759
|
0.0.0.0 music.apple
|
|
3756
3760
|
0.0.0.0 www.music.apple
|
|
3757
|
-
0.0.0.0 music.yandex
|
|
3758
|
-
0.0.0.0 www.music.yandex
|
|
3759
3761
|
0.0.0.0 music.youtube
|
|
3760
3762
|
0.0.0.0 www.music.youtube
|
|
3761
3763
|
0.0.0.0 musicdex.com
|
|
@@ -4730,6 +4732,8 @@
|
|
|
4730
4732
|
0.0.0.0 www.public-api.wordpress
|
|
4731
4733
|
0.0.0.0 public.api
|
|
4732
4734
|
0.0.0.0 www.public.api
|
|
4735
|
+
0.0.0.0 public.aurora
|
|
4736
|
+
0.0.0.0 www.public.aurora
|
|
4733
4737
|
0.0.0.0 puhutv.com
|
|
4734
4738
|
0.0.0.0 www.puhutv.com
|
|
4735
4739
|
0.0.0.0 puls4.com
|
|
@@ -5318,6 +5322,8 @@
|
|
|
5318
5322
|
0.0.0.0 www.solidarum.org
|
|
5319
5323
|
0.0.0.0 sonyliv.com
|
|
5320
5324
|
0.0.0.0 www.sonyliv.com
|
|
5325
|
+
0.0.0.0 sooplive.com
|
|
5326
|
+
0.0.0.0 www.sooplive.com
|
|
5321
5327
|
0.0.0.0 sound.orf
|
|
5322
5328
|
0.0.0.0 www.sound.orf
|
|
5323
5329
|
0.0.0.0 soundcloud.com
|
|
@@ -5776,6 +5782,8 @@
|
|
|
5776
5782
|
0.0.0.0 www.the-voice-of-germany.de
|
|
5777
5783
|
0.0.0.0 theater-complex.town
|
|
5778
5784
|
0.0.0.0 www.theater-complex.town
|
|
5785
|
+
0.0.0.0 thechosen.com
|
|
5786
|
+
0.0.0.0 www.thechosen.com
|
|
5779
5787
|
0.0.0.0 theepochtimes.com
|
|
5780
5788
|
0.0.0.0 www.theepochtimes.com
|
|
5781
5789
|
0.0.0.0 theguardian.com
|
|
@@ -7041,8 +7049,6 @@
|
|
|
7041
7049
|
0.0.0.0 www.yahoo.com
|
|
7042
7050
|
0.0.0.0 yandexdisk.com
|
|
7043
7051
|
0.0.0.0 www.yandexdisk.com
|
|
7044
|
-
0.0.0.0 yandexmusic.com
|
|
7045
|
-
0.0.0.0 www.yandexmusic.com
|
|
7046
7052
|
0.0.0.0 yinyue.kuwo
|
|
7047
7053
|
0.0.0.0 www.yinyue.kuwo
|
|
7048
7054
|
0.0.0.0 yoga.appsvcs
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Video URL Detection Patterns
|
|
2
|
-
# Generated on: 2026-
|
|
2
|
+
# Generated on: 2026-05-22 11:05:44 UTC
|
|
3
3
|
# Source: yt-dlp extractors (https://github.com/yt-dlp/yt-dlp) + manual patterns
|
|
4
4
|
# Purpose: Regex patterns to detect video URLs vs other content
|
|
5
5
|
#
|
|
@@ -190,26 +190,26 @@ https?://(?:www\.)?gronkh\.tv(?:/feed)?/?(?:#|$)
|
|
|
190
190
|
# Original: https?://(?:www\.)?gronkh\.tv/vods/streams/?(?:#|$)
|
|
191
191
|
https?://(?:www\.)?gronkh\.tv/vods/streams/?(?:#|$)
|
|
192
192
|
|
|
193
|
-
# Source: internetvideoarchive
|
|
194
|
-
# Pattern: https?://video\.internetvideoarchive\.net/(?:player|flash/players)/.*?\?.*?publishedid.*?
|
|
195
|
-
# Original: https?://video\.internetvideoarchive\.net/(?:player|flash/players)/.*?\?.*?publishedid.*?
|
|
196
|
-
https?://video\.internetvideoarchive\.net/(?:player|flash/players)/.*?\?.*?publishedid.*?
|
|
197
|
-
|
|
198
193
|
# Source: iqiyi
|
|
199
194
|
# Pattern: https?://(?:(?:[^.]+\.)?iqiyi\.com|www\.pps\.tv)/.+\.html
|
|
200
195
|
# Original: https?://(?:(?:[^.]+\.)?iqiyi\.com|www\.pps\.tv)/.+\.html
|
|
201
196
|
https?://(?:(?:[^.]+\.)?iqiyi\.com|www\.pps\.tv)/.+\.html
|
|
202
197
|
|
|
203
|
-
# Source:
|
|
204
|
-
# Pattern: https
|
|
205
|
-
# Original: https
|
|
206
|
-
https
|
|
198
|
+
# Source: internetvideoarchive
|
|
199
|
+
# Pattern: https?://video\.internetvideoarchive\.net/(?:player|flash/players)/.*?\?.*?publishedid.*?
|
|
200
|
+
# Original: https?://video\.internetvideoarchive\.net/(?:player|flash/players)/.*?\?.*?publishedid.*?
|
|
201
|
+
https?://video\.internetvideoarchive\.net/(?:player|flash/players)/.*?\?.*?publishedid.*?
|
|
207
202
|
|
|
208
203
|
# Source: japandiet
|
|
209
204
|
# Pattern: https?://www\.webtv\.sangiin\.go\.jp/webtv/index\.php
|
|
210
205
|
# Original: https?://www\.webtv\.sangiin\.go\.jp/webtv/index\.php
|
|
211
206
|
https?://www\.webtv\.sangiin\.go\.jp/webtv/index\.php
|
|
212
207
|
|
|
208
|
+
# Source: jeuxvideo
|
|
209
|
+
# Pattern: https?://.*?\.jeuxvideo\.com/.*/(.*?)\.htm
|
|
210
|
+
# Original: https?://.*?\.jeuxvideo\.com/.*/(.*?)\.htm
|
|
211
|
+
https?://.*?\.jeuxvideo\.com/.*/(.*?)\.htm
|
|
212
|
+
|
|
213
213
|
# Source: leeco
|
|
214
214
|
# Pattern: https?://yuntv\.letv\.com/bcloud.html\?.+
|
|
215
215
|
# Original: https?://yuntv\.letv\.com/bcloud.html\?.+
|
data/url_categorise.gemspec
CHANGED
|
@@ -30,11 +30,11 @@ Gem::Specification.new do |spec|
|
|
|
30
30
|
spec.add_dependency 'fileutils', '>= 1.7.0', '< 2.0'
|
|
31
31
|
spec.add_dependency 'httparty', '>= 0.24.0', '< 1.0'
|
|
32
32
|
spec.add_dependency 'json', '>= 2.7.0', '< 3.0'
|
|
33
|
-
spec.add_dependency 'kaggle', '>= 0.0.
|
|
33
|
+
spec.add_dependency 'kaggle', '>= 0.0.6', '< 1.0'
|
|
34
34
|
spec.add_dependency 'nokogiri', '>= 1.19.1', '< 2.0'
|
|
35
35
|
spec.add_dependency 'reline', '>= 0.6.2', '< 2.0'
|
|
36
36
|
spec.add_dependency 'resolv', '>= 0.4.0', '< 1.0'
|
|
37
|
-
spec.add_dependency 'rubyzip', '>=
|
|
37
|
+
spec.add_dependency 'rubyzip', '>= 3.4.0', '< 4.0'
|
|
38
38
|
|
|
39
39
|
# Development dependancies
|
|
40
40
|
spec.add_development_dependency 'minitest', '~> 5.25.5'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: UrlCategorise
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- trex22
|
|
@@ -155,7 +155,7 @@ dependencies:
|
|
|
155
155
|
requirements:
|
|
156
156
|
- - ">="
|
|
157
157
|
- !ruby/object:Gem::Version
|
|
158
|
-
version: 0.0.
|
|
158
|
+
version: 0.0.6
|
|
159
159
|
- - "<"
|
|
160
160
|
- !ruby/object:Gem::Version
|
|
161
161
|
version: '1.0'
|
|
@@ -165,7 +165,7 @@ dependencies:
|
|
|
165
165
|
requirements:
|
|
166
166
|
- - ">="
|
|
167
167
|
- !ruby/object:Gem::Version
|
|
168
|
-
version: 0.0.
|
|
168
|
+
version: 0.0.6
|
|
169
169
|
- - "<"
|
|
170
170
|
- !ruby/object:Gem::Version
|
|
171
171
|
version: '1.0'
|
|
@@ -235,20 +235,20 @@ dependencies:
|
|
|
235
235
|
requirements:
|
|
236
236
|
- - ">="
|
|
237
237
|
- !ruby/object:Gem::Version
|
|
238
|
-
version:
|
|
238
|
+
version: 3.4.0
|
|
239
239
|
- - "<"
|
|
240
240
|
- !ruby/object:Gem::Version
|
|
241
|
-
version: '
|
|
241
|
+
version: '4.0'
|
|
242
242
|
type: :runtime
|
|
243
243
|
prerelease: false
|
|
244
244
|
version_requirements: !ruby/object:Gem::Requirement
|
|
245
245
|
requirements:
|
|
246
246
|
- - ">="
|
|
247
247
|
- !ruby/object:Gem::Version
|
|
248
|
-
version:
|
|
248
|
+
version: 3.4.0
|
|
249
249
|
- - "<"
|
|
250
250
|
- !ruby/object:Gem::Version
|
|
251
|
-
version: '
|
|
251
|
+
version: '4.0'
|
|
252
252
|
- !ruby/object:Gem::Dependency
|
|
253
253
|
name: minitest
|
|
254
254
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -476,6 +476,7 @@ files:
|
|
|
476
476
|
- bin/generate_categorised_lists
|
|
477
477
|
- bin/generate_social_media_lists
|
|
478
478
|
- bin/generate_video_lists
|
|
479
|
+
- bin/generate_video_lists_focused
|
|
479
480
|
- bin/rake
|
|
480
481
|
- bin/setup
|
|
481
482
|
- correct_usage_example.rb
|