|
3 | 3 |
|
4 | 4 | require "date" |
5 | 5 | require "fileutils" |
| 6 | +require_relative "../lib/publishers/publisher" |
| 7 | +require_relative "../lib/publishers/mastodon_publisher" |
| 8 | +require_relative "../lib/publishers/bluesky_publisher" |
| 9 | + |
| 10 | +PUBLISHERS = [ |
| 11 | + MastodonPublisher.new, |
| 12 | + BlueskyPublisher.new |
| 13 | +].freeze |
6 | 14 |
|
7 | 15 | def usage |
8 | 16 | puts <<~USAGE |
@@ -63,25 +71,144 @@ def cmd_new(args) |
63 | 71 | puts "Created new event post at #{filename}" |
64 | 72 | end |
65 | 73 |
|
66 | | -def cmd_publish(args) |
67 | | - puts "Staging changes..." |
68 | | - unless system("git add src/_posts/") |
69 | | - puts "Failed to add changes to git." |
70 | | - exit 1 |
| 74 | +def parse_front_matter(content) |
| 75 | + match = content.match(/\A---\n(.*?\n)---\n(.*)\z/m) |
| 76 | + return [{}, content] unless match |
| 77 | + fm = {} |
| 78 | + match[1].each_line do |line| |
| 79 | + if line =~ /\A(\w[\w_]*):\s*(.*)\s*\z/ |
| 80 | + key = $1 |
| 81 | + val = $2.strip |
| 82 | + val = val[1..-2] if val.start_with?('"') && val.end_with?('"') |
| 83 | + fm[key] = val |
| 84 | + end |
71 | 85 | end |
| 86 | + [fm, match[2]] |
| 87 | +end |
72 | 88 |
|
73 | | - puts "Committing changes..." |
74 | | - unless system("git commit -m 'Add new event post'") |
75 | | - puts "No new changes to commit, or commit failed." |
| 89 | +def update_front_matter_field(content, key, value) |
| 90 | + if content =~ /^#{Regexp.escape(key)}:/ |
| 91 | + content.sub(/^#{Regexp.escape(key)}:.*$/, "#{key}: \"#{value}\"") |
| 92 | + else |
| 93 | + content.sub(/\A(---\n.*?)^(---\n)/m, "\\1#{key}: \"#{value}\"\n\\2") |
76 | 94 | end |
| 95 | +end |
| 96 | + |
| 97 | +def cmd_publish(args) |
| 98 | + require "readline" |
| 99 | + |
| 100 | + posts = Dir.glob("src/_posts/*.md").map do |path| |
| 101 | + content = File.read(path) |
| 102 | + fm, _ = parse_front_matter(content) |
| 103 | + { path: path, fm: fm, content: content } |
| 104 | + end |
| 105 | + |
| 106 | + posts.sort_by! { |p| p[:fm]["event_date"] || File.basename(p[:path]) }.reverse! |
77 | 107 |
|
78 | | - puts "Pushing to remote to trigger deployment..." |
79 | | - unless system("git push") |
80 | | - puts "Failed to push to remote." |
| 108 | + puts "Select an event to post about:" |
| 109 | + posts.each_with_index do |p, i| |
| 110 | + published = p[:fm]["mastodon_post_url"] ? "[Published]" : "[Unpublished]" |
| 111 | + puts " #{i + 1}) #{p[:fm]['event_date']} - #{p[:fm]['title']} #{published}" |
| 112 | + end |
| 113 | + print "Choice: " |
| 114 | + choice = $stdin.gets.strip.to_i |
| 115 | + if choice < 1 || choice > posts.length |
| 116 | + puts "Invalid choice." |
| 117 | + exit 1 |
| 118 | + end |
| 119 | + |
| 120 | + selected = posts[choice - 1] |
| 121 | + |
| 122 | + title = selected[:fm]["title"] |
| 123 | + date = selected[:fm]["event_date"] |
| 124 | + basename = File.basename(selected[:path], ".md") |
| 125 | + if basename =~ /^(\d{4})-(\d{2})-(\d{2})-(.+)$/ |
| 126 | + website_url = "https://rubyaz.org/#{$1}/#{$2}/#{$3}/#{$4}/" |
| 127 | + else |
| 128 | + website_url = "https://rubyaz.org/" |
| 129 | + end |
| 130 | + |
| 131 | + puts "\nSelect post type:" |
| 132 | + puts " 1) Original (Announce the event)" |
| 133 | + puts " 2) Reminder (A few days before)" |
| 134 | + puts " 3) Post-Event (Thanks and recap)" |
| 135 | + print "Choice: " |
| 136 | + type_choice = $stdin.gets.strip |
| 137 | + |
| 138 | + case type_choice |
| 139 | + when "1" |
| 140 | + default_text = "Join us for #{title} on #{date}!\n\nRSVP & Details: #{website_url}\n\n#ruby #rubyaz" |
| 141 | + when "2" |
| 142 | + default_text = "Reminder! We're meeting for #{title} on #{date}.\n\nSee you there: #{website_url}\n\n#ruby #rubyaz" |
| 143 | + when "3" |
| 144 | + default_text = "Thanks to everyone who joined us for #{title}!\n\nCheck out the slides and recap: #{website_url}\n\n#ruby #rubyaz" |
| 145 | + else |
| 146 | + puts "Invalid choice." |
81 | 147 | exit 1 |
82 | 148 | end |
83 | 149 |
|
84 | | - puts "Successfully published events!" |
| 150 | + # Replace escaped newlines so they render correctly in Readline |
| 151 | + default_text = default_text.gsub('\\n', "\n") |
| 152 | + |
| 153 | + puts "\nEdit your post text (press Enter to accept):" |
| 154 | + |
| 155 | + Readline.pre_input_hook = -> { |
| 156 | + Readline.insert_text(default_text) |
| 157 | + Readline.redisplay |
| 158 | + Readline.pre_input_hook = nil |
| 159 | + } |
| 160 | + |
| 161 | + final_text = Readline.readline("> ", false) |
| 162 | + |
| 163 | + puts "\nFinal Text:" |
| 164 | + puts "---" |
| 165 | + puts final_text |
| 166 | + puts "---" |
| 167 | + print "Publish this? (y/n): " |
| 168 | + unless $stdin.gets.strip.downcase == 'y' |
| 169 | + puts "Aborted." |
| 170 | + exit 0 |
| 171 | + end |
| 172 | + |
| 173 | + updates_made = false |
| 174 | + new_content = selected[:content] |
| 175 | + |
| 176 | + PUBLISHERS.each do |publisher| |
| 177 | + existing_url = selected[:fm][publisher.front_matter_key] |
| 178 | + reply_to = existing_url && !existing_url.empty? ? existing_url : nil |
| 179 | + |
| 180 | + if reply_to |
| 181 | + puts "Posting to #{publisher.name} as a reply to #{reply_to}..." |
| 182 | + else |
| 183 | + puts "Posting to #{publisher.name}..." |
| 184 | + end |
| 185 | + |
| 186 | + result = publisher.post(final_text, reply_to: reply_to) |
| 187 | + |
| 188 | + if result[:error] |
| 189 | + puts "FAILED" |
| 190 | + puts " #{result[:error]}" |
| 191 | + else |
| 192 | + puts "OK" |
| 193 | + puts " #{result[:url]}" |
| 194 | + unless reply_to |
| 195 | + new_content = update_front_matter_field(new_content, publisher.front_matter_key, result[:url]) |
| 196 | + updates_made = true |
| 197 | + end |
| 198 | + end |
| 199 | + end |
| 200 | + |
| 201 | + if updates_made |
| 202 | + File.write(selected[:path], new_content) |
| 203 | + puts "\nStaging changes..." |
| 204 | + system("git add src/_posts/") |
| 205 | + puts "Committing changes..." |
| 206 | + system("git commit -m 'Add social URLs to #{basename}'") |
| 207 | + puts "Pushing to remote to trigger deployment..." |
| 208 | + system("git push") |
| 209 | + end |
| 210 | + |
| 211 | + puts "Done!" |
85 | 212 | end |
86 | 213 |
|
87 | 214 | case ARGV[0] |
|
0 commit comments