comer_de_tapas 0.1.0
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/CONTRIBUTING.md +41 -0
- data/DEVELOPMENT.md +15 -0
- data/LICENSE +21 -0
- data/README.md +81 -0
- data/Rakefile +11 -0
- data/bin/comer_de_tapas +5 -0
- data/comer_de_tapas.gemspec +29 -0
- data/lib/comer_de_tapas/cli.rb +33 -0
- data/lib/comer_de_tapas/client.rb +207 -0
- data/lib/comer_de_tapas/constants.rb +12 -0
- data/lib/comer_de_tapas/fetcher.rb +16 -0
- data/lib/comer_de_tapas/subscription.rb +65 -0
- data/lib/comer_de_tapas/version.rb +3 -0
- data/lib/comer_de_tapas.rb +9 -0
- data/test/cli_test.rb +12 -0
- data/test/client_test.rb +7 -0
- data/test/fetcher_test.rb +7 -0
- data/test/subscription_test.rb +6 -0
- data/test/test_helper.rb +11 -0
- metadata +126 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 52d7624ee230325d84d34d1d7dbed242eff3f67c
|
|
4
|
+
data.tar.gz: 821ec2bcb59323e569227d7996bf751a77e09a2b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0e13a238ba77729967bafa0c02f20f5352f0bf0b243bcecaee12249163504c463110d9ad4c26fe8e1a98e4ecfefa3b034e159308d9772d938fd99a33414215b1
|
|
7
|
+
data.tar.gz: 524d6b69a68edbeac46176d4ec624cfdb2a36bd9fc0488c4cc5822f9a31581ace50d1da03d8a365af02440a6e90673e9426acac33e66153ebdcc57b8d52366bd
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
## Contributing
|
|
2
|
+
|
|
3
|
+
**Everyone** is encouraged to help improve this project.
|
|
4
|
+
|
|
5
|
+
Ways to contribute:
|
|
6
|
+
|
|
7
|
+
* by reporting bugs
|
|
8
|
+
* by suggesting new features
|
|
9
|
+
* by writing or editing documentation
|
|
10
|
+
* by writing code (**no patch is too small**: fix typos, add comments, clean up
|
|
11
|
+
inconsistent whitespace)
|
|
12
|
+
* by refactoring code
|
|
13
|
+
* by fixing [issues][]
|
|
14
|
+
* by reviewing patches
|
|
15
|
+
|
|
16
|
+
[issues]: https://github.com/juanitofatas/comer_de_tapas/issues
|
|
17
|
+
|
|
18
|
+
## Submit an Issue
|
|
19
|
+
|
|
20
|
+
We use the [GitHub issue tracker][issues] to track bugs and features. Before
|
|
21
|
+
submitting a bug report or feature request, check to make sure it hasn't
|
|
22
|
+
already been submitted. When submitting a bug report, please include a [Gist][]
|
|
23
|
+
that includes a stack trace and any details that may be necessary to reproduce
|
|
24
|
+
the bug, including your gem version, Ruby version, and operating system.
|
|
25
|
+
Ideally, a bug report should include a pull request with failing specs.
|
|
26
|
+
|
|
27
|
+
[gist]: https://gist.github.com/
|
|
28
|
+
|
|
29
|
+
## Submit a Pull Request
|
|
30
|
+
|
|
31
|
+
1. [Fork the repository.][fork]
|
|
32
|
+
2. [Create a topic branch.][branch]
|
|
33
|
+
3. Add tests for your unimplemented feature or bug fix.
|
|
34
|
+
4. Implement your feature or bug fix.
|
|
35
|
+
5. Run `rake test`. If your tests pass, go to step 6.
|
|
36
|
+
6. Add, commit, and push your changes.
|
|
37
|
+
7. [Submit a pull request.][pr]
|
|
38
|
+
|
|
39
|
+
[fork]: http://help.github.com/fork-a-repo/
|
|
40
|
+
[branch]: http://learn.github.com/p/branching.html
|
|
41
|
+
[pr]: http://help.github.com/send-pull-requests/
|
data/DEVELOPMENT.md
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Juanito Fatas
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Comer de Tapas
|
|
2
|
+
==============
|
|
3
|
+
|
|
4
|
+
[Ruby Tapas](http://www.rubytapas.com/) Downloader episodes for subscribers.
|
|
5
|
+
|
|
6
|
+
Installation
|
|
7
|
+
------------
|
|
8
|
+
|
|
9
|
+
$ gem install comer_de_tapas
|
|
10
|
+
|
|
11
|
+
Preparation
|
|
12
|
+
-----------
|
|
13
|
+
|
|
14
|
+
$ comer_de_tapas init
|
|
15
|
+
|
|
16
|
+
This will create a directory `~/.rubytapas` And a yaml `~/.rubytapas/.credentials`.
|
|
17
|
+
|
|
18
|
+
Please fill in your subscription information in `~/.rubytapas/.credentials`.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
---
|
|
24
|
+
credentials:
|
|
25
|
+
- email: foo@example.com
|
|
26
|
+
- password: password
|
|
27
|
+
- save_path: ~/Downloads
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
If you want to save all Ruby Tapas episodes in your home folder. Please write it explicily as: `/Users/YOUR-USER-NAME`, please do not write `~`, because in Ruby, `~` considered as `nil` in YAML.
|
|
31
|
+
|
|
32
|
+
Usage
|
|
33
|
+
-----
|
|
34
|
+
|
|
35
|
+
$ comer_de_tapas download
|
|
36
|
+
|
|
37
|
+
Will fetch all episodes, then start to download it.
|
|
38
|
+
|
|
39
|
+
By default it will save a `~/.rubytapas/episodes.json`, to cache all episode attachment links for 3 days.
|
|
40
|
+
|
|
41
|
+
Why 3 days? Because normally our Chef Avdi ships new episode in 3.75 days on average.
|
|
42
|
+
|
|
43
|
+
But if Avdi ships within < 3 days, you can force it to get latest episodes:
|
|
44
|
+
|
|
45
|
+
$ comer_de_tapas download --force # or `-f`.
|
|
46
|
+
|
|
47
|
+
Command References
|
|
48
|
+
------------------
|
|
49
|
+
|
|
50
|
+
| command | purpose | Options |
|
|
51
|
+
| ----------------------------- | ----------------------------------|---------|
|
|
52
|
+
| comer_de_tapas init | Initialize ComerDeTapas. | |
|
|
53
|
+
| comer_de_tapas download | Download episodes. | `-f` |
|
|
54
|
+
| comer_de_tapas version | Display version of Comer de Tapas | |
|
|
55
|
+
|
|
56
|
+
Similar Tools
|
|
57
|
+
-------------
|
|
58
|
+
|
|
59
|
+
* [bf4/downloader](https://github.com/bf4/downloader)
|
|
60
|
+
* [leafac/ruby-tapas-downloader](https://github.com/leafac/ruby-tapas-downloader)
|
|
61
|
+
* [xpepper/download_rubytapas.rb](https://gist.github.com/xpepper/5872399)
|
|
62
|
+
* [ebarendt/tapas](https://github.com/ebarendt/tapas)
|
|
63
|
+
* [YaronWittenstein/next-rubytapas](https://github.com/YaronWittenstein/next-rubytapas)
|
|
64
|
+
* [cibernox/rubytapas_downloader](https://github.com/cibernox/rubytapas_downloader)
|
|
65
|
+
|
|
66
|
+
Questions
|
|
67
|
+
---------
|
|
68
|
+
|
|
69
|
+
Feel free to [open an issue](https://github.com/juanitofatas/comer_de_tapas/issues/new).
|
|
70
|
+
|
|
71
|
+
Development
|
|
72
|
+
-----------
|
|
73
|
+
|
|
74
|
+
Please see [DEVELOPMENT](/DEVELOPMENT.md) and [CONTRIBUTING](/CONTRIBUTING.md).
|
|
75
|
+
|
|
76
|
+
If you like this small tool, please give it a tweet!
|
|
77
|
+
|
|
78
|
+
License
|
|
79
|
+
-------
|
|
80
|
+
|
|
81
|
+
MIT License. Please see [LICENSE](/LICENSE).
|
data/Rakefile
ADDED
data/bin/comer_de_tapas
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require "comer_de_tapas/version"
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "comer_de_tapas"
|
|
8
|
+
spec.version = ComerDeTapas::VERSION
|
|
9
|
+
spec.authors = ["Juanito Fatas"]
|
|
10
|
+
spec.email = ["katehuang0320@gmail.com"]
|
|
11
|
+
spec.summary = %q{Ruby Tapas Episode Downloader.}
|
|
12
|
+
spec.description = spec.summary
|
|
13
|
+
spec.homepage = "https://github.com/juanitofatas/comer_de_tapas"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = %w[CONTRIBUTING.md DEVELOPMENT.md LICENSE README.md Rakefile comer_de_tapas.gemspec]
|
|
17
|
+
spec.files += Dir.glob("lib/**/*.rb")
|
|
18
|
+
spec.files += Dir.glob("bin/**/*")
|
|
19
|
+
spec.files += Dir.glob("test/**/*")
|
|
20
|
+
|
|
21
|
+
spec.executables = ["comer_de_tapas"]
|
|
22
|
+
spec.test_files = Dir.glob("test/**/*")
|
|
23
|
+
spec.require_paths = ["lib"]
|
|
24
|
+
|
|
25
|
+
spec.add_dependency "thor"
|
|
26
|
+
spec.add_dependency "http", ">= 0.6"
|
|
27
|
+
spec.add_dependency "nokogiri"
|
|
28
|
+
spec.add_dependency "celluloid-io"
|
|
29
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
|
|
3
|
+
module ComerDeTapas
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
def initialize(*)
|
|
6
|
+
@client = Client.new
|
|
7
|
+
super
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
desc 'version', 'Show version'
|
|
11
|
+
def version
|
|
12
|
+
say VERSION
|
|
13
|
+
end
|
|
14
|
+
map %w[-v --version] => :version
|
|
15
|
+
|
|
16
|
+
desc 'init', 'Create config folder and files'
|
|
17
|
+
def init
|
|
18
|
+
@client.init!
|
|
19
|
+
say 'Please fill in your subscription info in ~/.rubytapas/.credentials'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# -f, --force, options[:force] => true, otherwise nil.
|
|
23
|
+
desc 'download', 'Download RubyTapas episodes'
|
|
24
|
+
method_option 'force', :aliases => '-f', type: :boolean, desc: 'Force download.'
|
|
25
|
+
def download
|
|
26
|
+
@client.fetch_episodes!(options[:force])
|
|
27
|
+
@client.prepare_save_folder!
|
|
28
|
+
@client.authenticate
|
|
29
|
+
@client.load_episodes
|
|
30
|
+
@client.download_all_tapas!
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
require 'http'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
module ComerDeTapas
|
|
7
|
+
class Client
|
|
8
|
+
|
|
9
|
+
# Initialize comer de tapas
|
|
10
|
+
# $ mkdir -p ~/.rubytapas/
|
|
11
|
+
# $ touch ~/.rubytapas/.credentials
|
|
12
|
+
def init!
|
|
13
|
+
if File.exist?(RUBYTAPAS_DIR) && File.exist?(CREDENTIAL_FILE)
|
|
14
|
+
abort 'Credentials found. type `comer_de_tapas download` to download.'
|
|
15
|
+
end
|
|
16
|
+
create_rubytapas_files!
|
|
17
|
+
puts '~/.rubytapas/.credentials folder and file has been created.'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Fetch latest feed on rubytapas.dpdcart.com
|
|
21
|
+
# Parse it to episode, save episodes data as json to ~/.rubytapas.json
|
|
22
|
+
def fetch_episodes! force=nil
|
|
23
|
+
return puts 'Use cached episode data.' if fresh? && force.nil?
|
|
24
|
+
puts 'Fetching episodes...'
|
|
25
|
+
get_feed_with_basic_auth
|
|
26
|
+
save_feed_data parse_xml_feed
|
|
27
|
+
puts 'Episodes successfully fetched.'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Create user specified folder: credentials[:save_path]
|
|
31
|
+
def prepare_save_folder!
|
|
32
|
+
return puts "#{save_folder} found." if File.exist? save_folder
|
|
33
|
+
|
|
34
|
+
FileUtils.mkdir_p save_folder.expand_path
|
|
35
|
+
puts "#{save_folder} created."
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Authenticate and return Cookie
|
|
39
|
+
def authenticate
|
|
40
|
+
@cookie ||= HTTP.post(LOGIN_URL, form_params).headers['Set-Cookie']
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Load episodes json from EPISODES_JSON_FILE
|
|
44
|
+
def load_episodes
|
|
45
|
+
@episodes ||= JSON.parse(File.read EPISODES_JSON_FILE)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# User spefified folder to save episodes.
|
|
49
|
+
# @return [Pathname]
|
|
50
|
+
def save_folder
|
|
51
|
+
Pathname credentials[:save_path]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Download episode in parallel using Actors
|
|
55
|
+
# Powered by Celluloid::IO
|
|
56
|
+
def download_all_tapas!
|
|
57
|
+
episodes.each do |episode|
|
|
58
|
+
FileUtils.cd(save_folder.expand_path) do
|
|
59
|
+
episode_title = episode['title']
|
|
60
|
+
puts "Downloading Epsiode #{episode_title}..."
|
|
61
|
+
|
|
62
|
+
episode_folder = save_folder.join(sanitized episode_title).expand_path
|
|
63
|
+
|
|
64
|
+
FileUtils.mkdir_p episode_folder unless File.exist? episode_folder
|
|
65
|
+
|
|
66
|
+
FileUtils.cd episode_folder do
|
|
67
|
+
fetcher = Fetcher.new
|
|
68
|
+
file_and_links = episode['links']
|
|
69
|
+
downloadables = find_downloadables file_and_links
|
|
70
|
+
|
|
71
|
+
if downloadables.all? &:nil?
|
|
72
|
+
puts 'Already downloaded, skip.'
|
|
73
|
+
next
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
download_parallelly! downloadables
|
|
77
|
+
puts "Episode #{episode_title} content all saved."
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
attr_reader :feed_xml, :cookie, :episodes
|
|
86
|
+
|
|
87
|
+
# Download episode all attachments
|
|
88
|
+
# compact to remove attachment that already downloaded
|
|
89
|
+
# @param [Array] downloadables
|
|
90
|
+
def download_parallelly! downloadables
|
|
91
|
+
downloadables.compact.each do |file, future|
|
|
92
|
+
response = future.value.to_s
|
|
93
|
+
puts "Downloading #{file}..."
|
|
94
|
+
IO.write file, response
|
|
95
|
+
puts "#{file} saved."
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Find episode's attachment that has not been downloaded
|
|
100
|
+
# @param [Array] file_and_links
|
|
101
|
+
def find_downloadables file_and_links
|
|
102
|
+
file_and_links.map do |file_and_link|
|
|
103
|
+
next if File.exist? file_and_link['filename']
|
|
104
|
+
|
|
105
|
+
q, v = file_and_link['link'].split('?').last.split('=')
|
|
106
|
+
[file_and_link['filename'], fetcher.future.fetch(DOWNLOAD_URL, cookie, { q => v })]
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# mkdir -p ~/.rubytapas
|
|
111
|
+
# touch ~/.rubytapas/.credentials
|
|
112
|
+
def create_rubytapas_files!
|
|
113
|
+
FileUtils.mkdir_p RUBYTAPAS_DIR
|
|
114
|
+
FileUtils.touch CREDENTIAL_FILE
|
|
115
|
+
IO.write CREDENTIAL_FILE, credential_template
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Use to create empty credential file
|
|
119
|
+
def credential_template
|
|
120
|
+
require 'yaml'
|
|
121
|
+
{"credentials"=>[{"email"=>nil}, {"password"=>nil}, {"save_path"=>nil}]}.to_yaml
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Get raw feed data (XML), RSS
|
|
125
|
+
def get_feed_with_basic_auth
|
|
126
|
+
puts 'Authorizing...'
|
|
127
|
+
@feed_xml = HTTP.auth(:basic, authenticate_params).get(FEED_URL).body.to_s
|
|
128
|
+
puts 'Authroized.'
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Params for basic authentication
|
|
132
|
+
def authenticate_params
|
|
133
|
+
{ user: credentials[:email], pass: credentials[:password] }
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# RubyTapas subscription credentials (~/.rubytapas/.credentials)
|
|
137
|
+
# @return [Hash]
|
|
138
|
+
def credentials
|
|
139
|
+
Subscription.new.to_h
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Parse raw feed data (XML), retrive episode's title and links.
|
|
143
|
+
# @return [Array<Hash>]
|
|
144
|
+
def parse_xml_feed
|
|
145
|
+
puts 'Parsing Episodes...'
|
|
146
|
+
require 'nokogiri'
|
|
147
|
+
items = Nokogiri::XML(feed_xml).xpath('//item')
|
|
148
|
+
|
|
149
|
+
epsiode_data = items.map do |item|
|
|
150
|
+
children = item.children
|
|
151
|
+
|
|
152
|
+
title = (children / 'title').first.child.content
|
|
153
|
+
description = (children / 'description').first.child.content
|
|
154
|
+
|
|
155
|
+
links = Nokogiri::HTML(description).css('ul li a')
|
|
156
|
+
|
|
157
|
+
{ title: title, links: attachments(links) }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
puts 'Episodes parsed successfully.'
|
|
161
|
+
|
|
162
|
+
return epsiode_data
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Given links, parse to
|
|
166
|
+
# { filename: "123.rb", "/subscriber/download?file_id=34567" }
|
|
167
|
+
# @return [Array<Hash>]
|
|
168
|
+
def attachments links
|
|
169
|
+
links.each_with_object([]) do |link, episode|
|
|
170
|
+
if link['href'] =~ /rubytapas.dpdcart.com\/subscriber\/download/
|
|
171
|
+
episode << { filename: link.content, link: link['href'].gsub(/#{BASE_URL}/, '') }
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Write episodes data to ~/.rubytapas/episodes.json
|
|
177
|
+
def save_feed_data feed
|
|
178
|
+
puts 'Saving episodes data to ~/.rubytapas/episodes.json...'
|
|
179
|
+
IO.write EPISODES_JSON_FILE, feed.to_json
|
|
180
|
+
puts 'Saved.'
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Return each episode's folder name
|
|
184
|
+
def sanitized title
|
|
185
|
+
dasherize_file_name(title)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Before: 999 Array.first, Foo::Bar, Class<<self
|
|
189
|
+
# After: 999-array-first-foo-bar-class<<self
|
|
190
|
+
def dasherize_file_name file_name
|
|
191
|
+
file_name.downcase.gsub('<', '<').gsub(/[^\w<>#?!$]+/, '-')
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Form params to post for HTTP
|
|
195
|
+
# @return [Hash]
|
|
196
|
+
def form_params
|
|
197
|
+
{ form: { username: credentials[:email], password: credentials[:password] } }
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# If the episodes json was made of 259_200.seconds.ago (3 days)
|
|
201
|
+
# @return [Boolean] true if episodes.json creation time < 3 days
|
|
202
|
+
def fresh?
|
|
203
|
+
return false unless File.exist? EPISODES_JSON_FILE
|
|
204
|
+
Time.now - File.ctime(EPISODES_JSON_FILE) < 259_200
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
3
|
+
module ComerDeTapas
|
|
4
|
+
BASE_URL = 'https://rubytapas.dpdcart.com'
|
|
5
|
+
DOWNLOAD_URL = BASE_URL + '/subscriber/download'
|
|
6
|
+
LOGIN_URL = BASE_URL + '/subscriber/login'
|
|
7
|
+
FEED_URL = BASE_URL + '/feed'
|
|
8
|
+
|
|
9
|
+
RUBYTAPAS_DIR = Pathname.new(ENV['HOME']).join('.rubytapas')
|
|
10
|
+
EPISODES_JSON_FILE = RUBYTAPAS_DIR.join('episodes.json')
|
|
11
|
+
CREDENTIAL_FILE = RUBYTAPAS_DIR.join('.credentials')
|
|
12
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'celluloid/io'
|
|
2
|
+
|
|
3
|
+
module ComerDeTapas
|
|
4
|
+
class Fetcher
|
|
5
|
+
include Celluloid::IO
|
|
6
|
+
|
|
7
|
+
# Fetch url with given cookie, and query string (optional)
|
|
8
|
+
# @param [String] url
|
|
9
|
+
# @param cookie
|
|
10
|
+
# @option query [Hash]
|
|
11
|
+
def fetch url, cookie, query={}
|
|
12
|
+
require 'http'
|
|
13
|
+
HTTP.with('Cookie' => cookie).get(url, ssl_socket_class: Celluloid::IO::SSLSocket, params: query)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module ComerDeTapas
|
|
2
|
+
class Subscription
|
|
3
|
+
CredentialYamlNotExist = Class.new StandardError
|
|
4
|
+
CredentialYamlKeyError = Class.new StandardError
|
|
5
|
+
CredentialYamlValueError = Class.new StandardError
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
raise CredentialYamlNotExist, 'Please run `comer_de_tapas init` first' unless File.exist? CREDENTIAL_FILE
|
|
9
|
+
|
|
10
|
+
set_subscription_data if subscription_data_valid?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @return [Hash] User's Ruby Tapas credential information
|
|
14
|
+
def to_h
|
|
15
|
+
{ email: email, password: password, save_path: save_path }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
attr_reader :email, :password, :save_path
|
|
21
|
+
|
|
22
|
+
# Load ~/.rubytapas/.credentials yaml
|
|
23
|
+
def load_credential_data
|
|
24
|
+
require 'yaml'
|
|
25
|
+
@credential_yaml ||= YAML.load_file CREDENTIAL_FILE
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Check if ~/.rubytapas/.credentials files are filled and corrected.
|
|
29
|
+
def subscription_data_valid?
|
|
30
|
+
# empty credential file's size is about 50-55.
|
|
31
|
+
# 65 is when you have a very short email, password, and save_path.
|
|
32
|
+
# So when you filled in data, probably will > 65.
|
|
33
|
+
if File.size(CREDENTIAL_FILE) < 65
|
|
34
|
+
puts "Did you fill in your subscription data in #{CREDENTIAL_FILE}?"
|
|
35
|
+
return false
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
credential_data_valid?(get_validate load_credential_data)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Check if credential data valid?
|
|
42
|
+
def credential_data_valid? data
|
|
43
|
+
data.each do |hash|
|
|
44
|
+
hash.each do |k,v|
|
|
45
|
+
raise CredentialYamlKeyError, "Valid yaml keys: #{KEYS.join(' ,')}." unless %w(email password save_path).include? k
|
|
46
|
+
raise CredentialYamlValueError, "Please fill value for this one: #{k}" if v.nil?
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
return true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Get credential data from loaded yaml for validation.
|
|
54
|
+
def get_validate data
|
|
55
|
+
data.values.flatten
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Set subscription data from ~/.rubytapas/.credentials yaml
|
|
59
|
+
def set_subscription_data
|
|
60
|
+
@email ||= load_credential_data['credentials'][0]['email']
|
|
61
|
+
@password ||= load_credential_data['credentials'][1]['password']
|
|
62
|
+
@save_path ||= load_credential_data['credentials'][2]['save_path']
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
data/test/cli_test.rb
ADDED
data/test/client_test.rb
ADDED
data/test/test_helper.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: comer_de_tapas
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Juanito Fatas
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-06-16 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: thor
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: http
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0.6'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0.6'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: nokogiri
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: celluloid-io
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
description: Ruby Tapas Episode Downloader.
|
|
70
|
+
email:
|
|
71
|
+
- katehuang0320@gmail.com
|
|
72
|
+
executables:
|
|
73
|
+
- comer_de_tapas
|
|
74
|
+
extensions: []
|
|
75
|
+
extra_rdoc_files: []
|
|
76
|
+
files:
|
|
77
|
+
- CONTRIBUTING.md
|
|
78
|
+
- DEVELOPMENT.md
|
|
79
|
+
- LICENSE
|
|
80
|
+
- README.md
|
|
81
|
+
- Rakefile
|
|
82
|
+
- bin/comer_de_tapas
|
|
83
|
+
- comer_de_tapas.gemspec
|
|
84
|
+
- lib/comer_de_tapas.rb
|
|
85
|
+
- lib/comer_de_tapas/cli.rb
|
|
86
|
+
- lib/comer_de_tapas/client.rb
|
|
87
|
+
- lib/comer_de_tapas/constants.rb
|
|
88
|
+
- lib/comer_de_tapas/fetcher.rb
|
|
89
|
+
- lib/comer_de_tapas/subscription.rb
|
|
90
|
+
- lib/comer_de_tapas/version.rb
|
|
91
|
+
- test/cli_test.rb
|
|
92
|
+
- test/client_test.rb
|
|
93
|
+
- test/fetcher_test.rb
|
|
94
|
+
- test/subscription_test.rb
|
|
95
|
+
- test/test_helper.rb
|
|
96
|
+
homepage: https://github.com/juanitofatas/comer_de_tapas
|
|
97
|
+
licenses:
|
|
98
|
+
- MIT
|
|
99
|
+
metadata: {}
|
|
100
|
+
post_install_message:
|
|
101
|
+
rdoc_options: []
|
|
102
|
+
require_paths:
|
|
103
|
+
- lib
|
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
105
|
+
requirements:
|
|
106
|
+
- - ">="
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: '0'
|
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
|
+
requirements:
|
|
111
|
+
- - ">="
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: '0'
|
|
114
|
+
requirements: []
|
|
115
|
+
rubyforge_project:
|
|
116
|
+
rubygems_version: 2.3.0
|
|
117
|
+
signing_key:
|
|
118
|
+
specification_version: 4
|
|
119
|
+
summary: Ruby Tapas Episode Downloader.
|
|
120
|
+
test_files:
|
|
121
|
+
- test/cli_test.rb
|
|
122
|
+
- test/client_test.rb
|
|
123
|
+
- test/fetcher_test.rb
|
|
124
|
+
- test/subscription_test.rb
|
|
125
|
+
- test/test_helper.rb
|
|
126
|
+
has_rdoc:
|