chromecast 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/README.rdoc +47 -0
- data/chromecast.gemspec +31 -0
- data/init.rb +1 -0
- data/lib/chromecast.rb +13 -0
- data/lib/chromecast/application.rb +7 -0
- data/lib/chromecast/channel.rb +10 -0
- data/lib/chromecast/channel/base.rb +52 -0
- data/lib/chromecast/channel/connection.rb +19 -0
- data/lib/chromecast/channel/heartbeat.rb +20 -0
- data/lib/chromecast/channel/media.rb +34 -0
- data/lib/chromecast/channel/receiver.rb +51 -0
- data/lib/chromecast/connection.rb +87 -0
- data/lib/chromecast/protocol.pb.rb +68 -0
- data/lib/chromecast/tasks.rb +24 -0
- data/protocol.proto +79 -0
- metadata +87 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ab0190901c9fd66715415de2eded3dea8404e4cb
|
4
|
+
data.tar.gz: 3ce530143c686dc4cb515e708ab6b00999af77fd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a6f3a8461d4a2260def97f0f7c7f1c06fe66f4d994e0ec733899c399d1d5d2d0ac9bc53aae4c727a243fa64e5f03c2b190a1b2148e726e04787bf73d516fb9c9
|
7
|
+
data.tar.gz: 0b80dd58061653159e6646792aca290fca6f2fa80a49c19f79f5d08c0c3b8da888970ba21e06860f3eaad07a2f7d102cfcbcab2360b34de2fa00e96353493a24
|
data/README.rdoc
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
= chromecast
|
2
|
+
|
3
|
+
A simple Ruby library you can use to monitor and control basic features of
|
4
|
+
your Chromecast.
|
5
|
+
|
6
|
+
== Quick start
|
7
|
+
|
8
|
+
Install the gem:
|
9
|
+
|
10
|
+
gem install chromecast
|
11
|
+
|
12
|
+
Or add it to your Gemfile:
|
13
|
+
|
14
|
+
gem "chromecast"
|
15
|
+
|
16
|
+
Generate a certificate to be used for TLS connetion:
|
17
|
+
|
18
|
+
bundle exec rake setup:certificate
|
19
|
+
|
20
|
+
Use it:
|
21
|
+
|
22
|
+
require 'chromecast'
|
23
|
+
|
24
|
+
c = Chromecast::Connection.new(CHROMECAST_IP).open
|
25
|
+
c.connection.connect
|
26
|
+
|
27
|
+
while true
|
28
|
+
msg = c.read
|
29
|
+
|
30
|
+
puts msg
|
31
|
+
|
32
|
+
if msg['type'] == 'PING'
|
33
|
+
c.heartbeat.pong
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
== To Do
|
38
|
+
|
39
|
+
* Scanning for devices
|
40
|
+
* EventMachine support
|
41
|
+
* Proper documentation
|
42
|
+
* Tests
|
43
|
+
* Support for more namespaces
|
44
|
+
|
45
|
+
== License
|
46
|
+
|
47
|
+
This gem is released under the {MIT License}[http://www.opensource.org/licenses/MIT].
|
data/chromecast.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "chromecast"
|
3
|
+
s.version = "1.0"
|
4
|
+
s.date = "2014-10-04"
|
5
|
+
s.summary = "Basic Chromecast controll via a Ruby library"
|
6
|
+
s.description = "The gem lets you monitor Chromecast status, control volume and launch apps."
|
7
|
+
s.authors = ["Robert Nasiadek"]
|
8
|
+
s.files = [
|
9
|
+
"init.rb",
|
10
|
+
"lib/chromecast.rb",
|
11
|
+
"lib/chromecast/tasks.rb",
|
12
|
+
"lib/chromecast/protocol.pb.rb",
|
13
|
+
"lib/chromecast/channel/media.rb",
|
14
|
+
"lib/chromecast/channel/connection.rb",
|
15
|
+
"lib/chromecast/channel/base.rb",
|
16
|
+
"lib/chromecast/channel/receiver.rb",
|
17
|
+
"lib/chromecast/channel/heartbeat.rb",
|
18
|
+
"lib/chromecast/connection.rb",
|
19
|
+
"lib/chromecast/application.rb",
|
20
|
+
"lib/chromecast/channel.rb",
|
21
|
+
"protocol.proto",
|
22
|
+
"README.rdoc",
|
23
|
+
"chromecast.gemspec"
|
24
|
+
]
|
25
|
+
s.email = "robert@kapati.net"
|
26
|
+
s.homepage = "http://robzon.pl/"
|
27
|
+
s.license = "MIT"
|
28
|
+
|
29
|
+
s.add_runtime_dependency 'ruby-tls', '~> 1.0'
|
30
|
+
s.add_runtime_dependency 'protobuf', '~> 3.3'
|
31
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'chromecast'
|
data/lib/chromecast.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'protobuf'
|
3
|
+
|
4
|
+
require 'chromecast/protocol.pb'
|
5
|
+
require 'chromecast/connection'
|
6
|
+
require 'chromecast/channel'
|
7
|
+
require 'chromecast/application'
|
8
|
+
|
9
|
+
module Chromecast
|
10
|
+
APP_DEFAULT_MEDIA_RECEIVER = 'CC1AD845'
|
11
|
+
APP_BACKDROP = 'E8C28D3C'
|
12
|
+
APP_YOUTUBE = '233637DE'
|
13
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Chromecast
|
2
|
+
module Channel
|
3
|
+
class Base
|
4
|
+
attr_accessor :connection, :namespace, :type
|
5
|
+
|
6
|
+
def initialize connection, namespace, type
|
7
|
+
self.connection = connection
|
8
|
+
self.namespace = namespace
|
9
|
+
self.type = type
|
10
|
+
end
|
11
|
+
|
12
|
+
def send data
|
13
|
+
#puts "SEND: #{data}"
|
14
|
+
#puts ""
|
15
|
+
|
16
|
+
msg = new_message(data)
|
17
|
+
|
18
|
+
encoded = msg.encode
|
19
|
+
size = [encoded.size].pack('N')
|
20
|
+
|
21
|
+
connection.write(size + encoded)
|
22
|
+
|
23
|
+
return nil
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def new_message(payload)
|
29
|
+
m = Protocol::CastMessage.new
|
30
|
+
|
31
|
+
m.protocol_version = Protocol::CastMessage::ProtocolVersion::CASTV2_1_0
|
32
|
+
m.source_id = connection.source
|
33
|
+
m.destination_id = connection.destination
|
34
|
+
m.namespace = namespace
|
35
|
+
|
36
|
+
case type
|
37
|
+
when :json
|
38
|
+
m.payload_type = Protocol::CastMessage::PayloadType::STRING
|
39
|
+
m.payload_utf8 = payload.to_json
|
40
|
+
when :string
|
41
|
+
m.payload_type = Protocol::CastMessage::PayloadType::STRING
|
42
|
+
m.payload_utf8 = payload
|
43
|
+
when :binary
|
44
|
+
m.payload_type = Protocol::CastMessage::PayloadType::BINARY
|
45
|
+
m.payload_binary = payload
|
46
|
+
end
|
47
|
+
|
48
|
+
return m
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Chromecast
|
2
|
+
module Channel
|
3
|
+
class Connection < Base
|
4
|
+
NAMESPACE = 'urn:x-cast:com.google.cast.tp.connection'
|
5
|
+
|
6
|
+
def initialize connection
|
7
|
+
super(connection, NAMESPACE, :json)
|
8
|
+
end
|
9
|
+
|
10
|
+
def connect
|
11
|
+
send(type: 'CONNECT')
|
12
|
+
end
|
13
|
+
|
14
|
+
def close
|
15
|
+
send(type: 'CLOSE')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Chromecast
|
2
|
+
module Channel
|
3
|
+
class Heartbeat < Base
|
4
|
+
NAMESPACE = 'urn:x-cast:com.google.cast.tp.heartbeat'
|
5
|
+
|
6
|
+
def initialize connection
|
7
|
+
super(connection, NAMESPACE, :json)
|
8
|
+
end
|
9
|
+
|
10
|
+
def ping
|
11
|
+
send(type: 'PING')
|
12
|
+
end
|
13
|
+
|
14
|
+
def pong
|
15
|
+
send(type: 'PONG')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Chromecast
|
2
|
+
module Channel
|
3
|
+
class Media < Base
|
4
|
+
NAMESPACE = 'urn:x-cast:com.google.cast.media'
|
5
|
+
|
6
|
+
def initialize connection
|
7
|
+
super(connection, NAMESPACE, :json)
|
8
|
+
@request_id = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_status
|
12
|
+
send(type: 'GET_STATUS')
|
13
|
+
end
|
14
|
+
|
15
|
+
def pause
|
16
|
+
send(type: 'PAUSE')
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def next_request_id
|
22
|
+
@request_id += 1
|
23
|
+
end
|
24
|
+
|
25
|
+
def send data
|
26
|
+
super(data.merge(
|
27
|
+
requestId: next_request_id,
|
28
|
+
mediaSessionId: '0B5C6066-F8B2-77F4-E5F1-8CEC223F0A22'
|
29
|
+
))
|
30
|
+
@request_id
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Chromecast
|
2
|
+
module Channel
|
3
|
+
class Receiver < Base
|
4
|
+
NAMESPACE = 'urn:x-cast:com.google.cast.receiver'
|
5
|
+
|
6
|
+
def initialize connection
|
7
|
+
super(connection, NAMESPACE, :json)
|
8
|
+
@request_id = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def launch app_id
|
12
|
+
send(type: 'LAUNCH', appId: app_id)
|
13
|
+
end
|
14
|
+
|
15
|
+
def stop session_id
|
16
|
+
send(type: 'STOP', sessionId: session_id)
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_status
|
20
|
+
send(type: 'GET_STATUS')
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_app_availability apps
|
24
|
+
send(type: 'GET_APP_AVAILABILITY', appId: [apps].flatten)
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_volume level
|
28
|
+
send(type: 'SET_VOLUME', volume: {level: level})
|
29
|
+
end
|
30
|
+
|
31
|
+
def mute
|
32
|
+
send(type: 'SET_VOLUME', volume: {muted: true})
|
33
|
+
end
|
34
|
+
|
35
|
+
def unmute
|
36
|
+
send(type: 'SET_VOLUME', volume: {muted: false})
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def next_request_id
|
42
|
+
@request_id += 1
|
43
|
+
end
|
44
|
+
|
45
|
+
def send data
|
46
|
+
super(data.merge(requestId: next_request_id))
|
47
|
+
@request_id
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'json'
|
3
|
+
require 'socket'
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
module Chromecast
|
7
|
+
class Connection
|
8
|
+
DEFAULT_PORT = 8009
|
9
|
+
DEFAULT_SOURCE = 'source-0'
|
10
|
+
DEFAULT_DESTINATION = 'receiver-0'
|
11
|
+
|
12
|
+
attr_reader :host, :port, :source, :destination, :socket
|
13
|
+
attr_accessor :key_file, :crt_file
|
14
|
+
|
15
|
+
def initialize(host)
|
16
|
+
@host = host
|
17
|
+
@port = DEFAULT_PORT
|
18
|
+
@source = DEFAULT_SOURCE
|
19
|
+
@destination = DEFAULT_DESTINATION
|
20
|
+
@key_file = 'certificate.key'
|
21
|
+
@crt_file = 'certificate.crt'
|
22
|
+
end
|
23
|
+
|
24
|
+
def certificate(type)
|
25
|
+
case type
|
26
|
+
when :crt
|
27
|
+
return File.open(crt_file).read
|
28
|
+
when :key
|
29
|
+
return File.open(key_file).read
|
30
|
+
end
|
31
|
+
return nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def open
|
35
|
+
tcp = TCPSocket.new(host, port)
|
36
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
37
|
+
ctx.cert = OpenSSL::X509::Certificate.new(certificate(:crt))
|
38
|
+
ctx.key = OpenSSL::PKey::RSA.new(certificate(:key))
|
39
|
+
ctx.ssl_version = :SSLv23
|
40
|
+
ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
41
|
+
|
42
|
+
@socket = OpenSSL::SSL::SSLSocket.new(tcp, ctx).tap do |socket|
|
43
|
+
socket.sync_close = true
|
44
|
+
socket.connect
|
45
|
+
end
|
46
|
+
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def write data
|
51
|
+
@socket.write data
|
52
|
+
end
|
53
|
+
|
54
|
+
def has_data?
|
55
|
+
ready = IO.select([@socket], nil, nil, 0)
|
56
|
+
|
57
|
+
return ready != nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def read
|
61
|
+
return nil unless has_data?
|
62
|
+
|
63
|
+
resp_size = @socket.read(4).unpack('N').first
|
64
|
+
resp_data = @socket.read(resp_size)
|
65
|
+
|
66
|
+
resp = Protocol::CastMessage.decode(resp_data)
|
67
|
+
|
68
|
+
JSON.parse(resp.payload_utf8)
|
69
|
+
end
|
70
|
+
|
71
|
+
def connection
|
72
|
+
@connection_channel ||= Channel::Connection.new(self)
|
73
|
+
end
|
74
|
+
|
75
|
+
def receiver
|
76
|
+
@receiver_channel ||= Channel::Receiver.new(self)
|
77
|
+
end
|
78
|
+
|
79
|
+
def heartbeat
|
80
|
+
@heartbeat_channel ||= Channel::Heartbeat.new(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
def media
|
84
|
+
@media_channel ||= Channel::Media.new(self)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
##
|
2
|
+
# This file is auto-generated. DO NOT EDIT!
|
3
|
+
#
|
4
|
+
require 'protobuf/message'
|
5
|
+
|
6
|
+
module Chromecast
|
7
|
+
module Protocol
|
8
|
+
|
9
|
+
##
|
10
|
+
# Message Classes
|
11
|
+
#
|
12
|
+
class CastMessage < ::Protobuf::Message
|
13
|
+
class ProtocolVersion < ::Protobuf::Enum
|
14
|
+
define :CASTV2_1_0, 0
|
15
|
+
end
|
16
|
+
|
17
|
+
class PayloadType < ::Protobuf::Enum
|
18
|
+
define :STRING, 0
|
19
|
+
define :BINARY, 1
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class AuthChallenge < ::Protobuf::Message; end
|
25
|
+
class AuthResponse < ::Protobuf::Message; end
|
26
|
+
class AuthError < ::Protobuf::Message
|
27
|
+
class ErrorType < ::Protobuf::Enum
|
28
|
+
define :INTERNAL_ERROR, 0
|
29
|
+
define :NO_TLS, 1
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class DeviceAuthMessage < ::Protobuf::Message; end
|
35
|
+
|
36
|
+
|
37
|
+
##
|
38
|
+
# Message Fields
|
39
|
+
#
|
40
|
+
class CastMessage
|
41
|
+
required ::Chromecast::Protocol::CastMessage::ProtocolVersion, :protocol_version, 1
|
42
|
+
required :string, :source_id, 2
|
43
|
+
required :string, :destination_id, 3
|
44
|
+
required :string, :namespace, 4
|
45
|
+
required ::Chromecast::Protocol::CastMessage::PayloadType, :payload_type, 5
|
46
|
+
optional :string, :payload_utf8, 6
|
47
|
+
optional :bytes, :payload_binary, 7
|
48
|
+
end
|
49
|
+
|
50
|
+
class AuthResponse
|
51
|
+
required :bytes, :signature, 1
|
52
|
+
required :bytes, :client_auth_certificate, 2
|
53
|
+
end
|
54
|
+
|
55
|
+
class AuthError
|
56
|
+
required ::Chromecast::Protocol::AuthError::ErrorType, :error_type, 1
|
57
|
+
end
|
58
|
+
|
59
|
+
class DeviceAuthMessage
|
60
|
+
optional ::Chromecast::Protocol::AuthChallenge, :challenge, 1
|
61
|
+
optional ::Chromecast::Protocol::AuthResponse, :response, 2
|
62
|
+
optional ::Chromecast::Protocol::AuthError, :error, 3
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Chromecast
|
2
|
+
class Tasks
|
3
|
+
include Rake::DSL if defined? Rake::DSL
|
4
|
+
|
5
|
+
def install_tasks
|
6
|
+
desc "Setup all necessary files"
|
7
|
+
task setup: ['setup:protocol', 'setup:certificate']
|
8
|
+
|
9
|
+
namespace :setup do
|
10
|
+
desc "Generate certificates for TLS"
|
11
|
+
task :certificate do
|
12
|
+
system('openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout certificate.key -out certificate.crt')
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Generate Ruby code for Chromecast protocol"
|
16
|
+
task :protocol do
|
17
|
+
system('protoc --ruby_out lib/chromecast/ protocol.proto && echo Generated protocol code')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Chromecast::Tasks.new.install_tasks
|
data/protocol.proto
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
// Copyright 2013 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
syntax = "proto2";
|
6
|
+
|
7
|
+
option optimize_for = LITE_RUNTIME;
|
8
|
+
|
9
|
+
package Chromecast.Protocol;
|
10
|
+
|
11
|
+
message CastMessage {
|
12
|
+
// Always pass a version of the protocol for future compatibility
|
13
|
+
// requirements.
|
14
|
+
enum ProtocolVersion {
|
15
|
+
CASTV2_1_0 = 0;
|
16
|
+
}
|
17
|
+
required ProtocolVersion protocol_version = 1;
|
18
|
+
|
19
|
+
// source and destination ids identify the origin and destination of the
|
20
|
+
// message. They are used to route messages between endpoints that share a
|
21
|
+
// device-to-device channel.
|
22
|
+
//
|
23
|
+
// For messages between applications:
|
24
|
+
// - The sender application id is a unique identifier generated on behalf of
|
25
|
+
// the sender application.
|
26
|
+
// - The receiver id is always the the session id for the application.
|
27
|
+
//
|
28
|
+
// For messages to or from the sender or receiver platform, the special ids
|
29
|
+
// 'sender-0' and 'receiver-0' can be used.
|
30
|
+
//
|
31
|
+
// For messages intended for all endpoints using a given channel, the
|
32
|
+
// wildcard destination_id '*' can be used.
|
33
|
+
required string source_id = 2;
|
34
|
+
required string destination_id = 3;
|
35
|
+
|
36
|
+
// This is the core multiplexing key. All messages are sent on a namespace
|
37
|
+
// and endpoints sharing a channel listen on one or more namespaces. The
|
38
|
+
// namespace defines the protocol and semantics of the message.
|
39
|
+
required string namespace = 4;
|
40
|
+
|
41
|
+
// Encoding and payload info follows.
|
42
|
+
|
43
|
+
// What type of data do we have in this message.
|
44
|
+
enum PayloadType {
|
45
|
+
STRING = 0;
|
46
|
+
BINARY = 1;
|
47
|
+
}
|
48
|
+
required PayloadType payload_type = 5;
|
49
|
+
|
50
|
+
// Depending on payload_type, exactly one of the following optional fields
|
51
|
+
// will always be set.
|
52
|
+
optional string payload_utf8 = 6;
|
53
|
+
optional bytes payload_binary = 7;
|
54
|
+
}
|
55
|
+
|
56
|
+
// Messages for authentication protocol between a sender and a receiver.
|
57
|
+
message AuthChallenge {
|
58
|
+
}
|
59
|
+
|
60
|
+
message AuthResponse {
|
61
|
+
required bytes signature = 1;
|
62
|
+
required bytes client_auth_certificate = 2;
|
63
|
+
}
|
64
|
+
|
65
|
+
message AuthError {
|
66
|
+
enum ErrorType {
|
67
|
+
INTERNAL_ERROR = 0;
|
68
|
+
NO_TLS = 1; // The underlying connection is not TLS
|
69
|
+
}
|
70
|
+
required ErrorType error_type = 1;
|
71
|
+
}
|
72
|
+
|
73
|
+
message DeviceAuthMessage {
|
74
|
+
// Request fields
|
75
|
+
optional AuthChallenge challenge = 1;
|
76
|
+
// Response fields
|
77
|
+
optional AuthResponse response = 2;
|
78
|
+
optional AuthError error = 3;
|
79
|
+
}
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chromecast
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Robert Nasiadek
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-tls
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: protobuf
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.3'
|
41
|
+
description: The gem lets you monitor Chromecast status, control volume and launch
|
42
|
+
apps.
|
43
|
+
email: robert@kapati.net
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- README.rdoc
|
49
|
+
- chromecast.gemspec
|
50
|
+
- init.rb
|
51
|
+
- lib/chromecast.rb
|
52
|
+
- lib/chromecast/application.rb
|
53
|
+
- lib/chromecast/channel.rb
|
54
|
+
- lib/chromecast/channel/base.rb
|
55
|
+
- lib/chromecast/channel/connection.rb
|
56
|
+
- lib/chromecast/channel/heartbeat.rb
|
57
|
+
- lib/chromecast/channel/media.rb
|
58
|
+
- lib/chromecast/channel/receiver.rb
|
59
|
+
- lib/chromecast/connection.rb
|
60
|
+
- lib/chromecast/protocol.pb.rb
|
61
|
+
- lib/chromecast/tasks.rb
|
62
|
+
- protocol.proto
|
63
|
+
homepage: http://robzon.pl/
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
metadata: {}
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 2.2.1
|
84
|
+
signing_key:
|
85
|
+
specification_version: 4
|
86
|
+
summary: Basic Chromecast controll via a Ruby library
|
87
|
+
test_files: []
|