kodi_client 0.4.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,300 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kodi_client/global_types/item_types'
4
+ require 'kodi_client/global_types/global_types'
5
+ require 'kodi_client/util/comparable'
6
+ require 'kodi_client/util/iterable'
7
+
8
+ module KodiClient
9
+ module Types
10
+ module Player
11
+
12
+ # enum for in/out zoom
13
+ module Zoom
14
+ extend Iterable
15
+
16
+ IN = 'in'
17
+ OUT = 'out'
18
+ end
19
+
20
+ # Player.ViewMode https://kodi.wiki/view/JSON-RPC_API/v12#Player.ViewMode
21
+ module ViewMode
22
+ extend Iterable
23
+ NORMAL = 'normal'
24
+ ZOOM = 'zoom'
25
+ STRETCH_4x3 = 'strech4x3'
26
+ WIDE_ZOOM = 'widezoom'
27
+ STRETCH_16x9 = 'stretch16x9'
28
+ ORIGINAL = 'original'
29
+ STRETCH_16x9_NONLIN = 'stretch16x9nonline'
30
+ ZOOM_120_WIDTH = 'zoom120width'
31
+ ZOOM_110_WIDTH = 'zoom110width'
32
+ end
33
+
34
+ # player types
35
+ module PlayerVisibilityType
36
+ extend Iterable
37
+ INTERNAL = 'internal'
38
+ EXTERNAL = 'external'
39
+ REMOTE = 'remote'
40
+ end
41
+
42
+ # Player.Type https://kodi.wiki/view/JSON-RPC_API/v12#Player.Type
43
+ module PlayerType
44
+ extend Iterable
45
+
46
+ VIDEO = 'video'
47
+ AUDIO = 'audio'
48
+ PICTURE = 'picture'
49
+ end
50
+
51
+ # Player.Repeat https://kodi.wiki/view/JSON-RPC_API/v12#Player.Repeat
52
+ module PlayerRepeat
53
+ extend Iterable
54
+
55
+ OFF = 'off'
56
+ ONE = 'one'
57
+ ALL = 'all'
58
+ CYCLE = 'cycle'
59
+ end
60
+
61
+ # player speed enum, -32 to 32
62
+ module PlayerSpeed
63
+ extend Iterable
64
+
65
+ MINUS_32 = -32
66
+ MINUS_16 = -16
67
+ MINUS_8 = -8
68
+ MINUS_4 = -4
69
+ MINUS_2 = -2
70
+ MINUS_1 = -1
71
+ NEUTRAL = 0
72
+ PLUS_1 = 1
73
+ PLUS_2 = 2
74
+ PLUS_4 = 4
75
+ PLUS_8 = 8
76
+ PLUS_16 = 16
77
+ PLUS_32 = 32
78
+ end
79
+
80
+ # player id and type
81
+ class Player
82
+ include Comparable
83
+
84
+ attr_reader :player_id, :player_type, :type, :name, :plays_audio, :plays_video
85
+
86
+ def initialize(hash)
87
+ @player_id = hash['playerid']
88
+ @player_type = hash['playertype']
89
+ @type = hash['type']
90
+ @name = hash['name']
91
+ @plays_audio = hash['playsaudio']
92
+ @plays_video = hash['playsvideo']
93
+ end
94
+
95
+ def ==(other)
96
+ compare(self, other)
97
+ end
98
+ end
99
+
100
+ # Player Subtitle https://kodi.wiki/view/JSON-RPC_API/v12#Player.Subtitle
101
+ class Subtitle
102
+ include Comparable
103
+
104
+ attr_reader :index, :is_default, :is_forced, :is_impaired, :language, :name
105
+
106
+ def initialize(hash)
107
+ @index = hash['index']
108
+ @is_default = hash['isdefault']
109
+ @is_forced = hash['isforced']
110
+ @is_impaired = hash['isimpaired']
111
+ @language = hash['language']
112
+ @name = hash['name']
113
+ end
114
+
115
+ def ==(other)
116
+ compare(self, other)
117
+ end
118
+ end
119
+
120
+ # Player.Audio.Stream https://kodi.wiki/view/JSON-RPC_API/v12#Player.Audio.Stream
121
+ class AudioStream
122
+ include Comparable
123
+
124
+ attr_reader :bitrate, :channels, :codec, :index, :is_default, :is_forced, :is_original, :language,
125
+ :name, :sample_rate
126
+
127
+ def initialize(hash)
128
+ @bitrate = hash['bitrate']
129
+ @channels = hash['channels']
130
+ @codec = hash['codec']
131
+ @index = hash['index']
132
+ @is_default = hash['isdefault']
133
+ @is_forced = hash['isforced']
134
+ @is_original = hash['isoriginal']
135
+ @language = hash['language']
136
+ @name = hash['name']
137
+ @sample_rate = hash['samplerate']
138
+ end
139
+
140
+ def ==(other)
141
+ compare(self, other)
142
+ end
143
+ end
144
+
145
+ # Player.Video.Stream https://kodi.wiki/view/JSON-RPC_API/v12#Player.Video.Stream
146
+ class VideoStream
147
+ include Comparable
148
+
149
+ attr_reader :codec, :height, :index, :language, :name, :width, :duration, :aspect
150
+
151
+ def initialize(hash)
152
+ @codec = hash['codec']
153
+ @height = hash['height']
154
+ @index = hash['index']
155
+ @language = hash['language']
156
+ @name = hash['name']
157
+ @width = hash['width']
158
+ @duration = hash['duration']
159
+ @aspect = hash['aspect']
160
+ end
161
+
162
+ def ==(other)
163
+ compare(self, other)
164
+ end
165
+ end
166
+
167
+ # Player.Property.Name https://kodi.wiki/view/JSON-RPC_API/v12#Player.Property.Name
168
+ module PropertyName
169
+ extend Iterable
170
+
171
+ AUDIOSTREAMS = 'audiostreams'
172
+ CANCHANGESPEED = 'canchangespeed'
173
+ CANMOVE = 'canmove'
174
+ CANREPEAT = 'canrepeat'
175
+ CANROTATE = 'canrotate'
176
+ CANSEEK = 'canseek'
177
+ CANSHUFFLE = 'canshuffle'
178
+ CANZOOM = 'canzoom'
179
+ CURRENTAUDIOSTREAM = 'currentaudiostream'
180
+ CURRENTSUBTITLE = 'currentsubtitle'
181
+ CURRENTVIDEOSTREAM = 'currentvideostream'
182
+ LIVE = 'live'
183
+ PARTYMODE = 'partymode'
184
+ PERCENTAGE = 'percentage'
185
+ PLAYLISTID = 'playlistid'
186
+ POSITION = 'position'
187
+ REPEAT = 'repeat'
188
+ SHUFFLED = 'shuffled'
189
+ SPEED = 'speed'
190
+ SUBTITLEENABLED = 'subtitleenabled'
191
+ SUBTITLES = 'subtitles'
192
+ TIME = 'time'
193
+ TOTALTIME = 'totaltime'
194
+ TYPE = 'type'
195
+ VIDEOSTREAMS = 'videostreams'
196
+ end
197
+
198
+ # Player.Property.Value https://kodi.wiki/view/JSON-RPC_API/v12#Player.Property.Name
199
+ class PropertyValue
200
+ include Comparable
201
+
202
+ def initialize(hash)
203
+ @audio_streams = hash['audiostreams'].map { |it| AudioStream.new(it) }
204
+ @cache_percentage = hash['cachepercentage']
205
+ @can_change_speed = hash['canchangespeed']
206
+ @can_move = hash['canmove']
207
+ @can_repeat = hash['canrepeat']
208
+ @can_rotate = hash['canrotate']
209
+ @can_seek = hash['canseek']
210
+ @can_shuffle = hash['canshuffle']
211
+ @can_zoom = hash['canzoom']
212
+ @current_audio_stream = AudioStream.new(hash['currentaudiostream'])
213
+ @current_subtitle = Subtitle.new(hash['currentsubtitle'])
214
+ @current_video_stream = VideoStream.new(hash['currentvideostream'])
215
+ @live = hash['live']
216
+ @party_mode = hash['partymode']
217
+ @percentage = hash['percentage']
218
+ @playlist_id = hash['playlistid'].nil? ? -1 : hash['playlistid']
219
+ @position = hash['position'].nil? ? -1 : hash['position']
220
+ @position = hash['position'].nil? ? -1 : hash['position']
221
+ @repeat = hash['repeat'].nil? ? PlayerRepeat::OFF : hash['repeat']
222
+ @shuffled = hash['shuffled']
223
+ @speed = hash['speed']
224
+ @subtitle_enabled = hash['subtitleenabled']
225
+ @subtitles = hash['subtitles'].map { |it| Subtitle.new(it) }
226
+ @time = Types::Global::GlobalTime.new(hash['time'])
227
+ @total_time = Types::Global::GlobalTime.new(hash['totaltime'])
228
+ @type = hash['type'].nil? ? PlayerType::VIDEO : hash['type']
229
+ @video_streams = hash['videostreams'].map { |it| VideoStream.new(it) }
230
+ end
231
+
232
+ def ==(other)
233
+ compare(self, other)
234
+ end
235
+ end
236
+
237
+ # return value for Player.GetViewMode
238
+ class PlayerViewMode
239
+ include Comparable
240
+
241
+ attr_reader :nonlinear_stretch, :pixel_ratio, :vertical_shift, :view_mode, :zoom
242
+
243
+ def initialize(hash)
244
+ @nonlinear_stretch = hash['nonlinearstretch']
245
+ @pixel_ratio = hash['pixelratio']
246
+ @vertical_shift = hash['verticalshift']
247
+ @view_mode = hash['viewed']
248
+ @zoom = hash['zoom']
249
+ end
250
+
251
+ def ==(other)
252
+ compare(self, other)
253
+ end
254
+ end
255
+
256
+ # Player.Position.Time https://kodi.wiki/view/JSON-RPC_API/v12#Player.Position.Time
257
+ class PlayerPositionTime
258
+ include Comparable
259
+
260
+ attr_reader :hours, :minutes, :seconds, :milliseconds
261
+
262
+ def initialize(hash)
263
+ @hours = hash['hours']
264
+ @minutes = hash['minutes']
265
+ @seconds = hash['seconds']
266
+ @milliseconds = hash['milliseconds']
267
+ end
268
+
269
+ def ==(other)
270
+ compare(self, other)
271
+ end
272
+ end
273
+
274
+ # defines the jump size for seek
275
+ module SeekJump
276
+ include Iterable
277
+
278
+ SMALL_FORWARD = 'smallforward'
279
+ SMALL_BACKWARD = 'smallbackward'
280
+ BIG_FORWARD = 'bigforward'
281
+ BIG_BACKWARD = 'bigbackward'
282
+ end
283
+
284
+ # return value of Player.Seek
285
+ class SeekReturnValue
286
+ include Comparable
287
+
288
+ def initialize(hash)
289
+ @percentage = hash['percentage']
290
+ @time = Types::Global::GlobalTime.new(hash['time'])
291
+ @total_time = Types::Global::GlobalTime.new(hash['totaltime'])
292
+ end
293
+
294
+ def ==(other)
295
+ compare(self, other)
296
+ end
297
+ end
298
+ end
299
+ end
300
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kodi_client/util/iterable'
4
+
5
+ module KodiClient
6
+ module Types
7
+ module PVR
8
+
9
+ # PVR.Channel.Type https://kodi.wiki/view/JSON-RPC_API/v12#PVR.Channel.Type
10
+ module ChannelType
11
+ TV = 'TV'
12
+ RADIO = 'Radio'
13
+ end
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kodi_client/global_types/media_types'
4
+ require 'kodi_client/global_types/player_type'
5
+ require 'kodi_client/util/comparable'
6
+
7
+ module KodiClient
8
+ module Types
9
+ module Video
10
+
11
+ # Video.Details.Base https://kodi.wiki/view/JSON-RPC_API/v12#Video.Details.Base
12
+ module VideoDetailsBase
13
+ include Media::MediaDetailsBase
14
+
15
+ attr_reader :art, :play_count
16
+
17
+ def video_details_base(hash)
18
+ @art = Types::Media::MediaArtwork.new(hash['art'])
19
+ @play_count = ['playcount']
20
+ media_details_base(hash)
21
+ end
22
+ end
23
+
24
+ # Video.Cast https://kodi.wiki/view/JSON-RPC_API/v12#Video.Cast
25
+ class VideoCast
26
+ include Comparable
27
+
28
+ attr_reader :name, :order, :role, :thumbnail
29
+
30
+ def initialize(hash)
31
+ @name = hash['name']
32
+ @order = hash['order']
33
+ @role = hash['role']
34
+ @thumbnail = hash['thumbnail']
35
+ end
36
+
37
+ def ==(other)
38
+ compare(self, other)
39
+ end
40
+ end
41
+
42
+ # Video.Details.Media https://kodi.wiki/view/JSON-RPC_API/v12#Video.Details.Media
43
+ module VideoDetailsMedia
44
+ include VideoDetailsBase
45
+
46
+ attr_reader :title
47
+
48
+ def video_details_media(hash)
49
+ @title = hash['title']
50
+ video_details_base(hash)
51
+ end
52
+ end
53
+
54
+ # Video.Details.Item https://kodi.wiki/view/JSON-RPC_API/v12#Video.Details.Item
55
+ module VideoDetailsItem
56
+ include VideoDetailsMedia
57
+
58
+ attr_reader :date_added, :file, :last_played, :plot
59
+
60
+ def video_details_item(hash)
61
+ @date_added = hash['dateadded']
62
+ @file = hash['file']
63
+ @last_played = hash['lastplayed']
64
+ @plot = hash['plot']
65
+ video_details_media(hash)
66
+ end
67
+ end
68
+
69
+ # Video.Details.File https://kodi.wiki/view/JSON-RPC_API/v12#Video.Details.File
70
+ module VideoDetailsFile
71
+ include VideoDetailsItem
72
+
73
+ attr_reader :director, :resume, :runtime, :stream_details
74
+
75
+ def video_details_file(hash)
76
+ @director = hash['director']
77
+ @resume = VideoResume.new(hash['resume'])
78
+ @runtime = hash['runtime']
79
+ @stream_details = Streams.new(hash['streamdetails'])
80
+ video_details_item(hash)
81
+ end
82
+ end
83
+
84
+ # Video.Resume https://kodi.wiki/view/JSON-RPC_API/v12#Video.Resume
85
+ class VideoResume
86
+ include Comparable
87
+
88
+ attr_reader :position, :total
89
+
90
+ def initialize(hash)
91
+ @position = hash['position']
92
+ @total = hash['total']
93
+ end
94
+
95
+ def ==(other)
96
+ compare(self, other)
97
+ end
98
+ end
99
+
100
+ # Video.Streams https://kodi.wiki/view/JSON-RPC_API/v12#Video.Streams
101
+ class Streams
102
+ include Comparable
103
+
104
+ attr_reader :audio, :subtitle, :video
105
+
106
+ def initialize(hash)
107
+ @audio = hash['audio'].nil? ? [] : hash['audio'].map { |it| Types::Player::AudioStream.new(it) }
108
+ @subtitle = hash['subtitle'].nil? ? [] : hash['subtitle'].map { |it| Types::Player::Subtitle.new(it) }
109
+ @video = hash['video'].nil? ? [] : hash['video'].map { |it| Types::Player::VideoStream.new(it) }
110
+ end
111
+
112
+ def ==(other)
113
+ compare(self, other)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'http'
4
+ require 'kodi_client/util/comparable'
5
+
6
+ module KodiClient
7
+
8
+ # the client that stores
9
+ class KodiModule
10
+
11
+ def apply_options(options)
12
+ @endpoint_url = "#{options.tls ? 'https://' : 'http://'}#{options.ip}:#{options.port}/jsonrpc"
13
+ @options = options
14
+ end
15
+
16
+ def invoke_api(request)
17
+ h = request.instance_variables.each_with_object({}) do |var, hash|
18
+ hash[var.to_s.delete('@')] = request.instance_variable_get(var)
19
+ end
20
+ @http_client ||= build_client
21
+ response = @http_client.post(@endpoint_url, json: h).to_s
22
+ JSON.parse(response)
23
+ end
24
+
25
+ def build_client
26
+ client = HTTP.headers(Content_Type: 'application/json')
27
+ if !@options.username.nil? && !@options.password.nil?
28
+ client = client.basic_auth({ user: @options.username, pass: @options.password })
29
+ end
30
+
31
+ client
32
+ end
33
+
34
+ private :build_client
35
+ end
36
+
37
+ # represents an error response
38
+ class KodiError
39
+
40
+ attr_reader :code, :message
41
+
42
+ def initialize(hash)
43
+ @code = hash['code']
44
+ @message = hash['message']
45
+ end
46
+
47
+ def ==(other)
48
+ @code == other.code && @message == other.message
49
+ end
50
+ end
51
+
52
+ # represents a kodi requests
53
+ class KodiRequest
54
+
55
+ attr_accessor :id, :jsonrpc, :method, :params
56
+
57
+ def initialize(kodi_id, method, params = {}, jsonrpc = '2.0')
58
+ @id = kodi_id
59
+ @jsonrpc = jsonrpc
60
+ @method = method
61
+ @params = params
62
+ end
63
+ end
64
+
65
+ # represents a kodi response
66
+ class KodiResponse
67
+ include Comparable
68
+
69
+ attr_reader :id, :jsonrpc, :result, :error
70
+
71
+ def initialize(hash)
72
+ @id = hash['id']
73
+ @jsonrpc = hash['jsonrpc']
74
+ @result = hash['result']
75
+ @error = KodiError.new(hash['error']) unless hash['error'].nil?
76
+ end
77
+
78
+ def error?
79
+ !@error.nil?
80
+ end
81
+
82
+ def ==(other)
83
+ compare(self, other)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kodi_client/kodi_module'
4
+ require 'kodi_client/global_types/addon_types'
5
+ require 'kodi_client/global_types/list_types'
6
+
7
+ module KodiClient
8
+ module Modules
9
+ # contains all Kodi Application methods
10
+ class Addons < KodiModule
11
+
12
+ EXECUTE_ADDON = 'Addons.ExecuteAddon'
13
+ GET_ADDON_DETAILS = 'Addons.GetAddonDetails'
14
+ GET_ADDONS = 'Addons.GetAddons'
15
+ SET_ADDON_ENABLED = 'Addons.SetAddonEnabled'
16
+
17
+ def get_addons(type = Types::Addons::AddonTypes::UNKNOWN,
18
+ content = Types::Addons::AddonContent::UNKNOWN,
19
+ enabled = nil, properties = [],
20
+ limit = Types::List::ListLimits.new(0, 50), installed = nil, kodi_id = 1)
21
+ request = KodiRequest.new(kodi_id, GET_ADDONS,
22
+ {
23
+ 'type' => type,
24
+ 'content' => content,
25
+ 'enabled' => enabled.nil? || !enabled ? 'all' : 'enabled',
26
+ 'properties' => properties,
27
+ 'limits' => { 'start' => limit.list_start, 'end' => limit.list_end },
28
+ 'installed' => installed.nil? || !installed ? 'all' : 'installed'
29
+ })
30
+ json = invoke_api(request)
31
+
32
+ result = json['result'].nil? ? nil : Types::Addons::Addons.new(json['result'])
33
+ json['result'] = result
34
+ KodiResponse.new(json)
35
+ end
36
+
37
+ def get_addon_details(addon_id = nil, properties = [], kodi_id = 1)
38
+ request = KodiRequest.new(kodi_id, GET_ADDON_DETAILS,
39
+ {
40
+ 'addonid' => addon_id,
41
+ 'properties' => properties
42
+ })
43
+ json = invoke_api(request)
44
+
45
+ result = json['result'].nil? ? nil : Types::Addons::Addon.new(json['result'])
46
+ json['result'] = result
47
+ KodiResponse.new(json)
48
+ end
49
+
50
+ def execute_addon(addon_id = nil, params = '', wait = false, kodi_id = 1)
51
+ request = KodiRequest.new(kodi_id, EXECUTE_ADDON,
52
+ {
53
+ 'addonid' => addon_id,
54
+ 'params' => params,
55
+ 'wait' => wait
56
+ })
57
+ json = invoke_api(request)
58
+ KodiResponse.new(json)
59
+ end
60
+
61
+ def set_addon_enabled(addon_id = nil, enabled = Types::Global::Toggle::TOGGLE, kodi_id = 1)
62
+ request = KodiRequest.new(kodi_id, SET_ADDON_ENABLED,
63
+ {
64
+ 'addonid' => addon_id,
65
+ 'enabled' => enabled
66
+ })
67
+ json = invoke_api(request)
68
+ KodiResponse.new(json)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kodi_client/kodi_module'
4
+ require 'kodi_client/global_types/application_types'
5
+
6
+ module KodiClient
7
+ module Modules
8
+ # contains all Kodi Application methods
9
+ class Application < KodiModule
10
+
11
+ QUIT = 'Application.Quit'
12
+ SET_MUTE = 'Application.SetMute'
13
+ SET_VOLUME = 'Application.SetVolume'
14
+ GET_PROPERTIES = 'Application.GetProperties'
15
+
16
+ def quit(kodi_id = 1)
17
+ request = KodiRequest.new(kodi_id, QUIT)
18
+ json = invoke_api(request)
19
+ KodiResponse.new(json)
20
+ end
21
+
22
+ def mute(kodi_id = 1, mute_state: Types::Global::Toggle::TOGGLE)
23
+ request = KodiRequest.new(kodi_id, SET_MUTE, { 'mute' => mute_state })
24
+ json = invoke_api(request)
25
+ KodiResponse.new(json)
26
+ end
27
+
28
+ def get_properties(properties = Types::Application::PropertyName.all_properties, kodi_id = 1)
29
+ request = KodiRequest.new(kodi_id, GET_PROPERTIES, { 'properties' => properties })
30
+ json = invoke_api(request)
31
+ result = json['result'].nil? ? nil : Types::Application::PropertyValue.new(json['result'])
32
+ json['result'] = result
33
+ KodiResponse.new(json)
34
+ end
35
+
36
+ def set_volume(volume, kodi_id = 1)
37
+ set_volume_incr_decr_vol(volume, kodi_id)
38
+ end
39
+
40
+ def increment_volume(kodi_id = 1)
41
+ set_volume_incr_decr_vol(Types::Global::IncrementDecrement::INCREMENT, kodi_id)
42
+ end
43
+
44
+ def decrement_volume(kodi_id = 1)
45
+ set_volume_incr_decr_vol(Types::Global::IncrementDecrement::INCREMENT, kodi_id)
46
+ end
47
+
48
+ def set_volume_incr_decr_vol(volume, kodi_id = 1)
49
+ if volume.is_a?(Integer) && (volume > 100 || volume.negative?)
50
+ throw ArgumentError.new('Volume must be between 0 and 100.')
51
+ end
52
+ request = KodiRequest.new(kodi_id, SET_VOLUME, { 'volume' => volume })
53
+ json = invoke_api(request)
54
+ KodiResponse.new(json)
55
+ end
56
+
57
+ private :set_volume_incr_decr_vol
58
+ end
59
+ end
60
+ end