This is the repository for the online module Bots as Digital Infrapuncture, commissioned by the Utrecht University
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

436 lines
16 KiB

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Mastodon bot Example"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This Mastodon bot example is part of the module *Bots as Digital Infrapunctures* done by Cristina Cochior and Manetta Berends in the proximity of [Varia](https://varia.zone/en/). The module is produced in the context of the course *Data-driven research and digital tools* at the [Department of Media & Culture, Utrecht University](https://www.uu.nl/en/organisation/department-of-media-and-culture-studies) in collaboration with [Dr. Karin van Es](https://www.karinvanes.net) and [Creative Coding Utrecht](https://creativecodingutrecht.nl/)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We now find ourselves in a Jupyter Notebook — an open-source web application that allows you to create and share documents that contain live code, equations, visualizations and narrative text. This notebook gives us the possibility to write comments alongside the code, and to write run code without installing the dependencies on our own computers.\n",
"\n",
"We're going to be using the [Python](https://www.python.org/) programming language for this example.\n",
"\n",
"In order to *run* (execute) a block of code, click the ▶️ symbol from the toolbox on the top right corner.\n",
"\n",
"You can change the code blocks by double clicking the block and you can run them in order to see the effects.\n",
"\n",
"The bot we will be tooting on the Mastodon instance [botsin.space](https://botsin.space/about), a space dedicated fully to bot users. \n",
"You can find the @infrapunctures bot [here](https://botsin.space/@infrapunctures)."
]
},
{
4 years ago
"cell_type": "markdown",
"metadata": {},
"source": [
4 years ago
"## Import the Mastodon library"
]
},
{
4 years ago
"cell_type": "markdown",
"metadata": {},
"source": [
"We started by importing a Python code library that is written for Mastodon. You can find more information about it on its [code respository](https://github.com/halcy/Mastodon.py). The first two lines were already executed, we we have commented them out for now.\n",
4 years ago
"\n",
"Some of the lines you will see below have a \"#\" in front of them, this turns them into comments instead of executable lines, so they will not run. These only need to be run once, which was done in preparation for this bot."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting Mastodon.py\n",
" Downloading https://files.pythonhosted.org/packages/7c/80/f12b205fc529fff8e3245fe8e6cafb870f1783476449d3ea2a32b40928c5/Mastodon.py-1.5.1-py2.py3-none-any.whl\n",
"Requirement already satisfied: requests>=2.4.2 in /home/ccl/Documents/bots-as-digital-infrapunctures/bots-venv/lib/python3.7/site-packages (from Mastodon.py) (2.24.0)\n",
"Requirement already satisfied: pytz in /home/ccl/Documents/bots-as-digital-infrapunctures/bots-venv/lib/python3.7/site-packages (from Mastodon.py) (2020.1)\n",
"Collecting blurhash>=1.1.4 (from Mastodon.py)\n",
" Downloading https://files.pythonhosted.org/packages/80/08/163cb166a2464223a5eb8890a92cc1cf7e8c7c79a2c75e497e3d8f3a4711/blurhash-1.1.4-py2.py3-none-any.whl\n",
"Requirement already satisfied: decorator>=4.0.0 in /home/ccl/Documents/bots-as-digital-infrapunctures/bots-venv/lib/python3.7/site-packages (from Mastodon.py) (4.4.2)\n",
"Collecting python-magic (from Mastodon.py)\n",
" Downloading https://files.pythonhosted.org/packages/59/77/c76dc35249df428ce2c38a3196e2b2e8f9d2f847a8ca1d4d7a3973c28601/python_magic-0.4.18-py2.py3-none-any.whl\n",
"Requirement already satisfied: python-dateutil in /home/ccl/Documents/bots-as-digital-infrapunctures/bots-venv/lib/python3.7/site-packages (from Mastodon.py) (2.8.1)\n",
"Requirement already satisfied: six in /home/ccl/Documents/bots-as-digital-infrapunctures/bots-venv/lib/python3.7/site-packages (from Mastodon.py) (1.15.0)\n",
"Requirement already satisfied: chardet<4,>=3.0.2 in /home/ccl/Documents/bots-as-digital-infrapunctures/bots-venv/lib/python3.7/site-packages (from requests>=2.4.2->Mastodon.py) (3.0.4)\n",
"Requirement already satisfied: certifi>=2017.4.17 in /home/ccl/Documents/bots-as-digital-infrapunctures/bots-venv/lib/python3.7/site-packages (from requests>=2.4.2->Mastodon.py) (2020.6.20)\n",
"Requirement already satisfied: idna<3,>=2.5 in /home/ccl/Documents/bots-as-digital-infrapunctures/bots-venv/lib/python3.7/site-packages (from requests>=2.4.2->Mastodon.py) (2.10)\n",
"Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /home/ccl/Documents/bots-as-digital-infrapunctures/bots-venv/lib/python3.7/site-packages (from requests>=2.4.2->Mastodon.py) (1.25.10)\n",
"Installing collected packages: blurhash, python-magic, Mastodon.py\n",
"Successfully installed Mastodon.py-1.5.1 blurhash-1.1.4 python-magic-0.4.18\n"
]
}
],
"source": [
4 years ago
"# import sys\n",
"# !{sys.executable} -m pip install Mastodon.py"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
4 years ago
"from mastodon import Mastodon "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Configuring the infrastructure"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With the code below we are choosing which Mastodon instance we want to use."
]
},
{
"cell_type": "code",
4 years ago
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
4 years ago
"instance = 'https://botsin.space'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Starting the bot"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We have saved the user credentials in a file called 'mastodon-bot-usercred.secret' which contains a token code for indentifying our bot and the name of the instance. In the code below we access this secret file in order to get authorisation to post on the bot's behalf."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'Mastodon' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-1-2d1cf0b59a74>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m mastodon = Mastodon(\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0maccess_token\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'mastodon-bot-usercred.secret'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mapi_base_url\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minstance\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m )\n",
"\u001b[0;31mNameError\u001b[0m: name 'Mastodon' is not defined"
]
}
],
"source": [
"mastodon = Mastodon(\n",
" access_token = 'mastodon-bot-usercred.secret',\n",
" api_base_url = instance\n",
")"
]
},
4 years ago
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tooting time! \n",
"\n",
"The following code blocks will already allow us to toot! Tooting in Mastodon vernacular means posting. \n",
"\n",
"Each block will toot something else. You can make changes to the variables in order to toot something else."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is the simplest command you need to run to make a toot:"
4 years ago
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"mastodon.toot('testing tooting')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the code below we tell the bot to go through the list and toot each element every 5 minutes."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'mastodon' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-2-53a6b322c1fc>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mtoot\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtoots\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0mmastodon\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtoot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtoot\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 13\u001b[0m \u001b[0msleep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m300\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# 300 seconds = 5 minutes\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mNameError\u001b[0m: name 'mastodon' is not defined"
]
}
],
"source": [
"from time import sleep\n",
"\n",
"toots = [\n",
" 'Sentence 1',\n",
" 'Sentence 2',\n",
" 'Sentence 3',\n",
" 'Sentence 4',\n",
" 'Sentence 5'\n",
"]\n",
"\n",
"for toot in toots:\n",
" mastodon.toot(toot)\n",
" sleep(300) # 300 seconds = 5 minutes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we are tooting a media file (audio, video, image) using their urls. You can read more about it [here](https://mastodonpy.readthedocs.io/en/stable/#media-dicts)."
]
},
{
"cell_type": "code",
4 years ago
"execution_count": 24,
"metadata": {},
4 years ago
"outputs": [
{
"data": {
"text/plain": [
"{'id': 105158839281621670,\n",
" 'type': 'image',\n",
" 'url': 'https://files.botsin.space/media_attachments/files/105/158/839/281/621/670/original/b6092861a5b9fea8.png',\n",
" 'preview_url': 'https://files.botsin.space/media_attachments/files/105/158/839/281/621/670/small/b6092861a5b9fea8.png',\n",
" 'remote_url': None,\n",
" 'preview_remote_url': None,\n",
" 'text_url': 'https://botsin.space/media/DMDQwSmifxEp29TPEVw',\n",
" 'meta': {'original': {'width': 1707,\n",
" 'height': 960,\n",
" 'size': '1707x960',\n",
" 'aspect': 1.778125},\n",
" 'small': {'width': 533,\n",
" 'height': 300,\n",
" 'size': '533x300',\n",
" 'aspect': 1.7766666666666666}},\n",
" 'description': None,\n",
" 'blurhash': 'UIFPBE9F00?bIUM{%MofRjt7oft7t7M{Rjj['}"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
4 years ago
"import urllib.request\n",
"\n",
"url = 'https://vvvvvvaria.org/bots-as-digital-infrapunctures/images/slide.png'\n",
"caption = 'Testing'\n",
"\n",
4 years ago
"urllib.request.urlretrieve(url, 'media/tmp.jpg')\n",
"mastodon.media_post('media/tmp.jpg', 'image/jpeg')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this block we will generate a sentence with random names and toot it."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'mastodon' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-3-cc0db0b7253a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mtoot\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0mmastodon\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtoot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtoot\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mNameError\u001b[0m: name 'mastodon' is not defined"
]
}
],
"source": [
4 years ago
"import random\n",
"\n",
"names = ['Rosa', 'Luxembourg', 'Parks']\n",
"objects = ['orange', 'mango', 'lychee']\n",
"actions = ['eats', 'draws', 'picks up']\n",
4 years ago
"\n",
"n = random.choice(names)\n",
"o = random.choice(objects)\n",
"a = random.choice(actions)\n",
"\n",
"toot = ''\n",
"mastodon.toot(toot)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The code bellow will make your bot toot if ..."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2020-11-05 17:31:54.233814\n"
]
}
],
"source": [
"# Using the current time\n",
"\n",
"from datetime import datetime\n",
"\n",
"print(datetime.now())\n"
]
},
4 years ago
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Make your own bot"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"These have been only a few things you can try out that are meant to illustrate some of the programming logic we mentioned in the module. You can always make your own bot and complexify the code.\n",
"\n",
"If you would like to make your own bot from scratch, you can remove the '#' from every line below and save it as a new file. \n",
"\n",
"(We didn't include this section in the code bot above because it was already executed in the preparation and only needs to be done once.)"
]
},
4 years ago
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# instance = 'URL'\n",
"# username = 'USERNAME'\n",
"# password = 'PASSWORD'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Register the bot as an application, save details as a (.secret) plain text file.\n",
"\n",
"# This only needs to be done once!\n",
"# (we already did it)\n",
"\n",
"# Mastodon.create_app(\n",
"# 'bots-as-infrapunctures',\n",
"# api_base_url = instance,\n",
"# to_file = 'mastodon-bot.secret'\n",
"# )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Write your login details to a (.secret) plain text file.\n",
"\n",
"# This only needs to be done once!\n",
"# (we already did it)\n",
"\n",
"# mastodon = Mastodon(\n",
"# client_id = 'mastodon-bot.secret',\n",
"# api_base_url = instance\n",
"# )\n",
"\n",
"# mastodon.log_in(\n",
"# username,\n",
"# password,\n",
"# to_file = 'mastodon-bot-usercred.secret'\n",
"# )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}