poms 0.0.3
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/Gemfile +4 -0
- data/Gemfile.lock +80 -0
- data/Guardfile +12 -0
- data/LICENSE.txt +22 -0
- data/README.md +26 -0
- data/Rakefile +7 -0
- data/lib/poms.rb +110 -0
- data/lib/poms/base.rb +7 -0
- data/lib/poms/broadcast.rb +46 -0
- data/lib/poms/builder.rb +78 -0
- data/lib/poms/has_ancestors.rb +42 -0
- data/lib/poms/has_base_attributes.rb +20 -0
- data/lib/poms/schedule_event.rb +36 -0
- data/lib/poms/season.rb +13 -0
- data/lib/poms/series.rb +12 -0
- data/lib/poms/version.rb +3 -0
- data/spec/fabricators/poms_fabricator.rb +39 -0
- data/spec/fixtures/poms_broadcast.json +307 -0
- data/spec/fixtures/poms_broadcast_multiple_schedule_events.json +354 -0
- data/spec/fixtures/poms_broadcast_pippi.json +180 -0
- data/spec/fixtures/poms_series.json +49 -0
- data/spec/fixtures/poms_zapp.json +47363 -0
- data/spec/lib/poms/broadcast_spec.rb +44 -0
- data/spec/lib/poms/buider_spec.rb +19 -0
- data/spec/lib/poms/schedule_event_spec.rb +15 -0
- data/spec/lib/poms_spec.rb +57 -0
- data/spec/spec_helper.rb +7 -0
- metadata +198 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2e3aa1829a203b60720b24083855ffb8a9f41621
|
4
|
+
data.tar.gz: 60ddc33138bde526bf72892201877abce90dbc29
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 755e683ca19d2c23d29555426309d3618bfe2b0dcb30651341053c9332b8c61db00e0968dea06a1105ec9bf55b1c85ba71a867eeef1e7c7b29e3edf70480c3cb
|
7
|
+
data.tar.gz: 8f4e26864b024263e36f830cad01cd56a915c438d979c0ef3304b2d0217661f41d21f0fddb606029eec76ebf70e9b7aadfebb2549d699154d46a93393759bad7
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
poms (0.0.3)
|
5
|
+
activesupport
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (4.1.5)
|
11
|
+
i18n (~> 0.6, >= 0.6.9)
|
12
|
+
json (~> 1.7, >= 1.7.7)
|
13
|
+
minitest (~> 5.1)
|
14
|
+
thread_safe (~> 0.1)
|
15
|
+
tzinfo (~> 1.1)
|
16
|
+
celluloid (0.15.2)
|
17
|
+
timers (~> 1.1.0)
|
18
|
+
coderay (1.1.0)
|
19
|
+
diff-lcs (1.2.5)
|
20
|
+
fabrication (2.11.3)
|
21
|
+
fakeweb (1.3.0)
|
22
|
+
ffi (1.9.3)
|
23
|
+
formatador (0.2.5)
|
24
|
+
guard (2.6.1)
|
25
|
+
formatador (>= 0.2.4)
|
26
|
+
listen (~> 2.7)
|
27
|
+
lumberjack (~> 1.0)
|
28
|
+
pry (>= 0.9.12)
|
29
|
+
thor (>= 0.18.1)
|
30
|
+
guard-rspec (4.3.1)
|
31
|
+
guard (~> 2.1)
|
32
|
+
rspec (>= 2.14, < 4.0)
|
33
|
+
i18n (0.6.11)
|
34
|
+
json (1.8.1)
|
35
|
+
listen (2.7.9)
|
36
|
+
celluloid (>= 0.15.2)
|
37
|
+
rb-fsevent (>= 0.9.3)
|
38
|
+
rb-inotify (>= 0.9)
|
39
|
+
lumberjack (1.0.9)
|
40
|
+
method_source (0.8.2)
|
41
|
+
minitest (5.4.1)
|
42
|
+
pry (0.10.1)
|
43
|
+
coderay (~> 1.1.0)
|
44
|
+
method_source (~> 0.8.1)
|
45
|
+
slop (~> 3.4)
|
46
|
+
rake (10.3.2)
|
47
|
+
rb-fsevent (0.9.4)
|
48
|
+
rb-inotify (0.9.5)
|
49
|
+
ffi (>= 0.5.0)
|
50
|
+
rspec (3.0.0)
|
51
|
+
rspec-core (~> 3.0.0)
|
52
|
+
rspec-expectations (~> 3.0.0)
|
53
|
+
rspec-mocks (~> 3.0.0)
|
54
|
+
rspec-core (3.0.4)
|
55
|
+
rspec-support (~> 3.0.0)
|
56
|
+
rspec-expectations (3.0.4)
|
57
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
58
|
+
rspec-support (~> 3.0.0)
|
59
|
+
rspec-mocks (3.0.4)
|
60
|
+
rspec-support (~> 3.0.0)
|
61
|
+
rspec-support (3.0.4)
|
62
|
+
slop (3.6.0)
|
63
|
+
thor (0.19.1)
|
64
|
+
thread_safe (0.3.4)
|
65
|
+
timers (1.1.0)
|
66
|
+
tzinfo (1.2.2)
|
67
|
+
thread_safe (~> 0.1)
|
68
|
+
|
69
|
+
PLATFORMS
|
70
|
+
ruby
|
71
|
+
|
72
|
+
DEPENDENCIES
|
73
|
+
bundler (~> 1.3)
|
74
|
+
fabrication
|
75
|
+
fakeweb
|
76
|
+
guard
|
77
|
+
guard-rspec
|
78
|
+
poms!
|
79
|
+
rake
|
80
|
+
rspec
|
data/Guardfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard :rspec do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
10
|
+
watch('config/routes.rb') { "spec/routing" }
|
11
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
12
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Brightin BV
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Poms
|
2
|
+
|
3
|
+
The Poms gem provides an interface to the Dutch public broadcaster API: POMS. It
|
4
|
+
is a couchdb service that is publicly available.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'poms'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install poms
|
19
|
+
|
20
|
+
## Contributing
|
21
|
+
|
22
|
+
1. Fork it
|
23
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
24
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
25
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
26
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/poms.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'json'
|
4
|
+
require 'poms/base'
|
5
|
+
require 'poms/version'
|
6
|
+
require 'poms/builder'
|
7
|
+
require 'poms/schedule_event'
|
8
|
+
require 'poms/broadcast'
|
9
|
+
require 'poms/season'
|
10
|
+
require 'poms/series'
|
11
|
+
|
12
|
+
module Poms
|
13
|
+
extend self
|
14
|
+
URL = 'http://docs.poms.omroep.nl'
|
15
|
+
MEDIA_PATH = '/media/'
|
16
|
+
BROADCASTS_VIEW_PATH = '/media/_design/media/_view/broadcasts-by-broadcaster-and-start'
|
17
|
+
ANCESTOR_AND_TYPE_PATH = '/media/_design/media/_view/by-ancestor-and-type'
|
18
|
+
ANCESTOR_AND_SORTDATE_PATH = '/media/_design/media/_view/by-ancestor-and-sortdate'
|
19
|
+
CHANNEL_AND_START_PATH = '/media/_design/media/_view/broadcasts-by-channel-and-start'
|
20
|
+
VALID_CHANNELS = /^NED(1|2|3)$/
|
21
|
+
# ?startkey=[\"Zapp\",1369755130000]&endkey=[\"Zapp\",1370964770000]&reduce=false&include_docs=true
|
22
|
+
|
23
|
+
def fetch(mid)
|
24
|
+
return nil if mid.nil?
|
25
|
+
hash = fetch_raw_json mid
|
26
|
+
Poms::Builder.process_hash hash
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch_raw_json(mid)
|
30
|
+
uri = [MEDIA_PATH, mid].join
|
31
|
+
get_json(uri)
|
32
|
+
end
|
33
|
+
|
34
|
+
def upcoming_broadcasts(zender, start_time = Time.now, end_time = Time.now+7.days)
|
35
|
+
uri = [BROADCASTS_VIEW_PATH, broadcast_view_params(zender, start_time, end_time )].join
|
36
|
+
hash = get_json(uri)
|
37
|
+
hash['rows'].map {|item| Poms::Builder.process_hash item['doc']}
|
38
|
+
end
|
39
|
+
|
40
|
+
def fetch_descendants_for_serie(mid, type='BROADCAST')
|
41
|
+
uri = [ANCESTOR_AND_TYPE_PATH, ancestor_type_params(mid, type) ].join
|
42
|
+
hash = get_json(uri) || {'rows' => []}
|
43
|
+
hash['rows'].map {|item| Poms::Builder.process_hash item['doc']}
|
44
|
+
end
|
45
|
+
|
46
|
+
alias_method :fetch_broadcasts_for_serie, :fetch_descendants_for_serie
|
47
|
+
|
48
|
+
def fetch_descendants_by_date_for_serie(mid, start_time=1.week.ago)
|
49
|
+
uri = [ANCESTOR_AND_SORTDATE_PATH, ancestor_sortdate_params(mid, start_time) ].join
|
50
|
+
hash = get_json(uri) || {'rows' => []}
|
51
|
+
hash['rows'].map {|item| Poms::Builder.process_hash item['doc']}
|
52
|
+
end
|
53
|
+
|
54
|
+
def fetch_descendant_mids(mid, type='BROADCAST')
|
55
|
+
uri = [ANCESTOR_AND_TYPE_PATH, ancestor_type_params(mid, type), "&include_docs=false"].join
|
56
|
+
hash = get_json(uri) || {'rows' => []}
|
57
|
+
hash['rows'].map {|item| item['id']}
|
58
|
+
end
|
59
|
+
|
60
|
+
def fetch_broadcasts_by_channel_and_start(channel, start_time=1.week.ago, end_time=Time.now)
|
61
|
+
uri = [CHANNEL_AND_START_PATH, channel_params(channel, start_time, end_time) ].join
|
62
|
+
hash = get_json(uri)
|
63
|
+
hash['rows'].map {|item| Poms::Builder.process_hash item['doc']}
|
64
|
+
end
|
65
|
+
|
66
|
+
def fetch_current_broadcast(channel)
|
67
|
+
uri = [CHANNEL_AND_START_PATH, channel_params(channel, Time.now, 1.day.ago), '&descending=true&limit=1' ].join
|
68
|
+
hash = get_json(uri)
|
69
|
+
rows = hash['rows']
|
70
|
+
Poms::Builder.process_hash(rows.empty? ? {} : rows.first['doc'])
|
71
|
+
end
|
72
|
+
|
73
|
+
def fetch_next_broadcast(channel)
|
74
|
+
uri = [CHANNEL_AND_START_PATH, channel_params(channel, Time.now, 1.day.from_now), '&limit=1' ].join
|
75
|
+
hash = get_json(uri)
|
76
|
+
rows = hash['rows']
|
77
|
+
Poms::Builder.process_hash(rows.empty? ? {} : rows.first['doc'])
|
78
|
+
end
|
79
|
+
|
80
|
+
# private
|
81
|
+
def broadcast_view_params(zender, start_time, end_time)
|
82
|
+
zender = zender.capitalize
|
83
|
+
"?startkey=[\"#{zender}\",#{start_time.to_i * 1000}]&endkey=[\"#{zender}\",#{end_time.to_i * 1000}]&reduce=false&include_docs=true"
|
84
|
+
end
|
85
|
+
|
86
|
+
def ancestor_type_params(mid, type)
|
87
|
+
"?reduce=false&key=[\"#{mid}\",\"#{type}\"]&include_docs=true"
|
88
|
+
end
|
89
|
+
|
90
|
+
def ancestor_sortdate_params(mid, start_time=1.month.ago)
|
91
|
+
end_time_i = 1.week.from_now.to_i * 1000
|
92
|
+
start_time_i = start_time.to_i * 1000
|
93
|
+
"?reduce=false&startkey=[\"#{mid}\",#{start_time_i}]&endkey=[\"#{mid}\",#{end_time_i}]&include_docs=true"
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def channel_params(channel, start_time, end_time)
|
98
|
+
"?startkey=[\"#{channel}\",#{start_time.to_i * 1000}]&endkey=[\"#{channel}\",#{end_time.to_i * 1000}]&reduce=false&include_docs=true"
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_json(uri)
|
102
|
+
begin
|
103
|
+
JSON.parse(open(URI.escape [URL, uri].join).read)
|
104
|
+
rescue OpenURI::HTTPError => e
|
105
|
+
raise e unless e.message.match(/404/)
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
data/lib/poms/base.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'poms/has_ancestors'
|
2
|
+
require 'poms/has_base_attributes'
|
3
|
+
|
4
|
+
module Poms
|
5
|
+
class Broadcast < Poms::Builder::NestedOpenStruct
|
6
|
+
|
7
|
+
include Poms::HasAncestors
|
8
|
+
include Poms::HasBaseAttributes
|
9
|
+
|
10
|
+
def initialize hash
|
11
|
+
super
|
12
|
+
process_schedule_events
|
13
|
+
end
|
14
|
+
|
15
|
+
def process_schedule_events
|
16
|
+
if schedule_events
|
17
|
+
schedule_events.select! { |e| e.channel.match Poms::VALID_CHANNELS }
|
18
|
+
end
|
19
|
+
self.schedule_events = schedule_events.map { |e| Poms::ScheduleEvent.new e.marshal_dump } if schedule_events
|
20
|
+
end
|
21
|
+
|
22
|
+
def series_mid
|
23
|
+
serie.try :mid_ref || serie.mid
|
24
|
+
end
|
25
|
+
|
26
|
+
def odi_streams
|
27
|
+
return [] if locations.nil? or locations.empty?
|
28
|
+
odi_streams = locations.select { |l| l.program_url.match(/^odi/) }
|
29
|
+
streams = odi_streams.map do |l|
|
30
|
+
l.program_url.match(/^[\w+]+\:\/\/[\w\.]+\/video\/(\w+)\/\w+/)[1]
|
31
|
+
end
|
32
|
+
streams.uniq
|
33
|
+
end
|
34
|
+
|
35
|
+
def available_until
|
36
|
+
return nil if locations.nil? or locations.empty?
|
37
|
+
timestamp = locations.map(&:publish_stop).compact.first
|
38
|
+
return Time.at(timestamp / 1000).to_datetime if timestamp
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
class Strand < Broadcast
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/lib/poms/builder.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'active_support/all'
|
3
|
+
|
4
|
+
module Poms
|
5
|
+
class Builder
|
6
|
+
def self.process_hash(hash)
|
7
|
+
return unless hash
|
8
|
+
underscored_hash = {}
|
9
|
+
hash.each { |k,v| underscored_hash[k.underscore] = v }
|
10
|
+
class_name = (underscored_hash['type'] || "Typeless").capitalize
|
11
|
+
begin
|
12
|
+
klass = Poms.const_get class_name
|
13
|
+
rescue NameError
|
14
|
+
# c = Class.new(Poms::NestedOpenStruct)
|
15
|
+
klass = Poms.const_set class_name, Class.new(Poms::Builder::NestedOpenStruct)
|
16
|
+
end
|
17
|
+
klass.send(:new, underscored_hash)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
|
23
|
+
class NestedOpenStruct < OpenStruct
|
24
|
+
|
25
|
+
include Poms::Base
|
26
|
+
|
27
|
+
def initialize(hash)
|
28
|
+
@hash = hash
|
29
|
+
@hash.each do |k,v|
|
30
|
+
process_key_value(k,v)
|
31
|
+
end
|
32
|
+
super hash
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def process_key_value(k, v)
|
38
|
+
case v
|
39
|
+
when Array
|
40
|
+
struct_array = v.map do |element|
|
41
|
+
process_element(element)
|
42
|
+
end
|
43
|
+
@hash.send("[]=", k, struct_array)
|
44
|
+
when Hash
|
45
|
+
@hash.send("[]=", k, Poms::Builder.process_hash(v))
|
46
|
+
when String, Integer
|
47
|
+
|
48
|
+
case k
|
49
|
+
when "start", "end", "sort_date"
|
50
|
+
@hash.send("[]=", k, Time.at(v / 1000))
|
51
|
+
end
|
52
|
+
when NilClass, FalseClass, TrueClass, Time, Poms::Typeless
|
53
|
+
# do nothing
|
54
|
+
else
|
55
|
+
raise Poms::Exceptions::UnkownStructure, "Error processing #{v.class}: #{v}, which was expected to be a String or Array"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_element(element)
|
60
|
+
case element
|
61
|
+
when String, Integer
|
62
|
+
element
|
63
|
+
when Hash
|
64
|
+
Poms::Builder.process_hash element
|
65
|
+
else
|
66
|
+
raise Poms::Exceptions::UnkownStructure, "Error processing #{element}: which was expected to be a String nor a Hash"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
module Exceptions
|
74
|
+
class UnkownStructure < StandardError
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Poms
|
2
|
+
module HasAncestors
|
3
|
+
module ClassMethods
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
module InstanceMethods
|
8
|
+
def series
|
9
|
+
return @series if @series
|
10
|
+
descendant_series = descendant_of.reject { |obj| obj.class != Poms::Series }
|
11
|
+
if descendant_of.blank?
|
12
|
+
[]
|
13
|
+
elsif descendant_series.blank?
|
14
|
+
descendant_of
|
15
|
+
else
|
16
|
+
descendant_series
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def serie
|
21
|
+
series.first
|
22
|
+
end
|
23
|
+
|
24
|
+
def serie_mid
|
25
|
+
return nil if serie.nil?
|
26
|
+
serie.mid_ref || serie.mid
|
27
|
+
end
|
28
|
+
|
29
|
+
def ancestor_mids
|
30
|
+
return @ancestor_mids if @ancestor_mids
|
31
|
+
descendant_of_mids = descendant_of.map(&:mid_ref) rescue []
|
32
|
+
episode_of_mids = episode_of.map(&:mid_ref) rescue []
|
33
|
+
@ancestor_mids = (descendant_of_mids + episode_of_mids).flatten.compact.uniq
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.included(receiver)
|
38
|
+
receiver.extend ClassMethods
|
39
|
+
receiver.send :include, InstanceMethods
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|