Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into retrieve-asset-metadata
- Loading branch information
Showing
24 changed files
with
389 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
--format documentation | ||
--color | ||
--fail-fast | ||
--tag ~rate_limited | ||
--tag ~flaky | ||
--tag ~extended_permissions | ||
--exclude_pattern spec/requests/as_content_owner/*_spec.rb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
require 'yt/models/video' | ||
require 'yt/models/playlist' | ||
require 'yt/models/channel' | ||
|
||
module Yt | ||
module Models | ||
# Provides methods to identify YouTube resources from names or URLs. | ||
# @see https://developers.google.com/youtube/v3/docs | ||
# @example Identify a YouTube video from its short URL: | ||
# url = Yt::URL.new 'youtu.be/kawaiiguy' | ||
# url.id # => 'UC4lU5YG9QDgs0X2jdnt7cdQ' | ||
# url.resource # => #<Yt::Channel @id=UC4lU5YG9QDgs0X2jdnt7cdQ> | ||
class URL | ||
# @param [String] text the name or URL of a YouTube resource (in any form). | ||
def initialize(text) | ||
@text = text.to_s.strip | ||
@match = find_pattern_match | ||
end | ||
|
||
# @return [Symbol] the kind of YouTube resource matching the URL. | ||
# Possible values are: +:playlist+, +:video+, +:channel+, and +:unknown:. | ||
def kind | ||
@match[:kind] | ||
end | ||
|
||
# @return [<String, nil>] the ID of the YouTube resource matching the URL. | ||
def id | ||
@match['id'] ||= fetch_id | ||
end | ||
|
||
# @return [<Yt::Channel>] the resource associated with the URL | ||
def resource(options = {}) | ||
@resource ||= case kind | ||
when :channel then Yt::Channel | ||
when :video then Yt::Video | ||
when :playlist then Yt::Playlist | ||
else raise Yt::Errors::NoItems | ||
end.new options.merge(id: id) | ||
end | ||
|
||
# @return [Array<Regexp>] patterns matching URLs of YouTube playlists. | ||
PLAYLIST_PATTERNS = [ | ||
%r{^(?:https?://)?(?:www\.)?youtube\.com/playlist/?\?list=(?<id>[a-zA-Z0-9_-]+)}, | ||
] | ||
|
||
# @return [Array<Regexp>] patterns matching URLs of YouTube videos. | ||
VIDEO_PATTERNS = [ | ||
%r{^(?:https?://)?(?:www\.)?youtube\.com/watch\?v=(?<id>[a-zA-Z0-9_-]{11})}, | ||
%r{^(?:https?://)?(?:www\.)?youtu\.be/(?<id>[a-zA-Z0-9_-]{11})}, | ||
%r{^(?:https?://)?(?:www\.)?youtube\.com/embed/(?<id>[a-zA-Z0-9_-]{11})}, | ||
%r{^(?:https?://)?(?:www\.)?youtube\.com/v/(?<id>[a-zA-Z0-9_-]{11})}, | ||
] | ||
|
||
# @return [Array<Regexp>] patterns matching URLs of YouTube channels. | ||
CHANNEL_PATTERNS = [ | ||
%r{^(?:https?://)?(?:www\.)?youtube\.com/channel/(?<id>UC[a-zA-Z0-9_-]{22})}, | ||
%r{^(?:https?://)?(?:www\.)?youtube\.com/(?<format>c/|user/)?(?<name>[a-zA-Z0-9_-]+)} | ||
] | ||
|
||
private | ||
|
||
def find_pattern_match | ||
patterns.find(-> {{kind: :unknown}}) do |kind, regex| | ||
if data = @text.match(regex) | ||
# Note: With Ruby 2.4, the following is data.named_captures | ||
break data.names.zip(data.captures).to_h.merge kind: kind | ||
end | ||
end | ||
end | ||
|
||
def patterns | ||
# @note: :channel *must* be the last since one of its regex eats the | ||
# remaining patterns. In short, don't change the following order. | ||
Enumerator.new do |patterns| | ||
VIDEO_PATTERNS.each {|regex| patterns << [:video, regex]} | ||
PLAYLIST_PATTERNS.each {|regex| patterns << [:playlist, regex]} | ||
CHANNEL_PATTERNS.each {|regex| patterns << [:channel, regex]} | ||
end | ||
end | ||
|
||
def fetch_id | ||
response = Net::HTTP.start 'www.youtube.com', 443, use_ssl: true do |http| | ||
http.request Net::HTTP::Get.new("/#{@match['format']}#{@match['name']}") | ||
end | ||
if response.is_a?(Net::HTTPRedirection) | ||
response = Net::HTTP.start 'www.youtube.com', 443, use_ssl: true do |http| | ||
http.request Net::HTTP::Get.new(response['location']) | ||
end | ||
end | ||
regex = %r{<meta itemprop="channelId" content="(?<id>UC[a-zA-Z0-9_-]{22})">} | ||
if data = response.body.match(regex) | ||
data[:id] | ||
else | ||
raise Yt::Errors::NoItems | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
module Yt | ||
VERSION = '0.32.2' | ||
VERSION = '0.32.3' | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
require 'spec_helper' | ||
require 'yt/models/url' | ||
|
||
describe Yt::URL do | ||
subject(:url) { Yt::URL.new text } | ||
|
||
context 'given a YouTube playlist URL' do | ||
let(:text) { "https://www.youtube.com/playlist?list=#{id}" } | ||
|
||
describe 'works with existing playlists' do | ||
let(:id) { 'LLxO1tY8h1AhOz0T4ENwmpow' } | ||
it {expect(url.id).to eq id } | ||
end | ||
|
||
describe 'works with unknown playlists' do | ||
let(:id) { 'PL12--not-a-playlist' } | ||
it {expect(url.id).to eq id } | ||
end | ||
end | ||
|
||
context 'given a YouTube video URL' do | ||
let(:text) { "https://www.youtube.com/watch?v=#{id}" } | ||
|
||
describe 'works with existing videos' do | ||
let(:id) { 'gknzFj_0vvY' } | ||
it {expect(url.id).to eq id } | ||
end | ||
|
||
describe 'works with unknown videos' do | ||
let(:id) { 'abc123abc12' } | ||
it {expect(url.id).to eq id } | ||
end | ||
end | ||
|
||
context 'given a YouTube channel URL in the ID form' do | ||
let(:text) { "https://www.youtube.com/channel/#{id}" } | ||
|
||
describe 'works with existing channels' do | ||
let(:id) { 'UC4lU5YG9QDgs0X2jdnt7cdQ' } | ||
it {expect(url.id).to eq id } | ||
end | ||
|
||
describe 'works with unknown channels' do | ||
let(:id) { 'UC-not-an-actual-channel' } | ||
it {expect(url.id).to eq id } | ||
end | ||
end | ||
|
||
context 'given an existing YouTube channel' do | ||
let(:text) { 'youtube.com/channel/UCxO1tY8h1AhOz0T4ENwmpow' } | ||
it {expect(url.kind).to eq :channel } | ||
end | ||
|
||
context 'given an existing YouTube video' do | ||
let(:text) { 'youtube.com/watch?v=gknzFj_0vvY' } | ||
it {expect(url.kind).to eq :video } | ||
end | ||
|
||
context 'given an existing YouTube playlist' do | ||
let(:text) { 'youtube.com/playlist?list=LLxO1tY8h1AhOz0T4ENwmpow' } | ||
it {expect(url.kind).to eq :playlist } | ||
end | ||
|
||
context 'given an unknown YouTube channel URL' do | ||
let(:text) { 'youtube.com/channel/UC-too-short-to-be-an-id' } | ||
it {expect(url.kind).to eq :channel } | ||
end | ||
|
||
context 'given an unknown YouTube video URL' do | ||
let(:text) { 'youtu.be/not-an-id' } | ||
it {expect(url.kind).to eq :unknown } | ||
end | ||
|
||
context 'given an unknown text' do | ||
let(:text) { 'not-really-anything---' } | ||
it {expect(url.kind).to eq :unknown } | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.