Metadata-Version: 2.4
Name: tootsnoop
Version: 2026.3.1.2
Summary: Statisics of the last x days for your Mastodon messages
Author-email: Karl Voit <tools@Karl-Voit.at>
License-Expression: GPL-3.0-or-later
Project-URL: Homepage, https://gitlab.com/publicvoit/tootsnoop
Project-URL: Repository, https://gitlab.com/publicvoit/tootsnoop
Project-URL: Issues, https://gitlab.com/publicvoit/tootsnoop/-/issues
Keywords: mastodon,statistics,fediverse
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/plain
Requires-Dist: mastodon-py>=1.8.1
Requires-Dist: pytz>=2024.2
Requires-Dist: pudb>=2024.1.3
Requires-Dist: pypandoc>=1.15

* tootsnoop - You Mastodon message statistics tool

# #+BEGIN_SRC sh :results output :wrap src
# uv run ./tootsnoop/__init__.py --help
# #+END_SRC

: usage: tootsnoop [-h] --days DAYNUMBER --count COUNTNUMBER
:                                [--verbose]
: 
: This tool prints a brief statistics about your Mastodon messages of the latest DAYNUMBER days.
: 
: The output constist of:
: - timestamp (now)
: - number of toots retrieved
: - your current number of followers
: - top COUNTNUMBER most boosted messages (or less if no more found)
: - top COUNTNUMBER most favored messages (or less if no more found)
: - top COUNTNUMBER most replied messages (or less if no more found)
: 
: Example usages:
:   poetry run python3 PATH/TO/tootsnoop/__init__.py --days 7 --count 10
:       … prints the topmost 10 entries for the last 7 days
: 
: One-time setup:
: 
: 1. Configure you access token:
:    - Login to your Mastodon instance in your web browser.
:    - Go to Preference → Development and click on "New Application".
:    - Enter "tootsnoop" as the name of the new application and modify the scopes:
:      - You will need only read permissions, no write permissions.
:    - Submit and click on "tootsnoop".
:    - Copy your new Access Token.
:    - Paste this Access Token into a "access_token.txt" file in the main directory of this tool.
: 2. Configure your mastodon instance:
:    - Paste the main URL of your Mastodon instance into a "instance_url.txt" file in the main
:      directory of this tool.
:      - It looks like: "https://graz.social"
: 
: options:
:   -h, --help           show this help message and exit
:   --days DAYNUMBER     Number of days to look back
:   --count COUNTNUMBER  Number of topmost entries to show
:   --verbose            Enable verbose mode
: 
: :copyright: (c) by Karl Voit <tools@Karl-Voit.at>
: :license: GPL v3 or any later version
: :URL: https://gitlab.com/publicvoit/tootsnoop
: :bugreports: via https://gitlab.com/publicvoit/tootsnoop/-/issues
: :version: 2026-03-01
: ·
: 

