AnimeDL 0.1.1
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/.gitignore +1 -0
- data/LICENSE.txt +21 -0
- data/README.md +26 -0
- data/anime_dl.gemspec +18 -0
- data/bin/anime_dl +276 -0
- data/lib/anime_dl.rb +90 -0
- data/lib/anime_dl/anime_heaven.rb +48 -0
- data/lib/anime_dl/version.rb +3 -0
- data/lib/episode.rb +30 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 749ae8ea30b343616260eede819cda37c01148b5
|
4
|
+
data.tar.gz: 623dd8328333bbc3cab908b0ddf2340889ccdd38
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f91608397485ae824c5a24307d5f5105869c506dbf1245d177738dafc3cba0388e17fb5ee867d5da3359f1696161e9f1162120097b75bcaf9cba7f5978b4bc71
|
7
|
+
data.tar.gz: b098d18960bd46965e632504383e5efe2e9afe569f9d96b160509f48c54258eb73315b49ce56f434d1ed75b54a06a87c338fc394fd3c8e6d86e9b3fdce248284
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
test*
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Anirudh Sundar
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# AnimeDL
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
Add this line to your application's Gemfile:
|
6
|
+
|
7
|
+
```
|
8
|
+
gem 'AnimeDL'
|
9
|
+
```
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install AnimeDL
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
|
24
|
+
## License
|
25
|
+
|
26
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/anime_dl.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "anime_dl/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "AnimeDL"
|
5
|
+
spec.version = "0.1.1"
|
6
|
+
spec.authors = ["Anirudh Sundar"]
|
7
|
+
spec.email = "anirudhsundar@hotmail.com"
|
8
|
+
|
9
|
+
spec.summary = %q{The AnimeDL gem is used to get episode links or download episodes for a particular anime}
|
10
|
+
spec.homepage = "https://github.com/anirudhsundar98/AnimeDL"
|
11
|
+
spec.license = "MIT"
|
12
|
+
|
13
|
+
spec.require_paths = ["lib"]
|
14
|
+
spec.files = `git ls-files`.split("\n")
|
15
|
+
spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
16
|
+
|
17
|
+
spec.add_runtime_dependency 'mechanize', '~> 2.7'
|
18
|
+
end
|
data/bin/anime_dl
ADDED
@@ -0,0 +1,276 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "anime_dl"
|
3
|
+
require "optparse"
|
4
|
+
|
5
|
+
# APP OPTIONS
|
6
|
+
options = { option: "link", episode: true, file: nil, quiet: false }
|
7
|
+
help_statements = {
|
8
|
+
option: %Q[Option (default: "link"). Values: "l" (or) "link", "d" (or) "download"],
|
9
|
+
episode: %Q[Prevents the app from asking for an Episodes prompt. Gets detals for all episodes.],
|
10
|
+
file: %Q[Provide location to store extracted details. Exits if path does not exist. (Usage Examples below).],
|
11
|
+
quiet: %Q[Suppresses large, in-program help statements.],
|
12
|
+
help: %Q[Show this message and exit.]
|
13
|
+
}
|
14
|
+
|
15
|
+
ARGV.options do |opts|
|
16
|
+
opts.banner = "AnimeDL: An anime link scraper and downloader"
|
17
|
+
opts.define_head "Usage: #{File.basename($PROGRAM_NAME)} [options] file"
|
18
|
+
opts.separator ""
|
19
|
+
opts.separator "User can either download episodes or get links to video sources of episodes of a particular anime."
|
20
|
+
opts.separator "On running the command the program prompts the user for a search query and prints a list of search results."
|
21
|
+
opts.separator "The user can then choose a particular anime. Details for all episodes are scraped."
|
22
|
+
opts.separator "To select particular episodes call the app with the '-e' option."
|
23
|
+
opts.separator ""
|
24
|
+
opts.separator "Links: "
|
25
|
+
opts.separator " To output links to a file, provide the path to a file as the last argument."
|
26
|
+
opts.separator " If argument is a directory, a new text file will be created in that directory."
|
27
|
+
opts.separator "Downloads: "
|
28
|
+
opts.separator " To download videos to particular directory, specify the directory as the last argument."
|
29
|
+
opts.separator " If no directory is specified the videos are downloaded to ~/AnimeDL/anime_name/"
|
30
|
+
opts.separator ""
|
31
|
+
opts.separator "Options:"
|
32
|
+
|
33
|
+
opts.on("-o option", "--option option", help_statements[:option]) do |option|
|
34
|
+
unless (['l', 'link', 'd', 'download'].include? option)
|
35
|
+
puts "Invalid argument to --option"
|
36
|
+
puts %Q[Valid options: "l" (or) "link", "d" (or) "download"]
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
|
40
|
+
options[:option] = option
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("-e", "--episode", help_statements[:episode]) do
|
44
|
+
options[:episode] = false
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on("-f file", "--file=file", help_statements[:file]) do |file|
|
48
|
+
options[:file] = file
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on("-q", "--quiet", help_statements[:quiet]) do
|
52
|
+
options[:quiet] = true
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
opts.on( "-h", "--help", help_statements[:help]) do
|
57
|
+
puts opts
|
58
|
+
exit
|
59
|
+
end
|
60
|
+
|
61
|
+
opts.separator ""
|
62
|
+
opts.separator "Examples:"
|
63
|
+
opts.separator %Q[ `anime_dl` (outputs link urls on the terminal)]
|
64
|
+
opts.separator %Q[ `anime_dl -f rel/path/to/filename.txt` (outputs link urls to 'rel/path/to/filename.txt')]
|
65
|
+
opts.separator %Q[ `anime_dl -o link -f rel/path/to/directory/` (outputs link urls to 'rel/path/to/directory/anime_name.txt')]
|
66
|
+
opts.separator %Q[ `anime_dl -o download` (downloads videos to './anime_name/')]
|
67
|
+
opts.separator %Q[ `anime_dl -o download -f .` (downloads videos to './')]
|
68
|
+
opts.separator %Q[ `anime_dl -o d -f /abs/path/to/directory` (downloads videos to '/abs/path/to/directory/anime_name/')]
|
69
|
+
opts.separator %Q[ `anime_dl -o download -f /abs/path/to/directory/` (downloads videos to '/abs/path/to/directory/anime_name/')]
|
70
|
+
opts.separator ""
|
71
|
+
|
72
|
+
opts.separator "Example App Usage:"
|
73
|
+
opts.separator "`anime_dl -q`"
|
74
|
+
opts.separator " Enter Search Query: fullmetal alchemist b"
|
75
|
+
opts.separator " 0. (Exit)"
|
76
|
+
opts.separator " 1. Fullmetal Alchemist Brotherhood Dubbed | Hagane no Renkinjutsushi (2009) Dubbed"
|
77
|
+
opts.separator " 2. Fullmetal Alchemist Brotherhood | Hagane no Renkinjutsushi (2009)"
|
78
|
+
opts.separator " 3. (Enter new Search Query)"
|
79
|
+
opts.separator ""
|
80
|
+
opts.separator " Choice: 4"
|
81
|
+
opts.separator " (Empty response gets all episodes, '-1' to exit)."
|
82
|
+
opts.separator " Total number of Episodes - 20 (0-19)"
|
83
|
+
opts.separator " Episodes: -1"
|
84
|
+
|
85
|
+
opts.separator ""
|
86
|
+
opts.separator ""
|
87
|
+
opts.separator "When the '-e' option is not provided, the app asks for 'Episodes' after retrieving the user's anime choice."
|
88
|
+
opts.separator "The user can provide induvidual space-seperated episodes."
|
89
|
+
opts.separator "The user can also provide multiple space-seperated ranges with each range having the format 'start-end'."
|
90
|
+
opts.separator "Below are a few examples (assuming anime has more than 18 episodes)."
|
91
|
+
opts.separator %Q[ `Episodes: 2 4 5` - Retrieves details for episodes 2, 4 and 5]
|
92
|
+
opts.separator %Q[ `Episodes: 4-8` - Retrieves details for episodes 4 to 8]
|
93
|
+
opts.separator %Q[ `Episodes: 8-l` - Retrieves details for episodes 8 to the last episode]
|
94
|
+
opts.separator %Q[ `Episodes: 2 9-13 18-l` - Retrieves details for episodes 2, 9 to 13 and 18 to end]
|
95
|
+
opts.separator ""
|
96
|
+
opts.separator "NOTE: "
|
97
|
+
opts.separator "The page being scraped from, \"animeheaven.eu\", only allows a certain number of page views per day (>150, <300)."
|
98
|
+
opts.separator "Once that limit is exceed, you will have tochange networks or try again in 24 hours."
|
99
|
+
|
100
|
+
begin
|
101
|
+
opts.parse!
|
102
|
+
rescue OptionParser::MissingArgument, OptionParser::InvalidArgument => error
|
103
|
+
puts "Error: #{error}"
|
104
|
+
puts "Enter `anime_dl - h` for usage options"
|
105
|
+
exit
|
106
|
+
rescue => error
|
107
|
+
puts "Error: #{error}"
|
108
|
+
puts "Enter `anime_dl - h` for usage options"
|
109
|
+
exit
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
# File Check
|
115
|
+
if (options[:file])
|
116
|
+
|
117
|
+
if (options[:option][0] == "l")
|
118
|
+
if ( File.directory?(options[:file]) )
|
119
|
+
unless (File.exists?(options[:file]))
|
120
|
+
puts "Directory does not exist"
|
121
|
+
exit
|
122
|
+
end
|
123
|
+
elsif ( !File.exists?( File.split(options[:file])[0] ) )
|
124
|
+
puts "Directory does not exist"
|
125
|
+
exit
|
126
|
+
end
|
127
|
+
|
128
|
+
elsif ( !File.exists?(options[:file]) || !File.directory?(options[:file]) )
|
129
|
+
puts "Directory does not exist (or) argument is not a directory"
|
130
|
+
puts "For --option=download , argument to --file must be a directory"
|
131
|
+
exit
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
# New Instance
|
139
|
+
instance = AnimeDL::AnimeHeaven.new
|
140
|
+
|
141
|
+
# App Prompts/Help Text
|
142
|
+
unless (options[:quiet])
|
143
|
+
$user_prompts = {
|
144
|
+
search: "\nNo Results Found. Please check your search query.\n(Its worth noting that AnimeHeaven does not have some old anime)\n",
|
145
|
+
episodes: "\nEnter the desired episodes.\nYou can provide induvidual space-seperated episodes.\n" +
|
146
|
+
"Or you can also provide multiple space-seperated ranges with each range having the format 'start-end'.\n" +
|
147
|
+
"Examples (assuming anime has more than 18 episodes):\n" +
|
148
|
+
" `Episodes: 2 4 5` - Retrieves details for episodes 2, 4 and 5\n" +
|
149
|
+
" `Episodes: 4-8` - Retrieves details for episodes 4 to 8\n" +
|
150
|
+
" `Episodes: 8-l` - Retrieves details for episodes 8 to the last episode\n" +
|
151
|
+
" `Episodes: 2 9-13 18-l` - Retrieves details for episodes 2, 9 to 13 and 18 to end\n" +
|
152
|
+
"(Enter empty response to get all episodes, '-1' exits).\n\n"
|
153
|
+
}
|
154
|
+
else
|
155
|
+
$user_prompts = {
|
156
|
+
search: "No Results Found.\n",
|
157
|
+
episodes: "\n(Empty response gets all episodes, '-1' exits).\n"
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
# UTILITY METHODS
|
163
|
+
# Result Print
|
164
|
+
def output(results)
|
165
|
+
puts "0. (Exit)\n"
|
166
|
+
for i in 0...results.length do
|
167
|
+
print i+1, ". ", results[i].text
|
168
|
+
puts
|
169
|
+
end
|
170
|
+
|
171
|
+
puts "#{results.length + 1}. (Enter new Search Query)\n"
|
172
|
+
print $user_prompts[:search] if (results.length == 0)
|
173
|
+
puts "\n"
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
# Option Check
|
178
|
+
def check(input, max)
|
179
|
+
exit if (input == "0")
|
180
|
+
return 1 if ( (1..(max + 1)).include? input.to_i )
|
181
|
+
|
182
|
+
puts "Invalid input.\n\n"
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
# Write links to file
|
187
|
+
def file_write(file, links, choice)
|
188
|
+
details = ""
|
189
|
+
puts links.pop.link if (links.last.number == nil)
|
190
|
+
exit if links.empty?
|
191
|
+
|
192
|
+
for l in links
|
193
|
+
details += l.details
|
194
|
+
end
|
195
|
+
|
196
|
+
puts "Writing"
|
197
|
+
if ( File.directory?(file) )
|
198
|
+
file = File.new( File.join(file, choice.content.split(" | ")[0] + ".txt"), "a+" )
|
199
|
+
file.write(details + "\n")
|
200
|
+
file.close
|
201
|
+
else
|
202
|
+
file = File.new(file, "a+")
|
203
|
+
file.write(details + "\n")
|
204
|
+
file.close
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
|
210
|
+
# APP LOGIC
|
211
|
+
# Search
|
212
|
+
while true
|
213
|
+
print "Enter Search Query: "
|
214
|
+
search_query = gets.strip.split(" ").join("+")
|
215
|
+
puts "\n"
|
216
|
+
results = instance.search(search_query)
|
217
|
+
output(results)
|
218
|
+
puts "\n"
|
219
|
+
|
220
|
+
# Anime Choice
|
221
|
+
while true
|
222
|
+
print "Choice: "
|
223
|
+
input = gets.strip
|
224
|
+
break if (check(input, results.length) == 1)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Re-enter search query
|
228
|
+
break unless (input.to_i == results.length + 1)
|
229
|
+
puts "\n"
|
230
|
+
end
|
231
|
+
|
232
|
+
# Choice as Nokogiri Element
|
233
|
+
choice = results[input.to_i - 1]
|
234
|
+
|
235
|
+
# Range
|
236
|
+
range = []
|
237
|
+
if (options[:episode])
|
238
|
+
puts "\n"
|
239
|
+
print $user_prompts[:episodes]
|
240
|
+
puts "\n"
|
241
|
+
|
242
|
+
first, last = instance.getTotal(choice)
|
243
|
+
puts "Total number of Episodes - #{last - first + 1} (#{first}-#{last})"
|
244
|
+
print "Episodes: "
|
245
|
+
range = gets.strip
|
246
|
+
exit if range == "-1"
|
247
|
+
|
248
|
+
range = range.split(" ")
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
# Data Retrieval
|
253
|
+
puts "Scraping: " + choice.content + "\n\n"
|
254
|
+
|
255
|
+
if ( options[:option][0] == 'l' && !options[:file])
|
256
|
+
to_print = true
|
257
|
+
else
|
258
|
+
to_print = false
|
259
|
+
end
|
260
|
+
|
261
|
+
# Links
|
262
|
+
links = instance.getLinks(choice, range, options[:quiet], to_print)
|
263
|
+
file_write(options[:file], links, choice) if (options[:file] && options[:option][0] == 'l')
|
264
|
+
|
265
|
+
# Downloads
|
266
|
+
if ( options[:option][0] == 'd' )
|
267
|
+
if (options[:file] == nil)
|
268
|
+
options[:file] = choice.content.split(" | ")[0]
|
269
|
+
Dir.mkdir( options[:file] )
|
270
|
+
end
|
271
|
+
|
272
|
+
AnimeDL.download(options[:file], links)
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
END { puts "Exiting" }
|
data/lib/anime_dl.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require "mechanize"
|
2
|
+
require "anime_dl/version"
|
3
|
+
require "anime_dl/anime_heaven"
|
4
|
+
require "episode"
|
5
|
+
# Methods to get links in 'anime_dl/#{anime_site}.rb'
|
6
|
+
|
7
|
+
module AnimeDL
|
8
|
+
class AnimeHeaven
|
9
|
+
def initialize
|
10
|
+
@agent = Mechanize.new
|
11
|
+
@agent.user_agent_alias = 'Windows Chrome'
|
12
|
+
@anime_page = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
# Search
|
16
|
+
def search(query)
|
17
|
+
results_page = @agent.get("http://animeheaven.eu/search.php?q=#{query}")
|
18
|
+
return results_page.search(".iepsan")
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the total number of episodes
|
22
|
+
def getTotal(option = nil)
|
23
|
+
@anime_page = @agent.get(option.attributes['href'].value) unless (@anime_page)
|
24
|
+
episodes = @anime_page.search(".infoepbox").search("a")
|
25
|
+
|
26
|
+
first = episodes.last.search(".infoept2")[0].content.to_i
|
27
|
+
last = episodes.first.search(".infoept2")[0].content.to_i
|
28
|
+
return first, last
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# UTILITY
|
33
|
+
def limit_exceeded(quiet)
|
34
|
+
return "Unfortunately \"animeheaven.eu\" only allows a certain number of page views per day.\n" +
|
35
|
+
"It seems you have exceeded that limit :(.\n" +
|
36
|
+
"Please change networks or try again in 24 hours." if (!quiet)
|
37
|
+
|
38
|
+
return "(Limit exceeded)"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# Download
|
44
|
+
def self.download(path, episodes)
|
45
|
+
episodes.each do |episode|
|
46
|
+
if ( File.exists?( File.join( path, "Episode #{episode.number}.mp4" )) )
|
47
|
+
puts "Skipping Episode #{episode.number} (already exists)"
|
48
|
+
next
|
49
|
+
else
|
50
|
+
puts "Downloading Episode #{episode.number}"
|
51
|
+
end
|
52
|
+
|
53
|
+
status = episode.download_to(path)
|
54
|
+
return if status == -1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Episode Range Handler
|
59
|
+
def self.range_handle(range, first, last)
|
60
|
+
temp = []
|
61
|
+
|
62
|
+
range.each do |arg|
|
63
|
+
# Basic REGEX match
|
64
|
+
unless (arg.match(/\A[0-9]+\Z|\A[0-9]+\-[0-9l]+\Z/))
|
65
|
+
puts "'#{arg}' is an invalid input for 'Episodes'"
|
66
|
+
next
|
67
|
+
end
|
68
|
+
|
69
|
+
if (arg.include?("-"))
|
70
|
+
f, l = arg.split("-").collect(&:to_i)
|
71
|
+
l = last if (arg[-1] == "l")
|
72
|
+
|
73
|
+
next unless (f && l)
|
74
|
+
next if f > last
|
75
|
+
l = last if l > last
|
76
|
+
|
77
|
+
(f..l).each do |n|
|
78
|
+
temp << n if ( (first..last).include? n )
|
79
|
+
end
|
80
|
+
|
81
|
+
else
|
82
|
+
temp << arg.to_i if ( (first..last).include? arg.to_i )
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
return temp.uniq.sort
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module AnimeDL
|
2
|
+
class AnimeHeaven
|
3
|
+
|
4
|
+
# Return the required page links based on user input
|
5
|
+
def getPageLinks(option, range)
|
6
|
+
@anime_page = @agent.get(option.attributes['href'].value) unless (@anime_page)
|
7
|
+
page_links = @anime_page.search(".infoepbox").search("a").reverse
|
8
|
+
return page_links if range.empty?
|
9
|
+
|
10
|
+
links_required = []
|
11
|
+
first, last = getTotal(option)
|
12
|
+
range = AnimeDL.range_handle(range, first, last)
|
13
|
+
range.each { |num| links_required << page_links[num - first] }
|
14
|
+
|
15
|
+
return links_required
|
16
|
+
end
|
17
|
+
|
18
|
+
# Video Links
|
19
|
+
def getLinks(option, range, quiet = false, output = false)
|
20
|
+
episode_links = getPageLinks(option, range)
|
21
|
+
episodes = []
|
22
|
+
|
23
|
+
puts "Fetching Links..." unless (output)
|
24
|
+
|
25
|
+
episode_links.each do |link|
|
26
|
+
episode_page = @agent.get(link.attributes['href'].value)
|
27
|
+
|
28
|
+
# Limit Check
|
29
|
+
if (episode_page.search(".c").search("b").length != 0)
|
30
|
+
episodes << Episode.new(nil, limit_exceeded(quiet))
|
31
|
+
puts limit_exceeded(quiet) if (output)
|
32
|
+
break
|
33
|
+
end
|
34
|
+
|
35
|
+
# Video Link Retrieval
|
36
|
+
episode_no = episode_page.uri.to_s[/e=.+/][2..-1] # (Regex for safety)
|
37
|
+
video_src = episode_page.search("script")[2].to_s[/src='http.*?'/][5...-1]
|
38
|
+
|
39
|
+
episode = Episode.new(episode_no, video_src)
|
40
|
+
episodes << episode
|
41
|
+
puts episode.details if (output)
|
42
|
+
end
|
43
|
+
|
44
|
+
return episodes
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/episode.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
|
3
|
+
class Episode
|
4
|
+
def initialize(episode_no, link)
|
5
|
+
@number = episode_no
|
6
|
+
@link = link
|
7
|
+
end
|
8
|
+
attr_reader :number, :link
|
9
|
+
|
10
|
+
def download_to(path = ".")
|
11
|
+
# Limit Check
|
12
|
+
unless @number
|
13
|
+
puts @link
|
14
|
+
return -1
|
15
|
+
end
|
16
|
+
|
17
|
+
open("#{@link}") do |video|
|
18
|
+
file = File.new( File.join( path, "Episode #{@number}.mp4" ), 'w')
|
19
|
+
puts "Writing"
|
20
|
+
file.write(video.read)
|
21
|
+
file.close
|
22
|
+
end
|
23
|
+
|
24
|
+
return 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def details
|
28
|
+
return "Episode #{@number}: #{@link}\n"
|
29
|
+
end
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: AnimeDL
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anirudh Sundar
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-08-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mechanize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.7'
|
27
|
+
description:
|
28
|
+
email: anirudhsundar@hotmail.com
|
29
|
+
executables:
|
30
|
+
- anime_dl
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".gitignore"
|
35
|
+
- LICENSE.txt
|
36
|
+
- README.md
|
37
|
+
- anime_dl.gemspec
|
38
|
+
- bin/anime_dl
|
39
|
+
- lib/anime_dl.rb
|
40
|
+
- lib/anime_dl/anime_heaven.rb
|
41
|
+
- lib/anime_dl/version.rb
|
42
|
+
- lib/episode.rb
|
43
|
+
homepage: https://github.com/anirudhsundar98/AnimeDL
|
44
|
+
licenses:
|
45
|
+
- MIT
|
46
|
+
metadata: {}
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 2.6.8
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: The AnimeDL gem is used to get episode links or download episodes for a particular
|
67
|
+
anime
|
68
|
+
test_files: []
|