All notable changes to this project will be documented in this file.
For more information about changelogs, check Keep a Changelog and Vandamme.
- [FEATURE] New
by: :month
option for reports. - [FEATURE] New
.reports
method to fetch multiple metrics at once.
How to upgrade
If your code expects reports to return results by day then you must add
the by: :day
option to your report method. The new default is by: :range
.
For instance channel.views
would return
{Wed, 8 May 2014 => 12.4, Thu, 9 May 2014 => 3.2, Fri, 10 May 2014 => …}
and now returns the same as calling channel.views by: :range
:
{total: 3450}
Additionally, if you expect reports by day then you must specify the
:since
option to your report method. Previously, this value was set to
5.days.ago
, but now is required. :until
still defaults to Date.today
.
Finally, if you expect reports for the entire range, notice that the default
:since
option is now set to the date when YouTube opened. Therefore calling a
method like channel.views
now returns the lifetime views of a channel.
- [ENHANCEMENT] Change default from
by: :day
toby: :range
. - [ENHANCEMENT] Require
:since
options for any report by day. - [ENHANCEMENT] Change default range for reports by range to lifetime.
- [FEATURE] New
by: :search_term
option for reports. - [FEATURE] New
in: {state: 'XX'}
option to limit reports to a US state - [FEATURE] New
uniques by: :day
report
- [FEATURE] New
by: :country
option for channel, video and playlist reports - [FEATURE] New
by: :state
option for channel, video and playlist reports - [FEATURE] New
:in
option to limit reports to a country
How to upgrade
If your code expects any of the following method to return Float values, then
be aware that they now return Integer. You can still call to_f
if you do need
a Float: views, comments
, likes
, dislikes
, shares
, subscribers_gained
,
subscribers_lost
, favorites_added
, favorites_removed
, annotations
,
impressions
, monetized_plybacks
, playlist_starts
.
- [ENHANCEMENT] Return
Integer
values for reports that can never return decimal digits. - [FEATURE] New
by: :range
option for reports, to return a metric without dimensions (that is, for the whole range)
How to upgrade
If your code doesn’t use PolicyRule#ACTIONS
, then you are good to go.
If it does, then you should redefine the constant in your own app.
- [REMOVAL] Remove
PolicyRule#ACTIONS
(was%q(block monetize takedown track)
). - [BUGFIX] Make
account.playlists
andaccount.channel.playlists
behave the same.
How to upgrade
If your code doesn’t use any of the following constants that were public but undocumented, then you are good to go.
If it does, then you should redefine those constants in your own app, since it’s not Yt’s goal to validate the values posted to YouTube API.
- [REMOVAL] Remove
Asset#STATUSES
(was%q(active inactive pending)
). - [REMOVAL] Remove
Claim#STATUSES
(was%q(active appealed disputed inactive pending potential takedown unknown)
). - [REMOVAL] Remove
Claim#CONTENT_TYPES
(was%q(audio video audiovisual)
). - [REMOVAL] Remove
Reference#STATUSES
(was%q(activating active checking computing_fingerprint deleted duplicate_on_hold inactive live_streaming_processing urgent_reference_processing)
). - [REMOVAL] Remove
Reference#CONTENT_TYPES
(was%q(audio video audiovisual)
). - [REMOVAL] Remove
Status#PRIVACY_STATUSES
(was%q(private public unlisted)
).
How to upgrade
If your code never calls partnered_channels.includes(:viewer_percentages)
on
a Yt::ContentOwner, then you are good to go.
If it does, then be aware that viewer percentage is not eager-loaded anymore,
so the call above is equivalent to partenered_channels
. The reason is that
viewer percentage requires a time-range, and using a default range of the
last 3 months can generate more confusion than added value.
Also if your code still uses the deprecated:
.viewer_percentages
method, replace with.viewer_percentage
.policy.time_updated
method, replace withpolicy.updated_at
.video.uploaded?
method, replace withvideo.uploading?
.
- [REMOVAL] Remove
.includes(:viewer_percentages)
oncontent_owner.partnered_channels
. - [REMOVAL] Remove deprecated
viewer_percentages
(useviewer_percentage
instead) - [REMOVAL] Remove deprecated
policy.time_updated
(useupdated_at
instead) - [REMOVAL] Remove deprecated
video.uploaded?
(useuploading?
instead)
How to upgrade
If your code never calls public?
, private?
or unlisted?
on a Status
object, then you are good to go.
If it does, then call the same methods on the parent Resource object instead.
For instance, replace video.status.private?
with video.private?
.
- [ENHANCEMENT] Don’t over-delegate privacy status methods of Resource.
How to upgrade
If your code never calls video-specific methods on video.status
, then you are
good to go.
If it does, then call the same methods on video
, rather than video.status
.
For instance, replace video.status.deleted?
with video.deleted?
.
- [ENHANCEMENT] Don’t over-delegate methods of Video.
- [ENHANCEMENT] Complete documentation of Yt::Video.
How to upgrade
If your code never calls video.uploaded?
, then you are good to go.
If it does, then replace your calls with video.uploading?
.
In fact, the YouTube constant uploaded
identifies the status where a
video is being uploaded.
- [ENHANCEMENT] Rename
uploaded?
touploading?
to avoid confusion.
- [FEATURE] New
file_size
,file_type
,container
methods for Yt::Video. - [BUGFIX] Retrieve
category_id
also for videos obtained through a search. - [FEATURE] Add .includes(:category) to .videos in order to eager-load category title and ID of a collection of videos
- [FEATURE] New
embed_html
method for Yt::Video.
- [FEATURE] New
annotation clicks
report for videos and channels. - [FEATURE] New
annotation click-through rate
report for videos and channels. - [FEATURE] New
annotation close rate
report for videos and channels.
How to upgrade
If your code never calls the viewer_percentage(gender: [:female|:male])
method
on a Channel or Video object, then you are good to go.
If it does, then replace your calls to viewer_percentage(gender: :female)
with viewer_percentage(by: gender)[:female]
, and do the same for :male
.
Note that the plural viewer_percentages
method still works but it’s
deprecated: you should use viewer_percentage
instead.
- [ENHANCEMENT] Remove
:gender
option inviewer_percentage
in favor of a more generic:by
- [FEATURE] New
by: :gender
option for reports, to return viewer percentage by gender - [FEATURE] New
by: :age_group
option for reports, to return viewer percentage by age group - [ENHANCEMENT] The viewer percentage report now accepts start/end date options (like any other report)
- [DEPRECATION] Deprecate
viewer_percentages
in favor ofviewer_percentage
.
- [FEATURE] New
by: :device_type
option for reports, to return views and estimated watched minutes (channels) by device
- [BUGFIX] Rescue OpenSSL::SSL::SSLErrorWaitReadable only on version of Ruby that define it.
- [BUGFIX] Raise
Yt::Errors::RequestError
when passing an invalid path or URL toupload_thumbnail
- [FEATURE] New
by: :embedded_player_location
option for reports, to return views and estimated watched minutes (channels) by URL where the player was embedded - [FEATURE] New
by: :playback_location
option for reports, to return views and estimated watched minutes (channels) by watch/embedded/channel/external app/mobile. - [FEATURE] New
by: :related_video
option for reports, to return views and estimated watched minutes (channels) by the video that linked there.
- [BUGFIX] Don't let request errors crash Yt in Ruby 1.9.3.
- [FEATURE] Make
Annotation#text
a public method. - [FEATURE] Make
data
a public method for Snippet, Status, ContentDetail and StatisticsSet. - [FEATURE] Add .includes to .videos, so you can eager load snippet, status, statistics and content details for a collection of videos
- [FEATURE] New
monetized playbacks
report for channels. - [FEATURE] New
estimated watched minutes
report for videos. - [FEATURE] New video reports:
average_view_duration
,average_view_percentage
. - [FEATURE] New
by: :playlist
option for reports, to return views and estimated watched minutes (channels) by playlist. - [FEATURE] New playlist reports:
views
,playlist_starts
,average_time_in_playlist
,views_per_playlist_start
.
- [FEATURE] New
by: :traffic_source
option for reports, to return views (channels/videos) and estimated watched minutes (channels) by traffic source. - [FEATURE] New
by: :video
option for reports, to return views and estimated watched minutes (channels) by video.
- [FEATURE] New channel/video reports:
favorites_added
,favorites_removed
.
- [FEATURE] New channel reports:
subscribers_gained
,subscribers_lost
. - [FEATURE] New video reports:
subscribers_gained
,subscribers_lost
. - [FEATURE] New channel reports:
estimated_minutes_watched
,average_view_duration
,average_view_percentage
.
- [FEATURE] New
video.upload_thumbnail
to upload the thumbnail for a video.
- [ENHANCEMENT] Accept
force: true
inauthentication_url
to force approval prompt.
- [FEATURE] AssetSearch resources available.
- [FEATURE] Access asset metadata (
effective
andmine
) via the asset object. - [ENHANCEMENT] Support
isManualClaim
parameter in claims#insert.
- [FEATURE] New video reports: monetized playbacks.
- [ENHANCEMENT] Accept
includes(:viewer_percentages)
in.partnered_channels
to eager-load multiple viewer percentages at once. - [ENHANCEMENT] Accept
where
in ViewerPercentages to collect data for multiple channels at once. - [ENHANCEMENT] Accept
part
in thewhere
clause of Channels, so statistics can be loaded at once.
- [ENHANCEMENT] Add
advertising_options_set
andad_formats
to video
- [ENHANCEMENT] Accept
policy
(with custom set of rules) incontent_owner.create_claim
- [BUGFIX] Rescue OpenSSL::SSL::SSLErrorWaitReadable raised by YouTube servers.
- [FEATURE] Add
release!
to Ownership.
- [BUGFIX] Make list videos by id work for exactly 50 ids.
How to upgrade
If your code never calls the create_playlist
on a Channel object, then you
are good to go.
If it does, then replace your calls to channel.create_playlist
with
account.create_playlist
, that is, call create_playlist
on the channel’s
account instead.
- [ENHANCEMENT] Remove
create_playlist
from Channel (still exists on Account) - [ENHANCEMENT] Accept
category_id
inupload_video
.
- [ENHANCEMENT] Accept
part
in thewhere
clause of Videos, so statistics and content details can be eagerly loaded.
- [ENHANCEMENT] Add
position
option to add_video (to specify where in a playlist to add a video) - [FEATURE] Add
update
to PlaylistItem (to change the position of the item in the playlist)
How to upgrade
If your code never calls the delete
method directly on a Subscription
object (to delete subscriptions by id), then you are good to go.
If it does, then be aware that trying to delete an unknown subscription will
now raise a RequestError, and will not accept ignore_errors
as an option:
account = Yt::Account.new access_token: 'ya29...'
subscription = Yt::Subscription.new id: '--unknown-id--', auth: account
# old behavior
subscription.delete ignore_errors: true # => false
# new behavior
subscription.delete # => raises Yt::Errors::RequestError "subscriptionNotFound"
Note that the unsubscribe
and unsubscribe!
methods of Channel
have not
changed, so you can still try to unsubscribe from a channel and not raise an
error by using the unsubscribe
method:
account = Yt::Account.new access_token: 'ya29...'
channel = Yt::Channel.new id: 'UC-CHANNEL-ID', auth: account
channel.unsubscribe # => returns falsey if you were not subscribed
channel.unsubscribe! # => raises Yt::Errors::RequestError if you were not subscribed
- [ENHANCEMENT] Replace
has_many :subscriptions
withhas_one :subscription
in Channel - [FEATURE] Add
subscribed_channels
to Channel (list which channels the channel is subscribed to) - [FEATURE] Add
subscribers
to Account (list which channels are subscribed to an account)
- [BUGFIX] Make Resource.new(url: url).title hit the right endpoint
- [BUGFIX] Make videos.where(id: 'MESycYJytkU').first.id return 'MESycYJytkU'
- [ENHANCEMENT] Add Video search even by id, chart or rating
- [FEATURE] Add
ActiveSupport::Notification
to inspect HTTP requests
- [FEATURE] Add
update
method to Asset model
- [FEATURE] Add AdvertisingOptionsSet with
update
to change the advertising settings of a video - [FEATURE] Add
content_owner.create_claim
andclaim.delete
- [FEATURE] Add
update
method to Ownership to change owners of an asset - [FEATURE] Add
asset.ownership
to list the owners of an asset - [FEATURE] Add
content_owner.create_asset
and Asset model
- [ENHANCEMENT] Add Video search even without a parent account or channel
For instance, to search for the most viewed video on the whole YouTube, run:
videos = Yt::Collections::Videos.new
videos.where(order: 'viewCount').first.title #=> "PSY - GANGNAM STYLE"
How to upgrade
When a request to YouTube fails, Yt used to print out a verbose error message, including the response body and the request that caused the error (in curl format). This output could include sensitive data (such as the authentication token). For security reasons, Yt will not print it out anymore by default.
If this is acceptable, then you are good to go.
If you want the old behavior, set the log_level
of Yt to :debug
:
Yt.configure do |config|
config.log_level = :debug
end
- [ENHANCEMENT] Add
log_level
to Yt.configuration
- [ENHANCEMENT] Use PATCH rather than PUT to partially update a MatchPolicy
- [BUGFIX] List tags of videos retrieved with channel.videos and account.videos
- [FEATURE] Add methods to insert and delete ContentID references
- [FEATURE] Add
.match_reference_id
to Claim model
- [FEATURE] Add
MatchPolicy
class with.update
to change the policy used by an asset
- [BUGFIX] Make Yt work on Ruby 1.9.3 / ActiveSupport 3.0 again (was broken by 0.10.0)
How to upgrade
If your code never calls the size
method to count how many items a list of
results has (e.g., how many videos an account has), then you are good to go.
If it does, then be aware that size
will now return try to the number of
items as specified in the "totalResults" field of the first page of the YouTube
response, rather than loading all the pages (possibly thousands) and counting
exactly how many items are returned.
If this is acceptable, then you are good to go.
If you want the old behavior, replace size
with count
:
account = Yt::Account.new access_token: 'ya29...'
# old behavior
account.videos.size # => retrieved *all* the pages of the account’s videos
# new behavior
account.videos.size # => retrieves only the first page, returning the totalResults counter
account.videos.count # => retrieves *all* the pages of the account’s videos
- [ENHANCEMENT] Calling
size
on a collection does not load all the pages of the collection - [ENHANCEMENT] Alias
policy.time_updated
to more coherentpolicy.updated_at
- [FEATURE] Add
.content_owner
and.linked_at
to channels managed by a CMS content owner
- [BUGFIX] Correctly parse videos’ duration for videos longer than 24 hours
- [ENHANCEMENT] Accept angle brackets characters in videos’ and playlists’ metadata
- [FEATURE] Allow status attributes of a video to be updated
video.update
now accepts three new attributes: privacy_status
,
public_stats_viewable
and publish_at
.
- [FEATURE] Expose metadata for live-streaming videos
New method are now available for Video
instance to check their live-streaming
details: actual_start_time
, actual_end_time
, scheduled_start_time
,
scheduled_end_time
and concurrent_viewers
.
- [BUGFIX] Don’t cache
.where
conditions on multiple calls
For instance, invoking account.videos.where(q: 'x').count
followed by
account.videos.count
used to return the same result, because the where
conditions of the first request were wrongly kept for the successive request.
- [FEATURE] Check if a ContentID claim is third-party with
claim.third_party?
- [ENHANCEMENT]
update
methods accept both underscore and camel-case attributes
For instance, either of the following syntaxes can now be used:
video.update categoryId: "22"
or video.update category_id: "22"
.
- [FEATURE] List ContentID policies with
content_owner.policies
- [FEATURE] List ContentID references with
content_owner.references
- [ENHANCEMENT]
playlist.update
accepts bothprivacyStatus
andprivacy_status
For instance, either of the following syntaxes can now be used:
playlist.update privacyStatus: "unlisted"
or
playlist.update privacy_status: "unlisted"
.
How to upgrade
If your code never declares instances of Yt::Rating
, or never calls the
update
method on them, then you are good to go.
If it does, then simply replace update
with set
:
rating = Yt::Rating.new
# old syntax
rating.update :like
# new syntax
rating.set :like
- [ENHANCEMENT]
rating.set
replacesrating.update
to rate a video
- [FEATURE] Delete a video with
video.delete
- [BUGFIX] Correctly parse annotations with timestamp written as
t='0'
- [FEATURE] List content owners managed by an account with
account.content_owners
- [FEATURE] List ContentID claims administered by a content owner with
content_owner.claims
- [FEATURE] Include all the video-related status information in
video.status
New method are now available for Video
instance to check their status
information: public?
, uploaded?
, rejected?
, failed?
, processed?
,
deleted?
, uses_unsupported_codec?
, has_failed_conversion?
, empty?
,
invalid?
, too_small?
, aborted?
, claimed?
, infringes_copyright?
,
duplicate?
, inappropriate?
, too_long?
, belongs_to_closed_account?
,
infringes_trademark?
, violates_terms_of_use?
, has_public_stats_viewable?
,
belongs_to_suspended_account?
, scheduled?
, scheduled_at
, embeddable?
licensed_as_creative_commons?
and licensed_as_standard_youtube?
.
How to upgrade
If your code never declares instances of Yt::Channel
, or never calls the
subscribe
method on them, then you are good to go.
If it does, then be aware that subscribe
will not raise an error anymore if
a YouTube user tries to subscribe to her/his own YouTube channel. Instead,
subscribe
will simply return nil
.
If this is acceptable, then you are good to go.
If you want the old behavior, replace subscribe
with subscribe!
:
account = Yt::Account.new access_token: 'ya29...'
channel = account.channel
# old behavior
channel.subscribe # => raised an error
# new behavior
channel.subscribe # => nil
channel.subscribe! # => raises an error
- [ENHANCEMENT]
channel.subscribe
does not raise error when trying to subscribe to one’s own channel
- [breaking change] Rename DetailsSet to ContentDetail
- Add statistics_set to Video (views, likes, dislikes, favorites, comments)
- Add statistics_set to Channel (views, comments, videos, subscribers)
- More snippet methods for Video (channel_id, channel_title, category_id, live_broadcast_content)
- More snippet methods for Playlist (channel_id, channel_title)
- More snippet methods for PlaylistItem (channel_id, channel_title, playlist_id, video_id)
- More status methods for PlaylistItem (privacy_status, public?, private?, unlisted?)
- Add video.update to update title, description, tags and categoryId of a video
- Sort channel.videos by most recent first
- Extract Reports (earnings, views) into module with macro
has_report
- New channel reports: comments, likes, dislikes, shares and impressions
- Allow both normal and partnered channels to retrieve reports about views, comments, likes, dislikes, shares
- Make reports available also on Video (not just Channel)
- New account.upload_video to upload a video (either local or remote).
- Make channel.videos access more than 500 videos per channel
- Add viewer percentage (age group, gender) to Channel and Video reports
- [breaking change] Rename Channel#earning to Channel#earnings_on
- [breaking change] Account#videos shows all videos owned by account (public and private)
- Add the .status association to every type of resource (Channel, Video, Playlist)
- Allow account.videos to be chained with .where, such as in account.videos.where(q: 'query')
- Retry request once when YouTube times out
- Handle annotations with "never" as the timestamp, without text, singleton positions, of private videos
- New methods for Video: hd?, stereoscopic?, captioned?, licensed?
- More complete custom exception Yt::Error, with code, body and curl
- Replace
:ignore_not_found
and:ignore_duplicates
with:ignore_errors
- Allow resources to be initialized with a url, such as Yt::Resource.new url: 'youtube.com/fullscreen'
- Add
has_one :id
to resources, to retrieve the ID of resources initialized by URL - Raise an error if some
has_one
associations are not found (id, snippet, details set, user info) - Don't check for the right :scope if Account is initialized with credentials
- Move models in Yt::Models but still auto-include them in the main namespace
- New Authentication model to separate
access_token
andrefresh_token
from Account - New types of Errors that render more verbose errors and the failing request in cURL syntax
- Separate Error class for 500 error, so they can be easily found in app logs
- New Earning collection to retrieve estimated earning for YouTube-partnered channels
- Rename error classes so they match the corresponding Net::HTTP errors (e.g. Unauthorized)
- Separate Error class for 403 Error
- Retry once YouTube earning queries that return error 400 "Invalid query. Query did not conform to the expectations"
- Update RSpec to 3.0 (only required in development/testing)
- New ContentOwner subclass of Account with access to partnered channels
- Automatically refresh the access token when it expires or becomes invalid
- Retry once YouTube earning queries that return error 503
- Wait 3 seconds and retry every request that returns 500, 503 or 400 with "Invalid query"
- New Views collection to retrieve view count for YouTube-partnered channels
- Complete rewrite, using ActiveSupport and separating models and collections
- New methods to handle annotations, details sets
- Supports also ActiveSupport 3 and Ruby 1.9.3 (not just AS4 + Ruby 2)
- Fix parsing annotation and timestamps longer than 1 hour
- Fix delegating tags from resources to snippets
- Two options to add videos to a playlist: fail or not if a video is missing or its account terminated
- Allow to configure Yt credentials through environment variables
- When updating a playlist, only changes the specified attributes
- New and improved methods to handle subscriptions, playlists, playlist items
find_or_create_playlist_by
does not yield a block anymoreaccount.subscribe_to!
raises error in case of duplicate subscription, butaccount.subscribe_to
does not
account.subscribe_to!
does not raise error in case of duplicate subscription- Accountable objects can be initialized with the OAuth access token if there's no need to get a fresh one with a refresh token
- Replaced
account.perform!
withaccount.like!
,account.subscribe_to!
- Added
account.add_to!
to add a video to an account’s playlist - Added
account.find_or_create_playlist_by
to find or create an account’s playlist
- Added support for Ruby 2.0.0
- Support for authenticated resources: Youtube accounts and Google accounts
- Support for public Youtube resources: channels and videos
- Available actions for authenticated Youtube accounts: like a video, subscribe to a channel