Skip to content

Instantly share code, notes, and snippets.

@tsub
Last active July 2, 2019 13:12
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 tsub/0aa7eecf53dac0abf3ab0855273c531d to your computer and use it in GitHub Desktop.
Save tsub/0aa7eecf53dac0abf3ab0855273c531d to your computer and use it in GitHub Desktop.
esa の記事のカテゴリを整理するための雑スクリプト群
ESA_ACCESS_TOKEN=
ESA_TEAM=
.env
Gemfile.lock
author_mappings.json
author_mappings_modified.json
vendor/bundle

esa の記事のカテゴリを整理するための雑スクリプト群。

一回切りの整理用で記事タイトルのフォーマットがバラバラ過ぎてトライアンドエラーでやるため、かなり雑に作っている。

各スクリプト説明

  • daily_report.rb
    • 「日報」記事のカテゴリを整理するためのスクリプト
  • daily_report_for_no_title.rb
    • 「日報」記事のカテゴリを整理するためのスクリプト。タイトルがない記事用
    • author_mappings_modified.json を参照して、記事内の Created by: に書かれた Qiita:Team のユーザー名を元にタイトルに入れる名前を決定する
  • daily_report_for_no_year.rb
    • 「日報」記事のカテゴリを整理するためのスクリプト。「年」がない記事用
    • 記事内の Original created at: に書かれた Qiita:Team に記事を作成した日付を元にタイトルに入れる日付を決定する
    • author_mappings_modified.json を参照して、記事内の Created by: に書かれた Qiita:Team のユーザー名を元にタイトルに入れる名前を決定する
  • daily_report_for_multiple_days.rb
    • 「日報」記事のカテゴリを整理するためのスクリプト。複数の日付についての記事用
    • author_mappings_modified.json を参照して、記事内の Created by: に書かれた Qiita:Team のユーザー名を元にタイトルに入れる名前を決定する
  • create_author_mappings.rb
    • Qiita:Team のユーザー名とタイトルに入れたい名前のマッピング表を作るためのスクリプト
    • author_mappings.json が生成されるので、それをコピーして author_mappings_modified.json を作り、値の部分を手動で編集して他のスクリプトから使う
    • 手動編集を楽にするため、esa にユーザーが存在する場合は esa のユーザー名をデフォルト値として入れている
