kandianying 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/kandianying.gemspec +1 -0
  3. data/lib/kandianying/ambassador.rb +11 -36
  4. data/lib/kandianying/ambassador_scrape.rb +48 -0
  5. data/lib/kandianying/{vieshow_search.rb → search.rb} +2 -2
  6. data/lib/kandianying/version.rb +2 -2
  7. data/lib/kandianying/vieshow.rb +2 -2
  8. data/spec/ambassador_spec.rb +48 -7
  9. data/spec/fixtures/ambassador_name_38897fa9-094f-4e63-9d6d-c52408438cb6.yml +2 -5
  10. data/spec/fixtures/ambassador_name_5c2d4697-7f54-4955-800c-7b3ad782582c.yml +9 -0
  11. data/spec/fixtures/ambassador_table_38897fa9-094f-4e63-9d6d-c52408438cb6.yml +130 -67
  12. data/spec/fixtures/ambassador_table_5c2d4697-7f54-4955-800c-7b3ad782582c.yml +304 -0
  13. data/spec/fixtures/vcr_cassettes/ambassador_name_38897fa9-094f-4e63-9d6d-c52408438cb6.yml +1456 -8515
  14. data/spec/fixtures/vcr_cassettes/ambassador_name_5c2d4697-7f54-4955-800c-7b3ad782582c.yml +2609 -0
  15. data/spec/fixtures/vcr_cassettes/ambassador_table_38897fa9-094f-4e63-9d6d-c52408438cb6.yml +1456 -8515
  16. data/spec/fixtures/vcr_cassettes/ambassador_table_5c2d4697-7f54-4955-800c-7b3ad782582c.yml +2609 -0
  17. data/spec/fixtures/vcr_cassettes/vieshow_name_05.yml +221 -167
  18. data/spec/fixtures/vcr_cassettes/vieshow_name_12.yml +174 -127
  19. data/spec/fixtures/vcr_cassettes/vieshow_table_05.yml +221 -167
  20. data/spec/fixtures/vcr_cassettes/vieshow_table_12.yml +174 -127
  21. data/spec/fixtures/vieshow_name_05.yml +7 -11
  22. data/spec/fixtures/vieshow_name_12.yml +5 -6
  23. data/spec/fixtures/vieshow_table_05.yml +414 -279
  24. data/spec/fixtures/vieshow_table_12.yml +334 -237
  25. data/spec/support/vcr_setup.rb +15 -0
  26. data/spec/vieshow_spec.rb +1 -12
  27. metadata +26 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9c8543cbbbdef138447df2a0c72440176f541236
4
- data.tar.gz: 3e54ddd7955b093e1f6141604c07eda379f49dd1
3
+ metadata.gz: d16fe1b8b27ad6f575ed6e12b92e244dd64c4402
4
+ data.tar.gz: ac70497b5450250a5d9ad9a5e3c3ad19b0802fe0
5
5
  SHA512:
6
- metadata.gz: a71a2984902e8c134f41742a95ef0f573c7fbdb4304395802c2a7444289d54f58cd244bbf4c92457b6402750ca9f65ba0583e2a523f3bf2cd5a07cc2111848f9
7
- data.tar.gz: 2fa04974fd39eaca35e50b42d19dc00bcb57bc9ca8d800070456908ca5aec840807414c1ac76dc2082b89e115a40209ab57c6d837bf1c19a0b5277706f1d61e2
6
+ metadata.gz: 6837f76db4416653311efa7dc798e13acb18f54f75a0274c7a6ed91ad1f0dfcba029fcf0871bd01c0f9d40b020ee4310a612a6791a2050cf460726118313d832
7
+ data.tar.gz: 4765e731a2c172515b740650bb60338460470dec84b688ab489ff0015f04d81a0a0037db3e987607c745b21085d820964c6559fa62fd8607a0a2b7c995afd4cd
@@ -21,4 +21,5 @@ Gem::Specification.new do |s|
21
21
  s.add_development_dependency 'vcr'
22
22
  s.add_development_dependency 'webmock'
23
23
  s.add_runtime_dependency 'nokogiri'
24
+ s.add_runtime_dependency 'concurrent-ruby'
24
25
  end
@@ -2,55 +2,30 @@ require 'open-uri'
2
2
  require 'nokogiri'
3
3
  require 'json'
4
4
  require 'yaml'
5
+ require 'concurrent'
6
+ require_relative 'ambassador_scrape'
7
+ require_relative 'search'
5
8
 
6
9
  # Scraper for Ambassador
7
10
  module Ambassador
8
- AMBASSADOR_THEATER_ID_URL = 'http://www.ambassador.com.tw/showtime_list.html'
9
- AMBASSADOR_THEATER_ID_XPATH = "//*[@class='list-group sidebar-nav-v1']//li//a"
10
- AMBASSADOR_TIME_API = 'http://cinemaservice.ambassador.com.tw/ambassadorsite.webapi/api/Movies/GetScreeningDateListForTheater/?'
11
- AMBASSADOR_FILM_API = 'http://cinemaservice.ambassador.com.tw/ambassadorsite.webapi/api/Movies/GetShowtimeListForTheater/?'
12
11
  # Class for Vieshow films
13
12
  class Ambassador
14
- attr_reader :movie_table
15
- attr_reader :theater_id_table
16
- def initialize
13
+ include AmbassadorScrape, Search
14
+ attr_reader :movie_table, :theater_id_table, :cinema_name
15
+
16
+ def initialize(id)
17
17
  @movie_table = {}
18
18
  @theater_id_table = fetch_theater_id_table(AMBASSADOR_THEATER_ID_URL)
19
19
  theater_id_table.each do |theater_id, theater_name|
20
+ next unless theater_id.include? id
20
21
  date_list = fetch_theater_date(theater_id)
22
+ @cinema_name = theater_name
21
23
  @movie_table[theater_name] = fetch_movie_info(theater_id, date_list)
22
24
  end
23
25
  end
24
26
 
25
- def fetch_movie_info(theater_id, date_list)
26
- movie_info = Hash.new { |h, k| h[k] = {} }
27
- date_list.each do |date|
28
- ur = "#{AMBASSADOR_FILM_API}theaterId=#{theater_id}&showingDate=#{date}"
29
- movies = JSON.parse(Nokogiri::HTML(open(ur)).text)
30
- movies.each do |movie|
31
- name = movie['ForeignName']
32
- time = movie['PeriodShowtime'].first['Showtimes']
33
- movie_info[name][date] = time
34
- end
35
- end
36
- movie_info
37
- end
38
-
39
- def fetch_theater_date(theater_id)
40
- url = "#{AMBASSADOR_TIME_API}theaterId=#{theater_id}"
41
- JSON.parse(Nokogiri::HTML(open(url)).text)
42
- end
43
-
44
- def fetch_theater_id_table(url)
45
- theater_id_list = {}
46
- open_doc = Nokogiri::HTML(open(url))
47
- theater = open_doc.xpath(AMBASSADOR_THEATER_ID_XPATH)
48
- theater.each do |t|
49
- theater_id = t.attributes['href'].value.split("'")[1]
50
- theater_name = t.text
51
- theater_id_list[theater_id] = theater_name
52
- end
53
- theater_id_list
27
+ def movie_names
28
+ @movie_table.values[0].keys
54
29
  end
55
30
 
56
31
  def to_json
@@ -0,0 +1,48 @@
1
+ # Helper module to get data from Ambassador
2
+ module AmbassadorScrape
3
+ AMBASSADOR_THEATER_ID_URL = 'http://www.ambassador.com.tw/showtime_list.html'
4
+ AMBASSADOR_THEATER_ID_XPATH = "//*[@class='list-group sidebar-nav-v1']//li//a"
5
+ AMBASSADOR_TIME_API = 'http://cinemaservice.ambassador.com.tw/ambassadorsite.webapi/api/Movies/GetScreeningDateListForTheater/?'
6
+ AMBASSADOR_FILM_API = 'http://cinemaservice.ambassador.com.tw/ambassadorsite.webapi/api/Movies/GetShowtimeListForTheater/?'
7
+
8
+ def fetch_movie_info(theater_id, date_list)
9
+ movie_info = Hash.new { |hash, key| hash[key] = {} }
10
+ date_list.map do |date|
11
+ url = "#{AMBASSADOR_FILM_API}theaterId=#{theater_id}&showingDate=#{date}"
12
+ # concurrent_retrieve_info(url, date, movie_info)
13
+ JSON.parse(Nokogiri::HTML(open(url)).text).map do |movie|
14
+ name = movie['ForeignName']
15
+ time = movie['PeriodShowtime'].first['Showtimes']
16
+ movie_info[name][date] = time
17
+ end
18
+ end # .map(&:execute).map(&:value)
19
+ movie_info # .sort.to_h
20
+ end
21
+
22
+ def concurrent_retrieve_info(url, date, movie_info)
23
+ Concurrent::Future.new do
24
+ JSON.parse(Nokogiri::HTML(open(url)).text).map do |movie|
25
+ name = movie['ForeignName']
26
+ time = movie['PeriodShowtime'].first['Showtimes']
27
+ movie_info[name][date] = time
28
+ end
29
+ end
30
+ end
31
+
32
+ def fetch_theater_date(theater_id)
33
+ url = "#{AMBASSADOR_TIME_API}theaterId=#{theater_id}"
34
+ JSON.parse(Nokogiri::HTML(open(url)).text)
35
+ end
36
+
37
+ def fetch_theater_id_table(url)
38
+ theater_id_list = {}
39
+ open_doc = Nokogiri::HTML(open(url))
40
+ theater = open_doc.xpath(AMBASSADOR_THEATER_ID_XPATH)
41
+ theater.each do |t|
42
+ theater_id = t.attributes['href'].value.split("'")[1]
43
+ theater_name = t.text
44
+ theater_id_list[theater_id] = theater_name
45
+ end
46
+ theater_id_list
47
+ end
48
+ end
@@ -1,5 +1,5 @@
1
1
  # Helper module to search for films
