yt 0.0.1 → 0.4.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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +24 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/.yardopts +1 -0
  6. data/Gemfile +9 -0
  7. data/Gemfile.lock +78 -0
  8. data/HISTORY.md +37 -0
  9. data/MIT-LICENSE +20 -0
  10. data/README.md +325 -0
  11. data/Rakefile +1 -0
  12. data/TODO.md +11 -0
  13. data/bin/yt +31 -0
  14. data/lib/yt.rb +2 -0
  15. data/lib/yt/actions/delete.rb +27 -0
  16. data/lib/yt/actions/delete_all.rb +28 -0
  17. data/lib/yt/actions/insert.rb +29 -0
  18. data/lib/yt/actions/list.rb +65 -0
  19. data/lib/yt/actions/update.rb +25 -0
  20. data/lib/yt/associations.rb +33 -0
  21. data/lib/yt/associations/annotations.rb +15 -0
  22. data/lib/yt/associations/channels.rb +20 -0
  23. data/lib/yt/associations/details_sets.rb +20 -0
  24. data/lib/yt/associations/playlist_items.rb +26 -0
  25. data/lib/yt/associations/playlists.rb +22 -0
  26. data/lib/yt/associations/ratings.rb +39 -0
  27. data/lib/yt/associations/snippets.rb +20 -0
  28. data/lib/yt/associations/statuses.rb +14 -0
  29. data/lib/yt/associations/subscriptions.rb +38 -0
  30. data/lib/yt/associations/user_infos.rb +21 -0
  31. data/lib/yt/associations/videos.rb +14 -0
  32. data/lib/yt/collections/annotations.rb +43 -0
  33. data/lib/yt/collections/base.rb +13 -0
  34. data/lib/yt/collections/channels.rb +32 -0
  35. data/lib/yt/collections/details_sets.rb +32 -0
  36. data/lib/yt/collections/playlist_items.rb +50 -0
  37. data/lib/yt/collections/playlists.rb +56 -0
  38. data/lib/yt/collections/ratings.rb +32 -0
  39. data/lib/yt/collections/snippets.rb +38 -0
  40. data/lib/yt/collections/subscriptions.rb +67 -0
  41. data/lib/yt/collections/user_infos.rb +41 -0
  42. data/lib/yt/collections/videos.rb +32 -0
  43. data/lib/yt/config.rb +55 -0
  44. data/lib/yt/models/account.rb +68 -0
  45. data/lib/yt/models/annotation.rb +137 -0
  46. data/lib/yt/models/base.rb +11 -0
  47. data/lib/yt/models/channel.rb +17 -0
  48. data/lib/yt/models/configuration.rb +29 -0
  49. data/lib/yt/models/description.rb +98 -0
  50. data/lib/yt/models/details_set.rb +31 -0
  51. data/lib/yt/models/playlist.rb +65 -0
  52. data/lib/yt/models/playlist_item.rb +42 -0
  53. data/lib/yt/models/rating.rb +28 -0
  54. data/lib/yt/models/snippet.rb +48 -0
  55. data/lib/yt/models/status.rb +26 -0
  56. data/lib/yt/models/subscription.rb +35 -0
  57. data/lib/yt/models/user_info.rb +66 -0
  58. data/lib/yt/models/video.rb +16 -0
  59. data/lib/yt/utils/request.rb +85 -0
  60. data/lib/yt/version.rb +3 -0
  61. data/spec/associations/device_auth/channels_spec.rb +10 -0
  62. data/spec/associations/device_auth/details_sets_spec.rb +19 -0
  63. data/spec/associations/device_auth/playlist_items_spec.rb +42 -0
  64. data/spec/associations/device_auth/playlists_spec.rb +42 -0
  65. data/spec/associations/device_auth/ratings_spec.rb +30 -0
  66. data/spec/associations/device_auth/snippets_spec.rb +30 -0
  67. data/spec/associations/device_auth/subscriptions_spec.rb +27 -0
  68. data/spec/associations/device_auth/user_infos_spec.rb +10 -0
  69. data/spec/associations/device_auth/videos_spec.rb +22 -0
  70. data/spec/associations/no_auth/annotations_spec.rb +15 -0
  71. data/spec/associations/server_auth/channels_spec.rb +2 -0
  72. data/spec/associations/server_auth/details_sets_spec.rb +18 -0
  73. data/spec/associations/server_auth/playlist_items_spec.rb +17 -0
  74. data/spec/associations/server_auth/playlists_spec.rb +17 -0
  75. data/spec/associations/server_auth/ratings_spec.rb +2 -0
  76. data/spec/associations/server_auth/snippets_spec.rb +28 -0
  77. data/spec/associations/server_auth/subscriptions_spec.rb +2 -0
  78. data/spec/associations/server_auth/user_infos_spec.rb +2 -0
  79. data/spec/associations/server_auth/videos_spec.rb +20 -0
  80. data/spec/collections/annotations_spec.rb +6 -0
  81. data/spec/collections/channels_spec.rb +6 -0
  82. data/spec/collections/details_sets_spec.rb +6 -0
  83. data/spec/collections/playlist_items_spec.rb +23 -0
  84. data/spec/collections/playlists_spec.rb +26 -0
  85. data/spec/collections/ratings_spec.rb +6 -0
  86. data/spec/collections/snippets_spec.rb +6 -0
  87. data/spec/collections/subscriptions_spec.rb +30 -0
  88. data/spec/collections/user_infos_spec.rb +6 -0
  89. data/spec/collections/videos_spec.rb +6 -0
  90. data/spec/models/annotation_spec.rb +131 -0
  91. data/spec/models/channel_spec.rb +13 -0
  92. data/spec/models/description_spec.rb +94 -0
  93. data/spec/models/details_set_spec.rb +23 -0
  94. data/spec/models/playlist_item_spec.rb +32 -0
  95. data/spec/models/playlist_spec.rb +52 -0
  96. data/spec/models/rating_spec.rb +13 -0
  97. data/spec/models/snippet_spec.rb +66 -0
  98. data/spec/models/status_spec.rb +42 -0
  99. data/spec/models/subscription_spec.rb +37 -0
  100. data/spec/models/user_info_spec.rb +69 -0
  101. data/spec/models/video_spec.rb +13 -0
  102. data/spec/spec_helper.rb +15 -0
  103. data/spec/support/device_app.rb +16 -0
  104. data/spec/support/server_app.rb +10 -0
  105. data/yt.gemspec +30 -0
  106. metadata +209 -17
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/TODO.md ADDED
@@ -0,0 +1,11 @@
1
+ * find by url (either video or channel or.. playlist)
2
+ * Google accounts?
3
+ * ENV support
4
+
5
+ * add has_one :status to video
6
+
7
+ * operations like subscribe that require authentication should not fail if
8
+ called on Yt::Channel without auth but, similarly to account, show the prompt
9
+ or ask for the device code
10
+
11
+ * scope
data/bin/yt ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'yt'
5
+ rescue LoadError
6
+ require 'rubygems'
7
+ require 'yt'
8
+ end
9
+
10
+ ############################
11
+
12
+ Yt.configure do |config|
13
+ config.scenario = :server_app
14
+ config.api_key = ENV['YT_TEST_APP_SERVER_API_KEY']
15
+ end
16
+
17
+ ############################
18
+
19
+ channel = Yt::Channel.new id: ARGV[0] || 'UCxO1tY8h1AhOz0T4ENwmpow'
20
+
21
+ puts "Title: #{channel.title}"
22
+ puts "Description: #{channel.description}"
23
+ puts "Thumbnail: #{channel.thumbnail_url}"
24
+ puts "Videos: "
25
+ channel.videos.each do |video|
26
+ puts " Annotations: #{video.annotations.count}"
27
+ puts " Duration: #{video.duration}s"
28
+ puts " Title: #{video.title}"
29
+ puts " Description: #{video.description}"
30
+ puts " Thumbnail: #{video.thumbnail_url}"
31
+ end
@@ -0,0 +1,2 @@
1
+ require 'yt/config'
2
+ require 'yt/models/account'
@@ -0,0 +1,27 @@
1
+ require 'yt/utils/request'
2
+
3
+ module Yt
4
+ module Actions
5
+ module Delete
6
+
7
+ private
8
+
9
+ def do_delete(extra_delete_params = {})
10
+ request = Request.new delete_params.merge(extra_delete_params)
11
+ response = request.run
12
+ raise unless response.is_a? Net::HTTPNoContent
13
+ yield response.body
14
+ end
15
+
16
+ def delete_params
17
+ {}.tap do |params|
18
+ params[:method] = :delete
19
+ params[:format] = :json
20
+ params[:host] = 'www.googleapis.com'
21
+ params[:scope] = 'https://www.googleapis.com/auth/youtube'
22
+ params[:auth] = @auth
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ require 'yt/actions/list'
2
+ require 'yt/utils/request'
3
+
4
+ module Yt
5
+ module Actions
6
+ module DeleteAll
7
+ include List
8
+
9
+ private
10
+
11
+ def do_delete_all(params = {})
12
+ where(params).map do |item|
13
+ yield item if block_given?
14
+ item.delete
15
+ end.tap { @items = [] }
16
+ end
17
+
18
+ def where(params = {})
19
+ list.find_all do |item|
20
+ params.all? do |method, value|
21
+ # TODO: could be symbol etc...
22
+ item.respond_to?(method) && item.send(method) == value
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ require 'yt/utils/request'
2
+
3
+ module Yt
4
+ module Actions
5
+ module Insert
6
+
7
+ private
8
+
9
+ def do_insert(extra_insert_params = {})
10
+ request = Request.new insert_params.merge(extra_insert_params)
11
+ response = request.run
12
+ raise unless response.is_a? Net::HTTPOK
13
+ @items = []
14
+ new_item response.body
15
+ end
16
+
17
+ def insert_params
18
+ {}.tap do |params|
19
+ params[:method] = :post
20
+ params[:format] = :json
21
+ params[:host] = 'www.googleapis.com'
22
+ params[:body_type] = :json
23
+ params[:scope] = 'https://www.googleapis.com/auth/youtube'
24
+ params[:auth] = @auth
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,65 @@
1
+ require 'yt/utils/request'
2
+
3
+ module Yt
4
+ module Actions
5
+ module List
6
+
7
+ delegate :count, :first, :any?, :each, :map, to: :list
8
+ alias size count
9
+
10
+ private
11
+
12
+ def list
13
+ @last_index, @page_token = 0, nil
14
+ Enumerator.new do |items|
15
+ while next_item = find_next
16
+ items << next_item
17
+ end
18
+ end
19
+ end
20
+
21
+ def find_next
22
+ @items ||= []
23
+ if @items[@last_index].nil? && more_pages?
24
+ more_items = next_page.map{|data| new_item data}
25
+ @items.concat more_items
26
+ end
27
+ @items[(@last_index +=1) -1]
28
+ end
29
+
30
+ # To be overriden by the subclasses
31
+ def new_item(data)
32
+ end
33
+
34
+ def more_pages?
35
+ @last_index.zero? || !@page_token.nil?
36
+ end
37
+
38
+ def next_page
39
+ params = list_params.dup
40
+ params[:params][:pageToken] = @page_token if @page_token
41
+ next_page = fetch_page params
42
+ @page_token = next_page[:token]
43
+ next_page[:items]
44
+ end
45
+
46
+ def fetch_page(params = {})
47
+ request = Request.new params
48
+ response = request.run
49
+ raise unless response.is_a? Net::HTTPOK
50
+ token = response.body['nextPageToken']
51
+ items = response.body.fetch 'items', []
52
+ {items: items, token: token}
53
+ end
54
+
55
+ def list_params
56
+ {}.tap do |params|
57
+ params[:method] = :get
58
+ params[:format] = :json
59
+ params[:host] = 'www.googleapis.com'
60
+ params[:auth] = @auth
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,25 @@
1
+ require 'yt/utils/request'
2
+
3
+ module Yt
4
+ module Actions
5
+ module Update
6
+ def do_update(extra_update_params = {}, options = {})
7
+ request = Request.new update_params.deep_merge(extra_update_params)
8
+ response = request.run
9
+ expected_response = options.fetch :expect, Net::HTTPNoContent
10
+ raise unless response.is_a? expected_response
11
+ yield response.body
12
+ end
13
+
14
+ def update_params
15
+ {}.tap do |params|
16
+ params[:method] = :put
17
+ params[:format] = :json
18
+ params[:host] = 'www.googleapis.com'
19
+ params[:scope] = 'https://www.googleapis.com/auth/youtube'
20
+ params[:auth] = @auth
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+ require 'active_support/dependencies/autoload'
3
+ require 'active_support/core_ext/string/inflections' # for camelize
4
+
5
+ module Yt
6
+ module Associations
7
+ # @note: Using Autoload to avoid circular dependencies.
8
+ # For instance: Yt::Channel requires Yt::Base, which requires
9
+ # Yt::Associations, which requires Yt::Associations::Subscription,
10
+ # which requires Yt::Subscription, which requires Yt::Base
11
+ extend ActiveSupport::Autoload
12
+
13
+ autoload :Annotations
14
+ autoload :Channels
15
+ autoload :DetailsSets
16
+ autoload :PlaylistItems
17
+ autoload :Playlists
18
+ autoload :Ratings
19
+ autoload :Snippets
20
+ autoload :Statuses
21
+ autoload :Subscriptions
22
+ autoload :UserInfos
23
+ autoload :Videos
24
+
25
+ def has_many(attributes, options = {})
26
+ mod = attributes.to_s.sub(/.*\./, '').camelize
27
+ include "Yt::Associations::#{mod.pluralize}".constantize
28
+ delegate *options[:delegate], to: attributes if options[:delegate]
29
+ end
30
+
31
+ alias has_one has_many
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ require 'yt/collections/annotations'
2
+
3
+ module Yt
4
+ module Associations
5
+ # Provides the `has_many :annotations` method to YouTube resources,
6
+ # which allows to access to content annotation set-specific methods.
7
+ # YouTube resources with annotations are: videos.
8
+ module Annotations
9
+ def annotations
10
+ @annotations ||= Collections::Annotations.by_video self
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,20 @@
1
+ require 'yt/collections/channels'
2
+
3
+ module Yt
4
+ module Associations
5
+ # Provides the `has_one :channel` method to YouTube resources, which
6
+ # allows to access to channel-specific methods like.
7
+ # YouTube resources with a channel are: account.
8
+ module Channels
9
+ def channel
10
+ @channel ||= channels.first
11
+ end
12
+
13
+ private
14
+
15
+ def channels
16
+ @channels ||= Collections::Channels.by_account self
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'yt/collections/details_sets'
2
+
3
+ module Yt
4
+ module Associations
5
+ # Provides the `has_one :details_set` method to YouTube resources, which
6
+ # allows to access to content detail set-specific methods like `duration`.
7
+ # YouTube resources with content details are: videos.
8
+ module DetailsSets
9
+ def details_set
10
+ @detail_set ||= details_sets.first
11
+ end
12
+
13
+ private
14
+
15
+ def details_sets
16
+ @details_sets ||= Collections::DetailsSets.by_video self
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ require 'yt/collections/playlist_items'
2
+
3
+ module Yt
4
+ module Associations
5
+ # Provides the `has_many :playlist_items` method to YouTube resources, which
6
+ # allows to invoke playlist_item-related methods, such as .add_video.
7
+ # YouTube resources with playlist items are: playlists.
8
+ module PlaylistItems
9
+ def playlist_items
10
+ @playlist_items ||= Collections::PlaylistItems.by_playlist self
11
+ end
12
+
13
+ def add_video(video_id)
14
+ playlist_items.insert id: video_id, kind: :video
15
+ end
16
+
17
+ def add_videos(video_ids = [])
18
+ video_ids.map{|video_id| add_video video_id}
19
+ end
20
+
21
+ def delete_playlist_items(attrs = {})
22
+ playlist_items.delete_all attrs
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ require 'yt/collections/playlists'
2
+
3
+ module Yt
4
+ module Associations
5
+ # Provides the `has_many :playlists` method to YouTube resources, which
6
+ # allows to invoke playlist-related methods, such as .create_playlist.
7
+ # YouTube resources with playlist are: channels.
8
+ module Playlists
9
+ def playlists
10
+ @playlists ||= Collections::Playlists.by_channel self
11
+ end
12
+
13
+ def create_playlist(params = {})
14
+ playlists.insert params
15
+ end
16
+
17
+ def delete_playlists(attrs = {})
18
+ playlists.delete_all attrs
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,39 @@
1
+ require 'yt/collections/ratings'
2
+
3
+ module Yt
4
+ module Associations
5
+ # Provides the `has_one :rating` method to YouTube resources, which
6
+ # allows to invoke rating-related methods, such as .like.
7
+ # YouTube resources with rating are: videos.
8
+ module Ratings
9
+ def rating
10
+ @rating ||= ratings.first
11
+ end
12
+
13
+ def liked?
14
+ rating.rating == :like
15
+ end
16
+
17
+ def like
18
+ rating.update :like
19
+ liked?
20
+ end
21
+
22
+ def dislike
23
+ rating.update :dislike
24
+ !liked?
25
+ end
26
+
27
+ def unlike
28
+ rating.update :none
29
+ !liked?
30
+ end
31
+
32
+ private
33
+
34
+ def ratings
35
+ @ratings ||= Collections::Ratings.by_video self
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,20 @@
1
+ require 'yt/collections/snippets'
2
+
3
+ module Yt
4
+ module Associations
5
+ # Provides the `has_one :snippet` method to YouTube resources, which
6
+ # allows to access to content detail set-specific methods like `title`.
7
+ # YouTube resources with content details are: videos and channels.
8
+ module Snippets
9
+ def snippet
10
+ @snippet ||= snippets.first
11
+ end
12
+
13
+ private
14
+
15
+ def snippets
16
+ @snippets ||= Collections::Snippets.by_resource self
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ require 'yt/models/status'
2
+
3
+ module Yt
4
+ module Associations
5
+ # Provides the `has_one :status` method to YouTube resources, which
6
+ # allows to access to status-specific methods like `public?`.
7
+ # YouTube resources with status are: playlists.
8
+ module Statuses
9
+ def status
10
+ @status
11
+ end
12
+ end
13
+ end
14
+ end