Skip to content
Open
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
15 changes: 14 additions & 1 deletion lib/yt/actions/list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,22 @@ def first!
first.tap{|item| raise Errors::NoItems, error_message unless item}
end

def etag
@etag ||= fetch_etag
end

private

def list
owner = self
@last_index, @page_token = 0, nil
Enumerator.new(-> {total_results}) do |items|
while next_item = find_next
items << next_item
end
@where_params = {}
end.tap do |enum|
enum.define_singleton_method(:etag) { owner.instance_variable_get(:@etag) }
end
end

Expand Down Expand Up @@ -63,7 +70,7 @@ def resource_class
# Can be overwritten by subclasses that initialize instance with
# a different set of parameters.
def new_item(data)
resource_class.new attributes_for_new_item(data)
resource_class.new attributes_for_new_item(data).merge(etag: data['etag'])
end

# @private
Expand Down Expand Up @@ -91,11 +98,17 @@ def eager_load_items_from(items)

def fetch_page(params = {})
@last_response = list_request(params).run
@etag = @last_response.body['etag']
token = @last_response.body['nextPageToken']
items = extract_items @last_response.body
{items: items, token: token}
end

def fetch_etag
response = list_request(list_params).run
response.body['etag']
end

def list_request(params = {})
@list_request = Yt::Request.new(params).tap do |request|
print "#{request.as_curl}\n" if Yt.configuration.developing?
Expand Down
2 changes: 1 addition & 1 deletion lib/yt/collections/assets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def insert(attributes = {})

def new_item(data)
klass = (data["kind"] == "youtubePartner#assetSnippet") ? Yt::AssetSnippet : Yt::Asset
klass.new attributes_for_new_item(data)
klass.new attributes_for_new_item(data).merge(etag: data['etag'])
end

# @return [Hash] the parameters to submit to YouTube to list assets
Expand Down
4 changes: 3 additions & 1 deletion lib/yt/collections/playlist_items.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ def list_params
end

def playlist_items_params
resources_params.merge playlist_id: @parent.id
params = resources_params
params.merge!(playlist_id: @parent.id) if @parent
apply_where_params! params
end

def insert_parts
Expand Down
2 changes: 1 addition & 1 deletion lib/yt/collections/resources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def insert(attributes = {}, options = {}) #
private

def attributes_for_new_item(data)
{id: data['id'], snippet: data['snippet'], status: data['status'], auth: @auth}
{id: data['id'], snippet: data['snippet'], status: data['status'], auth: @auth, etag: data['etag']}
end

def resources_params
Expand Down
5 changes: 0 additions & 5 deletions lib/yt/models/playlist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,6 @@ def reports_params
end
end

# @private
def exists?
!@id.nil?
end

private

# @see https://developers.google.com/youtube/v3/docs/playlists/update
Expand Down
5 changes: 0 additions & 5 deletions lib/yt/models/playlist_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,6 @@ def video

### PRIVATE API ###

# @private
def exists?
!@id.nil?
end

# @private
# Override Resource's new to set video if the response includes it
def initialize(options = {})
Expand Down
27 changes: 27 additions & 0 deletions lib/yt/models/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ def id
end
end

### ETAG ###
def etag
return nil unless exists?

@etag ||= fetch_etag
end

### EXISTS? ###

def exists?
!@id.nil?
end

### STATUS ###

has_one :status
Expand Down Expand Up @@ -56,6 +69,7 @@ def initialize(options = {})
@id = options[:id]
end
@auth = options[:auth]
@etag = options[:etag]
@snippet = Snippet.new(data: options[:snippet]) if options[:snippet]
@status = Status.new(data: options[:status]) if options[:status]
end
Expand Down Expand Up @@ -139,6 +153,19 @@ def fetch_channel_id
end
end

def fetch_etag
return nil if @id.nil?

collection = resource_collection.new(auth: @auth).where(id: @id)&.first
collection&.etag
end

def resource_collection
name = self.class.to_s.demodulize.pluralize
require "yt/collections/#{name.underscore}"
"Yt::Collections::#{name}".constantize
end

# Since YouTube API only returns tags on Videos#list, the memoized
# `@snippet` is erased if the video was instantiated through Video#search
# (e.g., by calling account.videos or channel.videos), so that the full
Expand Down
5 changes: 0 additions & 5 deletions lib/yt/models/video.rb
Original file line number Diff line number Diff line change
Expand Up @@ -635,11 +635,6 @@ def initialize(options = {})
end
end

# @private
def exists?
!@id.nil?
end

# @private
# Tells `has_reports` to retrieve the reports from YouTube Analytics API
# either as a Channel or as a Content Owner.
Expand Down
20 changes: 20 additions & 0 deletions spec/collections/channels_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'spec_helper'
require 'yt/collections/channels'

describe Yt::Collections::Channels do
subject(:collection) { Yt::Collections::Channels.new }

describe '#etag' do
let(:etag) { 'etag123' }

before do
expect_any_instance_of(Yt::Request).to receive(:run).once do
double(body: {'etag'=> etag, 'items'=> [], 'pageInfo'=> {'totalResults'=>0}})
end
end

it 'returns the etag from the list response' do
expect(collection.etag).to eq etag
end
end
end
15 changes: 15 additions & 0 deletions spec/collections/comment_threads_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,19 @@
end
end
end

describe '#etag' do
let(:parent) { Yt::Video.new id: 'any-id' }
let(:etag) { 'etag123' }

before do
expect_any_instance_of(Yt::Request).to receive(:run).once do
double(body: {'etag'=> etag, 'items'=> [], 'pageInfo'=> {'totalResults'=>0}})
end
end

it 'returns the etag from the list response' do
expect(collection.etag).to eq etag
end
end
end
17 changes: 16 additions & 1 deletion spec/collections/playlist_items_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,19 @@

it { expect(collection.delete_all).to eq [true] }
end
end

describe '#etag' do
let(:etag) { 'etag123' }
let(:behave) { receive(:fetch_etag).and_call_original }

before do
expect_any_instance_of(Yt::Request).to receive(:run).once do
double(body: {'etag'=> etag, 'items'=> [], 'pageInfo'=> {'totalResults'=>0}})
end
end

it 'returns the etag from the list response' do
expect(collection.etag).to eq etag
end
end
end
17 changes: 16 additions & 1 deletion spec/collections/playlists_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,19 @@

it { expect(collection.delete_all).to eq [true] }
end
end

describe '#etag' do
let(:etag) { 'etag123' }
let(:behave) { receive(:fetch_etag).and_call_original }

before do
expect_any_instance_of(Yt::Request).to receive(:run).once do
double(body: {'etag'=> etag, 'items'=> [], 'pageInfo'=> {'totalResults'=>0}})
end
end

it 'returns the etag from the list response' do
expect(collection.etag).to eq etag
end
end
end
19 changes: 17 additions & 2 deletions spec/collections/subscriptions_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require 'yt/collections/subscriptions'

describe Yt::Collections::Subscriptions do
subject(:collection) { Yt::Collections::Subscriptions.new }
subject(:collection) { Yt::Collections::Subscriptions.new parent: Yt::Channel.new(id: 'any-id') }
let(:msg) { {response_body: {error: {errors: [{reason: reason}]}}}.to_json }
before { expect(collection).to behave }

Expand All @@ -22,4 +22,19 @@
it { expect{collection.insert ignore_errors: true}.not_to fail }
end
end
end

describe '#etag' do
let(:etag) { 'etag123' }
let(:behave) { receive(:fetch_etag).and_call_original }

before do
expect_any_instance_of(Yt::Request).to receive(:run).once do
double(body: {'etag'=> etag, 'items'=> [], 'pageInfo'=> {'totalResults'=>0}})
end
end

it 'returns the etag from the list response' do
expect(collection.etag).to eq etag
end
end
end
15 changes: 15 additions & 0 deletions spec/collections/videos_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,19 @@
end
end
end

describe '#etag' do
let(:etag) { 'etag123' }

before do
expect_any_instance_of(Yt::Request).to receive(:run).once do
double(body: {'etag'=> etag, 'items'=> [], 'pageInfo'=> {'totalResults'=>0}})
end
end

it 'returns the etag from the list response' do
collection.count
expect(collection.etag).to eq etag
end
end
end
7 changes: 7 additions & 0 deletions spec/models/channel_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
describe Yt::Channel do
subject(:channel) { Yt::Channel.new attrs }

describe '#etag' do
context 'given the API response includes an etag' do
let(:attrs) { {id: 'any-id', etag: '12345'} }
it { expect(channel.etag).to eq '12345' }
end
end

describe '#title' do
context 'given a snippet with a title' do
let(:attrs) { {snippet: {"title"=>"Fullscreen"}} }
Expand Down
41 changes: 41 additions & 0 deletions spec/models/playlist_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,47 @@
describe Yt::Playlist do
subject(:playlist) { Yt::Playlist.new attrs }

describe '#etag' do
context 'given the API response includes an etag' do
let(:attrs) { {id: 'any-id', etag: 'etag123'} }
it { expect(playlist.etag).to eq 'etag123' }
end

context 'given only an ID is provided' do
let(:attrs) { {id: 'any-id', auth: double('auth')} }
let(:etag) { 'etag123' }

before do
expect_any_instance_of(Yt::Request).to receive(:run).once do
double(body: {'etag' => etag, 'items'=> [{'id'=> 'any-id', 'etag'=> etag}], 'pageInfo'=> {'totalResults'=> 1}})
end
end

it 'fetches the etag from YouTube' do
expect(playlist.etag).to eq etag
end
end

context 'given an ID is provided but no auth' do
let(:attrs) { {id: 'any-id'} }

it 'returns the etag from the API response even if no items are found' do
expect_any_instance_of(Yt::Request).to receive(:run).once do
double(body: {'etag' => 'mockedEtag', 'items'=> [], 'pageInfo'=> {'totalResults'=> 0}})
end
expect(playlist.etag).to eq 'mockedEtag'
end
end

context 'given no ID is provided' do
let(:attrs) { {} }

it 'returns nil' do
expect_any_instance_of(Yt::Request).not_to receive(:run)
expect(playlist.etag).to be_nil
end
end
end

describe '#title' do
context 'given a snippet with a title' do
Expand Down
Loading