Skip to content

Instantly share code, notes, and snippets.

@imaizume
Last active September 19, 2022 11:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imaizume/66cb946e5f8cf097bfba5f2d16b8bdbb to your computer and use it in GitHub Desktop.
Save imaizume/66cb946e5f8cf097bfba5f2d16b8bdbb to your computer and use it in GitHub Desktop.
A simple workflow to save YouTube video to Notion page.
# 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
# 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