subdl 0.0.6 → 0.0.7
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 +7 -0
- data/bin/subdl +6 -7
- data/lib/subdl.rb +90 -33
- metadata +16 -28
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b353f0e19e883d57a353f5ea315cc4d6ef1a71e6
|
4
|
+
data.tar.gz: b81266cb82694395f3b86f77bbee9a69f8723271
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f67572d0e484e3055ee9d61f389a9a16274bcffd9c3beee96389364e5a9cd43688523fb49c2c27fee8829b16d480e58b833b96b2dd90632f1aac89c9a09522db
|
7
|
+
data.tar.gz: cc0219092a9b21f22235e51edd83867b64f255eb66db0b5f35d03d26cebc72f535e41e494a3e0ced9dfa99f7ddc8c0b84922ec590266d746ba9bfd53d5a82777
|
data/bin/subdl
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
2
|
require 'subdl'
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
subdl = Subdl.new mechanize_agent,
|
5
|
+
ItasaLoginForm.new,
|
6
|
+
$stdout,
|
7
|
+
FileSystem.new,
|
8
|
+
FileReader.new
|
8
9
|
|
9
|
-
|
10
|
-
crawler.download_sub_for ARGV.shift
|
11
|
-
end
|
10
|
+
subdl.main ARGV
|
data/lib/subdl.rb
CHANGED
@@ -2,16 +2,37 @@ require 'mechanize'
|
|
2
2
|
require 'cgi'
|
3
3
|
require 'json'
|
4
4
|
require 'zipruby'
|
5
|
+
require 'nokogiri'
|
6
|
+
|
7
|
+
class Subdl
|
8
|
+
def initialize agent, itasa_login, stdout, file_system,
|
9
|
+
file_reader
|
10
|
+
itasa = Itasa.new(agent, itasa_login)
|
11
|
+
credentials = Credentials.new file_reader
|
12
|
+
@crawler = Crawler.new itasa, credentials, file_system, stdout
|
13
|
+
end
|
14
|
+
def main argv
|
15
|
+
until argv.empty? do
|
16
|
+
@crawler.download_sub_for argv.shift
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
5
20
|
|
6
21
|
class Crawler
|
7
22
|
|
8
|
-
def initialize itasa
|
23
|
+
def initialize itasa, credentials, file_system, stdout
|
9
24
|
@itasa = itasa
|
25
|
+
@credentials = credentials
|
26
|
+
@file_system = file_system
|
27
|
+
@stdout = stdout
|
10
28
|
end
|
11
29
|
|
12
30
|
def download_sub_for path
|
13
|
-
movie_file = MovieFile.new
|
14
|
-
@itasa.
|
31
|
+
movie_file = MovieFile.new path, @stdout
|
32
|
+
ids = @itasa.search_subtitles(movie_file.search_term)
|
33
|
+
|
34
|
+
ids.each do |id|
|
35
|
+
@itasa.login *@credentials.read
|
15
36
|
@itasa.download_zip id do |zip_contents|
|
16
37
|
unpack_subtitle_to zip_contents, movie_file
|
17
38
|
end
|
@@ -21,7 +42,7 @@ class Crawler
|
|
21
42
|
def unpack_subtitle_to zip_contents, movie_file
|
22
43
|
Zip::Archive.open_buffer(zip_contents) do |archive|
|
23
44
|
archive.each do |entry|
|
24
|
-
movie_file.
|
45
|
+
movie_file.save_subtitle entry.read, @file_system
|
25
46
|
end
|
26
47
|
end
|
27
48
|
end
|
@@ -30,8 +51,8 @@ end
|
|
30
51
|
|
31
52
|
class MovieFile
|
32
53
|
attr_reader :episode, :season, :show
|
33
|
-
|
34
|
-
def initialize filename
|
54
|
+
|
55
|
+
def initialize filename, stdout=nil
|
35
56
|
@filename = filename
|
36
57
|
text = File.basename filename
|
37
58
|
text = remove_year_from text
|
@@ -41,7 +62,7 @@ class MovieFile
|
|
41
62
|
@season = remove_leading_zeros m[2]
|
42
63
|
@episode = remove_leading_zeros m[3]
|
43
64
|
end
|
44
|
-
@
|
65
|
+
@stdout = stdout
|
45
66
|
end
|
46
67
|
|
47
68
|
def remove_year_from text
|
@@ -56,10 +77,11 @@ class MovieFile
|
|
56
77
|
"%s %dx%02d" % [show, season, episode]
|
57
78
|
end
|
58
79
|
|
59
|
-
def
|
80
|
+
def save_subtitle contents, fs
|
60
81
|
srt_filename = @filename.gsub /.mp4$/, ''
|
61
82
|
srt_filename += ".itasa#{next_distinguisher}.srt"
|
62
|
-
@
|
83
|
+
@stdout.puts "Downloaded as #{srt_filename}"
|
84
|
+
fs.save_file srt_filename, contents
|
63
85
|
end
|
64
86
|
|
65
87
|
def next_distinguisher
|
@@ -74,58 +96,81 @@ class MovieFile
|
|
74
96
|
end
|
75
97
|
|
76
98
|
class FileSystem
|
77
|
-
def
|
99
|
+
def save_file filename, contents
|
78
100
|
File.open filename, 'w' do |f|
|
79
101
|
f.write contents
|
80
102
|
end
|
81
103
|
end
|
82
104
|
end
|
83
105
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
a.user_agent_alias = 'Mac FireFox'
|
88
|
-
end
|
106
|
+
def mechanize_agent
|
107
|
+
Mechanize.new do |a|
|
108
|
+
a.user_agent_alias = 'Mac FireFox'
|
89
109
|
end
|
110
|
+
end
|
90
111
|
|
91
|
-
|
92
|
-
|
112
|
+
class ItasaLoginForm
|
113
|
+
|
114
|
+
def login username, password, page_where_to_login, agent
|
115
|
+
return if logged_in?
|
116
|
+
home_page = agent.get page_where_to_login
|
93
117
|
login_form = home_page.form 'login'
|
94
118
|
login_form.username = username
|
95
119
|
login_form.passwd = password
|
96
|
-
@page =
|
120
|
+
@page = agent.submit(login_form)
|
97
121
|
end
|
98
122
|
|
123
|
+
private
|
124
|
+
|
99
125
|
def logged_in?
|
100
126
|
return false unless @page
|
101
127
|
link_that_exists_only_once_logged = @page.search(
|
102
128
|
"//a[@href='forum/index.php?action=unreadreplies']")
|
103
|
-
link_that_exists_only_once_logged.first
|
129
|
+
return link_that_exists_only_once_logged.first != nil
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
class Itasa
|
136
|
+
def initialize agent, login_form
|
137
|
+
@agent = agent
|
138
|
+
@login_form = login_form || ItasaLoginForm.new
|
139
|
+
end
|
140
|
+
|
141
|
+
def login username, password
|
142
|
+
@login_form.login username, password, "http://#{host}", @agent
|
104
143
|
end
|
105
144
|
|
106
|
-
def
|
145
|
+
def autocomplete_data_for text
|
107
146
|
response = @agent.get search_url(text)
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
147
|
+
response.body
|
148
|
+
end
|
149
|
+
|
150
|
+
def search_subtitles text
|
151
|
+
json = autocomplete_data_for text
|
152
|
+
return extract_ids_from_autocomplete_data json
|
153
|
+
end
|
154
|
+
|
155
|
+
def extract_ids_from_autocomplete_data json
|
156
|
+
JSON.parse(json).map { |episode| episode['id'] }
|
112
157
|
end
|
113
158
|
|
114
159
|
def download_zip id
|
115
160
|
page = @agent.get subtitle_page_url(id)
|
116
|
-
zipped_subtitle = @agent.get subtitle_zip_url(page)
|
161
|
+
zipped_subtitle = @agent.get subtitle_zip_url(page.body)
|
117
162
|
yield zipped_subtitle.body
|
118
163
|
end
|
119
164
|
|
120
165
|
def subtitle_zip_url page
|
121
|
-
|
122
|
-
return
|
166
|
+
doc = Nokogiri::HTML(page)
|
167
|
+
return doc.at_xpath("//a[img[contains(@src,'download2.gif')]]")[:href]
|
123
168
|
end
|
124
169
|
|
125
170
|
def search_url text
|
126
171
|
url = URI.parse "http://#{host}/modules/mod_itasalivesearch/search.php"
|
127
172
|
url.query = "term=#{CGI.escape text}"
|
128
|
-
return url
|
173
|
+
return url.to_s
|
129
174
|
end
|
130
175
|
|
131
176
|
def subtitle_page_url id
|
@@ -139,10 +184,22 @@ class Itasa
|
|
139
184
|
end
|
140
185
|
|
141
186
|
class Credentials
|
142
|
-
def
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
187
|
+
def initialize file_reader
|
188
|
+
@file_reader = file_reader
|
189
|
+
end
|
190
|
+
def parse file_contents
|
191
|
+
lines = file_contents.lines.to_a
|
192
|
+
username = lines[0].chomp
|
193
|
+
password = lines[1].chomp
|
194
|
+
[username, password]
|
195
|
+
end
|
196
|
+
def read
|
197
|
+
parse @file_reader.read_expand('~/.itasa-credentials')
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
class FileReader
|
202
|
+
def read_expand expandable_path
|
203
|
+
File.read(File.expand_path(expandable_path))
|
147
204
|
end
|
148
205
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: subdl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.7
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Andrea Francia
|
@@ -14,81 +13,71 @@ dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: mechanize
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: zipruby
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: json
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: rspec
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: '0'
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - '>='
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: '0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: rake
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - '>='
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: '0'
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - '>='
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: '0'
|
94
83
|
description: A simple hello world gem
|
@@ -102,26 +91,25 @@ files:
|
|
102
91
|
- bin/subdl
|
103
92
|
homepage: https://github.com/andreafrancia/subdl
|
104
93
|
licenses: []
|
94
|
+
metadata: {}
|
105
95
|
post_install_message:
|
106
96
|
rdoc_options: []
|
107
97
|
require_paths:
|
108
98
|
- lib
|
109
99
|
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
-
none: false
|
111
100
|
requirements:
|
112
|
-
- -
|
101
|
+
- - '>='
|
113
102
|
- !ruby/object:Gem::Version
|
114
103
|
version: '0'
|
115
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
-
none: false
|
117
105
|
requirements:
|
118
|
-
- -
|
106
|
+
- - '>='
|
119
107
|
- !ruby/object:Gem::Version
|
120
108
|
version: '0'
|
121
109
|
requirements: []
|
122
110
|
rubyforge_project:
|
123
|
-
rubygems_version:
|
111
|
+
rubygems_version: 2.0.3
|
124
112
|
signing_key:
|
125
|
-
specification_version:
|
113
|
+
specification_version: 4
|
126
114
|
summary: Download subtitles for your favorite show.
|
127
115
|
test_files: []
|