Last active
September 19, 2022 11:50
-
-
Save imaizume/66cb946e5f8cf097bfba5f2d16b8bdbb to your computer and use it in GitHub Desktop.
A simple workflow to save YouTube video to Notion page.
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
# Copyright (c) 2022 Tomohiro Imaizumi All rights reserved. | |
require 'uri' | |
require 'net/http' | |
require "json" | |
require 'optparse' | |
# Secrets | |
NOTION_API_TOKEN = ENV["NOTION_API_TOKEN"] | |
# Properties | |
NOTION_DATABASE_ID = ENV["NOTION_DATABASE_ID"] | |
NOTION_MEMO_PAGE_ID = ENV["NOTION_MEMO_PAGE_ID"] | |
# Consts | |
NOTION_QUERY_API_BASE_URL = "https://api.notion.com/v1/databases/#{NOTION_DATABASE_ID}/query" | |
def fetch_page_id_and_properties | |
notion_query_uri = URI(NOTION_QUERY_API_BASE_URL) | |
http = Net::HTTP.new(notion_query_uri.hostname, notion_query_uri.port) | |
http.use_ssl = true | |
req = Net::HTTP::Post.new(notion_query_uri.request_uri) | |
req['Accept'] = 'application/json' | |
req['Authorization'] = "Bearer #{NOTION_API_TOKEN}" | |
req['Content-Type'] = 'application/json' | |
req['Notion-Version'] = '2022-06-28' | |
filter = { | |
:filter => { | |
:property => "Hope", | |
:checkbox => { | |
:equals => true | |
} | |
} | |
} | |
req.body = filter.to_json | |
response = http.request(req) | |
obj = JSON.parse(response.body, symbolize_names: true) | |
obj[:results].map { |result| [result[:id], result[:properties][:Name][:title].first[:plain_text]] }.to_h | |
end | |
def fetch_unchecked_item(page_id_and_titles) | |
page_id_and_titles.keys.map do |page_id| | |
next if page_id_and_titles[page_id].empty? | |
url = URI("https://api.notion.com/v1/blocks/#{page_id}/children") | |
http = Net::HTTP.new(url.hostname, url.port) | |
http.use_ssl = true | |
req = Net::HTTP::Get.new(url.request_uri) | |
req['Accept'] = 'application/json' | |
req['Authorization'] = "Bearer #{NOTION_API_TOKEN}" | |
req['Content-Type'] = 'application/json' | |
req['Notion-Version'] = '2022-06-28' | |
response = http.request(req) | |
obj = JSON.parse(response.body, symbolize_names: true) | |
val = obj[:results] | |
.filter { |result| result[:type] == "to_do" && !result[:to_do][:checked] } | |
.map { |result| result[:to_do][:rich_text].first[:plain_text] } | |
.map { |value| "#{value} (#{page_id_and_titles[page_id]})" } | |
end | |
end | |
def clear_blocks(page_id) | |
url = URI("https://api.notion.com/v1/blocks/#{page_id}/children") | |
http = Net::HTTP.new(url.hostname, url.port) | |
http.use_ssl = true | |
req = Net::HTTP::Get.new(url.request_uri) | |
req['Accept'] = 'application/json' | |
req['Authorization'] = "Bearer #{NOTION_API_TOKEN}" | |
req['Content-Type'] = 'application/json' | |
req['Notion-Version'] = '2022-06-28' | |
response = http.request(req) | |
obj = JSON.parse(response.body, symbolize_names: true) | |
block_ids = obj[:results].map { |result| result[:id] } | |
block_ids.each do |block_id| | |
url = URI("https://api.notion.com/v1/blocks/#{block_id}/") | |
http = Net::HTTP.new(url.hostname, url.port) | |
http.use_ssl = true | |
req = Net::HTTP::Delete.new(url.request_uri) | |
req['Accept'] = 'application/json' | |
req['Authorization'] = "Bearer #{NOTION_API_TOKEN}" | |
req['Content-Type'] = 'application/json' | |
req['Notion-Version'] = '2022-06-28' | |
http.request(req) | |
end | |
end | |
def add_blocks(page_id, items) | |
notion_page_url = URI("https://api.notion.com/v1/blocks/#{page_id}/children") | |
http = Net::HTTP.new(notion_page_url.hostname, notion_page_url.port) | |
http.use_ssl = true | |
item_array = items.map do |item| | |
{ | |
:object => "block", | |
:type => "to_do", | |
:to_do => { | |
:rich_text => [ | |
{ | |
:type => "text", | |
:text => { | |
content: item, | |
link: nil | |
} | |
} | |
], | |
:checked => false, | |
:color => "default" | |
} | |
} | |
end | |
req = Net::HTTP::Patch.new(notion_page_url.request_uri) | |
req['Accept'] = 'application/json' | |
req['Authorization'] = "Bearer #{NOTION_API_TOKEN}" | |
req['Content-Type'] = 'application/json' | |
req['Notion-Version'] = '2022-06-28' | |
content = { | |
:children => item_array | |
} | |
req.body = content.to_json | |
http.request(req) | |
end | |
page_id_and_titles = fetch_page_id_and_properties | |
unchecked_items = fetch_unchecked_item(page_id_and_titles) | |
items = unchecked_items.flatten.sort | |
puts items | |
clear_blocks NOTION_MEMO_PAGE_ID | |
add_blocks NOTION_MEMO_PAGE_ID, items |
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
# Copyright (c) 2022 Tomohiro Imaizumi All rights reserved. | |
require 'uri' | |
require 'net/http' | |
require "json" | |
require 'optparse' | |
# Secrets | |
YOUTUBE_API_KEY = ENV["YOUTUBE_API_KEY"] | |
NOTION_API_TOKEN = ENV["NOTION_API_TOKEN"] | |
# Properties | |
YOUTUBE_PLAYLIST_ID = ENV["YOUTUBE_PLAYLIST_ID"] | |
NOTION_DATABASE_ID = ENV["NOTION_DATABASE_ID"] | |
# Consts | |
NOTION_QUERY_API_BASE_URL = "https://api.notion.com/v1/databases/#{NOTION_DATABASE_ID}/query" | |
YOUTUBE_API_BASE_URL = "https://www.googleapis.com/youtube/v3/playlistItems" | |
NUMBER_OF_YOUTUBE_VIDEOS = 10 | |
def youtubeUrlsInPlaylist(max_results) | |
youtube_uri = URI(YOUTUBE_API_BASE_URL) | |
params = { | |
:key => YOUTUBE_API_KEY, | |
:part => "contentDetails,snippet", | |
:playlistId => YOUTUBE_PLAYLIST_ID, | |
:maxResults => max_results, | |
} | |
youtube_uri.query = URI.encode_www_form(params) | |
http = Net::HTTP.new(youtube_uri.hostname, youtube_uri.port) | |
http.use_ssl = true | |
req = Net::HTTP::Get.new(youtube_uri.request_uri) | |
req['Content-Type'] = 'application/json' | |
response = http.request(req) | |
obj = JSON.parse(response.body, symbolize_names: true) | |
res = obj[:items].map do |item| | |
[ | |
item[:contentDetails][:videoId], | |
{ | |
:description => item[:snippet][:description], | |
:title => item[:snippet][:title], | |
} | |
] | |
end | |
return res | |
end | |
def page_exists?(video_id) | |
notion_query_uri = URI(NOTION_QUERY_API_BASE_URL) | |
http = Net::HTTP.new(notion_query_uri.hostname, notion_query_uri.port) | |
http.use_ssl = true | |
req = Net::HTTP::Post.new(notion_query_uri.request_uri) | |
req['Accept'] = 'application/json' | |
req['Authorization'] = "Bearer #{NOTION_API_TOKEN}" | |
req['Content-Type'] = 'application/json' | |
req['Notion-Version'] = '2022-06-28' | |
filter = { | |
:filter => { | |
:property => "URL", | |
:rich_text => { | |
:contains => video_id | |
} | |
} | |
} | |
req.body = filter.to_json | |
response = http.request(req) | |
obj = JSON.parse(response.body, symbolize_names: true) | |
return (obj[:results].count || 0) > 0 | |
end | |
def create_page(videoId, title, description) | |
notion_page_url = URI("https://api.notion.com/v1/pages") | |
http = Net::HTTP.new(notion_page_url.hostname, notion_page_url.port) | |
http.use_ssl = true | |
req = Net::HTTP::Post.new(notion_page_url.request_uri) | |
req['Accept'] = 'application/json' | |
req['Authorization'] = "Bearer #{NOTION_API_TOKEN}" | |
req['Content-Type'] = 'application/json' | |
req['Notion-Version'] = '2022-06-28' | |
content = { | |
:parent => { | |
:database_id => NOTION_DATABASE_ID | |
}, | |
:icon => { | |
:type => "emoji", | |
:emoji => "🍳" | |
}, | |
:properties => { | |
:Name => { | |
:title => [ | |
{ | |
:type => "text", | |
:text => { | |
"content": title | |
} | |
} | |
] | |
}, | |
:URL => { | |
:type => "url", | |
:url => "https://youtu.be/#{videoId}" | |
} | |
}, | |
:children => [ | |
{ | |
:object => "block", | |
:type => "paragraph", | |
:paragraph => { | |
:rich_text => [ | |
{ | |
:type => "text", | |
:text => { | |
content: description | |
} | |
} | |
] | |
} | |
} | |
] | |
} | |
req.body = content.to_json | |
response = http.request(req) | |
obj = JSON.parse(response.body, symbolize_names: true) | |
end | |
OPTIONS = {} | |
OptionParser.new do |opts| | |
opts.on('-n [NUMBER_OF_VIDEOS]', 'Set number of videos to fetch.') do |n| | |
OPTIONS[:n] = n.to_i | |
end | |
end.parse! | |
youtubeUrlsInPlaylist(OPTIONS[:n] || NUMBER_OF_YOUTUBE_VIDEOS).each do |id| | |
videoId = id[0] | |
title = id[1][:title] | |
exists = page_exists?(videoId) | |
puts "#{videoId} #{exists ? %Q(exists) : %Q(does not exist so create new page)} in Notion" | |
puts "Title: #{title}\n" | |
next if exists | |
description = id[1][:description] | |
create_page(videoId, title, description) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment