Last active
July 1, 2022 11:49
-
-
Save noniq/8f40a8dccc02ac4062b3530561bdd507 to your computer and use it in GitHub Desktop.
Convert the messages.json file from an exported Flowdock flow into a static HTML 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
#!/usr/bin/env ruby | |
# Convert an exported Flowdock flow into a static HTML document. | |
# | |
# Usage: | |
# | |
# flowdock-archive-to-html messages.json > messages.html | |
# | |
# The script assumes that there is a subdirectory `files` containing all files referenced in the exported flow. (This is exactly the | |
# directory structure you get if you unzip an archive downloaded from Flowdock.) | |
# | |
# Only flow events of the types “message”, “comment”, and “file” are handled and thus included in the output. To include | |
# other events like “user-edit” or “mail”, add the appropriate formatting code to the huge `case` statement at the end of | |
# this file. | |
require "bundler/inline" | |
require "erb" | |
require "json" | |
gemfile do | |
source "https://rubygems.org" | |
gem "redcarpet", "~> 2.3.0" | |
end | |
# Add “userid => username” mappings for all users you want to identify by name. Missing users will show up as “User 123456”. | |
@usernames = { | |
"0" => "Flowdock", | |
} | |
HTML_HEADER = <<~HTML.freeze | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<style type="text/css"> | |
html { | |
font-family: sans-serif; | |
font-size: 14px; | |
line-height: 1.5; | |
} | |
.message { | |
display: flex; | |
flex-direction: row; | |
margin: 0 0 1em; | |
padding: 0 0 1em; | |
border-bottom: 1px solid #f4f4f4; | |
} | |
.message p { | |
margin: 0; | |
overflow-wrap: break-word; | |
} | |
.message pre { | |
background: #eee; | |
padding: 0.5em 1em; | |
max-width: 100%; | |
overflow: scroll; | |
} | |
.message img { | |
max-width: 75%; | |
max-height: 50vh; | |
} | |
.message blockquote { | |
background: #f6f6f9; | |
padding: 0.5em 1em; | |
border-left: 3px solid #9898B0; | |
margin: 0 0 1em; | |
color: #2E2E75; | |
} | |
.date { | |
flex: 0 14em; | |
color: #999; | |
font-size: 80%; | |
text-align: right; | |
} | |
.user { | |
flex: 0 5em; | |
color: #999; | |
font-weight: bold; | |
text-align: right; | |
margin-right: 1em; | |
} | |
.content { | |
min-width: 0; /* To make `max-width: 100%` work in contained elements, see http://stackoverflow.com/a/31972181/566850 */ | |
flex: 1; | |
} | |
</style> | |
</head> | |
<body> | |
HTML | |
HTML_FOOTER = <<~HTML.freeze | |
</body> | |
</html> | |
HTML | |
@markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(escape_html: true, hard_wrap: true), autolink: true, no_intra_emphasis: true, space_after_headers: true) | |
def h(str) | |
ERB::Util.h(str) | |
end | |
def markdown(str) | |
@markdown.render(str.to_s) | |
end | |
def render_message(message, content) | |
date = Time.at(message['sent'] / 1000) | |
user = @usernames.fetch(message['user']) do | |
fallback_username = "User #{message['user']}" | |
$stderr.puts "WARNING: No username mapping for userid #{message['user']} - using '#{fallback_username}' instead." | |
@usernames[message['user']] = fallback_username | |
end | |
puts <<~HTML | |
<div class='message'> | |
<div class='user'>#{h user}</div> | |
<div class='content'>#{content}</div> | |
<div class='date'>#{date.strftime('%H:%M – %b. %d, %Y')}</div> | |
</div> | |
HTML | |
end | |
puts HTML_HEADER | |
JSON.parse(File.read("messages.json")).each do |message| | |
event = message["event"] | |
case event | |
when "message", "comment" | |
content = | |
if event == "comment" | |
message['content']['title'].gsub(/^/, '> \1') + "\n\n" + message['content']['text'] | |
else | |
message['content'] | |
end | |
render_message(message, markdown(content)) | |
when "file" | |
path = "files/" + message["content"]["path"].gsub(%r{\A/files/\d+/}, "").tr("/", "_") | |
link_text = | |
if message["content"].key?("image") | |
"<img src='#{path}'>" | |
else | |
h(message["content"]["file_name"]) | |
end | |
render_message(message, "<a href='#{path}'>#{link_text}</a>") | |
when "action", "user-edit", "mail", "open-invitation-enable", "line", "status", "discussion", "activity" | |
# ignore | |
else | |
$stderr.puts "WARNING: Unknown event type in JSON data: `#{message['event']}`" | |
$stderr.puts message.inspect + "\n\n" | |
end | |
end | |
puts HTML_FOOTER |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment