Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/yt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require 'yt/models/claim'
require 'yt/models/claim_history'
require 'yt/models/content_owner'
require 'yt/models/live_broadcast'
require 'yt/models/match_policy'
require 'yt/models/playlist'
require 'yt/models/playlist_item'
Expand Down
8 changes: 5 additions & 3 deletions lib/yt/actions/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ def underscore(value)
# @see https://support.google.com/youtube/answer/57404?hl=en
def sanitize_brackets!(source)
case source
when String then source.gsub('<', '‹').gsub('>', '›')
when Array then source.map{|string| sanitize_brackets! string}
when Hash then source.each{|k,v| source[k] = sanitize_brackets! v}
when String then source.gsub('<', '‹').gsub('>', '›')
when Array then source.map{|string| sanitize_brackets! string}
when Hash then source.each{|k,v| source[k] = sanitize_brackets! v}
# Don't sanitize other types of objects
else source
end
end
end
Expand Down
45 changes: 45 additions & 0 deletions lib/yt/collections/live_broadcasts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'yt/collections/base'
require 'yt/models/video'

module Yt
module Collections
# Provides methods to interact with a collection of YouTube live broadcasts.
#
# Resources with live broadcasts are: {Yt::Models::Channel channels} and
# {Yt::Models::Account accounts}.
class LiveBroadcasts < Resources

private

# @return [Hash] the parameters to submit to YouTube to list live broadcasts.
# @see https://developers.google.com/youtube/v3/docs/liveBroadcasts/list
def list_params
super.tap{|params| params[:params] = live_broadcasts_params}
end

def live_broadcasts_params
if @where_params.blank?
{broadcastType: "all", mine: true}
else
apply_where_params! on_behalf_of_content_owner: @parent.owner_name
end
end

def attributes_for_new_item(data)
{}.tap do |attributes|
attributes[:id] = data['id']
attributes[:snippet] = data['snippet']
attributes[:status] = data['status']
attributes[:content_details] = data['contentDetails']
end
end

def insert_parts
snippet = {keys: [:title, :description, :scheduled_start_time, :scheduled_end_time, :default_language], sanitize_brackets: true}
status = {keys: [:privacy_status, :self_declared_made_for_kids]}
{snippet: snippet, status: status}
end
Comment on lines +37 to +41

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might have wanted to use insert_parts in insert method in this class.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must admit that I did not understand how this worked in other classes.
I looked at other collections and they seemed to use slightly different patterns.

Could you point me to a class that is a good example that I could study?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. @gmarziou

I was wondering if this part could be used and simplify insert method above, how do you think? If you don't mind, could you please try something like following code, for me to learn more?

def insert_parts
  snippet = {keys: [:title, :description, :scheduled_start_time, :scheduled_end_time, :default_language], sanitize_brackets: true}
  status = {keys: [:privacy_status, :self_declared_made_for_kids]}
  {snippet: snippet, status: status}
end

end

end
end
25 changes: 25 additions & 0 deletions lib/yt/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,27 @@ def create_playlist(params = {})
playlists.insert params
end

# Creates a live broadcast in the account’s channel.
# @return [Yt::Models::LiveBroadcast] the newly created broadcast.
# @param [Hash] params the attributes of the broadcast.
# @option params [String] :title The new broadcast’s title.
# Cannot have more than 100 characters. Can include the characters
# < and >, which are replaced to ‹ › in order to be accepted by YouTube.
# @option params [String] :description The new broadcast’s description.
# Cannot have more than 5000 bytes. Can include the characters
# < and >, which are replaced to ‹ › in order to be accepted by YouTube.
# @option params [Time] :scheduledStartTime The broadcast’s scheduled start time.
# Must be in the future and is mandatory.
# @option params [Time] :scheduledEndTime The broadcast’s scheduled end time.
# Must be in the future.
# @option params [String] :privacy_status The new broadcast’s privacy
# status. Must be one of: private, unlisted, public.
# @example Create a broadcast titled "My favorites".
# account.create_live_broadcast title: 'My favorites'
def create_live_broadcast(params = {})
live_broadcasts.insert params
end

