subdl 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|