Dimjournal is a powerful Python tool designed to create and maintain a local backup of your Midjourney image generations. It automates the process of downloading your job history (metadata) and upscaled images, organizing them neatly on your computer.
Dimjournal is a command-line and programmatic tool that interacts with the Midjourney web interface to back up your creative work. It downloads:
This tool is for any Midjourney user who wants:
Year/Month/ImageFileName.png
structure.Important: The terms of use of Midjourney may disallow or restrict automation or web scraping. Using this tool may be against Midjourney’s Terms of Service. You use Dimjournal at your own risk. The developers of Dimjournal are not responsible for any consequences that may arise from using this software, including but not limited to account suspension or termination.
Year/Month/ImageFileName.png
).undetected_chromedriver
(a dependency) relies on it.You can install Dimjournal using pip.
Stable Version (Recommended):
pip install dimjournal
Development Version (for the latest features and fixes):
pip install git+https://github.com/twardoch/dimjournal.git
After installation, you should be able to run dimjournal
from your terminal. If not, ensure your Python scripts directory is in your system’s PATH, or use python3 -m dimjournal
.
The first time you run Dimjournal, it will open a Chrome browser window. You will need to manually log in to your Midjourney account. After successful login, Dimjournal will save session cookies to expedite future logins.
Basic Usage (defaults to ~/Pictures/midjourney/dimjournal
or ~/My Pictures/midjourney/dimjournal
):
dimjournal
Specify a Custom Archive Folder:
dimjournal --archive_folder /path/to/your/custom_archive
or on Windows:
dimjournal --archive_folder C:\path\to\your\custom_archive
Limit Number of Job Pages to Crawl: Useful for initial testing or if you only want to fetch the most recent items. Each page typically contains about 50 jobs.
dimjournal --limit 5
This will crawl the 5 most recent pages of your job history for both upscaled jobs and all jobs.
You can integrate Dimjournal’s download functionality into your own Python scripts.
import logging
from pathlib import Path
from dimjournal import download
# It's good practice to configure logging to see Dimjournal's output
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Specify the directory where you want to store the data.
# If None, it defaults to Pictures/midjourney/dimjournal or My Pictures/midjourney/dimjournal.
archive_folder_path = Path("./my_midjourney_backup")
# archive_folder_path = None # To use the default location
# Specify a limit for the number of job history pages to crawl (optional).
# Set to None or omit to crawl all available history.
crawl_limit = 10 # Example: Crawl 10 pages of recent jobs
try:
print(f"Starting Dimjournal backup to: {archive_folder_path.resolve() if archive_folder_path else 'default location'}")
download(archive_folder=archive_folder_path, limit=crawl_limit)
print("Dimjournal process complete.")
except Exception as e:
logging.error(f"An error occurred during the Dimjournal process: {e}", exc_info=True)
print(f"An error occurred. Check logs for details.")
Dimjournal employs a series of steps to back up your Midjourney data:
undetected_chromedriver
, a specialized version of Selenium’s ChromeDriver, to launch and control a Google Chrome browser. This allows it to mimic human interaction with the Midjourney website.__Secure-next-auth.session-token
) to a local file (cookies.pkl
) within the archive directory.https://www.midjourney.com/account/
).user_id
, from a JSON object embedded in the page’s HTML (within a <script id="__NEXT_DATA__">
tag).user.json
in the archive directory.https://www.midjourney.com/api/app/recent-jobs/
) to fetch job listings.userId
, jobType
(e.g., ‘upscale’), page
, amount
, orderBy
, jobStatus
, etc.'upscale'
jobs (to get images).jobs_upscaled.json
(for upscales) and jobs.json
(for all jobs) within the archive directory. The crawler only adds new jobs not already present in these files.Constants.mj_download_image_js
) in the browser to fetch the image data as a base64 encoded string. This method can be more robust for images that are dynamically loaded or protected.ARCHIVE_FOLDER/YYYY/MM/YYYYMMDD-HHMM_prompt-slug_jobIDprefix.png
.
YYYY
: YearMM
: Month (zero-padded)YYYYMMDD-HHMM
: Timestamp of the jobprompt-slug
: A slugified version of the prompt (max 49 chars)jobIDprefix
: The first 4 characters of the job IDpymtpng
library to embed metadata (prompt, author, creation time, etc.) into the PNG’s tEXt chunks. Non-PNG images are saved as-is.logging
module, providing insight into operations and aiding in troubleshooting.Key Libraries Used:
undetected_chromedriver
& selenium
: For web browser automation and interaction.BeautifulSoup4
: For parsing HTML content (primarily to extract user info).Pillow (PIL)
: Used by pymtpng
for image manipulation before saving PNGs with metadata.pymtpng
: For embedding metadata into PNG files.python-slugify
: To create safe filenames from prompts.fire
: To create the command-line interface.tqdm
: For displaying progress bars during crawling and downloading.The project is organized as follows:
src/dimjournal/
dimjournal.py
: Contains the core logic of the application.
Constants
: Class holding various constants like URLs, cookie names, date formats.MidjourneyAPI
: Handles all direct interactions with Midjourney via the browser (login, fetching user info, making API calls for job data).MidjourneyJobCrawler
: Responsible for iterating through job history pages, fetching job data using MidjourneyAPI
, and saving/updating jobs_*.json
files.MidjourneyDownloader
: Manages the download of actual image files, organizes them into folders, and embeds metadata into PNGs.download()
: The main public function that orchestrates the instances of the above classes to perform the full backup process.__main__.py
: Provides the CLI entry point, using python-fire
to expose the download
function.__init__.py
: Makes the download
function available for import and sets up package versioning.tests/
: Contains unit and integration tests written using pytest
.
test_dimjournal.py
: Test suite for the core functionalities.setup.py
, pyproject.toml
, setup.cfg
: Files related to packaging, dependencies, and project configuration (following PyScaffold structure)..github/workflows/ci.yml
: GitHub Actions workflow for continuous integration (testing, linting).README.md
: This file.LICENSE.txt
: Apache 2.0 License.CHANGELOG.md
: History of changes to the project.AUTHORS.md
: List of contributors.MidjourneyAPI(driver, archive_folder)
log_in()
: Manages login, loads/saves cookies.get_user_info()
: Fetches and stores user ID and other account details.request_recent_jobs(...)
: Queries the Midjourney API for job listings.MidjourneyJobCrawler(api, archive_folder, job_type)
load_archive_data()
: Loads existing job data from local JSON files.update_archive_data(job_listing)
: Adds new jobs to the local archive and saves.crawl(limit, from_date)
: Iteratively calls api.request_recent_jobs()
and updates the archive.MidjourneyDownloader(api, archive_folder)
fetch_image(url)
: Retrieves image data using JavaScript execution in the browser.create_folders(dt_obj)
: Creates the year/month directory structure.fetch_and_write_image(image_url, image_path, info)
: Downloads an image and saves it, embedding metadata if it’s a PNG.download_missing()
: Iterates through upscaled jobs, downloads missing images, and updates job metadata with archive status.download(archive_folder, user_id, limit)
(in src/dimjournal/dimjournal.py
)
MidjourneyAPI
, MidjourneyJobCrawler
(for upscales and all jobs), and MidjourneyDownloader
.Contributions are highly welcome! If you’d like to improve Dimjournal, please follow these steps:
git clone https://github.com/YOUR_USERNAME/dimjournal.git
git checkout -b feature/your-feature-name
or git checkout -b fix/your-bug-fix
.python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -e ".[testing]" # Installs package in editable mode with testing extras
pip install pre-commit
pre-commit install # Sets up pre-commit hooks for formatting and linting
pre-commit run --all-files
pytest
feat: Add support for grid image downloads
or fix: Correctly handle XYZ error
).git push origin feature/your-feature-name
.dimjournal
repository. Clearly describe the changes you’ve made and why.Coding Conventions & Rules:
pre-commit
with flake8
and black
(if configured, or a similar formatter) will help enforce this.logging
module for diagnostic messages. Use appropriate log levels (DEBUG
, INFO
, WARNING
, ERROR
, CRITICAL
).pytest
. Ensure existing tests pass.CHANGELOG.md
.For a detailed history of changes, please refer to the CHANGELOG.md file.
Dimjournal is licensed under the Apache License, Version 2.0. See the LICENSE.txt file for the full license text.
Initial development assisted by AI.