kandianying 0.0.7 → 0.0.8

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.
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'