fcc 1.1 → 1.2.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 +4 -4
- data/Gemfile.lock +8 -6
- data/README.md +27 -22
- data/VERSION +1 -1
- data/fcc.gemspec +1 -1
- data/lib/fcc.rb +6 -0
- data/lib/fcc/station.rb +36 -16
- data/lib/fcc/station/cache.rb +9 -15
- data/lib/fcc/station/extended_info.rb +17 -13
- data/lib/fcc/station/extended_info/parser.rb +2 -3
- data/lib/fcc/station/index.rb +1 -1
- data/lib/fcc/station/info.rb +6 -2
- data/lib/fcc/station/result_delegate.rb +27 -9
- data/lib/version.rb +1 -1
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0c284a2224092f6ee580603ca213e6754277f0c205296a606dfa3b1c6d33990
|
4
|
+
data.tar.gz: da7535bfbc0a8f367f24d67f080a939fccced3a545c9f92d749aabf322ce4043
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef717fe2529d3773b8c68208b6fd3a1a86c6aa270873a9c4d4bf9a9a70caad6808f2e46a137dc1243f47129b15105954817d4217c0504bf3bcfd19d2b7224e09
|
7
|
+
data.tar.gz: 30a58df413f3e68a5a858b2fd24d147c40b3c694f2a12ce0c2275be48a19db0ad12c985f4d669a5a555573cfa6af76ee1186e63373d7607c38af287ad8b637df
|
data/Gemfile.lock
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fcc (1.
|
4
|
+
fcc (1.2.0)
|
5
5
|
activesupport (>= 6.1)
|
6
6
|
httparty (~> 0.18)
|
7
|
+
lightly (~> 0.3.3)
|
7
8
|
|
8
9
|
GEM
|
9
10
|
remote: https://rubygems.org/
|
10
11
|
specs:
|
11
|
-
activesupport (6.1.
|
12
|
+
activesupport (6.1.4)
|
12
13
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
13
14
|
i18n (>= 1.6, < 2)
|
14
15
|
minitest (>= 5.1)
|
@@ -16,17 +17,18 @@ GEM
|
|
16
17
|
zeitwerk (~> 2.3)
|
17
18
|
awesome_print (1.8.0)
|
18
19
|
byebug (11.1.3)
|
19
|
-
concurrent-ruby (1.1.
|
20
|
+
concurrent-ruby (1.1.9)
|
20
21
|
diff-lcs (1.4.4)
|
21
22
|
httparty (0.18.1)
|
22
23
|
mime-types (~> 3.0)
|
23
24
|
multi_xml (>= 0.5.2)
|
24
|
-
i18n (1.8.
|
25
|
+
i18n (1.8.10)
|
25
26
|
concurrent-ruby (~> 1.0)
|
27
|
+
lightly (0.3.3)
|
26
28
|
mime-types (3.3.1)
|
27
29
|
mime-types-data (~> 3.2015)
|
28
|
-
mime-types-data (3.
|
29
|
-
minitest (5.14.
|
30
|
+
mime-types-data (3.2021.0704)
|
31
|
+
minitest (5.14.4)
|
30
32
|
multi_xml (0.6.0)
|
31
33
|
rake (12.3.3)
|
32
34
|
rspec (3.9.0)
|
data/README.md
CHANGED
@@ -19,28 +19,33 @@ gem install fcc
|
|
19
19
|
```ruby
|
20
20
|
station = FCC::Station.find(:fm, "KOOP")
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
station.
|
25
|
-
station.
|
26
|
-
station.
|
27
|
-
station.
|
28
|
-
station.
|
29
|
-
station.
|
30
|
-
station.
|
31
|
-
station.
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
station.
|
36
|
-
station.
|
37
|
-
station.
|
38
|
-
station.
|
39
|
-
station.
|
40
|
-
station.
|
41
|
-
station.
|
42
|
-
station.
|
43
|
-
|
22
|
+
if station.exists? && station.licensed?
|
23
|
+
#Basic attributes, available quickly because the FCC actually caches these in a CDN:
|
24
|
+
station.id #=> 65320
|
25
|
+
station.status #=> LICENSED
|
26
|
+
station.rf_channel #=> 219
|
27
|
+
station.license_expiration_date #=> "08/01/2021"
|
28
|
+
station.facility_type #=> ED
|
29
|
+
station.frequency #=> 91.7
|
30
|
+
station.contact #=> <struct FCC::Station::Contact>
|
31
|
+
station.owner #=> <struct FCC::Station::Contact>
|
32
|
+
station.community #=> <struct FCC::Station::Community city="HORNSBY", state="TX">
|
33
|
+
|
34
|
+
# Extended attributes, takes several seconds to load initially because the FCC is running this endpoint on a 1960s era mainframe operated by trained hamsters.
|
35
|
+
station.station_class #=> A
|
36
|
+
station.signal_strength #=> 3.0 kW
|
37
|
+
station.antenna_type #=> ND
|
38
|
+
station.effective_radiated_power #=> 3.0 kW
|
39
|
+
station.haat_horizontal #=> 26.0
|
40
|
+
station.haat_vertical #=> 26.0
|
41
|
+
station.latitude #=> "30.266861111111112"
|
42
|
+
station.longitude #=> "-97.67444444444445"
|
43
|
+
station.file_number #=> BLED-19950103KA
|
44
|
+
```
|
45
|
+
end
|
46
|
+
|
47
|
+
### Caching
|
48
|
+
Extended attributes take several seconds to load from transition.fcc.gov. In order to work around this, we query the entire dataset and then cache the result locally for 3 days (using the lightly gem). To use your own cache, set `FCC.cache=` to your cache class (Rails.cache, maybe?) which should have a #fetch method that should take a key and a block like `cache.fetch(key) { // yield for expensive fetch }}`.
|
44
49
|
|
45
50
|
### Get all station call signs on a particular service (:fm, :am, :tv)
|
46
51
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
1.2.0
|
data/fcc.gemspec
CHANGED
@@ -6,7 +6,6 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = %q{fcc}
|
7
7
|
spec.version = FCC::VERSION
|
8
8
|
spec.authors = ["Jeff Keen"]
|
9
|
-
spec.date = %q{2011-01-30}
|
10
9
|
spec.description = %q{}
|
11
10
|
spec.email = %q{jeff@keen.me}
|
12
11
|
spec.homepage = "http://github.com/jkeen/fcc"
|
@@ -20,6 +19,7 @@ Gem::Specification.new do |spec|
|
|
20
19
|
spec.summary = %q{Searches the FCC's FM, AM, and TV databases}
|
21
20
|
spec.add_dependency "activesupport", ">= 6.1"
|
22
21
|
spec.add_dependency "httparty", "~> 0.18"
|
22
|
+
spec.add_dependency "lightly", "~> 0.3.3"
|
23
23
|
spec.add_development_dependency "bundler", "~> 2.1"
|
24
24
|
spec.add_development_dependency "rake", "~> 12.3.3"
|
25
25
|
spec.add_development_dependency 'rspec', '~> 3.9.0'
|
data/lib/fcc.rb
CHANGED
data/lib/fcc/station.rb
CHANGED
@@ -18,7 +18,9 @@ module FCC
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def self.find(service, call_sign, options = {})
|
21
|
-
Result.new(service, call_sign, options)
|
21
|
+
result = Result.new(service, call_sign, options)
|
22
|
+
|
23
|
+
result if result&.exists?
|
22
24
|
end
|
23
25
|
|
24
26
|
def self.index(service)
|
@@ -34,14 +36,12 @@ module FCC
|
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
|
-
def self.extended_info_cache
|
38
|
-
@cache ||=
|
39
|
-
@cache[service] ||= Station::Cache.new(service)
|
40
|
-
@cache[service]
|
39
|
+
def self.extended_info_cache
|
40
|
+
@cache ||= Station::Cache.new
|
41
41
|
end
|
42
42
|
|
43
43
|
class Result
|
44
|
-
EXTENDED_ATTRIBUTES = %i[signal_strength latitude longitude
|
44
|
+
EXTENDED_ATTRIBUTES = %i[signal_strength latitude longitude station_class file_number effective_radiated_power haat_horizontal haat_vertical antenna_type] # these take a long time to query
|
45
45
|
BASIC_ATTRIBUTES = %i[id call_sign status rf_channel license_expiration_date facility_type frequency]
|
46
46
|
|
47
47
|
delegate *EXTENDED_ATTRIBUTES, to: :extended_data
|
@@ -57,15 +57,31 @@ module FCC
|
|
57
57
|
data
|
58
58
|
end
|
59
59
|
|
60
|
+
def details_available?
|
61
|
+
exists? && data.latitude.present?
|
62
|
+
end
|
63
|
+
|
64
|
+
def licensed?
|
65
|
+
exists? && data.status == 'LICENSED' && data.license_expiration_date && Time.parse(data.license_expiration_date) > Time.now
|
66
|
+
end
|
67
|
+
|
68
|
+
def exists?
|
69
|
+
data.instance_variable_get('@result')
|
70
|
+
end
|
71
|
+
|
60
72
|
def to_json
|
61
73
|
{}.tap do |hash|
|
62
74
|
[EXTENDED_ATTRIBUTES | BASIC_ATTRIBUTES | %i[contact owner community]].flatten.each do |attr|
|
63
75
|
result = send(attr.to_sym)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
76
|
+
next unless result
|
77
|
+
|
78
|
+
hash[attr] = if result.is_a?(Struct)
|
79
|
+
result.to_h
|
80
|
+
elsif result.is_a?(Array) && result.compact.size > 0
|
81
|
+
result
|
82
|
+
elsif result.present?
|
83
|
+
result.to_s
|
84
|
+
end
|
69
85
|
end
|
70
86
|
end
|
71
87
|
end
|
@@ -78,23 +94,27 @@ module FCC
|
|
78
94
|
@community ||= Community.new(city: data.communityCity, state: data.communityState)
|
79
95
|
end
|
80
96
|
|
97
|
+
def operating_hours
|
98
|
+
extended_data.am_operating_time if @service == :am
|
99
|
+
end
|
100
|
+
|
81
101
|
def contact
|
82
102
|
contact = data.mainStudioContact
|
83
103
|
@contact ||= Contact.new(name: contact['contactName'], title: contact['contactTitle'], address: contact['contactAddress1'], address2: contact['contactAddress2'], city: contact['contactCity'], state: contact['contactState'], zip_code: contact['contactZip'], phone: contact['contactPhone'], fax: contact['contactFax'], email: contact['contactEmail'], website: contact['contactWebsite'])
|
84
104
|
end
|
85
105
|
|
86
|
-
def coordinates
|
87
|
-
[latitude.to_f, longitude.to_f].to_json
|
88
|
-
end
|
89
|
-
|
90
106
|
def coordinates_url
|
91
|
-
"https://www.google.com/maps/search/#{
|
107
|
+
"https://www.google.com/maps/search/#{latitude},#{longitude}" if latitude.present? && longitude.present?
|
92
108
|
end
|
93
109
|
|
94
110
|
def extended_data_url
|
95
111
|
"https://transition.fcc.gov/fcc-bin/#{@service.to_s.downcase}q?list=4&facid=#{id}"
|
96
112
|
end
|
97
113
|
|
114
|
+
def enterprise_data_url
|
115
|
+
"https://enterpriseefiling.fcc.gov/dataentry/public/tv/publicFacilityDetails.html?facilityId=#{id}"
|
116
|
+
end
|
117
|
+
|
98
118
|
def extended_data
|
99
119
|
@extended_data ||= ResultDelegate.new(ExtendedInfo.new(@service).find(@call_sign))
|
100
120
|
end
|
data/lib/fcc/station/cache.rb
CHANGED
@@ -1,28 +1,22 @@
|
|
1
1
|
require 'httparty'
|
2
|
-
require 'byebug'
|
3
2
|
require_relative './extended_info/parser'
|
3
|
+
require 'byebug'
|
4
|
+
require 'lightly'
|
4
5
|
|
5
6
|
module FCC
|
6
7
|
module Station
|
7
8
|
class Cache
|
8
9
|
attr_reader :store
|
9
10
|
|
10
|
-
def initialize
|
11
|
-
@
|
12
|
-
@store = Station::ExtendedInfo.new(@service)
|
13
|
-
end
|
14
|
-
|
15
|
-
def find(fcc_id)
|
16
|
-
results.detect { |r| r[:fcc_id].to_s == fcc_id.to_s }
|
17
|
-
end
|
18
|
-
|
19
|
-
def results
|
20
|
-
#TODO: add redis caching tie-in because this query is molasses
|
21
|
-
@store.all_results.parsed_response
|
11
|
+
def initialize
|
12
|
+
@lightly = Lightly.new dir: "tmp/fcc_#{@service}_data", life: '3d', hash: true
|
22
13
|
end
|
23
14
|
|
24
|
-
def
|
25
|
-
|
15
|
+
def fetch key
|
16
|
+
@lightly.get key.to_s do
|
17
|
+
puts "loading up cache with all results"
|
18
|
+
yield
|
19
|
+
end
|
26
20
|
end
|
27
21
|
end
|
28
22
|
end
|
@@ -7,7 +7,8 @@ module FCC
|
|
7
7
|
class ExtendedInfo
|
8
8
|
include HTTParty
|
9
9
|
attr_accessor :results, :service
|
10
|
-
|
10
|
+
|
11
|
+
base_uri 'https://transition.fcc.gov/fcc-bin/'
|
11
12
|
|
12
13
|
def initialize(service)
|
13
14
|
@service = service
|
@@ -19,8 +20,8 @@ module FCC
|
|
19
20
|
# call: nil,
|
20
21
|
# city: nil,
|
21
22
|
# arn: nil,
|
22
|
-
serv: service.to_s.downcase,
|
23
|
-
|
23
|
+
serv: service.to_s.downcase, # Only return primary main records, no backup transmitters, etc… for now
|
24
|
+
status: 3, # licensed records only
|
24
25
|
# freq: @service.to_sym == :fm ? '87.1' : '530',
|
25
26
|
# fre2: @service.to_sym == :fm ? '107.9' : '1700',
|
26
27
|
# facid: nil,
|
@@ -42,11 +43,16 @@ module FCC
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def all_results
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
begin
|
47
|
+
cache_key = "#{self.class.instance_variable_get('@default_options')[:base_uri]}/#{@service.to_s.downcase}q"
|
48
|
+
FCC.cache.fetch cache_key do
|
49
|
+
response = self.class.get("/#{service.to_s.downcase}q", @options.merge(query: @query))
|
50
|
+
puts response.request.uri.to_s.gsub('&list=4', '&list=0')
|
51
|
+
response.parsed_response
|
52
|
+
end
|
53
|
+
rescue StandardError => e
|
54
|
+
puts e.message
|
55
|
+
puts e.backtrace
|
50
56
|
end
|
51
57
|
end
|
52
58
|
|
@@ -58,13 +64,11 @@ module FCC
|
|
58
64
|
end
|
59
65
|
|
60
66
|
begin
|
61
|
-
|
62
|
-
rescue
|
67
|
+
all_results.filter { |r| r[:fcc_id].to_s == id.to_s }
|
68
|
+
rescue StandardError => e
|
63
69
|
response = self.class.get("/#{service.to_s.downcase}q", @options.merge(query: @query.merge(facid: id)))
|
64
70
|
puts response.request.uri.to_s.gsub('&list=4', '&list=0')
|
65
|
-
|
66
|
-
result['source_url'] = response.request.uri.to_s.gsub('&list=4', '&list=0')
|
67
|
-
result
|
71
|
+
response&.parsed_response
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'httparty'
|
2
|
-
require 'byebug'
|
3
2
|
|
4
3
|
module FCC
|
5
4
|
module Station
|
@@ -16,9 +15,9 @@ module FCC
|
|
16
15
|
attrs[:band] = fields[2]
|
17
16
|
attrs[:channel] = fields[3]
|
18
17
|
attrs[:antenna_type] = fields[4] # Directional Antenna (DA) or NonDirectional (ND)
|
19
|
-
attrs[:am_operating_time] = fields[5] if fields[5] && attrs[:band] == "AM" # (Only used for AM)
|
18
|
+
attrs[:am_operating_time] = fields[5] if fields[5] && attrs[:band]&.upcase == "AM" # (Only used for AM)
|
20
19
|
attrs[:station_class] = fields[6]
|
21
|
-
attrs[:region_2_station_class] = fields[7] if fields[7] && attrs[:band] == "AM" # (only used for AM)
|
20
|
+
attrs[:region_2_station_class] = fields[7] if fields[7] && attrs[:band]&.upcase == "AM" # (only used for AM)
|
22
21
|
attrs[:status] = fields[8]
|
23
22
|
attrs[:city] = fields[9]
|
24
23
|
attrs[:state] = fields[10]
|
data/lib/fcc/station/index.rb
CHANGED
data/lib/fcc/station/info.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'httparty'
|
2
|
-
require 'byebug'
|
3
2
|
|
4
3
|
module FCC
|
5
4
|
module Station
|
@@ -21,7 +20,12 @@ module FCC
|
|
21
20
|
end
|
22
21
|
|
23
22
|
response = self.class.get("/api/service/#{service.to_s.downcase}/facility/id/#{id}.json")
|
24
|
-
|
23
|
+
|
24
|
+
begin
|
25
|
+
response['results']['facility']
|
26
|
+
rescue StandardError => e
|
27
|
+
return nil
|
28
|
+
end
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'active_support/inflector'
|
2
|
-
require 'byebug'
|
3
2
|
|
4
3
|
module FCC
|
5
4
|
module Station
|
@@ -9,14 +8,33 @@ module FCC
|
|
9
8
|
end
|
10
9
|
|
11
10
|
def method_missing(m, *args, &block)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
return find_result(@result, m) unless @result.is_a?(Array)
|
12
|
+
return find_result(@result.first, m) if @result.size == 1
|
13
|
+
|
14
|
+
filtered_results = @result.filter { |result|
|
15
|
+
result[:status] == 'LIC' # Licensed only, no construction permits
|
16
|
+
}
|
17
|
+
|
18
|
+
filtered_results = filtered_results.collect { |res|
|
19
|
+
find_result(res, m)
|
20
|
+
}.uniq
|
21
|
+
|
22
|
+
filtered_results.size == 1 ? filtered_results.first : filtered_results
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def find_key(result, name)
|
28
|
+
result.keys.detect { |d| name.to_s == d.to_s } || result.keys.detect { |d| name.to_s == d.to_s.underscore }
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_result(result, name)
|
32
|
+
matched_key = find_key(result, name)
|
33
|
+
|
34
|
+
if matched_key
|
35
|
+
result[matched_key]
|
36
|
+
else
|
37
|
+
nil
|
20
38
|
end
|
21
39
|
end
|
22
40
|
end
|
data/lib/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fcc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Keen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.18'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: lightly
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.3.3
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.3.3
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -157,7 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
171
|
- !ruby/object:Gem::Version
|
158
172
|
version: '0'
|
159
173
|
requirements: []
|
160
|
-
rubygems_version: 3.1.
|
174
|
+
rubygems_version: 3.1.4
|
161
175
|
signing_key:
|
162
176
|
specification_version: 4
|
163
177
|
summary: Searches the FCC's FM, AM, and TV databases
|