# @!method delete_playlists(attributes = {})
# Deletes the account’s playlists matching all the given attributes.
# @return [Array<Boolean>] whether each playlist matching the given
Expand Down Expand Up @@ -174,6 +195,10 @@ def create_playlist(params = {})
# account is subscribed to.
delegate :subscribed_channels, to: :channel

# @!attribute [r] live_broadcasts
# @return [Yt::Collections::LiveBroadcasts] the live broadcasts owned by the account.
delegate :live_broadcasts, to: :channel

# @!attribute [r] videos
# @return [Yt::Collections::Videos] the videos owned by the account.
has_many :videos
Expand Down
4 changes: 4 additions & 0 deletions lib/yt/models/channel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ def unsubscribe!
# @return [Yt::Collections::ChannelSections] the channel’s channel sections.
has_many :channel_sections

# @!attribute [r] live_broadcasts
# @return [Yt::Collections::LiveBroadcasts] the channel’s live broadcasts.
has_many :live_broadcasts

### ANALYTICS ###

# @macro reports
Expand Down
84 changes: 84 additions & 0 deletions lib/yt/models/live_broadcast.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
require 'yt/models/base'

module Yt
module Models
# Provides methods to interact with YouTube Content ID live broadcasts.
# @see https://developers.google.com/youtube/v3/live/docs/liveBroadcasts
class LiveBroadcast < Resource

### SNIPPET ###

# @!attribute [r] title
# @return [String] the broadcast’s title.
delegate :title, to: :snippet

# @!attribute [r] description
# @return [String] the broadcast’s description.
delegate :description, to: :snippet

# @!attribute [r] scheduledStartTime
# @return [Time] the broadcast’s scheduled start time.
delegate :scheduled_start_time, to: :snippet

# @!attribute [r] scheduledEndTime
# @return [Time] the broadcast’s scheduled end time.
delegate :scheduled_end_time, to: :snippet

# @!attribute [r] published_at
# @return [Time] the date and time that the broadcast was published.
delegate :published_at, to: :snippet

# @return [String] the ID that YouTube assigns and uses to uniquely
# identify the live_broadcast.
has_attribute :id

### PRIVATE API ###

# @see https://developers.google.com/youtube/v3/docs/liveBroadcasts/update
def update_parts
snippet_keys = [:title, :description, :scheduled_start_time, :scheduled_end_time]
snippet = {keys: snippet_keys, sanitize_brackets: true}
status_keys = [:privacy_status, :recording_status,
:publish_at, :self_declared_made_for_kids]
{snippet: snippet, status: {keys: status_keys}}
end

### ACTIONS (UPLOAD, UPDATE, DELETE) ###

# Deletes the live broadcast.
# @return [Boolean] whether the live broadcast does not exist anymore.
# @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} is not an
# authenticated Yt::Account with permissions to delete the live broadcast.
def delete(options = {})
do_delete {@id = nil}
!exists?
end

# Updates the attributes of a broadcast.
# @return [Boolean] whether the broadcast was successfully updated.
# @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} is not an
# authenticated Yt::Account with permissions to update the broadcast.
# @param [Hash] attributes the attributes to update.
# @option attributes [String] :title The new broadcast’s title.
# Cannot have more than 100 characters. Can include the characters
# < and >, which are replaced to ‹ › in order to be accepted by YouTube.
# @option attributes [String] :description The new broadcast’s description.
# Cannot have more than 5000 bytes. Can include the characters
# < and >, which are replaced to ‹ › in order to be accepted by YouTube.
# @option attributes [String] :privacy_status The new broadcast’s privacy
# status. Must be one of: private, unscheduled, public.
# @example Update title and description of a broadcast.
# broadcast.update title: 'New title', description: 'New description'
# @example Update status of a broadcast.
# broadcast.update privacy_status: 'public'
def update(attributes = {})
super
end

# @private
def exists?
!@id.nil?
end
end
end
end
3 changes: 3 additions & 0 deletions lib/yt/models/snippet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module Models
# @see https://developers.google.com/youtube/v3/docs/playlistItems#resource
# @see https://developers.google.com/youtube/v3/docs/commentThreads#resource
# @see https://developers.google.com/youtube/v3/docs/comments#resource
# @see https://developers.google.com/youtube/v3/live/docs/liveBroadcasts#resource
class Snippet < Base
attr_reader :data

Expand Down Expand Up @@ -38,6 +39,8 @@ def initialize(options = {})
has_attribute :parent_id
has_attribute :like_count, type: Integer
has_attribute :updated_at, type: Time
has_attribute :scheduled_start_time, type: Time
has_attribute :scheduled_end_time, type: Time

has_attribute :last_updated, type: Time
has_attribute :language
Expand Down
16 changes: 16 additions & 0 deletions spec/collections/live_broadcasts_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require 'spec_helper'
require 'yt/collections/live_broadcasts'
require 'yt/models/live_broadcast'

describe Yt::Collections::LiveBroadcasts do
subject(:collection) { Yt::Collections::LiveBroadcasts.new }
before { expect(collection).to behave }

describe '#insert' do
let(:live_broadcast) { Yt::LiveBroadcast.new }
# TODO: separate stubs to show options translate into do_insert params
let(:behave) { receive(:do_insert).and_return live_broadcast }

it { expect(collection.insert).to eq live_broadcast }
end
end
83 changes: 83 additions & 0 deletions spec/models/live_broadcast_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
require 'spec_helper'
require 'yt/models/live_broadcast'

describe Yt::LiveBroadcast do
subject(:broadcast) { Yt::LiveBroadcast.new attrs }


describe '#title' do
context 'given a snippet with a title' do
let(:attrs) { {snippet: {"title"=>"Fullscreen"}} }
it { expect(broadcast.title).to eq 'Fullscreen' }
end

context 'given a snippet without a title' do
let(:attrs) { {snippet: {}} }
it { expect(broadcast.title).to eq '' }
end
end

describe '#published_at' do
context 'given a snippet with a timestamp' do # always returned by YouTube
let(:attrs) { {snippet: {"publishedAt"=>"2014-04-22T19:14:49.000Z"}} }
it { expect(broadcast.published_at.year).to be 2014 }
end
end

describe '#description' do
context 'given a snippet with a description' do
let(:attrs) { {snippet: {"description"=>"The first media company for the connected generation."}} }
it { expect(broadcast.description).to eq 'The first media company for the connected generation.' }
end

context 'given a snippet without a description' do
let(:attrs) { {snippet: {}} }
it { expect(broadcast.description).to eq '' }
end
end

describe '#exists?' do
context 'given a broadcast with an id' do
let(:attrs) { {id: 'PLSWYkYzOr'} }
it { expect(broadcast).to exist }
end

context 'given a broadcast without an id' do
let(:attrs) { {} }
it { expect(broadcast).not_to exist }
end
end

describe '#snippet' do
context 'given fetching a broadcast returns a snippet' do
let(:attrs) { {snippet: {"title"=>"Fullscreen"}} }
it { expect(broadcast.snippet).to be_a Yt::Snippet }
end
end

describe '#status' do
context 'given fetching a broadcast returns a status' do
let(:attrs) { {status: {"privacyStatus"=>"public"}} }
it { expect(broadcast.status).to be_a Yt::Status }
end
end

describe '#update' do
let(:attrs) { {id: 'PLSWYkYzOr', snippet: {'title'=>'old'}, status: {"privacyStatus"=>"public"}} }
before { expect(broadcast).to receive(:do_update).and_yield 'snippet'=>{'title'=>'new'} }

it { expect(broadcast.update title: 'new').to be true }
it { expect{broadcast.update title: 'new'}.to change{broadcast.title} }
end

describe '#delete' do
let(:attrs) { {id: 'PLSWYkYzOr'} }

context 'given an existing broadcast' do
before { expect(broadcast).to receive(:do_delete).and_yield }

it { expect(broadcast.delete).to be true }
it { expect{broadcast.delete}.to change{broadcast.exists?} }
end
end
end