# frozen_string_literal: true
require 'bundler/setup'
require 'esa'
require 'json'
require 'time'
search_query = 'in:"(unsorted)/all" title:日報'
daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})&#47;(?<month>[0-9]+)&#47;(?<day>[0-9]+)[\s ]*([((].+[))])*[\s ]*日報([\s ][(()]\d+[))])*\Z}
created_by_regexp = /Created by: (?<author>.+)\n/
client = Esa::Client.new(access_token: ENV.fetch('ESA_ACCESS_TOKEN'), current_team: ENV.fetch('ESA_TEAM'))
author_mappings = {}
page = 1
loop do
posts_response = client.posts(q: search_query, page: page, per_page: 100)
posts_response.body['posts'].each do |post|
full_name = post['full_name']
matches = daily_report_regexp.match(full_name)&.named_captures
next unless matches
body_matches = created_by_regexp.match(post['body_md'])&.named_captures
next unless body_matches
key = body_matches['author']
value = post['created_by']['name'] == 'esa_bot' ? nil : post['created_by']['name']
author_mappings.merge!(key => value)
end
page = posts_response.body['next_page']
puts "page: #{page}"
break if page.nil?
break if page > 100 # 10000 アイテム以上はページネーションで取得できないため
end
File.open('author_mappings.json', 'w') do |f|
f.write(JSON.pretty_generate(author_mappings))
end
# frozen_string_literal: true
require 'bundler/setup'
require 'esa'
require 'time'
# pattern 1: "日報" が名前より先
search_query = 'in:"(unsorted)/all" title:日報'
daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})(&#47;|-)(?<month>[0-9]+)(&#47;|-)(?<day>[0-9]+)[\s ]*([((].+[))])*[\s ]*日報[\s ]*(?<name>.+)}
# pattern 2: "日報" が名前より先で (1) などの数字入り
# search_query = 'in:"(unsorted)/all" title:日報 title:"(1)"'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})&#47;(?<month>[0-9]+)&#47;(?<day>[0-9]+)[\s ]*([((].+[))])*[\s ]*日報[\s ]*(?<name>.+)[\s ]([(()]\d+[))])*\Z}
# pattern 3: 週報
# search_query = 'in:"(unsorted)/all" title:週報'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})(&#47;|-)(?<month>[0-9]+)(&#47;|-)(?<day>[0-9]+)[\s ]*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)*[\s ](?<name>(ほぼ|隔)*週報.+)}
# pattern 4: 週報その2
# search_query = 'in:"(unsorted)/all" title:週報'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})(&#47;|-)(?<month>[0-9]+)(&#47;|-)(?<day>[0-9]+)(?<name>(ほぼ|隔)*週報.+)}
# 特殊フォーマットその1
# search_query = 'in:"(unsorted)/all" title:"日報 201"'
# daily_report_regexp = %r{\A\(unsorted\)/all/日報[\s ](?<year>[0-9]{4})&#47;(?<month>[0-9]+)&#47;(?<day>[0-9]+)[\s ]*([((].+[))])[\s ]*-[\s ]*(?<name>.+)}
# 特殊フォーマットその2
# search_query = 'in:"(unsorted)/all" title:"日報 201"'
# daily_report_regexp = %r{\A\(unsorted\)/all/日報[\s ](?<year>[0-9]{4})&#47;(?<month>[0-9]+)&#47;(?<day>[0-9]+)[\s ]*([((].+[))])[\s ]*(?<name>.+)}
# 特殊フォーマットその3
# search_query = 'in:"(unsorted)/all" title:"日報 201"'
# daily_report_regexp = %r{\A\(unsorted\)/all/日報[\s ](?<year>[0-9]{4})(&#47;|\s| )(?<month>[0-9]+)(&#47;|\s| )(?<day>[0-9]+)[\s ](?<name>.+)}
# 特殊フォーマットその4
# search_query = 'in:"(unsorted)/all" title:"日報 201"'
# daily_report_regexp = %r{\A\(unsorted\)/all/日報[\s ](?<year>[0-9]{4})(?<month>[0-9]{2})(?<day>[0-9]{2})[\s ](?<name>.+)}
# 特殊フォーマットその5
# search_query = 'in:"(unsorted)/all" title:日報'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})&#47;(?<month>[0-9]{2})&#47;(?<day>[0-9]{2})([((].+[))])[\s ](?<name>.+)[\s ]日報(?<additional_title>[\s ].+)*}
# 特殊フォーマットその6
# search_query = 'in:"(unsorted)/all" title:日報'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})&#47;(?<month>[0-9]{2})&#47;(?<day>[0-9]{2})[\s ](Mon|Tue|Wed|Thu|Fri|Sat|Sun)[\s ]日報[\s ](?<name>.+)}
# 特殊フォーマットその7
# search_query = 'in:"(unsorted)/all" title:"\'s 日報"'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})&#47;(?<month>[0-9]{2})&#47;(?<day>[0-9]{2})[\s ](?<name>.+)}
# 特殊フォーマットその8
# search_query = 'in:"(unsorted)/all" title:日報'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})&#47;(?<month>[0-9]{2})&#47;(?<day>[0-9]{2})[\s ](?<name>.+)[\s ]日報\Z}
# 特殊フォーマットその9
# search_query = 'in:"(unsorted)/all" title:日報'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})&#47;(?<month>[0-9]{2})&#47;(?<day>[0-9]{2})[\s ]*[<<][\s ]*日報[\s ]*[>>][\s ]*(?<name>.+)}
# 後から修正用
# search_query = 'in:"(unsorted)/日報" title:"(1)"'
# daily_report_regexp = %r{\A\(unsorted\)/日報/(?<year>[0-9]{4})/(?<month>[0-9]+)/(?<day>[0-9]+)(\s\(.\))/(?<name>.+)[\s ]([(()]\d+[))])*\Z}
client = Esa::Client.new(access_token: ENV.fetch('ESA_ACCESS_TOKEN'), current_team: ENV.fetch('ESA_TEAM'))
update_posts = []
page = 1
loop do
posts_response = client.posts(q: search_query, page: page, per_page: 100)
posts_response.body['posts'].each do |post|
number = post['number']
full_name = post['full_name']
matches = daily_report_regexp.match(full_name)&.named_captures
next unless matches
begin
date = Date.parse("#{matches['year']}/#{matches['month']}/#{matches['day']}")
rescue ArgumentError
puts matches
next
end
wday = %w[日 月 火 水 木 金 土][date.wday]
renamed_category = "(unsorted)/日報/#{date.strftime('%Y/%2m/%2d')} (#{wday})"
name = matches['additional_title'] ? "#{matches['name']}#{matches['additional_title']}" : matches['name']
update_post = { number: number, name: name, category: renamed_category }
puts "before: '#{full_name}', after: '#{update_post[:category]}/#{update_post[:name]}'"
update_posts << update_post
end
page = posts_response.body['next_page']
puts "page: #{page}"
break if page.nil?
break if page > 100 # 10000 アイテム以上はページネーションで取得できないため
end
puts "update_posts: #{update_posts.count}"
if ARGV[0] == 'run'
update_posts.each do |update_post|
client.update_post(update_post[:number], name: update_post[:name], category: update_post[:category])
end
end
# frozen_string_literal: true
require 'bundler/setup'
require 'esa'
require 'json'
require 'time'
# pattern 1
search_query = 'in:"(unsorted)/all" title:日報'
daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})&#47;(?<month>[0-9]{1,2})&#47;(?<multiple_days>[0-9]{1,2}[\,、\-~〜~・ &&++]+[0-9]{1,2})[\s ]*日報[\s ](?<name>.+)}
# pattern 2
# search_query = 'in:"(unsorted)/all" title:日報'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})&#47;(?<month>[0-9]+)&#47;(?<multiple_days>[0-9]+[\,、\-~〜][0-9]+)[\s ]([((].+[))])[\s ]日報(?<name>[\s ].+)*}
# pattern 3: 週報
# search_query = 'in:"(unsorted)/all" title:週報'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})(&#47;|-)(?<month>[0-9]+)(&#47;|-)(?<multiple_days>[0-9]{1,2}[\,、\-~〜~・ &&++]+[0-9]{1,2})[\s ]*(?<name>週報.+)}
created_by_regexp = /Created by: (?<author>.+)\n/
created_at_regexp = /Original created at: (?<created_at>.+)\n/
author_mappings = {}
File.open('author_mappings_modified.json') do |f|
author_mappings = JSON.parse(f.read)
end
client = Esa::Client.new(access_token: ENV.fetch('ESA_ACCESS_TOKEN'), current_team: ENV.fetch('ESA_TEAM'))
update_posts = []
page = 1
loop do
posts_response = client.posts(q: search_query, page: page, per_page: 100)
posts_response.body['posts'].each do |post|
number = post['number']
full_name = post['full_name']
matches = daily_report_regexp.match(full_name)&.named_captures
next unless matches
created_at_matches = created_at_regexp.match(post['body_md'])&.named_captures
next unless created_at_matches
created_at = Time.parse(created_at_matches['created_at'])
wday = %w[日 月 火 水 木 金 土][created_at.wday]
renamed_category = "(unsorted)/日報/#{created_at.strftime('%Y/%2m/%2d')} (#{wday})"
body_matches = created_by_regexp.match(post['body_md'])&.named_captures
next unless body_matches
qiita_team_author = body_matches['author'].delete("\r")
name = matches['name'] || author_mappings[qiita_team_author]
if name.nil?
p "unmapped name: '#{qiita_team_author}'"
next
end
update_post = { number: number, name: "#{matches['month']}&#47;#{matches['multiple_days']} #{name}", category: renamed_category }
puts "before: '#{full_name}', after: '#{update_post[:category]}/#{update_post[:name]}'"
update_posts << update_post
end
page = posts_response.body['next_page']
puts "page: #{page}"
break if page.nil?
break if page > 100 # 10000 アイテム以上はページネーションで取得できないため
end
puts "update_posts: #{update_posts.count}"
if ARGV[0] == 'run'
update_posts.each do |update_post|
client.update_post(update_post[:number], name: update_post[:name], category: update_post[:category])
end
end
# frozen_string_literal: true
require 'bundler/setup'
require 'esa'
require 'json'
require 'time'
# pattern 1: タイトルなし
search_query = 'in:"(unsorted)/all" title:日報'
daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})(&#47;|-)(?<month>[0-9]+)(&#47;|-)(?<day>[0-9]+)[\s ]*([((].+[))])*[\s ]*日報([\s ][(()]\d+[))])*\Z}
# pattern 2: (1) などの数字のみ
# search_query = 'in:"(unsorted)/all" title:日報 title:"(1)"'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})&#47;(?<month>[0-9]+)&#47;(?<day>[0-9]+)[\s ]*([((].+[))])*[\s ]*日報([\s ][(()]\d+[))])*\Z}
# pattern 3: 週報
# search_query = 'in:"(unsorted)/all" title:週報'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<year>[0-9]{4})(&#47;|-)(?<month>[0-9]+)(&#47;|-)(?<day>[0-9]+)[\s ]*週報[\s ]*\Z}
# 特殊フォーマットその1
# search_query = 'in:"(unsorted)/all" title:"日報:"'
# daily_report_regexp = %r{\A\(unsorted\)/all/日報[::][\s ]*(?<year>[0-9]{4})&#47;(?<month>[0-9]+)&#47;(?<day>[0-9]+)}
# 特殊フォーマットその2
# search_query = 'in:"(unsorted)/all" title:"日報 201"'
# daily_report_regexp = %r{\A\(unsorted\)/all/日報[\s ::]+(?<year>[0-9]{4})&#47;(?<month>[0-9]+)&#47;(?<day>[0-9]+)[\s ]*([((].+[))])}
# 特殊フォーマットその3
# search_query = 'in:"(unsorted)/all" title:"日報 201"'
# daily_report_regexp = %r{\A\(unsorted\)/all/日報[\s ::]+(?<year>[0-9]{4})&#47;(?<month>[0-9]+)&#47;(?<day>[0-9]+)\Z}
# 後から修正用
# search_query = 'in:"(unsorted)/日報" title:"(1)"'
# daily_report_regexp = %r{\A\(unsorted\)/日報/(?<year>[0-9]{4})/(?<month>[0-9]+)/(?<day>[0-9]+)(\s\(.\))/([(()]\d+[))])*\Z}
created_by_regexp = /Created by: (?<author>.+)\n/
author_mappings = {}
File.open('author_mappings_modified.json') do |f|
author_mappings = JSON.parse(f.read)
end
client = Esa::Client.new(access_token: ENV.fetch('ESA_ACCESS_TOKEN'), current_team: ENV.fetch('ESA_TEAM'))
update_posts = []
page = 1
loop do
posts_response = client.posts(q: search_query, page: page, per_page: 100)
posts_response.body['posts'].each do |post|
number = post['number']
full_name = post['full_name']
matches = daily_report_regexp.match(full_name)&.named_captures
next unless matches
begin
date = Date.parse("#{matches['year']}/#{matches['month']}/#{matches['day']}")
rescue ArgumentError
puts matches
next
end
wday = %w[日 月 火 水 木 金 土][date.wday]
renamed_category = "(unsorted)/日報/#{date.strftime('%Y/%2m/%2d')} (#{wday})"
body_matches = created_by_regexp.match(post['body_md'])&.named_captures
next unless body_matches
qiita_team_author = body_matches['author'].delete("\r")
name = author_mappings[qiita_team_author]
if name.nil?
p "unmapped name: '#{qiita_team_author}'"
next
end
update_post = { number: number, name: name, category: renamed_category }
puts "before: '#{full_name}', after: '#{update_post[:category]}/#{update_post[:name]}'"
update_posts << update_post
end
page = posts_response.body['next_page']
puts "page: #{page}"
break if page.nil?
break if page > 100 # 10000 アイテム以上はページネーションで取得できないため
end
puts "update_posts: #{update_posts.count}"
if ARGV[0] == 'run'
update_posts.each do |update_post|
client.update_post(update_post[:number], name: update_post[:name], category: update_post[:category])
end
end
# frozen_string_literal: true
require 'bundler/setup'
require 'esa'
require 'json'
require 'time'
# pattern 1
search_query = 'in:"(unsorted)/all" title:日報'
daily_report_regexp = %r{\A\(unsorted\)/all/(?<month>[0-9]{1,2})&#47;(?<day>[0-9]{1,2})[\s ]日報[\s ](?<name>.+)}
# pattern 2: 週報
# search_query = 'in:"(unsorted)/all" title:週報'
# daily_report_regexp = %r{\A\(unsorted\)/all/(?<month>[0-9]{1,2})(&#47;|-)(?<day>[0-9]{1,2})[\s ]*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)*[\s ](?<name>(ほぼ)*週報.+)}
created_by_regexp = /Created by: (?<author>.+)\n/
created_at_regexp = /Original created at: (?<created_at>.+)\n/
author_mappings = {}
File.open('author_mappings_modified.json') do |f|
author_mappings = JSON.parse(f.read)
end
client = Esa::Client.new(access_token: ENV.fetch('ESA_ACCESS_TOKEN'), current_team: ENV.fetch('ESA_TEAM'))
update_posts = []
page = 1
loop do
posts_response = client.posts(q: search_query, page: page, per_page: 100)
posts_response.body['posts'].each do |post|
number = post['number']
full_name = post['full_name']
matches = daily_report_regexp.match(full_name)&.named_captures
next unless matches
created_at_matches = created_at_regexp.match(post['body_md'])&.named_captures
next unless created_at_matches
created_at = Time.parse(created_at_matches['created_at'])
wday = %w[日 月 火 水 木 金 土][created_at.wday]
renamed_category = "(unsorted)/日報/#{created_at.strftime('%Y/%2m/%2d')} (#{wday})"
body_matches = created_by_regexp.match(post['body_md'])&.named_captures
next unless body_matches
qiita_team_author = body_matches['author'].delete("\r")
name = matches['name'] || author_mappings[qiita_team_author]
if name.nil?
p "unmapped name: '#{qiita_team_author}'"
next
end
update_post = { number: number, name: name, category: renamed_category }
puts "before: '#{full_name}', after: '#{update_post[:category]}/#{update_post[:name]}'"
update_posts << update_post
end
page = posts_response.body['next_page']
puts "page: #{page}"
break if page.nil?
break if page > 100 # 10000 アイテム以上はページネーションで取得できないため
end
puts "update_posts: #{update_posts.count}"
if ARGV[0] == 'run'
update_posts.each do |update_post|
client.update_post(update_post[:number], name: update_post[:name], category: update_post[:category])
end
end
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem "esa", "~> 1.14"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment