Full Code of bkettle/message-book for AI

main aa887728f38f cached
17 files
36.5 KB
12.2k tokens
10 symbols
1 requests
Download .txt
Repository: bkettle/message-book
Branch: main
Commit: aa887728f38f
Files: 17
Total size: 36.5 KB

Directory structure:
gitextract__yn_izhl/

├── .gitignore
├── Cargo.toml
├── README.md
├── example-output/
│   ├── Makefile
│   ├── ch-2023-10.tex
│   └── main.tex
├── src/
│   ├── main.rs
│   └── render.rs
├── templates/
│   ├── Makefile
│   ├── main.tex.template
│   └── {yyyy}-{mm}.tex.template
└── tex/
    ├── .gitignore
    ├── 2020-07.tex
    ├── main.dvi
    ├── main.fls
    ├── main.tex
    └── main.toc

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/target
/output


================================================
FILE: Cargo.toml
================================================
[package]
name = "message-book"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0.79"
chrono = "0.4.32"
clap = { version = "4.4.18", features = ["derive", "string"] }
imessage-database = "1.8.0"
regex = "1.10.3"
rusqlite = { version = "0.30.0", features = ["array"] }


================================================
FILE: README.md
================================================
# message-book

This is a tool to make a book out of a given iMessage conversation. To use it, you need either
an iPhone backup or a Mac that holds all the messages you want included. To use the tool, clone the repo and run: 

```
cargo run -- --help
```

The code is in pretty rough shape, but it should do the job. Let me know if you run into any issues.

An example of the output can be seen in the [example-output](example-output) directory.


![an example page, showing an automated reservation confirmation message on a blank page](example-output/reservation-page.png)

![an example table of contents for a book containing a whole year of text messages. Each month is listed with its page.](example-output/long-toc.png)

================================================
FILE: example-output/Makefile
================================================
main.pdf: main.tex $(wildcard ch-*.tex)
	latexmk -xelatex main.tex

================================================
FILE: example-output/ch-2023-10.tex
================================================
\chapter{October 2023}

\markright{October  6, 2023}
\rightmsg{Shizen: You have a reservation at 5:30 pm 10/07. Reply 1 to confirm; reply 4 to cancel. Reply STOP to end msgs}

\markright{October  6, 2023}
\leftmsg{1}

\markright{October  6, 2023}
\rightmsg{Shizen: Your reservation has been confirmed.}



================================================
FILE: example-output/main.tex
================================================
%!TEX TS-program = xelatex
%!TEX encoding = UTF-8 Unicode
% ^ we require xelatex for emoji support

\documentclass[9pt,postvopaper]{memoir}
\setlrmarginsandblock{0.75in}{0.5in}{*}
\setulmarginsandblock{0.75in}{0.75in}{*}
\checkandfixthelayout
\usepackage{palatino}
\usepackage[T1]{fontenc}
\usepackage{fontspec}
\usepackage{microtype}

% % set up font to support emojis - requires xetex
\usepackage[T1]{fontenc}
\usepackage[Latin,Greek,Emoticons]{ucharclasses}
\usepackage{fontspec}
 
\newfontfamily\emojifont{Noto Emoji}
% \setDefaultTransitions{\mydef}{}
% \newfontfamily\mynormal{Noto Sans}
% \setTransitionsForLatin{\mynormal}{}

\aliaspagestyle{title}{empty}




\author{}
\title{iMessage Book}
\date{}

\newcommand{\rightmsg}[1]{
\noindent\hfill%
\begin{minipage}{0.8\textwidth}
  \begin{flushright}
    #1
  \end{flushright}
\end{minipage}
\vspace{1mm}
}

\newcommand{\leftmsg}[1]{
\noindent\begin{minipage}{0.8\textwidth}
  #1
\end{minipage}
\vspace{1mm}
}


%%% BEGIN DOCUMENT

\begin{document}

\frontmatter

\begin{titlingpage}
\maketitle
\clearpage
\begin{flushleft}
\null\vfill
\textit{THE NAOMBEN CHRONICLES: VOLUME I}
\bigskip