Setup with [[https://docs.astral.sh/uv/][uv]]:

1. Install uv itself
2. Use =uv --project /path/to/tootsnoop run path/to/tootsnoop/__init__.py= command from above to run =tootsnoop=

Or:

Install via pip:

: pip install tootsnoop

... and start =tootsnoop -h=

* Example Output

: uv run tootsnoop/tootsnoop/__init__.py --days 7 --count 10

<2025-02-02 Sun 16:04> Summary of Mastodon Activity over the last 7 days:

- Toots retrieved: 40
- Current number of followers: 2936

*Top 10 Most Boosted Messages*

-  16 Boosts: [[https://graz.social/users/publicvoit/statuses/113929726001217896][<2025-02-01 Sat 17:07>]] This is golden: a non-tech guy is using [[https://graz.social/tags/Emacs][#Emacs]] and [[https://graz.social/tags/orgmode][#orgmode]] in his work life as well as at home: [[https://irreal.org/blog/?p=12755][https://irreal.org/blog/?p=12755]] • He amazes his colleagues with the usual Emacs foo other tools can not offer. • [[https://graz.social/tags/Fun][#Fun]] to read. 
-   7 Boosts: [[https://graz.social/users/publicvoit/statuses/113928326035465290][<2025-02-01 Sat 11:11>]] Informatik ist [[https://graz.social/tags/Allgemeinbildung][#Allgemeinbildung]] und sollte [[https://graz.social/tags/Pflichtfach][#Pflichtfach]] werden\\ [[https://www.derstandard.at/story/3000000254867/informatik-ist-allgemeinbildung-und-sollte-pflichtfach-werden?ref=shpost#posting-1133628571][https://www.derstandard.at/story/3000000254867/informatik-ist-allgemeinbildung-und-sollte-pflichtfach-werden?ref=shpost#posting-1133628571]] • [[https://graz.social/tags/Informatik][#Informatik]] ist nicht nur ein [[https://graz.social/tags/Schulfach][#Schulfach]]. • Informatik erklärt die Grundlagen unserer modernen Welt und macht Menschen zu mündigen Bürgern, die sich beispielsweise nicht von [[https://graz.social/tags/Algorithmen][#Algorithmen]] ausnutzen lassen (wollen). • Außerdem sorgt es dafür, dass wir in [[https://graz.social/tags/Europa][#Europa]] eine [[https://graz.social/tags/Zukunft][#Zukunft]] in dieser modernen Welt haben werden und nicht nur die passiven Datenlieferanten für außereuropäische Großkonzerne spielen, die uns damit massiv ausnutzen. • [[https://graz.social/tags/Schule][#Schule]] [[https://graz.social/tags/Bildung][#Bildung]] [[https://graz.social/tags/NAWI][#NAWI]] [[https://graz.social/tags/Naturwissenschaft][#Naturwissenschaft]] [[https://graz.social/tags/Zukunft][#Zukunft]] [[https://graz.social/tags/SozialeNetzwerke][#SozialeNetzwerke]] [[https://graz.social/tags/SozialeNetze][#SozialeNetze]] [[https://graz.social/tags/facebook][#facebook]] [[https://graz.social/tags/instagram][#instagram]] [[https://graz.social/tags/tiktok][#tiktok]] [[https://graz.social/tags/digitaleSouver%C3%A4nit%C3%A4t][#digitaleSouveränität]] 
-   1 Boosts: [[https://graz.social/users/publicvoit/statuses/113929755885888564][<2025-02-01 Sat 17:15>]] Marcin ‘mbork' Borkowski about his version of [[https://graz.social/tags/pomodoro][#pomodoro]] which he calls [[https://graz.social/tags/tomato][#tomato]]: [[https://mbork.pl/2025-02-01_ketchup.el][https://mbork.pl/2025-02-01_ketchup.el]] • Well, it sounds to me that the pomodoro method is not working for him for the same reasons it was not working for me - although I only tried for a brief period of time. • Marcin found some interesting variant. I would have declared this method non-functional for me instead. 😈 • [[https://graz.social/tags/PIM][#PIM]] [[https://graz.social/tags/timemanagement][#timemanagement]] [[https://graz.social/tags/productivity][#productivity]] [[https://graz.social/tags/pomodorotechnique][#pomodorotechnique]] [[https://graz.social/tags/Beeminder][#Beeminder]] 

*Top 10 Most Favored Messages*

-  23 Favorites: [[https://graz.social/users/publicvoit/statuses/113929726001217896][<2025-02-01 Sat 17:07>]] This is golden: a non-tech guy is using [[https://graz.social/tags/Emacs][#Emacs]] and [[https://graz.social/tags/orgmode][#orgmode]] in his work life as well as at home: [[https://irreal.org/blog/?p=12755][https://irreal.org/blog/?p=12755]] • He amazes his colleagues with the usual Emacs foo other tools can not offer. • [[https://graz.social/tags/Fun][#Fun]] to read. 
-   9 Favorites: [[https://graz.social/users/publicvoit/statuses/113928326035465290][<2025-02-01 Sat 11:11>]] Informatik ist [[https://graz.social/tags/Allgemeinbildung][#Allgemeinbildung]] und sollte [[https://graz.social/tags/Pflichtfach][#Pflichtfach]] werden\\ [[https://www.derstandard.at/story/3000000254867/informatik-ist-allgemeinbildung-und-sollte-pflichtfach-werden?ref=shpost#posting-1133628571][https://www.derstandard.at/story/3000000254867/informatik-ist-allgemeinbildung-und-sollte-pflichtfach-werden?ref=shpost#posting-1133628571]] • [[https://graz.social/tags/Informatik][#Informatik]] ist nicht nur ein [[https://graz.social/tags/Schulfach][#Schulfach]]. • Informatik erklärt die Grundlagen unserer modernen Welt und macht Menschen zu mündigen Bürgern, die sich beispielsweise nicht von [[https://graz.social/tags/Algorithmen][#Algorithmen]] ausnutzen lassen (wollen). • Außerdem sorgt es dafür, dass wir in [[https://graz.social/tags/Europa][#Europa]] eine [[https://graz.social/tags/Zukunft][#Zukunft]] in dieser modernen Welt haben werden und nicht nur die passiven Datenlieferanten für außereuropäische Großkonzerne spielen, die uns damit massiv ausnutzen. • [[https://graz.social/tags/Schule][#Schule]] [[https://graz.social/tags/Bildung][#Bildung]] [[https://graz.social/tags/NAWI][#NAWI]] [[https://graz.social/tags/Naturwissenschaft][#Naturwissenschaft]] [[https://graz.social/tags/Zukunft][#Zukunft]] [[https://graz.social/tags/SozialeNetzwerke][#SozialeNetzwerke]] [[https://graz.social/tags/SozialeNetze][#SozialeNetze]] [[https://graz.social/tags/facebook][#facebook]] [[https://graz.social/tags/instagram][#instagram]] [[https://graz.social/tags/tiktok][#tiktok]] [[https://graz.social/tags/digitaleSouver%C3%A4nit%C3%A4t][#digitaleSouveränität]] 
-   2 Favorites: [[https://graz.social/users/publicvoit/statuses/113929755885888564][<2025-02-01 Sat 17:15>]] Marcin ‘mbork' Borkowski about his version of [[https://graz.social/tags/pomodoro][#pomodoro]] which he calls [[https://graz.social/tags/tomato][#tomato]]: [[https://mbork.pl/2025-02-01_ketchup.el][https://mbork.pl/2025-02-01_ketchup.el]] • Well, it sounds to me that the pomodoro method is not working for him for the same reasons it was not working for me - although I only tried for a brief period of time. • Marcin found some interesting variant. I would have declared this method non-functional for me instead. 😈 • [[https://graz.social/tags/PIM][#PIM]] [[https://graz.social/tags/timemanagement][#timemanagement]] [[https://graz.social/tags/productivity][#productivity]] [[https://graz.social/tags/pomodorotechnique][#pomodorotechnique]] [[https://graz.social/tags/Beeminder][#Beeminder]] 
-   1 Favorites: [[https://graz.social/users/publicvoit/statuses/113923808732027509][<2025-01-31 Fri 16:02>]] [[https://graz.social/tags/Apple][#Apple]]-Besitzer sind schon ein seltsames Völkchen. • Offenbar ist es nicht möglich, ein Apple-Silicon-MacBook aufzuklappen ohne, dass es gestartet wird: [[https://www.heise.de/news/Fuer-Tastaturhygieniker-So-bleibt-das-MacBook-beim-Oeffnen-aus-10265728.html][https://www.heise.de/news/Fuer-Tastaturhygieniker-So-bleibt-das-MacBook-beim-Oeffnen-aus-10265728.html]] (von wegen Frickelsystem) • Wenn die wüssten, was ich alles bei meinem (Linux-lenovo-)Notebook alles anpassen darf ... 😈 

*Top 10 Most Replied Messages*

-   3 Replies: [[https://graz.social/users/publicvoit/statuses/113928326035465290][<2025-02-01 Sat 11:11>]] Informatik ist [[https://graz.social/tags/Allgemeinbildung][#Allgemeinbildung]] und sollte [[https://graz.social/tags/Pflichtfach][#Pflichtfach]] werden\\ [[https://www.derstandard.at/story/3000000254867/informatik-ist-allgemeinbildung-und-sollte-pflichtfach-werden?ref=shpost#posting-1133628571][https://www.derstandard.at/story/3000000254867/informatik-ist-allgemeinbildung-und-sollte-pflichtfach-werden?ref=shpost#posting-1133628571]] • [[https://graz.social/tags/Informatik][#Informatik]] ist nicht nur ein [[https://graz.social/tags/Schulfach][#Schulfach]]. • Informatik erklärt die Grundlagen unserer modernen Welt und macht Menschen zu mündigen Bürgern, die sich beispielsweise nicht von [[https://graz.social/tags/Algorithmen][#Algorithmen]] ausnutzen lassen (wollen). • Außerdem sorgt es dafür, dass wir in [[https://graz.social/tags/Europa][#Europa]] eine [[https://graz.social/tags/Zukunft][#Zukunft]] in dieser modernen Welt haben werden und nicht nur die passiven Datenlieferanten für außereuropäische Großkonzerne spielen, die uns damit massiv ausnutzen. • [[https://graz.social/tags/Schule][#Schule]] [[https://graz.social/tags/Bildung][#Bildung]] [[https://graz.social/tags/NAWI][#NAWI]] [[https://graz.social/tags/Naturwissenschaft][#Naturwissenschaft]] [[https://graz.social/tags/Zukunft][#Zukunft]] [[https://graz.social/tags/SozialeNetzwerke][#SozialeNetzwerke]] [[https://graz.social/tags/SozialeNetze][#SozialeNetze]] [[https://graz.social/tags/facebook][#facebook]] [[https://graz.social/tags/instagram][#instagram]] [[https://graz.social/tags/tiktok][#tiktok]] [[https://graz.social/tags/digitaleSouver%C3%A4nit%C3%A4t][#digitaleSouveränität]] 
-   1 Replies: [[https://graz.social/users/publicvoit/statuses/113929726001217896][<2025-02-01 Sat 17:07>]] This is golden: a non-tech guy is using [[https://graz.social/tags/Emacs][#Emacs]] and [[https://graz.social/tags/orgmode][#orgmode]] in his work life as well as at home: [[https://irreal.org/blog/?p=12755][https://irreal.org/blog/?p=12755]] • He amazes his colleagues with the usual Emacs foo other tools can not offer. • [[https://graz.social/tags/Fun][#Fun]] to read. 
-   1 Replies: [[https://graz.social/users/publicvoit/statuses/113923817200519535][<2025-01-31 Fri 16:04>]] [[https://bildung.social/@vermutliCHEmie][@vermutliCHEmie]] You would need to define the problem which is caused by that. I don't see any. • Furthermore: I don't use such tool-proprietary annotation workarounds. I annotate using my BOOX NoteAir which writes its annotations in the PDF directly - as PDF annotations. • YMMV. 
-   1 Replies: [[https://graz.social/users/publicvoit/statuses/113923808732027509][<2025-01-31 Fri 16:02>]] [[https://graz.social/tags/Apple][#Apple]]-Besitzer sind schon ein seltsames Völkchen. • Offenbar ist es nicht möglich, ein Apple-Silicon-MacBook aufzuklappen ohne, dass es gestartet wird: [[https://www.heise.de/news/Fuer-Tastaturhygieniker-So-bleibt-das-MacBook-beim-Oeffnen-aus-10265728.html][https://www.heise.de/news/Fuer-Tastaturhygieniker-So-bleibt-das-MacBook-beim-Oeffnen-aus-10265728.html]] (von wegen Frickelsystem) • Wenn die wüssten, was ich alles bei meinem (Linux-lenovo-)Notebook alles anpassen darf ... 😈 

* Optional: Convert Result to a Different Syntax
:PROPERTIES:
:CREATED:  [2025-02-04 Tue 16:42]
:END:

If you don't like [[https://gitlab.com/publicvoit/orgdown/][orgdown syntax]] as output, you might convert the script output on-the-fly via [[https://pandoc.org/][pandoc]].

Here is an example for [[https://karl-voit.at/2017/09/23/orgmode-as-markup-only/][the inferior Markdown syntax]] (in one flavour of many):

: uv --project /path/to/tootsnoop run /path/to/tootsnoop/__init__.py --days 1 --count 3 | pandoc --from org --to markdown --wrap=none

* Optional: Integration into Emacs Org-mode
:PROPERTIES:
:CREATED:  [2025-02-04 Tue 16:50]
:END:

In case you want to invoke tootsnoop from within [[https://karl-voit.at/orgmode/][Emacs Org-mode]], you can use a source block like that:

: #+BEGIN_SRC sh :results output raw
: cd /path/to/tootsnoop/
: uv --project /path/to/tootsnoop run /path/to/tootsnoop/tootsnoop/__init__.py --days 7 --count 10 --inactive
: #+END_SRC

If you've installed tootsnoop via =pip= this might probably work (not tested):

: #+BEGIN_SRC sh :results output raw
: tootsnoop --days 7 --count 10 --inactive
: #+END_SRC

* Optional: A Reccuring Job That Generates a Weekly Statistics
:PROPERTIES:
:CREATED:  [2025-02-06 Thu 19:45]
:END:

This is particularily interesting to people using [[https://karl-voit.at/orgmode/][Emacs Org-mode]]: I
want a weekly statisics generated each Sunday at 23:59.

For that, I created a shell script that contains the command to generate that statistics:

#+BEGIN_SRC bash
#!/usr/bin/env bash

TEMPFILE=$(mktemp)  ## used to storing the tootsnoop output
NOW_IN_ORG_TIMESTAMP="<`date '+%Y-%m-%d %a %H:%M'`>"  ## time-stamp for Org heading
TARGET_REFILE_ORG_FILE="notes.org"
TARGET_REFILE_HEADING="Weekly Mastodon statistics"

## adding a custom refile code snippet that 
## moves the heading to the desired heading 
## after inspecting and on invoking C-c C-c:
echo -e "\n#+BEGIN_SRC emacs-lisp\n(my-org-refile \"${TARGET_REFILE_ORG_FILE}\" \"${TARGET_REFILE_HEADING}\")\n#+END_SRC\n\n" > ${TEMPFILE}

## generate the statistics:
cd /path/to/tootsnoop/
uv --project /path/to/tootsnoop run /path/to/tootsnoop/__init__.py --days 7 --count 10 --inactive 2>&1 >>${TEMPFILE}
if [ "$?" != 0 ]; then
    echo "tootsnoop execution had an issue."
    appendorgheading --output ~/org/inbox.org \
        --level 1 \
        --title "${NOW_IN_ORG_TIMESTAMP} Weekly Mastodon Statistics: ERROR" \
        --filecontent ${TEMPFILE} \
        --daily --quiet
    exit 1
fi

## appends a new Orgdown heading to the output file with the statistics as body:
appendorgheading --output ~/org/inbox.org \
    --level 1 \
    --title "${NOW_IN_ORG_TIMESTAMP} Weekly Mastodon Statistics" \
    --filecontent ${TEMPFILE} \
    --blocktype NONE --nosanitize \
    --nodaily --quiet

rm "${TEMPFILE}"  ## remove temporary file
#end
#+END_SRC

This script requires:

- my other script: https://github.com/novoid/appendorgheading
  - e.g., via =pip install appendorgheading=
- an Orgdown file where the results gets appended
- an Orgdown heading title within that Orgdown file where this should get manually refiled to
- proper script paths (please adapt accordingly)

What it does:

- it generates a weekly statistics (7 days, top 10 each) with inactive time-stamps
- a handy babel snippet which refiles the heading to its final destination (after I took a brief look at it in my inbox file)

If you understand, what's going on, this is really a nice way of running tootsnoop. ;-)

* Related Projects
:PROPERTIES:
:CREATED:  [2025-02-10 Mon 11:25]
:END:

This is a far-from-complete list of projects with similar goals:

- <2024-09-18 Wed> Sacha Chua did [[https://sachachua.com/blog/2024/09/archiving-public-toots-on-my-blog/][an Elisp implementation of archiving
  her toots]]. I might have used her code as an starting point if I had
  read it earlier.

- https://mastometrics.com/ is a cool service with analytical
  features. I was using the service for many months, even spent a few
  Euros for it until it stopped working for me (constantly re-indexing
  without showing the most current results). Maybe it's working for
  you?

* How to Thank Me

I'm glad you like my tools. If you want to support me:

- Send old-fashioned *postcard* per snailmail - I love personal feedback!
  - see [[http://tinyurl.com/j6w8hyo][my address]]
- Send feature wishes or improvements as an issue on GitLab
- Create issues on GitLab for bugs
- Contribute merge requests for bug fixes
- Check out my other cool [[https://github.com/novoid][projects on GitHub]] and [[https://gitlab.com/publicvoit/][GitLab]]
  
