novacloud_client 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.
- checksums.yaml +7 -0
- data/.rubocop_todo.yml +5 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +142 -0
- data/Rakefile +12 -0
- data/lib/novacloud_client/client.rb +110 -0
- data/lib/novacloud_client/configuration.rb +31 -0
- data/lib/novacloud_client/errors.rb +26 -0
- data/lib/novacloud_client/middleware/authentication.rb +49 -0
- data/lib/novacloud_client/middleware/error_handler.rb +62 -0
- data/lib/novacloud_client/objects/base.rb +49 -0
- data/lib/novacloud_client/objects/control_log_entry.rb +21 -0
- data/lib/novacloud_client/objects/control_result.rb +55 -0
- data/lib/novacloud_client/objects/player.rb +37 -0
- data/lib/novacloud_client/objects/player_status.rb +29 -0
- data/lib/novacloud_client/objects/queued_request.rb +17 -0
- data/lib/novacloud_client/objects/screen.rb +21 -0
- data/lib/novacloud_client/objects/screen_detail.rb +29 -0
- data/lib/novacloud_client/objects/screen_monitor.rb +12 -0
- data/lib/novacloud_client/objects/solutions/offline_export_result.rb +80 -0
- data/lib/novacloud_client/objects/solutions/over_spec_detection_result.rb +80 -0
- data/lib/novacloud_client/objects/solutions/publish_result.rb +32 -0
- data/lib/novacloud_client/resources/base.rb +29 -0
- data/lib/novacloud_client/resources/concerns/payload_serializer.rb +46 -0
- data/lib/novacloud_client/resources/control.rb +250 -0
- data/lib/novacloud_client/resources/logs.rb +39 -0
- data/lib/novacloud_client/resources/players.rb +120 -0
- data/lib/novacloud_client/resources/scheduled_control.rb +221 -0
- data/lib/novacloud_client/resources/screens.rb +66 -0
- data/lib/novacloud_client/resources/solutions.rb +154 -0
- data/lib/novacloud_client/support/key_transform.rb +32 -0
- data/lib/novacloud_client/version.rb +5 -0
- data/lib/novacloud_client.rb +9 -0
- data/sig/novacloud_client.rbs +4 -0
- metadata +97 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module NovacloudClient
|
|
6
|
+
module Objects
|
|
7
|
+
# Represents a screen/device entry from VNNOXCare APIs.
|
|
8
|
+
class Screen < Base
|
|
9
|
+
attr_accessor :sid, :name, :mac, :sn, :address, :longitude, :latitude,
|
|
10
|
+
:status, :camera, :brightness, :env_brightness
|
|
11
|
+
|
|
12
|
+
def online?
|
|
13
|
+
status.to_i == 1
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def camera_enabled?
|
|
17
|
+
camera.to_i == 1
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module NovacloudClient
|
|
6
|
+
module Objects
|
|
7
|
+
# Represents detailed telemetry for a screen, including nested hardware info.
|
|
8
|
+
class ScreenDetail < Base
|
|
9
|
+
attr_accessor :identifier, :input_source, :mac, :master_control, :module,
|
|
10
|
+
:monitor_card, :receiving_card, :screen, :sid, :smart_module, :sn
|
|
11
|
+
|
|
12
|
+
NESTED_HASH_FIELDS = %i[input_source master_control module monitor_card receiving_card screen smart_module].freeze
|
|
13
|
+
|
|
14
|
+
def initialize(attributes = {})
|
|
15
|
+
super
|
|
16
|
+
ensure_nested_hashes!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def ensure_nested_hashes!
|
|
22
|
+
NESTED_HASH_FIELDS.each do |field|
|
|
23
|
+
value = public_send(field)
|
|
24
|
+
public_send("#{field}=", value || {})
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module NovacloudClient
|
|
6
|
+
module Objects
|
|
7
|
+
# Represents high-level monitoring metrics for a screen device.
|
|
8
|
+
class ScreenMonitor < Base
|
|
9
|
+
attr_accessor :display_device, :brightness, :env_brightness, :height, :width, :sn
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../base"
|
|
4
|
+
|
|
5
|
+
module NovacloudClient
|
|
6
|
+
module Objects
|
|
7
|
+
module Solutions
|
|
8
|
+
# Represents the payload returned from the offline export endpoint.
|
|
9
|
+
class OfflineExportResult < Base
|
|
10
|
+
attr_reader :display_solutions, :play_relations, :play_solutions,
|
|
11
|
+
:playlists, :schedule_constraints, :plan_json
|
|
12
|
+
|
|
13
|
+
def display_solutions=(value)
|
|
14
|
+
@display_solutions = build_artifact(value)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def play_relations=(value)
|
|
18
|
+
@play_relations = build_artifact(value)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def play_solutions=(value)
|
|
22
|
+
@play_solutions = build_artifact(value)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def playlists=(value)
|
|
26
|
+
@playlists = build_artifact(value)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def schedule_constraints=(value)
|
|
30
|
+
@schedule_constraints = build_artifact(value)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def plan_json=(value)
|
|
34
|
+
@plan_json = build_artifact(value)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def build_artifact(value)
|
|
40
|
+
return nil if value.nil?
|
|
41
|
+
|
|
42
|
+
if value.is_a?(Array)
|
|
43
|
+
value.map { |artifact| Artifact.new(artifact) }
|
|
44
|
+
else
|
|
45
|
+
Artifact.new(value)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Represents a downloadable artifact (JSON, playlist, etc.) returned by the export.
|
|
50
|
+
class Artifact < Base
|
|
51
|
+
attr_accessor :md5, :file_name, :url, :program_name
|
|
52
|
+
|
|
53
|
+
attr_writer :support_md5_checkout
|
|
54
|
+
|
|
55
|
+
def support_md5_checkout
|
|
56
|
+
return nil if @support_md5_checkout.nil?
|
|
57
|
+
|
|
58
|
+
!!@support_md5_checkout
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def support_md5_checkout?
|
|
62
|
+
support_md5_checkout
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Legacy camelCase accessors for backward compatibility with existing clients.
|
|
66
|
+
# Legacy camelCase accessors for backward compatibility with existing clients.
|
|
67
|
+
# rubocop:disable Naming/PredicatePrefix
|
|
68
|
+
def is_support_md5_checkout?
|
|
69
|
+
support_md5_checkout?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def is_support_md5_checkout=(value)
|
|
73
|
+
self.support_md5_checkout = value
|
|
74
|
+
end
|
|
75
|
+
# rubocop:enable Naming/PredicatePrefix
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../base"
|
|
4
|
+
|
|
5
|
+
module NovacloudClient
|
|
6
|
+
module Objects
|
|
7
|
+
module Solutions
|
|
8
|
+
# Represents the payload returned when checking program over-specification.
|
|
9
|
+
class OverSpecDetectionResult < Base
|
|
10
|
+
attr_accessor :logid, :status
|
|
11
|
+
attr_reader :items
|
|
12
|
+
|
|
13
|
+
def initialize(attributes = {})
|
|
14
|
+
@items = []
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def data=(value)
|
|
19
|
+
@items = Array(value).map { |entry| Item.new(entry) }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
alias data items
|
|
23
|
+
|
|
24
|
+
# Entry describing over-specification findings for a specific set of players.
|
|
25
|
+
class Item < Base
|
|
26
|
+
attr_accessor :over_spec_type
|
|
27
|
+
attr_reader :over_spec, :player_ids
|
|
28
|
+
|
|
29
|
+
def initialize(attributes = {})
|
|
30
|
+
@details = []
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def over_spec=(value)
|
|
35
|
+
@over_spec = !!value
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def over_spec?
|
|
39
|
+
over_spec
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def player_ids=(value)
|
|
43
|
+
@player_ids = Array(value)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def over_spec_detail=(value)
|
|
47
|
+
@details = Array(value).map { |detail| Detail.new(detail) }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def details
|
|
51
|
+
@details ||= []
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Detail record for a widget that exceeds specifications.
|
|
55
|
+
class Detail < Base
|
|
56
|
+
attr_accessor :page_id, :widget_id
|
|
57
|
+
attr_reader :over_spec_error_code, :recommendation
|
|
58
|
+
|
|
59
|
+
def over_spec_error_code=(value)
|
|
60
|
+
@over_spec_error_code = Array(value)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def over_spec_error_codes
|
|
64
|
+
@over_spec_error_code
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def recommend=(value)
|
|
68
|
+
@recommendation = value ? Recommendation.new(value) : nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Suggested adjustments for bringing a widget within spec.
|
|
72
|
+
class Recommendation < Base
|
|
73
|
+
attr_accessor :width, :height, :postfix, :fps, :byte_rate, :codec
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../base"
|
|
4
|
+
|
|
5
|
+
module NovacloudClient
|
|
6
|
+
module Objects
|
|
7
|
+
module Solutions
|
|
8
|
+
# Represents the publish result structure returned by solution endpoints.
|
|
9
|
+
class PublishResult < Base
|
|
10
|
+
def success=(value)
|
|
11
|
+
@successful = Array(value).compact
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def fail=(value)
|
|
15
|
+
@failed = Array(value).compact
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def all_successful?
|
|
19
|
+
failed.empty?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def failed
|
|
23
|
+
@failed ||= []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def successful
|
|
27
|
+
@successful ||= []
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NovacloudClient
|
|
4
|
+
module Resources
|
|
5
|
+
# Shared helpers for resource classes built on top of the client.
|
|
6
|
+
class Base
|
|
7
|
+
attr_reader :client
|
|
8
|
+
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def get(endpoint, params: {})
|
|
16
|
+
client.request(http_method: :get, endpoint: endpoint, params: params)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def post(endpoint, params: {})
|
|
20
|
+
client.request(http_method: :post, endpoint: endpoint, params: params)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def validate_player_ids!(ids, max: 100)
|
|
24
|
+
raise ArgumentError, "player_ids cannot be empty" if ids.nil? || ids.empty?
|
|
25
|
+
raise ArgumentError, "maximum #{max} player IDs allowed" if ids.size > max
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NovacloudClient
|
|
4
|
+
module Resources
|
|
5
|
+
module Concerns
|
|
6
|
+
# Provides camelCase serialization helpers for API payloads.
|
|
7
|
+
module PayloadSerializer
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def serialize_component(component)
|
|
11
|
+
case component
|
|
12
|
+
when nil
|
|
13
|
+
nil
|
|
14
|
+
when Hash
|
|
15
|
+
component.each_with_object({}) do |(key, value), result|
|
|
16
|
+
result[camelize_key(key)] = serialize_component(value)
|
|
17
|
+
end
|
|
18
|
+
when Array
|
|
19
|
+
component.map { |item| serialize_component(item) }
|
|
20
|
+
else
|
|
21
|
+
component.respond_to?(:to_h) ? serialize_component(component.to_h) : component
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def camelize_key(key)
|
|
26
|
+
return key unless key.is_a?(String) || key.is_a?(Symbol)
|
|
27
|
+
|
|
28
|
+
string = key.to_s
|
|
29
|
+
normalized = string
|
|
30
|
+
.gsub(/([a-z\d])([A-Z])/, "\\1_\\2")
|
|
31
|
+
.tr("-", "_")
|
|
32
|
+
.downcase
|
|
33
|
+
|
|
34
|
+
parts = normalized.split("_")
|
|
35
|
+
camelized = parts.map.with_index do |segment, index|
|
|
36
|
+
next segment if index.zero?
|
|
37
|
+
|
|
38
|
+
segment.capitalize
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
camelized.join
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "../objects/control_result"
|
|
5
|
+
require_relative "../objects/queued_request"
|
|
6
|
+
|
|
7
|
+
module NovacloudClient
|
|
8
|
+
module Resources
|
|
9
|
+
# Resource wrapper for control commands.
|
|
10
|
+
#
|
|
11
|
+
# @example Set player brightness
|
|
12
|
+
# client.control.brightness(
|
|
13
|
+
# player_ids: ["player-1"],
|
|
14
|
+
# brightness: 80,
|
|
15
|
+
# notice_url: "https://example.com/callback"
|
|
16
|
+
# )
|
|
17
|
+
#
|
|
18
|
+
# @example Check a queued request
|
|
19
|
+
# request = client.control.reboot(player_ids: ["player-1"], notice_url: callback)
|
|
20
|
+
# client.control.request_result(request_id: request.request_id)
|
|
21
|
+
class Control < Base
|
|
22
|
+
MAX_BATCH = 100
|
|
23
|
+
|
|
24
|
+
# Adjust brightness asynchronously for a batch of players.
|
|
25
|
+
#
|
|
26
|
+
# @param player_ids [Array<String>] NovaCloud player identifiers (max #{MAX_BATCH})
|
|
27
|
+
# @param brightness [Integer] percentage value between 0 and 100
|
|
28
|
+
# @param notice_url [String] HTTPS callback endpoint for async results
|
|
29
|
+
# @return [NovacloudClient::Objects::QueuedRequest]
|
|
30
|
+
# @raise [ArgumentError] when validation fails
|
|
31
|
+
def brightness(player_ids:, brightness:, notice_url:)
|
|
32
|
+
validate_percentage!(brightness, "brightness")
|
|
33
|
+
enqueue_control(
|
|
34
|
+
endpoint: "/v2/player/real-time-control/brightness",
|
|
35
|
+
player_ids: player_ids,
|
|
36
|
+
notice_url: notice_url,
|
|
37
|
+
extra_payload: { brightness: brightness }
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Adjust volume asynchronously for a batch of players.
|
|
42
|
+
#
|
|
43
|
+
# @param player_ids [Array<String>] NovaCloud player identifiers (max #{MAX_BATCH})
|
|
44
|
+
# @param volume [Integer] percentage value between 0 and 100
|
|
45
|
+
# @param notice_url [String] HTTPS callback endpoint for async results
|
|
46
|
+
# @return [NovacloudClient::Objects::QueuedRequest]
|
|
47
|
+
# @raise [ArgumentError] when validation fails
|
|
48
|
+
def volume(player_ids:, volume:, notice_url:)
|
|
49
|
+
validate_percentage!(volume, "volume")
|
|
50
|
+
enqueue_control(
|
|
51
|
+
endpoint: "/v2/player/real-time-control/volume",
|
|
52
|
+
player_ids: player_ids,
|
|
53
|
+
notice_url: notice_url,
|
|
54
|
+
extra_payload: { volume: volume }
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Switch the video input source (e.g., HDMI1) for the selected players.
|
|
59
|
+
#
|
|
60
|
+
# @param player_ids [Array<String>] NovaCloud player identifiers (max #{MAX_BATCH})
|
|
61
|
+
# @param source [String] identifier for the input source defined by NovaCloud (e.g., "HDMI1")
|
|
62
|
+
# @param notice_url [String] HTTPS callback endpoint for async results
|
|
63
|
+
# @return [NovacloudClient::Objects::QueuedRequest]
|
|
64
|
+
# @raise [ArgumentError] when validation fails
|
|
65
|
+
def video_source(player_ids:, source:, notice_url:)
|
|
66
|
+
validate_presence!(source, "source")
|
|
67
|
+
enqueue_control(
|
|
68
|
+
endpoint: "/v2/player/real-time-control/video-source",
|
|
69
|
+
player_ids: player_ids,
|
|
70
|
+
notice_url: notice_url,
|
|
71
|
+
extra_payload: { videoSource: source }
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Toggle screen power state for the selected players.
|
|
76
|
+
#
|
|
77
|
+
# @param player_ids [Array<String>] NovaCloud player identifiers (max #{MAX_BATCH})
|
|
78
|
+
# @param state [Symbol, String, Integer, TrueClass, FalseClass] desired power state
|
|
79
|
+
# (:on, :off, true, false, 1, or 0)
|
|
80
|
+
# @param notice_url [String] HTTPS callback endpoint for async results
|
|
81
|
+
# @return [NovacloudClient::Objects::QueuedRequest]
|
|
82
|
+
# @raise [ArgumentError] when validation fails
|
|
83
|
+
def screen_power(player_ids:, state:, notice_url:)
|
|
84
|
+
payload = { option: normalize_power_state(state) }
|
|
85
|
+
enqueue_control(
|
|
86
|
+
endpoint: "/v2/player/real-time-control/power",
|
|
87
|
+
player_ids: player_ids,
|
|
88
|
+
notice_url: notice_url,
|
|
89
|
+
extra_payload: payload
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Request a black screen/normal screen toggle for the selected players.
|
|
94
|
+
#
|
|
95
|
+
# @param player_ids [Array<String>] NovaCloud player identifiers (max #{MAX_BATCH})
|
|
96
|
+
# @param status [String, Symbol] desired screen mode (:open, :close, "OPEN", "CLOSE")
|
|
97
|
+
# @param notice_url [String] HTTPS callback endpoint for async results
|
|
98
|
+
# @return [NovacloudClient::Objects::QueuedRequest]
|
|
99
|
+
# @raise [ArgumentError] when validation fails
|
|
100
|
+
def screen_status(player_ids:, status:, notice_url:)
|
|
101
|
+
payload = { status: normalize_screen_status(status) }
|
|
102
|
+
enqueue_control(
|
|
103
|
+
endpoint: "/v2/player/real-time-control/screen-status",
|
|
104
|
+
player_ids: player_ids,
|
|
105
|
+
notice_url: notice_url,
|
|
106
|
+
extra_payload: payload
|
|
107
|
+
)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Trigger screenshots for the selected players.
|
|
111
|
+
#
|
|
112
|
+
# @param player_ids [Array<String>] NovaCloud player identifiers (max #{MAX_BATCH})
|
|
113
|
+
# @param notice_url [String] HTTPS callback endpoint receiving screenshot info
|
|
114
|
+
# @return [NovacloudClient::Objects::QueuedRequest]
|
|
115
|
+
# @raise [ArgumentError] when validation fails
|
|
116
|
+
def screenshot(player_ids:, notice_url:)
|
|
117
|
+
enqueue_control(
|
|
118
|
+
endpoint: "/v2/player/real-time-control/screen-capture",
|
|
119
|
+
player_ids: player_ids,
|
|
120
|
+
notice_url: notice_url
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Reboot one or more players asynchronously.
|
|
125
|
+
#
|
|
126
|
+
# @param player_ids [Array<String>] NovaCloud player identifiers (max #{MAX_BATCH})
|
|
127
|
+
# @param notice_url [String] HTTPS callback endpoint for async results
|
|
128
|
+
# @return [NovacloudClient::Objects::QueuedRequest]
|
|
129
|
+
# @raise [ArgumentError] when validation fails
|
|
130
|
+
def reboot(player_ids:, notice_url:)
|
|
131
|
+
enqueue_control(
|
|
132
|
+
endpoint: "/v2/player/real-time-control/reboot",
|
|
133
|
+
player_ids: player_ids,
|
|
134
|
+
notice_url: notice_url
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Configure NTP time synchronization for the selected players.
|
|
139
|
+
#
|
|
140
|
+
# @param player_ids [Array<String>] NovaCloud player identifiers (max #{MAX_BATCH})
|
|
141
|
+
# @param server [String] NTP server hostname
|
|
142
|
+
# @param enable [Boolean] flag indicating whether to enable synchronization
|
|
143
|
+
# @return [NovacloudClient::Objects::ControlResult]
|
|
144
|
+
def ntp_sync(player_ids:, server:, enable:)
|
|
145
|
+
validate_player_ids!(player_ids, max: MAX_BATCH)
|
|
146
|
+
validate_presence!(server, "server")
|
|
147
|
+
validate_boolean!(enable, "enable")
|
|
148
|
+
|
|
149
|
+
payload = {
|
|
150
|
+
playerIds: player_ids,
|
|
151
|
+
server: server,
|
|
152
|
+
enable: !enable.nil?
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
response = post("/v2/player/real-time-control/ntp", params: payload)
|
|
156
|
+
Objects::ControlResult.new(response)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Toggle synchronous playback mode in real-time.
|
|
160
|
+
#
|
|
161
|
+
# @param player_ids [Array<String>] NovaCloud player identifiers (max #{MAX_BATCH})
|
|
162
|
+
# @param option [Integer, Symbol, String, TrueClass, FalseClass] desired synchronous state
|
|
163
|
+
# @return [NovacloudClient::Objects::ControlResult]
|
|
164
|
+
def synchronous_playback(player_ids:, option:)
|
|
165
|
+
validate_player_ids!(player_ids, max: MAX_BATCH)
|
|
166
|
+
|
|
167
|
+
payload = {
|
|
168
|
+
playerIds: player_ids,
|
|
169
|
+
option: normalize_sync_option(option)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
response = post("/v2/player/real-time-control/simulcast", params: payload)
|
|
173
|
+
Objects::ControlResult.new(response)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Fetch the aggregated result of a previously queued control request.
|
|
177
|
+
#
|
|
178
|
+
# @param request_id [String] identifier returned by the queueing endpoints
|
|
179
|
+
# @return [NovacloudClient::Objects::ControlResult]
|
|
180
|
+
# @raise [ArgumentError] when the request ID is blank
|
|
181
|
+
def request_result(request_id:)
|
|
182
|
+
raise ArgumentError, "request_id is required" if request_id.to_s.strip.empty?
|
|
183
|
+
|
|
184
|
+
response = get("/v2/player/control/request-result", params: { requestId: request_id })
|
|
185
|
+
Objects::ControlResult.new(response)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
private
|
|
189
|
+
|
|
190
|
+
def validate_percentage!(value, field)
|
|
191
|
+
return if value.is_a?(Integer) && value.between?(0, 100)
|
|
192
|
+
|
|
193
|
+
raise ArgumentError, "#{field} must be an integer between 0 and 100"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def validate_notice_url!(notice_url)
|
|
197
|
+
raise ArgumentError, "notice_url is required" if notice_url.to_s.strip.empty?
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def validate_presence!(value, field)
|
|
201
|
+
raise ArgumentError, "#{field} is required" if value.to_s.strip.empty?
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def validate_boolean!(value, field)
|
|
205
|
+
return if [true, false].include?(value)
|
|
206
|
+
|
|
207
|
+
raise ArgumentError, "#{field} must be true or false"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def enqueue_control(endpoint:, player_ids:, notice_url:, extra_payload: {})
|
|
211
|
+
validate_player_ids!(player_ids, max: MAX_BATCH)
|
|
212
|
+
validate_notice_url!(notice_url)
|
|
213
|
+
|
|
214
|
+
payload = { playerIds: player_ids }
|
|
215
|
+
payload.merge!(extra_payload)
|
|
216
|
+
payload[:noticeUrl] = notice_url
|
|
217
|
+
|
|
218
|
+
response = post(endpoint, params: payload)
|
|
219
|
+
Objects::QueuedRequest.new(response)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def normalize_power_state(state)
|
|
223
|
+
case state
|
|
224
|
+
when true, :on, "on", "ON", 1 then 1
|
|
225
|
+
when false, :off, "off", "OFF", 0 then 0
|
|
226
|
+
else
|
|
227
|
+
raise ArgumentError, "state must be one of :on, :off, true, false, or 0/1"
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def normalize_screen_status(status)
|
|
232
|
+
case status
|
|
233
|
+
when :open, "open", "OPEN" then "OPEN"
|
|
234
|
+
when :close, "close", "CLOSE", :closed then "CLOSE"
|
|
235
|
+
else
|
|
236
|
+
raise ArgumentError, "status must be OPEN or CLOSE"
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def normalize_sync_option(option)
|
|
241
|
+
case option
|
|
242
|
+
when true, :on, "on", "ON", 1 then 1
|
|
243
|
+
when false, :off, "off", "OFF", 0 then 0
|
|
244
|
+
else
|
|
245
|
+
raise ArgumentError, "option must be one of :on, :off, true, false, or 0/1"
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "../objects/control_log_entry"
|
|
5
|
+
|
|
6
|
+
module NovacloudClient
|
|
7
|
+
module Resources
|
|
8
|
+
# Resource wrapper for log-related endpoints.
|
|
9
|
+
class Logs < Base
|
|
10
|
+
# Retrieve remote control execution history for a player.
|
|
11
|
+
#
|
|
12
|
+
# @param player_id [String] NovaCloud player identifier
|
|
13
|
+
# @param start [Integer] pagination offset (defaults to 0)
|
|
14
|
+
# @param count [Integer] number of records to request (defaults to 20)
|
|
15
|
+
# @param task_type [Integer, nil] optional numeric filter defined by NovaCloud
|
|
16
|
+
# @return [Array<NovacloudClient::Objects::ControlLogEntry>]
|
|
17
|
+
def control_history(player_id:, start: 0, count: 20, task_type: nil)
|
|
18
|
+
validate_presence!(player_id, "player_id")
|
|
19
|
+
|
|
20
|
+
params = {
|
|
21
|
+
"playerId" => player_id,
|
|
22
|
+
"start" => start.to_s,
|
|
23
|
+
"count" => count.to_s
|
|
24
|
+
}
|
|
25
|
+
params["taskType"] = task_type.to_s if task_type
|
|
26
|
+
|
|
27
|
+
response = get("/v2/logs/remote-control", params: params)
|
|
28
|
+
rows = response.fetch("rows", [])
|
|
29
|
+
rows.map { |attrs| Objects::ControlLogEntry.new(attrs) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def validate_presence!(value, field)
|
|
35
|
+
raise ArgumentError, "#{field} is required" if value.to_s.strip.empty?
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|