#!/usr/bin/ruby # BB_POSTINDEX.RB makes a neat post collection index for Xenforo2 forum # posts. Write the post summary text followed by the post URL in # any (raw) text editor, with a single newline separating the summary # from the URL, but as many blank lines as you want separating each # post summary. Optionally, prefix the summary with specific commands # to force different output formatting: # - !extra categorizes the comment as an extra to be placed at # the end of the post collection for the day, # - !daystart specifies that the following posts should be placed # inside spoiler tags given by the specified day (see example). # - !dayend similarly signals the end of the spoiler tags. # # Example: So the text files I write to sort posts look like: # # !daystart Saturday, 15 February 2020 # # Oh, snap! Things just got real ((@UserName) post) # https://blahblahblah/page-12#post-3456789 # # !extra (@WinnerPoster) made an interesting comment # https://blahblahblah/page-13#post-4214133 # # !dayend # # Then running this script with formats the posts with hyperlinks # to the posts, @'s for the credited users, and puts everything # behind spoiler tags separating the days. Within each day, the # normal posts are formatted with bullet points and a sans serif # font for whimsy, and the extra posts appear in a separate section # "Informative takes and extras:" at the end of the spoiler. # For whimsy, use Arial san serif font for the main post list. LIST_FORMAT_FONT = "arial" # Use text macros to dictate the format of the post collection index. # !daystart begins a spoiler tag for a given day DAY_START = "!daystart" # !dayend ends the spoiler tag for a given day DAY_END = "!dayend" # !extra specifies that the post is an informative extra, to appear # separately in a list at the end EXTRA = "!extra" # A class to represent an INDEXEDPOST with a given summary, user, # and post hyperlink. Optionally, the post may be specified as # an 'extra', in which case no list-style bullet point and sans # serif formatting is applied. # # Example: # # Create a new indexed post and print it in default list format # post1 = IndexedPost.new("List post (@User post)", "@User", "www.blah#p-1") # puts post1 #=> [FONT=arial][URL='www.blah#p-1']○ List post ([/URL] # # @User[URL='www.blah#p-1'] post)[/URL][/FONT] # # # Create a new indexed post and print it in extra format # post2 = IndexedPost.new("@User's extra post", "@User", "www.blah", true) # puts post2 #=> @User[URL='www.blah']'s extra post[/URL] # # And in list form: # puts post2.list_format #=> [FONT=arial][URL='www.blah']○ [/URL] # #@User[URL='www.blah']'s extra post[/URL][/FONT] # class IndexedPost # Create a new indexed post with the given SUMMARY, USER and # POST_HYPERLINK. If EXTRA is true, formats the post as an # informative extra without any explicit list formatting. def initialize(summary, user, post_hyperlink, extra=false) @summary = summary @user = user @post_hyperlink = post_hyperlink @extra = extra end # Return a string representation for this post in extra format, # i.e. in the regular font with just the hyperlink and no # additional formatting. def extra_format() text = @summary.split(@user).map do |part| if (part.length > 0) "[URL='" + @post_hyperlink + "']" + part + "[/URL]" end end text.join(" " + @user + " ") end # Return a string representation for this post in list format, # i.e. in sans serif font with an ASCII bullet point prepended. # TODO: These methods are very similar. Refactor to get rid of the # code duplication at some point later? def list_format() text = ("○ " + @summary).split(@user).map do |part| if (part.length > 0) "[URL='" + @post_hyperlink + "']" + part + "[/URL]" end end "[FONT=" + LIST_FORMAT_FONT + "]" + text.join(" " + @user + " ") + "[/FONT]" end # Return the printable string representation for this indexed post. def to_s() if (@extra) self.extra_format else self.list_format end end end # Assume that the file full of posts is the first command line arg if (ARGV.length < 1) raise(ArgumentError, "No post file specified in command line args") else posts_file = File.open(ARGV.join("")) end # Read lines from the post collection file (ignoring blank lines), and # generate the index structure. list_posts = [] extra_posts = [] day_active = false line = posts_file.gets.strip while (line) # Skip any preceding white space or blank lines line.strip! if (not line.empty?) case when line.start_with?(DAY_START) # Start the spoiler tag and refresh the post lists puts "[SPOILER=\"" + line.split(DAY_START)[1].strip! + "\"]" list_posts = [] extra_posts = [] day_active = true when line.start_with?(DAY_END) # Print all of the collected list posts list_posts.map { |post| puts post.list_format } # Print all of the collected extra posts in a separate section puts "\nInformative takes and extras:" extra_posts.map { |post| puts post.extra_format } # Finally, end the spoiler tag puts "[/SPOILER]" day_active = false else # If the line begins with !extra, it's an extra/informative post extra = line.start_with?(EXTRA) if (extra) line = line.split(EXTRA)[1].strip end # Parse the user name (assumed to be between a pair of parentheses # for simplicity) user_with_parens = line.scan(/\(@.+\)(?=['\s])/)[0].strip user = user_with_parens[1..-2] # And remove the extra parentheses in the formatted summary summary = line.gsub(user_with_parens, user) # Grab the next line too for the hyperlink post_hyperlink = posts_file.gets.strip # Instantiate a new post index and add it to the list. indexed_post = IndexedPost.new(summary, user, post_hyperlink, extra) if (extra) extra_posts << indexed_post else list_posts << indexed_post end end end # Read in the next line line = posts_file.gets end # Done reading! Close the collected posts file. posts_file.close() # Check: at the end here, if we still have collected posts for the day, # print them all now and close the spoiler tag. if (day_active) # TODO: Duplicate code from the case. Refactor? # Print all of the collected list posts list_posts.map { |post| puts post.list_format } # Print all of the collected extra posts in a separate section puts "\nInformative takes and extras:" extra_posts.map { |post| puts post.extra_format } # Finally, end the spoiler tag puts "[/SPOILER]" end