ALL RIGHTS RESERVED
\end{flushleft}
\end{titlingpage}

\movetooddpage
\begin{vplace}
\begin{center}
  \textit{Dedicated to you.}
\end{center}
\end{vplace}

\movetooddpage
\tableofcontents 

\cleartorecto
\mainmatter

\openany
\chapterstyle{dash}
\addtolength\afterchapskip{2cm}

% template must be finished with \includes and \end{document}
\include{ch-2023-10}
\end{document}

================================================
FILE: src/main.rs
================================================
use std::{path::{PathBuf, Path}, fs::{File, create_dir_all, copy}, io::{Read, Write}, rc::Rc};

use clap::Parser;
use imessage_database::{tables::{table::{get_connection, Table, DEFAULT_PATH_IOS, MESSAGE_ATTACHMENT_JOIN, MESSAGE, RECENTLY_DELETED, CHAT_MESSAGE_JOIN, DEFAULT_PATH_MACOS}, messages::Message, chat::Chat}, error::table::TableError, util::dates::get_offset};
use anyhow::Result;
use render::render_message;
use rusqlite::types::Value;

mod render;

const TEMPLATE_DIR: &str = "templates";

// default ios sms.db path is <backup-path>/3d/3d0d7e5fb2ce288813306e4d4636395e047a3d2

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Args {
    /// Phone number of the conversation to export, of the form '+15555555555'
    recipient: String,
    /// Where to find the iMessage database. If not provided, assumes it is in the default Mac location
    #[clap(flatten)]
    database_location: BackupPath,
    /// The directory to create the .tex files in
    #[arg(short, long, default_value = "output")]
    output_dir: PathBuf,
}

impl Args {
    fn get_db_location(&self) -> PathBuf {
        match &self.database_location {
            BackupPath { ios_backup_dir: Some(ios_dir), chat_database: None } => {
                let mut path = ios_dir.clone();
                path.push(DEFAULT_PATH_IOS);
                path
            },
            BackupPath { ios_backup_dir: None, chat_database: Some(db_path) } => db_path.to_owned(),
            BackupPath { ios_backup_dir: None, chat_database: None } => DEFAULT_PATH_MACOS.into(),
            _ => panic!("too many arguments for database location")
        }
    }
}

#[derive(Debug, clap::Args)]
#[group(required = false, multiple = false)]
struct BackupPath {
    /// Path to the root of an iOS backup folder
    #[arg(short, long)]
    ios_backup_dir: Option<PathBuf>,
    /// Path to the chat database directly. If neither `ios_backup_dir` or `chat_database` is provided, the location will be assumed to be the default MacOS location.
    #[arg(short, long)]
    chat_database: Option<PathBuf>,
}


fn iter_messages(db_path: &PathBuf, chat_identifier: &str, output_dir: &PathBuf) -> Result<(), TableError> {
    let db = get_connection(db_path).unwrap();

    let mut chat_stmt = Chat::get(&db)?;
    let chats: Vec<Chat> = chat_stmt
        .query_map([], |row| Chat::from_row(row))
        .unwrap()
        .filter_map(|c| c.ok())
        .filter(|c| c.chat_identifier == chat_identifier)
        .collect(); // we collect these into a vec since there should only be a couple, we don't need to stream them
    
    let chat_ids: Vec<i32> = chats.iter().map(|c| c.rowid).collect();

    // let mut msg_stmt = Message::get(&db)?;
    // using rarray as in the example at https://docs.rs/rusqlite/0.29.0/rusqlite/vtab/array/index.html to check if chat is ok
    // SQL almost entirely taken from imessage-database Message::get, with added filtering
    rusqlite::vtab::array::load_module(&db).expect("failed to load module");
    let mut msg_stmt = db.prepare(&format!(
        "SELECT
                 *,
                 c.chat_id,
                 (SELECT COUNT(*) FROM {MESSAGE_ATTACHMENT_JOIN} a WHERE m.ROWID = a.message_id) as num_attachments,
                 (SELECT b.chat_id FROM {RECENTLY_DELETED} b WHERE m.ROWID = b.message_id) as deleted_from,
                 (SELECT COUNT(*) FROM {MESSAGE} m2 WHERE m2.thread_originator_guid = m.guid) as num_replies
             FROM
                 message as m
                 LEFT JOIN {CHAT_MESSAGE_JOIN} as c ON m.ROWID = c.message_id
             WHERE
                 c.chat_id IN rarray(?1)
             ORDER BY
                 m.date
             LIMIT
                 100000;
            "
        )).expect("unable to build messages query");

    // unfortunately I don't think there is an easy way to add a WHERE clause
    // to the statement generated by Message::get.
    // So instead I generated my own SQL statement, based on Message::get
    // and I need to pass in the valid chat ids
    let chat_id_values = Rc::new(chat_ids.iter().copied().map(Value::from).collect::<Vec<Value>>());
    let msgs = msg_stmt
        .query_map([chat_id_values], |row| Message::from_row(row))
        .unwrap()
        .filter_map(|m| m.ok());
        // .filter(|m| m.chat_id.is_some_and(|id| chat_ids.contains(&id))); // not needed with new sql filtering

    chats.iter().for_each(|c| println!("Found chat {:?}", c));

    // need to create output dir first, so we can create files inside it
    create_dir_all(output_dir).expect("Could not create output directory");

    let filtered_msgs = msgs
        .filter(|m| !m.is_reaction() && !m.is_announcement() && !m.is_shareplay());

    let mut chapters: Vec<String> = vec![]; // the names of the chapters created, like 2020-11
    let mut current_output_info: Option<(String, File)> = None; // chapter_name, File
    for mut msg in filtered_msgs {

        // this is a mess. Basically we are updating current_output_file to be correct for the current message.
        // Since the messages are in chronological order, marching through messages and updating this, creating
        // files as necessary, should work
        let msg_date = msg.date(&get_offset()).expect("could not find date for message");
        let chapter_name = msg_date
            .format("ch-%Y-%m")
            .to_string();
        let out_fname = format!("{}.tex", &chapter_name);
        let create = match &current_output_info {
            None => {true},
            Some((ref name, _)) => {name != &chapter_name},
        };
        if create {
            println!("Starting chapter {}", &chapter_name);
            let out_path = Path::join(output_dir, &out_fname);
            let mut f = File::create(&out_path)
                // .expect("failed to create output file")
                .unwrap_or_else(|e| panic!("Failed to create output file: {} - {:?}", &out_path.to_string_lossy(), e));
            f.write(format!("\\chapter{{{}}}\n\n", msg_date.format("%B %Y").to_string()).as_bytes()).expect("Could not write to chapter file");
            current_output_info = Some((chapter_name.clone(), f));
            chapters.push(chapter_name);
        }

        match msg.gen_text(&db) {
            Ok(_) => {
                // Successfully generated message, proceed with rendering and writing to output file
                let rendered = render_message(&msg);
                let mut output_file = &current_output_info.as_ref().expect("Current output info was none while processing message").1;
                output_file.write(rendered.as_bytes()).expect("Unable to write message to output file");
            }
            Err(err) => {
                // Handle the error gracefully, you can log it or ignore it depending on your requirements
                eprintln!("Failed to generate message: {:?}", err);
            }
        }
    }

    // Once we create all the chapter files, we need to create the main.tex file to include them 
    let mut main_template_file = File::open([TEMPLATE_DIR, "main.tex.template"].iter().collect::<PathBuf>()).expect("Could not open template file");
    let mut main_template = String::new();
    main_template_file.read_to_string(&mut main_template).expect("could not read template main.tex");
    let mut main_tex_file = File::create(Path::join(output_dir, "main.tex")).expect("could not create main.tex in output dir");
    main_tex_file.write_all(main_template.as_bytes()).expect("Could not write main.tex");

    // now add the chapters to the main file
    chapters.iter()
        .for_each(|chapter_name| {
            main_tex_file.write(
                format!("\\include{{{}}}\n", chapter_name).as_bytes()
            )
            .expect("failed to write main file");
        });

    // and finish it with \end{document}
    // TODO: we should really do this with a templating engine
    main_tex_file.write(r"\end{document}".as_bytes()).expect("unable to finish main.tex");

    // finally, copy over the makefile
    copy([TEMPLATE_DIR, "Makefile"].iter().collect::<PathBuf>(), Path::join(output_dir, "Makefile")).expect("Could not copy makefile");

    Ok(())
}

fn main() {
    let args = Args::parse();
    let db_path = args.get_db_location();
    iter_messages(&db_path, &args.recipient, &args.output_dir).expect("failed :(");



    println!("Hello!")
}


================================================
FILE: src/render.rs
================================================
use chrono::{DateTime, Local};
use imessage_database::{tables::messages::{Message, BubbleType}, util::dates::get_offset};
use regex::Regex;

/// Make necessary replacements so that the text is ready for insertion
/// into latex
fn latex_escape(text: String) -> String {
    // TODO: gotta be a more efficient way to do this
    let escaped = text 
        // first, a bunch of weird characters replaced with ascii
        .replace("’", "'")
        .replace("“", "\"")
        .replace("”", "\"")
        .replace("…", "...")
        // now, actual latex escapes
        .replace(r"\", r"\textbackslash\ ")
        .replace("$", r"\$")
        .replace("%", r"\%")
        .replace("&", r"\&")
        .replace("_", r"\_")
        .replace("^", r"\textasciicircum\ ")
        .replace("~", r"\textasciitilde\ ")
        .replace("#", r"\#")
        .replace(r"{", r"\{")
        .replace(r"}", r"\}")
        .replace("\n", "\\newline\n") // since a single newline in latex doesn't make a line break, need to add explicit newlines
        // this last one is the "variation selector" which I think determines whether an emoji
        // should be displayed big or inline. The latex font doesn't support it, so we just strip it out.
        // More info here: https://stackoverflow.com/questions/38100329/what-does-u-ufe0f-in-an-emoji-mean-is-it-the-same-if-i-delete-it
        .replace("\u{FE0F}", "");

    // Now, we wrap emojis in {\emojifont XX}. The latex template has a different font for emojis, and
    // this allows emojis to use that font
    // TODO: Somehow move this regex out so we only compile it once
    let emoji_regex = Regex::new(r"(\p{Extended_Pictographic}+)").expect("Couldn't compile demoji regex");
    let demojid = emoji_regex.replace_all(&escaped, "{\\emojifont $1}").into_owned();

    demojid

}

struct LatexMessage {
    is_from_me: bool,
    body_text: Option<String>,
    attachment_count: i32,
    date: DateTime<Local>,
}

impl LatexMessage {
    fn render(self) -> String {
        let mut content = match self.body_text {
            Some(ref text) => latex_escape(text.to_string()), // probably not ideal to be cloning here
            None => "".to_string(),
        };

        // add attachment labels
        if self.attachment_count > 0 {
            if content.len() > 0 {
                // add some padding if there was text in the message with the attachment
                content.push_str("\\enskip")
            }
            content.push_str(format!("\\fbox{{{} Attachment{}}}", self.attachment_count, if self.attachment_count == 1 {""} else {"s"}).as_ref());
        }

        let date_str = self.date.format("%B %e, %Y").to_string();

        let mut rendered = format!("\\markright{{{}}}\n", date_str);

        rendered.push_str(&match self.is_from_me {
            // god generating latex code is so annoying with the escapes
            true => format!("\\leftmsg{{{}}}\n\n", content),
            false => format!("\\rightmsg{{{}}}\n\n", content),
        });

        rendered
    }
}

pub fn render_message(msg: &Message) -> String {
    let parts = msg.body();


    let mut latex_msg = LatexMessage { 
        is_from_me: msg.is_from_me, 
        body_text: None, 
        attachment_count: 0,
        date: msg.date(&get_offset()).expect("could not find date for message")
    };

    for part in parts {
        match part {
            BubbleType::Text(text) => { latex_msg.body_text = Some(text.to_owned())},
            BubbleType::Attachment => { latex_msg.attachment_count += 1 }
            _ => ()
        }
    }

    latex_msg.render()
}

================================================
FILE: templates/Makefile
================================================
main.pdf: main.tex $(wildcard ch-*.tex)
	latexmk -xelatex main.tex

================================================
FILE: templates/main.tex.template
================================================
%!TEX TS-program = xelatex
%!TEX encoding = UTF-8 Unicode
% ^ we require xelatex for emoji support

\documentclass[9pt,postvopaper]{memoir}
\setlrmarginsandblock{0.75in}{0.5in}{*}
\setulmarginsandblock{0.75in}{0.75in}{*}
\checkandfixthelayout
\usepackage{palatino}
\usepackage[T1]{fontenc}
\usepackage{fontspec}
\usepackage{microtype}

% % set up font to support emojis - requires xetex
\usepackage[T1]{fontenc}
\usepackage[Latin,Greek,Emoticons]{ucharclasses}
\usepackage{fontspec}
 
\newfontfamily\emojifont{Noto Emoji}
% \setDefaultTransitions{\mydef}{}
% \newfontfamily\mynormal{Noto Sans}
% \setTransitionsForLatin{\mynormal}{}

\aliaspagestyle{title}{empty}




\author{}
\title{iMessage Book}
\date{}

\newcommand{\rightmsg}[1]{
\noindent\hfill%
\begin{minipage}{0.8\textwidth}
  \begin{flushright}
    #1
  \end{flushright}
\end{minipage}
\vspace{1mm}
}

\newcommand{\leftmsg}[1]{
\noindent\begin{minipage}{0.8\textwidth}
  #1
\end{minipage}
\vspace{1mm}
}


%%% BEGIN DOCUMENT

\begin{document}

\frontmatter

\begin{titlingpage}
\maketitle
\clearpage
\begin{flushleft}
\null\vfill
\textit{iMessage Book}
\bigskip





ALL RIGHTS RESERVED
\end{flushleft}
\end{titlingpage}

\movetooddpage
\begin{vplace}
\begin{center}
  \textit{Dedicated to you.}
\end{center}
\end{vplace}

\movetooddpage
\tableofcontents 

\cleartorecto
\mainmatter

\openany
\chapterstyle{dash}
\addtolength\afterchapskip{2cm}

% template must be finished with \includes and \end{document}


================================================
FILE: templates/{yyyy}-{mm}.tex.template
================================================
\chapter{July, 2020}

hey hey hey


================================================
FILE: tex/.gitignore
================================================
*.aux
*.log
*.pdf
*.xdv
*.fdb_latexmk


================================================
FILE: tex/2020-07.tex
================================================
\chapter{July, 2020}

hey hey hey

\newpage

\markright{Hello}
another page

\newpage

\markright{yo yoy yo}
and one more


================================================
FILE: tex/main.fls
================================================
PWD /home/ben/dev/message-book/tex
INPUT /usr/share/texmf-dist/web2c/texmf.cnf
INPUT /var/lib/texmf/web2c/xetex/xelatex.fmt
INPUT main.tex
OUTPUT main.log
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/memoir/memoir.cls
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/latex/memoir/mem9.clo
INPUT /usr/share/texmf-dist/tex/latex/memoir/mem9.clo
INPUT /usr/share/texmf-dist/tex/latex/memoir/mem9.clo
INPUT /usr/share/texmf-dist/tex/latex/memoir/mem9.clo
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/dcolumn.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/delarray.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/tabularx.sty
INPUT /usr/share/texmf-dist/tex/latex/tools/array.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/textcase/textcase.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/lm/t1lmr.fd
INPUT /usr/share/texmf-dist/tex/latex/lm/t1lmr.fd
INPUT /usr/share/texmf-dist/tex/latex/lm/t1lmr.fd
INPUT /usr/share/texmf-dist/tex/latex/lm/t1lmr.fd
INPUT /usr/share/texmf-dist/fonts/map/fontname/texfonts.map
INPUT /usr/share/texmf-dist/fonts/tfm/public/lm/ec-lmr9.tfm
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3kernel/expl3.sty
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/l3backend/l3backend-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec-xetex.sty
INPUT /usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
INPUT /usr/share/texmf-dist/tex/latex/base/tuenc.def
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.cfg
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.cfg
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.cfg
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/graphics/keyval.sty
INPUT /usr/share/texmf-dist/tex/latex/etoolbox/etoolbox.sty
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype-xetex.def
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/microtype.cfg
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/palatino.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/base/fontenc.sty
INPUT /usr/share/texmf-dist/tex/latex/psnfss/t1ppl.fd
INPUT /usr/share/texmf-dist/tex/latex/psnfss/t1ppl.fd
INPUT /usr/share/texmf-dist/tex/latex/psnfss/t1ppl.fd
INPUT /usr/share/texmf-dist/tex/latex/psnfss/t1ppl.fd
INPUT /usr/share/texmf-dist/fonts/tfm/adobe/palatino/pplr8t.tfm
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/xelatex/ucharclasses/ucharclasses.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/ifxetex.sty
INPUT /usr/share/texmf-dist/tex/generic/iftex/iftex.sty
INPUT /usr/share/texmf-dist/tex/latex/fontspec/fontspec.sty
INPUT ./main.aux
INPUT main.aux
INPUT main.aux
INPUT ./2020-07.aux
INPUT 2020-07.aux
INPUT 2020-07.aux
OUTPUT main.aux
INPUT /usr/share/texmf-dist/tex/latex/base/ts1cmr.fd
INPUT /usr/share/texmf-dist/tex/latex/base/ts1cmr.fd
INPUT /usr/share/texmf-dist/tex/latex/base/ts1cmr.fd
INPUT /usr/share/texmf-dist/tex/latex/base/ts1cmr.fd
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-ppl.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-ppl.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-ppl.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-ppl.cfg
INPUT /usr/share/texmf-dist/fonts/tfm/adobe/palatino/pplr8t.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/adobe/palatino/pplr8t.tfm
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-LatinModernRoman.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-LatinModernRoman.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-LatinModernRoman.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-LatinModernRoman.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-cmr.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-cmr.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-cmr.cfg
INPUT /usr/share/texmf-dist/tex/latex/microtype/mt-cmr.cfg
OUTPUT main.xdv
INPUT /usr/share/texmf-dist/fonts/tfm/adobe/palatino/pplri8t.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/adobe/palatino/pplro8t.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/adobe/palatino/pplr8t.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/adobe/palatino/pplb8t.tfm
INPUT ./main.toc
INPUT main.toc
INPUT main.toc
INPUT /usr/share/texmf-dist/fonts/tfm/adobe/palatino/pplb8t.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/public/cm/cmmi9.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/public/cm/cmmi6.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/public/cm/cmsy9.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/public/cm/cmsy6.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/public/cm/cmr9.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/public/cm/cmr6.tfm
INPUT ./2020-07.tex
INPUT ./2020-07.tex
INPUT ./2020-07.tex
OUTPUT 2020-07.aux
INPUT ./2020-07.tex
INPUT ./2020-07.tex
INPUT ./2020-07.tex
INPUT 2020-07.tex
INPUT ./2020-07.tex
INPUT 2020-07.tex
INPUT /usr/share/texmf-dist/fonts/tfm/adobe/palatino/pplr8t.tfm
INPUT /usr/share/texmf-dist/fonts/tfm/adobe/palatino/pplb8t.tfm
OUTPUT main.toc
INPUT main.aux
INPUT ./2020-07.aux
INPUT 2020-07.aux
INPUT 2020-07.aux


================================================
FILE: tex/main.tex
================================================
%!TEX TS-program = xelatex
%!TEX encoding = UTF-8 Unicode
% ^ we require xelatex for emoji support

\documentclass[9pt,mediumvopaper]{memoir}
\setlrmarginsandblock{2cm}{2cm}{*}
\setulmarginsandblock{2cm}{3cm}{*}
\checkandfixthelayout
% TODO: figure out formatting for actual printing
\setlrmarginsandblock{2cm}{2cm}{*}
\setulmarginsandblock{2cm}{3cm}{*}
\checkandfixthelayout
\usepackage[T1]{fontenc}
\usepackage{fontspec}
\usepackage{microtype}
\usepackage{palatino}

% % set up font to support emojis - requires xetex
\usepackage[T1]{fontenc}
\usepackage[Latin,Greek,Emoticons]{ucharclasses}
\usepackage{fontspec}
 
\newfontfamily\emojifont{Noto Emoji Medium}
% \setDefaultTransitions{\mydef}{}
% \newfontfamily\mynormal{Noto Sans}
% \setTransitionsForLatin{\mynormal}{}

\makepagestyle{messagebookstyle}
\makeevenhead{messagebookstyle}{\thepage}{}{\slshape\leftmark}
\makeoddhead{messagebookstyle}{\slshape\rightmark}{}{\thepage}

\pagestyle{messagebookstyle}



\author{Assembled by Ben Kettle}
\title{THE NAOMBEN CHRONICLES}
\date{}

\newcommand{\rightmsg}[1]{
\noindent\hfill%
\begin{minipage}{0.8\textwidth}
  \begin{flushright}
    #1
  \end{flushright}
\end{minipage}
\vspace{1mm}
}

\newcommand{\leftmsg}[1]{
\noindent\begin{minipage}{0.8\textwidth}
  #1
\end{minipage}
\vspace{1mm}
}


%%% BEGIN DOCUMENT

\begin{document}

\let\cleardoublepage\clearpage

\maketitle






\frontmatter

\null\vfill

\begin{flushleft}
\textit{NAME OF BOOK}
\bigskip





ALL RIGHTS RESERVED OR COPYRIGHT LICENSE LANGUAGE




\end{flushleft}

\newpage
\tableofcontents 

\let\cleardoublepage\clearpage

\mainmatter

% template must be finished with \includes and \end{document}

\leftmsg{Hey!}

\rightmsg{How's it going? {\emojifont 😡😡😡😡} }

{\emojifont
😀😃😄😁😆😅😂🤣🥲🥹 ☺️😊😇🙂🙃😉😌😍🥰😘😗😙 😚😋😛😝😜🤪🤨🧐🤓😎🥸 🤩🥳😏😒😞😔😟😕🙁☹️😣 😖😫😩🥺😢😭😮‍💨 😤😠😡🤬🤯😳🥵🥶😱😨 😰😥😓🫣🤗🫡🤔🫢🤭🤫 🤥😶😶‍🌫️😐😑😬🫨🫠🙄😯😦 😧😮😲🥱😴🤤😪😵😵‍💫🫥🤐🥴🤢🤮 🤧😷🤒🤕🤑🤠😈👿👹👺🤡💩👻 💀☠️👽👾🤖🎃😺😸 😹😻😼😽🙀😿😾}

\leftmsg{Oh, great! How about for you?}

\rightmsg{Swell}

\leftmsg{Awesome}

\leftmsg{Glad to hear it.}

\include{2020-07}

\end{document}


================================================
FILE: tex/main.toc
================================================
\contentsline {chapter}{Contents}{ii}{}%
\contentsline {chapter}{\chapternumberline {1}July, 2020}{3}{}%
Download .txt
gitextract__yn_izhl/

├── .gitignore
├── Cargo.toml
├── README.md
├── example-output/
│   ├── Makefile
│   ├── ch-2023-10.tex
│   └── main.tex
├── src/
│   ├── main.rs
│   └── render.rs
├── templates/
│   ├── Makefile
│   ├── main.tex.template
│   └── {yyyy}-{mm}.tex.template
└── tex/
    ├── .gitignore
    ├── 2020-07.tex
    ├── main.dvi
    ├── main.fls
    ├── main.tex
    └── main.toc
Download .txt
SYMBOL INDEX (10 symbols across 2 files)

FILE: src/main.rs
  constant TEMPLATE_DIR (line 11) | const TEMPLATE_DIR: &str = "templates";
  type Args (line 17) | struct Args {
    method get_db_location (line 29) | fn get_db_location(&self) -> PathBuf {
  type BackupPath (line 45) | struct BackupPath {
  function iter_messages (line 55) | fn iter_messages(db_path: &PathBuf, chat_identifier: &str, output_dir: &...
  function main (line 177) | fn main() {

FILE: src/render.rs
  function latex_escape (line 7) | fn latex_escape(text: String) -> String {
  type LatexMessage (line 42) | struct LatexMessage {
    method render (line 50) | fn render(self) -> String {
  function render_message (line 79) | pub fn render_message(msg: &Message) -> String {
Condensed preview — 17 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (40K chars).
[
  {
    "path": ".gitignore",
    "chars": 16,
    "preview": "/target\n/output\n"
  },
  {
    "path": "Cargo.toml",
    "chars": 381,
    "preview": "[package]\nname = \"message-book\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc"
  },
  {
    "path": "README.md",
    "chars": 725,
    "preview": "# message-book\n\nThis is a tool to make a book out of a given iMessage conversation. To use it, you need either\nan iPhone"
  },
  {
    "path": "example-output/Makefile",
    "chars": 66,
    "preview": "main.pdf: main.tex $(wildcard ch-*.tex)\n\tlatexmk -xelatex main.tex"
  },
  {
    "path": "example-output/ch-2023-10.tex",
    "chars": 304,
    "preview": "\\chapter{October 2023}\n\n\\markright{October  6, 2023}\n\\rightmsg{Shizen: You have a reservation at 5:30 pm 10/07. Reply 1 "
  },
  {
    "path": "example-output/main.tex",
    "chars": 1523,
    "preview": "%!TEX TS-program = xelatex\n%!TEX encoding = UTF-8 Unicode\n% ^ we require xelatex for emoji support\n\n\\documentclass[9pt,p"
  },
  {
    "path": "src/main.rs",
    "chars": 8423,
    "preview": "use std::{path::{PathBuf, Path}, fs::{File, create_dir_all, copy}, io::{Read, Write}, rc::Rc};\n\nuse clap::Parser;\nuse im"
  },
  {
    "path": "src/render.rs",
    "chars": 3614,
    "preview": "use chrono::{DateTime, Local};\nuse imessage_database::{tables::messages::{Message, BubbleType}, util::dates::get_offset}"
  },
  {
    "path": "templates/Makefile",
    "chars": 66,
    "preview": "main.pdf: main.tex $(wildcard ch-*.tex)\n\tlatexmk -xelatex main.tex"
  },
  {
    "path": "templates/main.tex.template",
    "chars": 1469,
    "preview": "%!TEX TS-program = xelatex\n%!TEX encoding = UTF-8 Unicode\n% ^ we require xelatex for emoji support\n\n\\documentclass[9pt,p"
  },
  {
    "path": "templates/{yyyy}-{mm}.tex.template",
    "chars": 34,
    "preview": "\\chapter{July, 2020}\n\nhey hey hey\n"
  },
  {
    "path": "tex/.gitignore",
    "chars": 38,
    "preview": "*.aux\n*.log\n*.pdf\n*.xdv\n*.fdb_latexmk\n"
  },
  {
    "path": "tex/2020-07.tex",
    "chars": 122,
    "preview": "\\chapter{July, 2020}\n\nhey hey hey\n\n\\newpage\n\n\\markright{Hello}\nanother page\n\n\\newpage\n\n\\markright{yo yoy yo}\nand one mor"
  },
  {
    "path": "tex/main.fls",
    "chars": 18488,
    "preview": "PWD /home/ben/dev/message-book/tex\nINPUT /usr/share/texmf-dist/web2c/texmf.cnf\nINPUT /var/lib/texmf/web2c/xetex/xelatex."
  },
  {
    "path": "tex/main.tex",
    "chars": 2035,
    "preview": "%!TEX TS-program = xelatex\n%!TEX encoding = UTF-8 Unicode\n% ^ we require xelatex for emoji support\n\n\\documentclass[9pt,m"
  },
  {
    "path": "tex/main.toc",
    "chars": 105,
    "preview": "\\contentsline {chapter}{Contents}{ii}{}%\n\\contentsline {chapter}{\\chapternumberline {1}July, 2020}{3}{}%\n"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the bkettle/message-book GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 17 files (36.5 KB), approximately 12.2k tokens, and a symbol index with 10 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!