2
- module VieshowSearch
2
+ module Search
3
3
  NO_FILM = 'Film currently not on show'
4
4
  AN_HOUR = 1 / 24.to_f
5
5
  TIMEZONE = '+8'
@@ -32,7 +32,7 @@ module VieshowSearch
32
32
  def time_after(date, times, time_preferrence)
33
33
  times.select do |time|
34
34
  time if (MIDNIGHT.include? time[0..1]) ||
35
- (DateTime.parse("#{date}#{time}#{TIMEZONE}") >= time_preferrence)
35
+ (DateTime.parse("#{date} #{time}#{TIMEZONE}") >= time_preferrence)
36
36
  end
37
37
  end
38
38
 
@@ -1,5 +1,5 @@
1
1
  # Versioning
2
2
  module KanDianYing
3
- VERSION = '0.0.7'
4
- DATE = '2015-11-04'
3
+ VERSION = '0.0.8'
4
+ DATE = '2015-11-14'
5
5
  end
@@ -2,7 +2,7 @@ require 'open-uri'
2
2
  require 'nokogiri'
3
3
  require 'json'
4
4
  require_relative './vieshow_scrape'
5
- require_relative './vieshow_search'
5
+ require_relative './search'
6
6
 
7
7
  # Scraper for VieShow
8
8
  module VieShow
@@ -10,7 +10,7 @@ module VieShow
10
10
 
11
11
  # Class for Vieshow films
12
12
  class Vieshow
13
- include VieshowScrape, VieshowSearch
13
+ include VieshowScrape, Search
14
14
  # initialize movie_table with ID
15
15
  def initialize(vis_cinema_id)
16
16
  vis_cinema_id = vis_cinema_id.to_s
@@ -1,6 +1,7 @@
1
1
  require './spec/support/vcr_setup'
2
2
 
3
- AMBASSADOR_TEST_SITES = %w(38897fa9-094f-4e63-9d6d-c52408438cb6)
3
+ AMBASSADOR_TEST_SITES = %w(38897fa9-094f-4e63-9d6d-c52408438cb6
4
+ 5c2d4697-7f54-4955-800c-7b3ad782582c)
4
5
  # FAIL_SITES = %w(0 16)
5
6
  AMBASSADOR_FIXTURES = './spec/fixtures/ambassador_'
6
7
 
@@ -8,24 +9,64 @@ describe 'Get film information' do
8
9
  AMBASSADOR_TEST_SITES.each do |site|
9
10
  it "must return same list of movies for #{site}" do
10
11
  VCR.use_cassette("ambassador_name_#{site}") do
11
- cinema = HsinChuMovie::Ambassador.new
12
- name = cinema.theater_id_table[site]
12
+ cinema = HsinChuMovie::Ambassador.new site
13
13
  site_names = yml_load("#{AMBASSADOR_FIXTURES}name_#{site}.yml")
14
- site_names.must_equal cinema.movie_table[name].keys
14
+ site_names.must_equal cinema.movie_names
15
15
  end
16
16
  end
17
17
 
18
18
  it "must return same table for #{site}" do
19
19
  VCR.use_cassette("ambassador_table_#{site}") do
20
- cinema = HsinChuMovie::Ambassador.new
21
- name = cinema.theater_id_table[site]
20
+ cinema = HsinChuMovie::Ambassador.new site
22
21
  site_table = yml_load("#{AMBASSADOR_FIXTURES}table_#{site}.yml")
23
- site_table.must_equal cinema.movie_table[name]
22
+ site_table.must_equal cinema.movie_table
24
23
  end
25
24
  end
26
25
  end
27
26
  end
28
27
 
28
+ describe 'Get films after a given time on given day' do
29
+ AMBASSADOR_TEST_SITES.each do |site|
30
+ it "should only return films after a time for #{site}" do
31
+ VCR.use_cassette("ambassador_table_#{site}") do
32
+ cinema = HsinChuMovie::Ambassador.new site
33
+ time = DateTime.now.new_offset(TAIWAN_TIME)
34
+ time += GIVEN_DAY.sample
35
+ time_s = time.to_s
36
+ time_s[SEC_PART] = ZERO_SEC
37
+ day_films = cinema.films_on_day(time_s)
38
+ after_films = cinema.films_after_time(time_s)
39
+ # comparison_time is an hour earlier than specified time
40
+ comparison_time = (time - AN_HOUR).to_s[HOUR_MIN]
41
+ day_films.each do |film, date_times|
42
+ date_times.each do |date, show_times|
43
+ if after_films[film].nil?
44
+ # If empty, all show times must be less than comparison time
45
+ show_times.each do |show_time|
46
+ show_time.must_be :<, comparison_time
47
+ end
48
+ else
49
+ after_show_times = after_films[film][date]
50
+ after_show_times.each do |ast|
51
+ # On day show times must include after request show times
52
+ show_times.must_include ast
53
+ # After show times must be greater than comparison time
54
+ if (ast < comparison_time) &&
55
+ (MIDNIGHT.include? ast[HOUR_PART])
56
+ # Movies airing from midnight onwards are group with past day
57
+ ast[HOUR_PART] = "#{ast[HOUR_PART].to_i + ADD_24}"
58
+ end
59
+ ast.must_be :>=, comparison_time
60
+ end
61
+ show_times -= after_films[film][date]
62
+ # Any show time not returned must be less than comparison time
63
+ show_times.each do |show_time|
64
+ show_time.must_be :<, comparison_time
65
+ end
66
+ end; end; end; end; end
67
+ end
68
+ end
69
+
29
70
  # describe 'Outside of 1 and 14 must fail' do
30
71
  # FAIL_SITES.each do |site|
31
72
  # it "must fail for #{site}" do
@@ -1,7 +1,4 @@
1
1
  ---
2
- - The Little Prince
3
- - Crimson Peak
4
- - Bridge of Spies
5
- - The Martian
6
- - THE INTERN
2
+ - SCOUTS GUIDE TO THE ZOMBIE APOCALYPSE
7
3
  - Spectre
4
+ - The Little Prince
@@ -0,0 +1,9 @@
1
+ ---
2
+ - SCOUTS GUIDE TO THE ZOMBIE APOCALYPSE
3
+ - Queen Stain
4
+ - BUS657
5
+ - Spectre
6
+ - Burnt
7
+ - The Little Prince
8
+ - THE INTERN
9
+ - 'The Hunger Games: Mockingjay - Part 2'
@@ -1,68 +1,131 @@
1
1
  ---
