newznab-api 0.1.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.
@@ -0,0 +1,91 @@
1
+ module Newznab
2
+ module Api
3
+ ##
4
+ # Class representing a single Newznab item
5
+ class Item
6
+
7
+ attr_reader :title, :guid, :link, :pub_date, :description, :metadata
8
+
9
+ ##
10
+ # @param args [Hash<String, Object>] Item hash from response
11
+ # @return [Newznab::Item]
12
+ # @since 0.1.0
13
+ def initialize(args)
14
+
15
+ @raw_resp = args
16
+ @metadata = {}
17
+
18
+ args.each_pair do |k, v|
19
+ case k
20
+ when 'title'
21
+ @title = v
22
+ when 'guid'
23
+ @guid = v
24
+ when 'link'
25
+ @link = v
26
+ when 'pubDate'
27
+ @pub_date = Date.parse(v)
28
+ when 'description'
29
+ @description = v
30
+ when 'enclosure'
31
+ @_attributes = v['@attributes']
32
+ when 'attr'
33
+ @metadata = _parse_attr(v)
34
+ else
35
+ # Do nothing
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ ##
43
+ # @param attrs [Array<Hash<Hash<String, String>>>] Newznab attr array response
44
+ # @return [Hash<String, Array<String>>]
45
+ # @since 0.1.0
46
+ def _parse_attr(attrs)
47
+
48
+ metadata = {}
49
+ attrs.each do |attr|
50
+ name = attr['@attributes']['name']
51
+ value = attr['@attributes']['value']
52
+
53
+ if metadata.has_key? name
54
+ metadata[name].push value
55
+ else
56
+ metadata[name] = [value]
57
+ end
58
+ end
59
+ new_meta = {}
60
+ metadata.each { |k, v| new_meta[k] = v.count.eql?(1) ? v.first : v }
61
+ new_meta
62
+ end
63
+
64
+ # @since 0.1.0
65
+ def method_missing(id, *args)
66
+ begin
67
+ if @_attributes.has_key? id.to_s
68
+ @_attributes[id.to_s]
69
+ elsif @metadata.has_key? id.to_s
70
+ @metadata[id.to_s]
71
+ else
72
+ super
73
+ end
74
+ end
75
+ end
76
+
77
+ # @since 0.1.0
78
+ def respond_to_missing?(id, *args)
79
+ begin
80
+ if @_attributes.has_key? id.to_s
81
+ true
82
+ elsif @metadata.has_key? id.to_s
83
+ true
84
+ else
85
+ super
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,139 @@
1
+ require 'newznab/api'
2
+
3
+ module Newznab
4
+ module Api
5
+ ##
6
+ # Enumerable list for multiple results
7
+ class List
8
+ include Enumerable
9
+
10
+ attr_reader :total_count
11
+ attr_reader :offset
12
+ attr_reader :limit
13
+ attr_reader :cvos
14
+
15
+ # @since 0.1.0
16
+ def initialize(resp, options)
17
+ update_ivals(resp)
18
+
19
+ if options.has_key? :limit
20
+ @limit = options[:limit]
21
+ end
22
+ end
23
+
24
+ # @since 0.1.0
25
+ def each
26
+ @cvos.each { |c| yield c }
27
+ end
28
+
29
+ # Returns the current page the object is on
30
+ # @return [Integer]
31
+ # @since 0.1.0
32
+ def page
33
+ (self.offset / self.limit) + 1
34
+ end
35
+
36
+ # Returns the total number of pages available
37
+ # @return [Integer] Total number of pages
38
+ # @since 0.1.0
39
+ def total_pages
40
+ (self.total_count / self.limit) + 1
41
+ end
42
+
43
+ # Returns if there are more pages to load
44
+ # @return [true, false]
45
+ # @since 0.1.0
46
+ def has_more?
47
+ self.total_pages > self.page ? true : false
48
+ end
49
+
50
+ protected
51
+
52
+ ##
53
+ # Updates array list to new values
54
+ # @param new_cvol [Hash] Response hash from {Newznab::Api}
55
+ # @since 0.1.0
56
+ def update_ivals(new_cvol)
57
+ @_attributes = new_cvol['@attributes']
58
+
59
+ if new_cvol.has_key?('channel') && new_cvol['channel'].has_key?('response')
60
+ @total_count = new_cvol['channel']['response']['@attributes']['total'].to_i
61
+ @offset = new_cvol['channel']['response']['@attributes']['offset'].to_i
62
+
63
+ @cvos = new_cvol['channel']['item']
64
+ end
65
+ end
66
+
67
+ # @since 0.1.0
68
+ def method_missing(id, *args)
69
+ begin
70
+ if @_attributes.has_key? id.to_s
71
+ @_attributes[id.to_s]
72
+ elsif @cvos.respond_to? id
73
+ @cvos.method(id).call(*args)
74
+ else
75
+ super
76
+ end
77
+ end
78
+ end
79
+
80
+ # @since 0.1.0
81
+ def respond_to_missing?(id, *args)
82
+ begin
83
+ if @_attributes.has_key? id.to_s
84
+ true
85
+ elsif @cvos.respond_to? id
86
+ true
87
+ else
88
+ super
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ ##
95
+ # Enumerable list for multiple {Newznab::Api::Item} results. Including pagination, and methods to navigate them
96
+ class SearchResults < List
97
+
98
+ attr_reader :raw_resp, :query, :function
99
+
100
+ # @param resp [Hash] Response hash from {Newznab::Api}
101
+ # @param function [Symbol] Function from {Newznab::Api::API_FUNCTIONS}
102
+ # @param query [Hash] Query parameters from search
103
+ # @since 0.1.0
104
+ def initialize(resp, function, query)
105
+ super(resp, query)
106
+
107
+ @function = function
108
+ @raw_resp = resp
109
+ @query = query
110
+
111
+ # Check for multiple/single results
112
+ if resp['channel']['item'].kind_of? Array
113
+ @cvos = resp['channel']['item'].collect { |o| Newznab::Api::Item.new(o) }
114
+ elsif resp['channel']['item'].kind_of? Hash
115
+ @cvos = [Newznab::Api::Item.new(resp['channel']['item'])]
116
+ end
117
+
118
+ end
119
+
120
+ # ##
121
+ # Moves search to the next offset results
122
+ # @since 0.1.0
123
+ def next_page!
124
+ return nil if (self.offset + self.total_pages) >= self.total_count
125
+ @query[:offset] = self.offset + self.limit
126
+ self.update_ivals(Newznab::Api.get(api_function: self.function, **self.query))
127
+ end
128
+
129
+ ##
130
+ # Moves search to the previous offset results
131
+ # @since 0.1.0
132
+ def prev_page!
133
+ return nil if @offset == 0
134
+ @query[:offset] = self.offset - self.limit
135
+ self.update_ivals(Newznab::Api.get(api_function: self.function, **self.query))
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,193 @@
1
+ ## Yard Doc generation stuff
2
+ # @!macro [new] raise.FunctionNotSupportedError
3
+ # @raise [FunctionNotSupportedError] indicating the resource requested is not supported
4
+ # @!macro [new] raise.NewznabAPIError
5
+ # @raise [NewznabAPIError] indicating the api request code received
6
+ # @!macro [new] search.params
7
+ # @param query [String] Search input (URL/UTF-8 encoded). Case insensitive.
8
+ # @param group [Array] List of usenet groups to search delimited by ”,”
9
+ # @param limit [Integer] Upper limit for the number of items to be returned.
10
+ # @param cat [Array] List of categories to search delimited by ”,”
11
+ # @param attrs [Array] List of requested extended attributes delimeted by ”,”
12
+ # @param extended [true, false] List all extended attributes (attrs ignored)
13
+ # @param delete [true, false] Delete the item from a users cart on download.
14
+ # @param maxage [Integer] Only return results which were posted to usenet in the last x days.
15
+ # @param offset [Integer] The 0 based query offset defining which part of the response we want.
16
+
17
+ module Newznab
18
+ module Api
19
+ ##
20
+ # Module to hold search specific functions
21
+ module Search
22
+
23
+ ##
24
+ # Perform a search with the provided optional params
25
+ # @macro search.params
26
+ # @return [Newznab::SearchResults]
27
+ # @since 0.1.0
28
+ # @macro raise.NewznabAPIError
29
+ def search(**params)
30
+ args = _parse_search_args(**params)
31
+ Newznab::Api::SearchResults.new(_make_request(:search, **args), :search, args)
32
+ end
33
+
34
+ ##
35
+ # Perform a tv-search with the provided optional params
36
+ # @param rid [Integer] TVRage id of the item being queried.
37
+ # @param season [String] Season string, e.g S13 or 13 for the item being queried.
38
+ # @param ep [String] Episode string, e.g E13 or 13 for the item being queried.
39
+ # @macro search.params
40
+ # @macro raise.NewznabAPIError
41
+ # @return [Newznab::SearchResults]
42
+ # @since 0.1.0
43
+ def tv_search(rid: nil, season: nil, ep: nil, **params)
44
+ args = _parse_search_args(**params)
45
+
46
+ unless rid.nil?
47
+ args[:rid] = rid.to_s.encode('utf-8')
48
+ end
49
+
50
+ unless season.nil?
51
+ args[:season] = season.to_s.encode('utf-8')
52
+ end
53
+
54
+ unless ep.nil?
55
+ args[:ep] = ep.to_s.encode('utf-8')
56
+ end
57
+
58
+ Newznab::Api::SearchResults.new(_make_request(:tvsearch, **args), :tvsearch, args)
59
+ end
60
+
61
+ ##
62
+ # Perform a movie-search with the provided optional params
63
+ # @param imdbid [String] IMDB id of the item being queried e.g. 0058935.
64
+ # @param genre [String] A genre string i.e. ‘Romance’ would match ‘(Comedy, Drama, Indie, Romance)’
65
+ # @macro search.params
66
+ # @macro raise.NewznabAPIError
67
+ # @return [Newznab::SearchResults]
68
+ # @since 0.1.0
69
+ def movie_search(imdbid: nil, genre: nil, **params)
70
+ args = _parse_search_args(**params)
71
+
72
+ unless imdbid.nil?
73
+ args[:imdbid] = imdbid.to_s.encode('utf-8')
74
+ end
75
+
76
+ unless genre.nil?
77
+ args[:genre] = genre.to_s.encode('utf-8')
78
+ end
79
+
80
+ Newznab::Api::SearchResults.new(_make_request(:movie, **args), :movie, args)
81
+ end
82
+
83
+ ##
84
+ # Perform a music-search with the provided optional params
85
+ # @param album [String] Album title (URL/UTF-8 encoded). Case insensitive.
86
+ # @param artist [String] Artist name (URL/UTF-8 encoded). Case insensitive.
87
+ # @param label [String] Publisher/Label name (URL/UTF-8 encoded). Case insensitive.
88
+ # @param track [String] Track name (URL/UTF-8 encoded). Case insensitive.
89
+ # @param year [String] Four digit year of release.
90
+ # @param genre [String] A genre string i.e. ‘Romance’ would match ‘(Comedy, Drama, Indie, Romance)’
91
+ # @macro search.params
92
+ # @macro raise.NewznabAPIError
93
+ # @return [Newznab::SearchResults]
94
+ # @since 0.1.0
95
+ def music_search(album: nil, artist: nil, label: nil, track: nil, year: nil, genre: nil, **params)
96
+ args = _parse_search_args(**params)
97
+
98
+ unless album.nil?
99
+ args[:album] = album.to_s.encode('utf-8')
100
+ end
101
+
102
+ unless artist.nil?
103
+ args[:artist] = artist.to_s.encode('utf-8')
104
+ end
105
+
106
+ unless label.nil?
107
+ args[:label] = label.to_s.encode('utf-8')
108
+ end
109
+
110
+ unless track.nil?
111
+ args[:track] = track.to_s.encode('utf-8')
112
+ end
113
+
114
+ unless year.nil?
115
+ args[:year] = year.to_s.encode('utf-8')
116
+ end
117
+
118
+ unless genre.nil?
119
+ args[:genre] = genre.to_s.encode('utf-8')
120
+ end
121
+
122
+ Newznab::Api::SearchResults.new(_make_request(:music, **args), :music, args)
123
+ end
124
+
125
+ ##
126
+ # Perform a book-search with the provided optional params
127
+ # @param title [String] Book title (URL/UTF-8 encoded). Case insensitive.
128
+ # @param author [String] Author name (URL/UTF-8 encoded). Case insensitive.
129
+ # @macro search.params
130
+ # @macro raise.NewznabAPIError
131
+ # @return [Newznab::SearchResults]
132
+ # @since 0.1.0
133
+ def book_search(title: nil, author: nil, **params)
134
+ args = _parse_search_args(**params)
135
+
136
+ unless title.nil?
137
+ args[:title] = title.to_s.encode('utf-8')
138
+ end
139
+
140
+ unless author.nil?
141
+ args[:author] = author.to_s.encode('utf-8')
142
+ end
143
+
144
+ Newznab::Api::SearchResults.new(_make_request(:book, **args), :book, args)
145
+ end
146
+
147
+
148
+ private
149
+
150
+ ##
151
+ # @macro search.params
152
+ # @return [Hash]
153
+ # @since 0.1.0
154
+ def _parse_search_args(query: nil, group: [], limit: nil, cat: [], attrs: [], extended: false, delete: false, maxage: nil, offset: nil)
155
+ params = {
156
+ extended: extended ? '1' : '0',
157
+ del: delete ? '1' : '0',
158
+ }
159
+
160
+ unless query.nil?
161
+ params[:q] = query.to_s.encode('utf-8')
162
+ end
163
+
164
+ unless maxage.nil?
165
+ params[:maxage] = maxage.to_i
166
+ end
167
+
168
+ unless offset.nil?
169
+ params[:offset] = offset.to_i
170
+ end
171
+
172
+ unless limit.nil?
173
+ params[:limit] = limit.to_i
174
+ end
175
+
176
+ unless group.empty?
177
+ params[:group] = group.collect { |o| o.to_s.encode('utf-8') }.join(',')
178
+ end
179
+
180
+ unless cat.empty?
181
+ params[:cat] = cat.collect { |o| o.to_s.encode('utf-8') }.join(',')
182
+ end
183
+
184
+ unless attrs.empty?
185
+ params[:group] = attrs.collect { |o| o.to_s.encode('utf-8') }.join(',')
186
+ end
187
+
188
+ params
189
+ end
190
+
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,6 @@
1
+ module Newznab
2
+ module Api
3
+ # Newznab::Api gem version
4
+ VERSION = '0.1.0'
5
+ end
6
+ end
@@ -0,0 +1,42 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'newznab/api/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'newznab-api'
8
+ spec.version = Newznab::Api::VERSION
9
+ spec.authors = ['Holden Omans']
10
+ spec.email = ['holden.omans@gmail.com']
11
+
12
+ spec.summary = %q{Api interface to Newznab servers.}
13
+ spec.description = %q{Api interface to Newznab servers. Allows for searches and returning specific information on resources.}
14
+ spec.homepage = 'https://github.com/kalinon/ruby-newznab-api'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = 'exe'
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ['lib']
23
+ spec.required_ruby_version = '>= 2.2'
24
+
25
+ spec.cert_chain = ['certs/homans.pem']
26
+ spec.signing_key = File.expand_path('~/.ssh/gem-private_key.pem') if $0 =~ /gem\z/
27
+
28
+ spec.add_development_dependency 'bundler', '~> 1.13'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'minitest', '~> 5.9', '>= 5.9.1'
31
+ spec.add_development_dependency 'minitest-reporters', '~> 1.1', '>= 1.1.12'
32
+ spec.add_development_dependency 'rdoc', '~> 4.2', '>= 4.2.1'
33
+ spec.add_development_dependency 'yard', '~> 0.9', '>= 0.9.5'
34
+ spec.add_development_dependency 'dotenv-rails', '~> 2.2'
35
+ spec.add_development_dependency 'faker', '~> 1.7', '>= 1.7.3'
36
+ spec.add_development_dependency 'minitest-vcr', '~> 1.4'
37
+ spec.add_development_dependency 'nokogiri', '~> 1.7', '>= 1.7.1'
38
+
39
+ # Dependencies
40
+ spec.add_dependency 'rest-client', '~> 2.0'
41
+ spec.add_dependency 'mono_logger', '~> 1.1'
42
+ end