shrine-storage-you_tube 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +8 -0
- data/README.md +40 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/shrine/storage/you_tube/version.rb +7 -0
- data/lib/shrine/storage/you_tube.rb +153 -0
- data/shrine-storage-you_tube.gemspec +29 -0
- metadata +168 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 294ce939d884122234328a9458cbaceda8c7c53d
|
4
|
+
data.tar.gz: 5688b2ca8885b1cc6075485bf7ab4d52b0564456
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7892977f4c52e090bd56f015a6c3835006547923f2164df2648fecaced615c5499092577acdf3bf0cbbb73e33279286661ca5906c5c5160f8c8a020b99847a58
|
7
|
+
data.tar.gz: c3240f13832aabbb0662b19d83304c1112a807ff582022c745956de40cc4895e7e905ca4050466e3dc37965854c1d8b63a81f95c764f2664417c0dc4957b4b0c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Shrine::YouTube
|
2
|
+
|
3
|
+
Provides [YouTube](https://youtube.com) storage for [Shrine](http://shrinerb.com).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'shrine-storage-you_tube'
|
11
|
+
```
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
Since YouTube's API doesn't allow reading of uploaded data, the YouTube storage must be paired with another storage provider to hold the original videos. Videos are first uploaded to YouTube and then to the specified storage provider using the ID returned from the YouTube upload.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
require "shrine/storage/you_tube"
|
19
|
+
require "shrine/storage/s3"
|
20
|
+
|
21
|
+
s3 = Shrine::Storage::S3.new(**s3_options)
|
22
|
+
youtube = Shrine::Storage::YouTube.new(
|
23
|
+
original_storage: s3,
|
24
|
+
client_id: "abc123", # Google OAuth2 Client ID
|
25
|
+
client_secret: "def456", # Google OAuth2 Client Secret
|
26
|
+
refresh_token: "ghi789", # Refresh token for YouTube user
|
27
|
+
# optional parameters
|
28
|
+
channel_id: nil, # Channel ID for uploads, defaults to the user's channel
|
29
|
+
default_privacy: :private, # one of :private, :public, or :unlisted
|
30
|
+
upload_options: {} # may be used to set YouTube's snippet
|
31
|
+
)
|
32
|
+
|
33
|
+
Shrine.storages[:store] = youtube
|
34
|
+
```
|
35
|
+
|
36
|
+
## Development
|
37
|
+
|
38
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
39
|
+
|
40
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "shrine/storage/you_tube"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'shrine/storage/you_tube/version'
|
2
|
+
require 'google/apis/youtube_v3'
|
3
|
+
|
4
|
+
class Shrine
|
5
|
+
module Storage
|
6
|
+
class YouTube
|
7
|
+
class UserChannelNotFound < StandardError
|
8
|
+
def initialize(found_channel_count)
|
9
|
+
super("Could not determine the user's channel (found #{found_channel_count} channels). Create a channel at https://www.youtube.com/create_channel or set channel_id.")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class VideoNotFound < StandardError; end
|
14
|
+
|
15
|
+
attr_reader :original_storage, :youtube, :default_privacy, :upload_options
|
16
|
+
|
17
|
+
def initialize(
|
18
|
+
original_storage:,
|
19
|
+
client_id:,
|
20
|
+
client_secret:,
|
21
|
+
refresh_token:,
|
22
|
+
channel_id: nil,
|
23
|
+
default_privacy: :private,
|
24
|
+
upload_options: {}
|
25
|
+
)
|
26
|
+
@youtube = youtube_service(
|
27
|
+
client_id: client_id,
|
28
|
+
client_secret: client_secret,
|
29
|
+
refresh_token: refresh_token
|
30
|
+
)
|
31
|
+
|
32
|
+
@channel_id = channel_id
|
33
|
+
@default_privacy = default_privacy
|
34
|
+
@upload_options = upload_options
|
35
|
+
@original_storage = original_storage
|
36
|
+
end
|
37
|
+
|
38
|
+
extend Forwardable
|
39
|
+
delegate [:download, :open, :read, :stream] => :original_storage
|
40
|
+
|
41
|
+
def channel_id
|
42
|
+
@channel_id ||= find_user_channel
|
43
|
+
end
|
44
|
+
|
45
|
+
def upload(io, id, metadata = {}, **upload_options)
|
46
|
+
snippet = { title: metadata['filename'], channel_id: channel_id }
|
47
|
+
snippet.update(upload_options)
|
48
|
+
snippet.update(metadata.delete('youtube') || {})
|
49
|
+
|
50
|
+
video_data = Google::Apis::YoutubeV3::Video.new(snippet: snippet)
|
51
|
+
uploaded_video = upload_video(io, video_data)
|
52
|
+
|
53
|
+
id.replace(uploaded_video.id)
|
54
|
+
original_storage.upload(io, id, metadata)
|
55
|
+
|
56
|
+
uploaded_video.to_h
|
57
|
+
end
|
58
|
+
|
59
|
+
def exists?(id)
|
60
|
+
youtube.list_videos('id', id: id).page_info.total_results == 1
|
61
|
+
end
|
62
|
+
|
63
|
+
def delete(id)
|
64
|
+
return unless exists?(id)
|
65
|
+
youtube.delete_video(id)
|
66
|
+
original_storage.delete(id)
|
67
|
+
end
|
68
|
+
|
69
|
+
def url(id, type: nil, **options)
|
70
|
+
case type && type.to_sym
|
71
|
+
when :original
|
72
|
+
original_storage.url(id, **options)
|
73
|
+
when :embed
|
74
|
+
"https://youtube.com/embed/#{id}"
|
75
|
+
when :short
|
76
|
+
"https://youtu.be/#{id}"
|
77
|
+
else
|
78
|
+
"https://youtube.com/watch?v=#{id}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def clear!
|
83
|
+
while uploads_playlist_count > 0
|
84
|
+
uploads_playlist_items.items.each do |item|
|
85
|
+
video_id = item.snippet.resource_id.video_id
|
86
|
+
youtube.delete_video(video_id)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
original_storage.clear!
|
91
|
+
end
|
92
|
+
|
93
|
+
def update(id, metadata: {})
|
94
|
+
snippet = metadata.delete('youtube')
|
95
|
+
return unless snippet
|
96
|
+
|
97
|
+
video_query = youtube.list_videos('snippet', id: id)
|
98
|
+
raise VideoNotFound unless video_query.page_info.total_results == 1
|
99
|
+
|
100
|
+
existing_snippet = video_query.items.first.snippet.to_h
|
101
|
+
|
102
|
+
video_data = Google::Apis::YoutubeV3::Video.new(id: id, snippet: existing_snippet.merge(snippet))
|
103
|
+
updated_video = youtube.update_video('snippet', video_data)
|
104
|
+
updated_video.to_h
|
105
|
+
end
|
106
|
+
|
107
|
+
protected
|
108
|
+
|
109
|
+
def youtube_service(credentials)
|
110
|
+
service = Google::Apis::YoutubeV3::YouTubeService.new
|
111
|
+
service.authorization = Google::Auth::UserRefreshCredentials.new(credentials)
|
112
|
+
service
|
113
|
+
end
|
114
|
+
|
115
|
+
def find_user_channel
|
116
|
+
user_channels = youtube.list_channels('id', mine: true)
|
117
|
+
channel_count = user_channels.items.count
|
118
|
+
|
119
|
+
raise(UserChannelNotFound, channel_count) unless channel_count == 1
|
120
|
+
user_channels.items.first.id
|
121
|
+
end
|
122
|
+
|
123
|
+
def uploads_playlist_id
|
124
|
+
@uploads_playlist_id ||= begin
|
125
|
+
channel_response = youtube.list_channels('contentDetails', id: channel_id)
|
126
|
+
channel = channel_response.items.first
|
127
|
+
channel.content_details.related_playlists.uploads
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def uploads_playlist_items
|
132
|
+
youtube.list_playlist_items('snippet', playlist_id: uploads_playlist_id)
|
133
|
+
end
|
134
|
+
|
135
|
+
def uploads_playlist_count
|
136
|
+
uploads_playlist_items.page_info.total_results
|
137
|
+
end
|
138
|
+
|
139
|
+
def upload_video(io, video_data)
|
140
|
+
youtube.insert_video('snippet', video_data, upload_source: io)
|
141
|
+
rescue Google::Apis::ClientError => e
|
142
|
+
raise e unless (
|
143
|
+
e.message.include?('mediaBodyRequired') ||
|
144
|
+
e.message.include?('invalidFilename')
|
145
|
+
) && io.respond_to?(:download)
|
146
|
+
|
147
|
+
youtube.insert_video('snippet', video_data, upload_source: io.download)
|
148
|
+
ensure
|
149
|
+
io.rewind
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'shrine/storage/you_tube/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "shrine-storage-you_tube"
|
8
|
+
spec.version = Shrine::Storage::YouTube::VERSION
|
9
|
+
spec.authors = ["Reid Beels", "The Dyrt"]
|
10
|
+
spec.email = ["reid@thedyrt.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Provides YouTube storage for the Shrine file upload framework.}
|
13
|
+
spec.homepage = "https://github.com/thedyrt/shrine-storage-you_tube"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency 'shrine', '~> 2.0'
|
21
|
+
spec.add_dependency 'google-api-client', '~> 0.10.1'
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec"
|
26
|
+
spec.add_development_dependency "vcr", "~> 3.0"
|
27
|
+
spec.add_development_dependency "webmock", "~> 2.3"
|
28
|
+
spec.add_development_dependency "dotenv", "~> 2.0"
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shrine-storage-you_tube
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Reid Beels
|
8
|
+
- The Dyrt
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2017-03-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: shrine
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '2.0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '2.0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: google-api-client
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.10.1
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 0.10.1
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: bundler
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '1.10'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '1.10'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rake
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '10.0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '10.0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: vcr
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '3.0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '3.0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: webmock
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '2.3'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '2.3'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: dotenv
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '2.0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '2.0'
|
126
|
+
description:
|
127
|
+
email:
|
128
|
+
- reid@thedyrt.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- ".gitignore"
|
134
|
+
- ".rspec"
|
135
|
+
- ".travis.yml"
|
136
|
+
- Gemfile
|
137
|
+
- README.md
|
138
|
+
- Rakefile
|
139
|
+
- bin/console
|
140
|
+
- bin/setup
|
141
|
+
- lib/shrine/storage/you_tube.rb
|
142
|
+
- lib/shrine/storage/you_tube/version.rb
|
143
|
+
- shrine-storage-you_tube.gemspec
|
144
|
+
homepage: https://github.com/thedyrt/shrine-storage-you_tube
|
145
|
+
licenses: []
|
146
|
+
metadata: {}
|
147
|
+
post_install_message:
|
148
|
+
rdoc_options: []
|
149
|
+
require_paths:
|
150
|
+
- lib
|
151
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '0'
|
156
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
requirements: []
|
162
|
+
rubyforge_project:
|
163
|
+
rubygems_version: 2.5.2
|
164
|
+
signing_key:
|
165
|
+
specification_version: 4
|
166
|
+
summary: Provides YouTube storage for the Shrine file upload framework.
|
167
|
+
test_files: []
|
168
|
+
has_rdoc:
|