2
- The Little Prince:
3
- 2015/10/28:
4
- - '12:50'
5
- - '17:30'
6
- 2015/10/29:
7
- - '12:00'
8
- - '17:10'
9
- Crimson Peak:
10
- 2015/10/28:
11
- - '17:30'
12
- 2015/10/29:
13
- - '12:50'
14
- - '15:00'
15
- - '16:40'
16
- Bridge of Spies:
17
- 2015/10/28:
18
- - '12:40'
19
- - '19:40'
20
- 2015/10/29:
21
- - '12:10'
22
- - '16:50'
23
- - '18:50'
24
- - '21:20'
25
- The Martian:
26
- 2015/10/28:
27
- - '12:30'
28
- - '17:30'
29
- - '20:00'
30
- 2015/10/29:
31
- - '14:00'
32
- - '16:30'
33
- - '19:00'
34
- - '21:30'
35
- THE INTERN:
36
- 2015/10/28:
37
- - '12:20'
38
- - '16:30'
39
- - '18:40'
40
- - '20:50'
41
- 2015/10/29:
42
- - '12:30'
43
- - '14:40'
44
- - '19:20'
45
- - '21:30'
46
- Spectre:
47
- 2015/11/05:
48
- - '12:40'
49
- - '15:20'
50
- - '18:00'
51
- - '20:40'
52
- 2015/11/06:
53
- - '12:40'
54
- - '15:20'
55
- - '18:00'
56
- - '20:40'
57
- 2015/11/07:
58
- - '10:50'
59
- - '13:30'
60
- - '16:10'
61
- - '18:50'
62
- - '21:30'
63
- 2015/11/08:
64
- - '10:50'
65
- - '13:30'
66
- - '16:10'
67
- - '18:50'
68
- - '21:30'
2
+ 國賓影城@新竹環球世博店:
3
+ SCOUTS GUIDE TO THE ZOMBIE APOCALYPSE:
4
+ 2015/11/14:
5
+ - '10:30'
6
+ - '12:20'
7
+ - '14:10'
8
+ - '16:00'
9
+ - '17:50'
10
+ - '19:40'
11
+ - '21:30'
12
+ 2015/11/15:
13
+ - '10:30'
14
+ - '12:20'
15
+ - '14:10'
16
+ - '16:00'
17
+ - '17:50'
18
+ - '19:40'
19
+ - '21:30'
20
+ 2015/11/16:
21
+ - '12:00'
22
+ - '13:50'
23
+ - '15:40'
24
+ - '17:30'
25
+ - '19:20'
26
+ - '21:10'
27
+ 2015/11/17:
28
+ - '12:00'
29
+ - '13:50'
30
+ - '15:40'
31
+ - '17:30'
32
+ - '19:20'
33
+ - '21:10'
34
+ 2015/11/18:
35
+ - '12:00'
36
+ - '13:50'
37
+ - '15:40'
38
+ - '17:30'
39
+ - '19:20'
40
+ - '21:10'
41
+ 2015/11/19:
42
+ - '12:00'
43
+ - '13:50'
44
+ - '15:40'
45
+ - '17:30'
46
+ - '19:20'
47
+ - '21:10'
48
+ Spectre:
49
+ 2015/11/14:
50
+ - '10:20'
51
+ - '11:30'
52
+ - '13:00'
53
+ - '14:10'
54
+ - '16:40'
55
+ - '17:40'
56
+ - '18:50'
57
+ - '20:20'
58
+ - '21:30'
59
+ 2015/11/15:
60
+ - '10:20'
61
+ - '11:30'
62
+ - '13:00'
63
+ - '14:10'
64
+ - '16:40'
65
+ - '17:40'
66
+ - '18:50'
67
+ - '20:20'
68
+ - '21:30'
69
+ 2015/11/16:
70
+ - '11:30'
71
+ - '12:30'
72
+ - '14:10'
73
+ - '15:10'
74
+ - '16:20'
75
+ - '17:50'
76
+ - '18:50'
77
+ - '20:30'
78
+ - '21:30'
79
+ 2015/11/17:
80
+ - '11:30'
81
+ - '12:30'
82
+ - '14:10'
83
+ - '15:10'
84
+ - '16:10'
85
+ - '17:50'
86
+ - '18:50'
87
+ - '20:30'
88
+ - '21:30'
89
+ 2015/11/18:
90
+ - '11:30'
91
+ - '12:30'
92
+ - '14:10'
93
+ - '15:10'
94
+ - '16:20'
95
+ - '17:50'
96
+ - '18:50'
97
+ - '20:30'
98
+ - '21:30'
99
+ 2015/11/19:
100
+ - '11:30'
101
+ - '12:30'
102
+ - '14:10'
103
+ - '15:10'
104
+ - '16:20'
105
+ - '17:50'
106
+ - '18:50'
107
+ - '20:30'
108
+ - '21:30'
109
+ The Little Prince:
110
+ 2015/11/14:
111
+ - '10:40'
112
+ - '12:40'
113
+ - '15:40'
114
+ - '16:50'
115
+ 2015/11/15:
116
+ - '10:40'
117
+ - '12:40'
118
+ - '15:40'
119
+ - '16:50'
120
+ 2015/11/16:
121
+ - '12:20'
122
+ - '16:50'
123
+ 2015/11/17:
124
+ - '12:10'
125
+ - '16:50'
126
+ 2015/11/18:
127
+ - '12:20'
128
+ - '16:50'
129
+ 2015/11/19:
130
+ - '12:20'
131
+ - '16:50'