wwdcdownloader 20.13.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.
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "https://rubygems.org"
2
+
3
+ # If you make any changes in this file, please run `bundle install`.
4
+ # If new versions of your installed gems are available, run `bundle update`
5
+
6
+ gem "mechanize", "~> 2.7.1"
7
+ gem "json", "~> 1.8.0"
8
+ gem "highline", "~> 1.6.19"
9
+ gem "nokogiri", "~> 1.5.0"
10
+
11
+ group :development do
12
+ #gem "shoulda", ">= 0"
13
+ gem "bundler", "~> 1.0.0"
14
+ gem "jeweler", "~> 1.8.0"
15
+ gem "rcov", ">= 0"
16
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,49 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ domain_name (0.5.12)
5
+ unf (>= 0.0.5, < 1.0.0)
6
+ git (1.2.5)
7
+ highline (1.6.19)
8
+ http-cookie (1.0.1)
9
+ domain_name (~> 0.5)
10
+ jeweler (1.8.4)
11
+ bundler (~> 1.0)
12
+ git (>= 1.2.5)
13
+ rake
14
+ rdoc
15
+ json (1.8.0)
16
+ mechanize (2.7.1)
17
+ domain_name (~> 0.5, >= 0.5.1)
18
+ http-cookie (~> 1.0.0)
19
+ mime-types (~> 1.17, >= 1.17.2)
20
+ net-http-digest_auth (~> 1.1, >= 1.1.1)
21
+ net-http-persistent (~> 2.5, >= 2.5.2)
22
+ nokogiri (~> 1.4)
23
+ ntlm-http (~> 0.1, >= 0.1.1)
24
+ webrobots (>= 0.0.9, < 0.2)
25
+ mime-types (1.23)
26
+ net-http-digest_auth (1.3)
27
+ net-http-persistent (2.8)
28
+ nokogiri (1.5.10)
29
+ ntlm-http (0.1.1)
30
+ rake (10.0.4)
31
+ rcov (0.9.9)
32
+ rdoc (4.0.1)
33
+ json (~> 1.4)
34
+ unf (0.1.1)
35
+ unf_ext
36
+ unf_ext (0.0.6)
37
+ webrobots (0.1.1)
38
+
39
+ PLATFORMS
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ bundler (~> 1.0.0)
44
+ highline (~> 1.6.19)
45
+ jeweler (~> 1.8.0)
46
+ json (~> 1.8.0)
47
+ mechanize (~> 2.7.1)
48
+ nokogiri (~> 1.5.0)
49
+ rcov
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Johannes Fahrenkrug
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "wwdcdownloader"
16
+ gem.homepage = "https://github.com/jfahrenkrug/WWDC-Downloader"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{A small tool to download all the sample code of Apple's latest WWDC developer conference}
19
+ gem.description = %Q{At each year's WWDC, Apple releases great sample projects. Unfortunately it is very tedious to manually download all these treasures through your browser. WWDC-Downloader solves this problem for you!}
20
+ gem.email = "johannes@springenwerk.com"
21
+ gem.authors = ["Johannes Fahrenkrug"]
22
+
23
+ # dependencies defined in Gemfile
24
+ end
25
+ Jeweler::RubygemsDotOrgTasks.new
data/Readme.md ADDED
@@ -0,0 +1,22 @@
1
+ # WWDC 2013 Sample Code Downloader
2
+
3
+ ![First World WWDC Sample Code Problem](http://cdn.memegenerator.net/instances/400x/21928207.jpg)
4
+
5
+ ## Sad days are over
6
+
7
+ This script will download all the session material for you if you are a WWDC 2013 attendee OR NOT! This year you only need to have an Apple Developer account, that's it!
8
+ You can now simply install WWDC-Downloader as a ruby gem like this:
9
+
10
+ gem install wwdcdownloader
11
+
12
+ or
13
+
14
+ sudo gem install wwdcdownloader
15
+
16
+ Run the script like this:
17
+
18
+ wwdcdownloader <your Apple ID> [<target-dir>]
19
+
20
+ The script will create a directory called "wwdc2013-assets" (or <target-dir> if given) in the directory you run the script from.
21
+
22
+ That's it. Enjoy and see you next year.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 20.13.0
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'wwdcdownloader.rb'
4
+
5
+ exit WWDCDownloader.run!(*ARGV)
6
+
@@ -0,0 +1,240 @@
1
+ # Have fun. Use at your own risk.
2
+ # Copyright (c) 2013 Johannes Fahrenkrug
3
+
4
+ require 'rubygems'
5
+ require 'fileutils'
6
+ require 'net/http'
7
+
8
+ begin
9
+ require 'mechanize'
10
+ require 'json'
11
+ require 'highline/import'
12
+ rescue LoadError => e
13
+ puts
14
+ puts "You need to have the mechanize, json and highline gems installed."
15
+ puts "Install them by running"
16
+ puts
17
+ puts " bundle install"
18
+ puts
19
+ puts "and then run the script like this:"
20
+ puts
21
+ puts " bundle exec ruby lib/wwdcdownloader.rb"
22
+ puts
23
+ exit
24
+ end
25
+
26
+ class WWDCDownloader
27
+ BASE_URI = 'https://developer.apple.com/wwdc-services/cy4p09ns/a4363cb15472b00287b/sessions.json'
28
+
29
+ WWDC_LIBRARIES = [{:base => 'https://developer.apple.com/library/prerelease/ios', :lib => '/navigation/library.json'},
30
+ {:base => 'https://developer.apple.com/library/prerelease/mac', :lib => '/navigation/library.json'}]
31
+
32
+ attr_accessor :downloaded_files, :dl_dir, :mech, :min_date
33
+
34
+ def initialize(dl_dir, min_date)
35
+ self.dl_dir = dl_dir
36
+ self.min_date = min_date
37
+ self.mech = Mechanize.new
38
+ self.downloaded_files = []
39
+ end
40
+
41
+ # Creates the given directory if it doesn't exist already.
42
+ def mkdir(dir)
43
+ if File.exists?(dir)
44
+ false
45
+ else
46
+ Dir.mkdir dir
47
+ true
48
+ end
49
+ end
50
+
51
+ # Login
52
+ def login
53
+ wrong_password = true
54
+
55
+ while wrong_password do
56
+ password = ask("Enter your ADC password: ") { |q| q.echo = "*" }
57
+
58
+ self.mech.get('https://developer.apple.com/wwdc/videos/') do |page|
59
+ my_page = page.form_with(:name => 'appleConnectForm') do |f|
60
+ f.theAccountName = ARGV[0]
61
+ f.theAccountPW = password
62
+ end.click_button
63
+
64
+ if my_page.body =~ /incorrect/
65
+ puts "Wrong password, please try again."
66
+ else
67
+ wrong_password = false
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def download_sample_code_from_book_json(book_json_url, code_base_url, dest_dir, duplicates_ok)
74
+ did_download = false
75
+ self.mech.get(book_json_url) do |book_json|
76
+ if book_json.body[0,1] == '<'
77
+ puts " Sorry, this samplecode apparently isn't available yet: #{code_base_url}/book.json"
78
+ else
79
+ book_res = JSON.parse(book_json.body)
80
+ filename = book_res["sampleCode"]
81
+ url = "#{code_base_url}/#{filename}"
82
+
83
+ if duplicates_ok or !self.downloaded_files.include?(url)
84
+ # remember what we downloaded
85
+ self.downloaded_files << url
86
+
87
+ puts " Downloading #{url}"
88
+ begin
89
+ self.mech.get(url) do |downloaded_file|
90
+ open(dest_dir + "/" + filename, 'wb') do |file|
91
+ file.write(downloaded_file.body)
92
+ end
93
+ did_download = true
94
+ end
95
+ rescue Exception => e
96
+ puts " Download failed #{e}"
97
+ end
98
+ elsif !duplicates_ok
99
+ puts " Already downloaded this file, skipping."
100
+ end
101
+ end
102
+ end
103
+
104
+ did_download
105
+ end
106
+
107
+ def download_sample_code_for_page(a_page_url, dest_dir, duplicates_ok = true)
108
+ self.mech.get(a_page_url) do |page|
109
+ has_samplecode = false
110
+ page.links_with(:href => %r{/samplecode/} ).each do |link|
111
+ has_samplecode = true
112
+ code_base_url = File.dirname(link.href)
113
+
114
+ download_sample_code_from_book_json("#{code_base_url}/book.json", code_base_url, dest_dir, duplicates_ok)
115
+ end
116
+
117
+ if !has_samplecode
118
+ puts " Sorry, this session doesn't have samplecode, cleaning up."
119
+ begin
120
+ Dir.delete( dest_dir )
121
+ rescue
122
+ end
123
+ end
124
+
125
+ end
126
+ end
127
+
128
+ def load
129
+ mkdir(dl_dir)
130
+
131
+ # get the sessions JSON
132
+ self.mech.get(BASE_URI) do |page|
133
+ res = JSON.parse(page.body)
134
+
135
+ # Was there an error?
136
+ error = res['response']['error']
137
+
138
+ if (error)
139
+ STDERR.puts " Apple's API returned an error: '#{error}'"
140
+ exit
141
+ end
142
+
143
+ sessions = res['response']['sessions']
144
+
145
+ if sessions.size > 0
146
+
147
+ sessions.each do |session|
148
+ if session['type'] == 'Session'
149
+ title = session['title']
150
+ session_id = session['id']
151
+ puts "Session #{session_id} '#{title}'..."
152
+
153
+ # get the files
154
+ dirname = "#{dl_dir}/#{session_id}-#{title.gsub(/\/|&|!/, '')}"
155
+ puts " Creating #{dirname}"
156
+ mkdir(dirname)
157
+
158
+ begin
159
+ download_sample_code_for_page(session['url'], dirname)
160
+ rescue Mechanize::ResponseCodeError => e
161
+ STDERR.puts " Error retrieving list for session. Proceeding with next session (#{$!})"
162
+ next
163
+ end
164
+ end
165
+ end
166
+ else
167
+ print "No sessions :(.\n"
168
+ end
169
+ end
170
+
171
+ # scrape the WWDC libraries...
172
+ puts
173
+ puts "Scraping the WWDC libraries (not all sample code might be linked up correctly yet)"
174
+ WWDC_LIBRARIES.each do |lib_hash|
175
+ lib = "#{lib_hash[:base]}#{lib_hash[:lib]}"
176
+ self.mech.get(lib) do |page|
177
+ body = page.body.gsub("''", '""')
178
+ res = JSON.parse(body)
179
+
180
+ docs = res['documents']
181
+
182
+ if docs.size > 0
183
+
184
+ docs.each do |doc|
185
+ if doc[2] == 5 and doc[3] >= self.min_date # sample code and newer or equal to min date
186
+ title = doc[0]
187
+
188
+ puts "Sample Code '#{title}'..."
189
+
190
+ # get the files
191
+ dirname = "#{dl_dir}/#{title.gsub(/\/|&|!/, '')}"
192
+ puts " Creating #{dirname}"
193
+ did_create_dir = mkdir(dirname)
194
+
195
+ segments = doc[9].split('/')
196
+ url = "#{lib_hash[:base]}/samplecode/#{segments[2]}/book.json"
197
+
198
+ begin
199
+ puts url
200
+ did_download = download_sample_code_from_book_json(url, "#{lib_hash[:base]}/samplecode/#{segments[2]}", dirname, false)
201
+ if !did_download and did_create_dir
202
+ Dir.delete( dirname )
203
+ end
204
+ rescue Mechanize::ResponseCodeError => e
205
+ STDERR.puts " Error retrieving list for sample code. Proceeding with next one (#{$!})"
206
+ next
207
+ end
208
+ end
209
+ end
210
+ else
211
+ print "No code samples :(.\n"
212
+ end
213
+ end
214
+ end
215
+
216
+ puts "Done."
217
+ end
218
+
219
+ def self.run!(*args)
220
+ puts "WWDC 2013 Session Material Downloader"
221
+ puts "by Johannes Fahrenkrug, @jfahrenkrug, springenwerk.com"
222
+ puts "See you next year!"
223
+ puts
224
+
225
+ if args.size < 1
226
+ puts "Usage: wwdcdownloader <your Apple ID> [<target-dir>]"
227
+ exit
228
+ end
229
+
230
+ dl_dir = if args.size > 1
231
+ args.last
232
+ else
233
+ 'wwdc2013-assets'
234
+ end
235
+
236
+ w = WWDCDownloader.new(dl_dir, '2013-06-10')
237
+ w.login
238
+ w.load
239
+ end
240
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wwdcdownloader
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 20
7
+ - 13
8
+ - 0
9
+ version: 20.13.0
10
+ platform: ruby
11
+ authors:
12
+ - Johannes Fahrenkrug
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2013-06-12 00:00:00 +02:00
18
+ default_executable: wwdcdownloader
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ prerelease: false
22
+ type: :runtime
23
+ name: mechanize
24
+ version_requirements: &id001 !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 2
30
+ - 7
31
+ - 1
32
+ version: 2.7.1
33
+ requirement: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ prerelease: false
36
+ type: :runtime
37
+ name: json
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 1
44
+ - 8
45
+ - 0
46
+ version: 1.8.0
47
+ requirement: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ prerelease: false
50
+ type: :runtime
51
+ name: highline
52
+ version_requirements: &id003 !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 1
58
+ - 6
59
+ - 19
60
+ version: 1.6.19
61
+ requirement: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ prerelease: false
64
+ type: :runtime
65
+ name: nokogiri
66
+ version_requirements: &id004 !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 1
72
+ - 5
73
+ - 0
74
+ version: 1.5.0
75
+ requirement: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ prerelease: false
78
+ type: :development
79
+ name: bundler
80
+ version_requirements: &id005 !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ~>
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 1
86
+ - 0
87
+ - 0
88
+ version: 1.0.0
89
+ requirement: *id005
90
+ - !ruby/object:Gem::Dependency
91
+ prerelease: false
92
+ type: :development
93
+ name: jeweler
94
+ version_requirements: &id006 !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ~>
97
+ - !ruby/object:Gem::Version
98
+ segments:
99
+ - 1
100
+ - 8
101
+ - 0
102
+ version: 1.8.0
103
+ requirement: *id006
104
+ - !ruby/object:Gem::Dependency
105
+ prerelease: false
106
+ type: :development
107
+ name: rcov
108
+ version_requirements: &id007 !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ segments:
113
+ - 0
114
+ version: "0"
115
+ requirement: *id007
116
+ description: At each year's WWDC, Apple releases great sample projects. Unfortunately it is very tedious to manually download all these treasures through your browser. WWDC-Downloader solves this problem for you!
117
+ email: johannes@springenwerk.com
118
+ executables:
119
+ - wwdcdownloader
120
+ extensions: []
121
+
122
+ extra_rdoc_files:
123
+ - LICENSE.txt
124
+ files:
125
+ - Gemfile
126
+ - Gemfile.lock
127
+ - LICENSE.txt
128
+ - Rakefile
129
+ - Readme.md
130
+ - VERSION
131
+ - bin/wwdcdownloader
132
+ - lib/wwdcdownloader.rb
133
+ has_rdoc: true
134
+ homepage: https://github.com/jfahrenkrug/WWDC-Downloader
135
+ licenses:
136
+ - MIT
137
+ post_install_message:
138
+ rdoc_options: []
139
+
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ segments:
147
+ - 0
148
+ version: "0"
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ segments:
154
+ - 0
155
+ version: "0"
156
+ requirements: []
157
+
158
+ rubyforge_project:
159
+ rubygems_version: 1.3.6
160
+ signing_key:
161
+ specification_version: 3
162
+ summary: A small tool to download all the sample code of Apple's latest WWDC developer conference
163
+ test_files: []
164
+