pax_global_header 0000666 0000000 0000000 00000000064 14721113403 0014506 g ustar 00root root 0000000 0000000 52 comment=15ae571c648700206974403bb8db384ee67ae425
organize-3.3.0/ 0000775 0000000 0000000 00000000000 14721113403 0013327 5 ustar 00root root 0000000 0000000 organize-3.3.0/.dockerignore 0000664 0000000 0000000 00000000204 14721113403 0015777 0 ustar 00root root 0000000 0000000 # ignore everything
*
# except pyproject files
!poetry.lock
!pyproject.toml
!README.md
# and python scripts
!**/*.py
!**/py.typed
organize-3.3.0/.editorconfig 0000664 0000000 0000000 00000000523 14721113403 0016004 0 ustar 00root root 0000000 0000000 # EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
[{*.bat,Makefile}]
indent_style = tab
[*.rst]
indent_size = 2
[{*.yml,*.yaml}]
indent_size = 2
[*.md]
indent_size = 2
indent_style = space
organize-3.3.0/.github/ 0000775 0000000 0000000 00000000000 14721113403 0014667 5 ustar 00root root 0000000 0000000 organize-3.3.0/.github/FUNDING.yml 0000664 0000000 0000000 00000001070 14721113403 0016502 0 ustar 00root root 0000000 0000000 # These are supported funding model platforms
github: tfeldmann
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: tfeldmann
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ["paypal.me/tfeldmann42"]
organize-3.3.0/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 14721113403 0017052 5 ustar 00root root 0000000 0000000 organize-3.3.0/.github/ISSUE_TEMPLATE/bug_report.md 0000664 0000000 0000000 00000000647 14721113403 0021553 0 ustar 00root root 0000000 0000000 ---
name: Bug report
about: Create a report to help us improve
title: ""
labels: bug
assignees: ""
---
**Describe the bug**
A clear and concise description of what the bug is.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please complete the following information):**
- OS:
- Output of `organize --version`:
**Your config file**
```yaml
# paste your config file here
```
organize-3.3.0/.github/ISSUE_TEMPLATE/feature_request.md 0000664 0000000 0000000 00000001140 14721113403 0022573 0 ustar 00root root 0000000 0000000 ---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature request
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
organize-3.3.0/.github/PULL_REQUEST_TEMPLATE.md 0000664 0000000 0000000 00000001034 14721113403 0020466 0 ustar 00root root 0000000 0000000
## Change Summary
## Related issue number
## Checklist
- [ ] Tests for the changes exist and pass on CI
- [ ] Documentation reflects the changes where applicable
- [ ] Change is documented in CHANGELOG.md (if applicable)
- [ ] My PR is ready to review
organize-3.3.0/.github/dependabot.yml 0000664 0000000 0000000 00000000265 14721113403 0017522 0 ustar 00root root 0000000 0000000 version: 2
updates:
- package-ecosystem: pip
directory: /
schedule:
interval: monthly
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
organize-3.3.0/.github/workflows/ 0000775 0000000 0000000 00000000000 14721113403 0016724 5 ustar 00root root 0000000 0000000 organize-3.3.0/.github/workflows/publish-docker-image.yml 0000664 0000000 0000000 00000002327 14721113403 0023446 0 ustar 00root root 0000000 0000000 # This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# GitHub recommends pinning actions to a commit SHA.
# To get a newer version, you will need to update the SHA.
# You can also reference a tag or branch, but the action may change without warning.
name: Publish Docker image
on:
release:
types: [published]
jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: tfeldmann/organize
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
push: true
tags: tfeldmann/organize:latest
labels: ${{ steps.meta.outputs.labels }}
organize-3.3.0/.github/workflows/tests.yml 0000664 0000000 0000000 00000002262 14721113403 0020613 0 ustar 00root root 0000000 0000000 name: tests
on:
push:
paths-ignore:
- "docs/**"
- "*.md"
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
# https://github.com/python-poetry/poetry/issues/8623
env:
PYTHON_KEYRING_BACKEND: keyring.backends.null.Keyring
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.9", "3.10", "3.11", "3.12"]
fail-fast: false
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "${{ matrix.python-version }}"
- name: Setup Environment
env:
PYTHON_KEYRING_BACKEND: keyring.backends.null.Keyring
run: |
python3 -m pip install -U pip setuptools
python3 -m pip install poetry==1.7.1
poetry install --with=dev
- name: Version info
run: |
poetry run python main.py --version
- name: Test with pytest
run: |
poetry run pytest
- name: Check with MyPy
run: |
poetry run mypy .
organize-3.3.0/.gitignore 0000664 0000000 0000000 00000004156 14721113403 0015325 0 ustar 00root root 0000000 0000000 .configs
.pytest_cache/
**/.ruff_cache/
# Created by https://www.gitignore.io/api/python
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# End of https://www.gitignore.io/api/python
# Created by https://www.gitignore.io/api/visualstudiocode
### VisualStudioCode ###
.vscode
.history
# End of https://www.gitignore.io/api/visualstudiocode
.idea
# Created by https://www.toptal.com/developers/gitignore/api/macos
# Edit at https://www.toptal.com/developers/gitignore?templates=macos
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
# End of https://www.toptal.com/developers/gitignore/api/macos
organize-3.3.0/.pre-commit-config.yaml 0000664 0000000 0000000 00000001125 14721113403 0017607 0 ustar 00root root 0000000 0000000 repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: mixed-line-ending
args:
- --fix=lf
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.0
hooks:
# lint and fix
- id: ruff
args: [--fix]
# sort imports
- id: ruff
args: [--select=I, --fix]
# format
- id: ruff-format
- repo: https://github.com/python-poetry/poetry
rev: "1.8.0"
hooks:
- id: poetry-check
organize-3.3.0/.readthedocs.yml 0000664 0000000 0000000 00000000726 14721113403 0016422 0 ustar 00root root 0000000 0000000 # .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-20.04
tools:
python: "3.9"
mkdocs:
configuration: mkdocs.yml
# Optionally declare the Python requirements required to build your docs
python:
install:
- method: pip
path: .
extra_requirements:
- docs
organize-3.3.0/CHANGELOG.md 0000664 0000000 0000000 00000032223 14721113403 0015142 0 ustar 00root root 0000000 0000000 # Changelog
## [Unreleased]
## v3.3.0 (2024-11-25)
- Added a new conflict mode `deduplicate` which skips duplicate files and renames
non-duplicates (thanks @TheExistingOne).
- The `exif` filter now supports extracting metadata from non-image files such as EPUB
or PDF files.
- Loosen the pdfminer-six dependency version constraint for easier NixOS packaging.
- Fixes encoding issues in windows (thanks @Alimektor).
## v3.2.5 (2024-07-09)
- Fixes a bug where some location options did not accept yaml aliases
(#390, thanks for reporting @zany130).
## v3.2.4 (2024-07-07)
- Fixes a bug preventing organize from starting (thanks @feather42).
- Fixes a bug where ignoring failing shell commands would not work (thanks @florianklumb).
## v3.2.3 (2024-03-28)
- Improves the logic of finding and creating config files.
- Fixes a bug where config files in XDG_CONFIG_HOME are not found (#371).
- Fixes a bug in the `relative_path` parameter crashing on actions after moving files (#372).
## v3.2.2 (2024-03-04)
- Fixes an problem where the `organize new` command fails to create a new config file.
## v3.2.1 (2024-02-23)
- Files and folders are now handled in natural sort order (#354).
## v3.2.0 (2024-02-19)
- Integrated `.docx`, `.pdf` and various raw text parsers into `filecontent` filter.
- Removed `textract` and ~50 MB of dependencies as they are no longer required.
- Full Python 3.12 support
- Add support for piping in a config file from STDIN (`organize run --stdin < file.yml`)
**Important:**
You may have to adjust your `filecontent` regexes. The output should be a bit cleaner
now.
## v3.1.2 (2024-02-16)
- Fixes a validation error where correctly defined actions were not accepted in Python 3.12.2.
## v3.1.1 (2024-02-11)
- Fixes the `organize show` command which broke in v3.1.0.
## v3.1.0 (2024-02-04)
- Add a new output format `errorsonly` which only shows output if an error occured.
- Fixes a bug where messages and paths containing brackets where not printed correctly
(#348, thanks @kwbr!)
## v3.0.1 (2024-01-12)
- Fixes a bug where Quicktime and mp4 files return no Exif data.
(#313, @jleatham thanks for debugging!)
- Fixes a bug where `exlude_dirs` are not correctly excluded. (#339)
## v3.0.0 (2024-01-05)
- Supports `exiftool` in the `exif` filter by setting the `ORGANIZE_EXIFTOOL_PATH` env
var. (thanks to @HernandoR for working on qtff support)
- Fixes the `min_depth` location parameter. (thanks to @danielklim for working on this)
## v3.0.0a2 (2024-01-02)
- Fix bug on first run of `organize new`. Create the organize config directory if it
does not exist. (thanks @white-gecko)
- Adds action `hardlink`.
## v3.0.0a1 (2024-01-01)
- Default to UTF-8 encoding when reading and writing config files for windows users
who don't use python in UTF-8 mode (env variable `PYTHONUTF8=1`).
- `write`-action: Allow setting the text encoding.
## v3.0.0a0 (2023-12-31)
- New action: `write` to write lines into a file.
- New filter: `date_lastused` (macOS only).
- You can now specify the timezone in all time based filters.
- Removed hidden (deprecated) CLI option `--config-file`.
- Lots of new tests and some bugfixes.
- `exif` filter now supports the simplematch syntax.
- Placeholder`{now}` must be `{now()}` now.
- Multiple `path`s per location are now supported.
- Locations now support a `min_depth` option
- Duplicate filter: `detect_original_by` now supports `last_seen`.
- New command line interface (added `new`, `show` and `list` commands).
- `JSONL` output (`organize run --format=JSONL`)
- `move` and `copy` now intelligently autodetect if you mean to move to a folder
(This autodetection can be deactivated).
- `copy` action: You can now specify whether you want to continue with the original
or with the copy.
- Completely removes the `pyfilesystem` dependency.
- At least a 4x speed up. Often more than 10x.
## v2.4.3 (2023-10-14)
- Modified filter: `exif`. Enabled datetime fields on exif data (Issue #266) (Thanks @FlorianFritz)
- Support Exif data from Huawei and Honer phones (Thanks @HernandoR)
## v2.4.2 (2023-08-25)
- Fix reading exif data for HEIC images (Issue #267)
## v2.4.1 (2023-08-25)
- Fix unicode bug in logging (Issue #294) (Thanks @xdhmoore)
- Updated dependencies (Thanks @gaby)
- Removed support for python 3.7 (EOL - June 2023) (Thanks @gaby)
## v2.4.0 (2022-09-05)
- New action: `write`.
- New filter: `date_lastused` (macOS only).
- Conflict resolution renaming now starts with 2 instead of 1.
- Add support for FS urls as path to the config file and working dir
(both in the CLI and ORGANIZE_CONFIG environment variable).
- Removed hidden (deprecated) CLI option `--config-file`.
- Lots of new tests and some bugfixes.
## v2.3.0 (2022-07-26)
- New filter: `macos_tags` (macOS only).
- Ignore broken symlinks (Issue #202)
## v2.2.0 (2022-03-31)
- Tag support (#199) to run subsets of rules in your config.
## v2.1.2 (2022-02-13)
- Hotfix for `filecontent` filter.
## v2.1.1 (2022-02-13)
- `filecontent` filter: Fixes bug #188.
- Bugfix for #185 and #184.
## v2.1.0 (2022-02-11)
- Added filter `date_added` (macOS only)
- `created` filter now supports gnu coreutils stat utility for birthtime detection
- refactored time based filters into a common class
## v2.0.9 (2022-02-10)
- `shell` shows a message when code is not run in simulation
- `shell` add options `simulation_output` and `simulation_returncode`
- fixes a bug where location options are applied to other locations as well
- `created` filter now falls back to using the stat utility on linux systems where the
birthtime is not included in `os.stat`.
## v2.0.8 (2022-02-09)
- Bugfix `shell` for real.
## v2.0.7 (2022-02-09)
- Bugfix for `shell`.
## v2.0.6 (2022-02-09)
- Speed up moving files.
- `shell` action: Run command through the user's shell.
## v2.0.5 (2022-02-08)
- Fixed the migration message and docs URL
## v2.0.4 (2022-02-08)
- exclude_dir, system_exclude_dirs, exclude_files, system_exclude_files, filter and
filter_dirs now accept single strings.
- Fixed a bug in the name filter
## v2.0.3 (2022-02-07)
- Fixed typo: `system_exlude_files`
## v2.0.2 (2022-02-07)
- Bugfix in env variable expansion in locations
## v2.0.1 (2022-02-07)
- Small bugfix in `macos_tags` action.
- Bugfix in the migration detection.
## v2.0.0 (2022-02-07)
This is a huge update with lots of improvements.
Please backup all your important stuff before running and use the simulate option!
[**Migration Guide**](docs/updating-from-v1.md)
### what's new
- You can now [target directories](docs/rules.md#targeting-directories) with your rules
(copying, renaming, etc a whole folder)
- [Organize inside or between (S)FTP, S3 Buckets, Zip archives and many more](docs/locations.md#remote-filesystems-and-archives)
(list of [available filesystems](https://www.pyfilesystem.org/page/index-of-filesystems/)).
- [`max_depth`](docs/locations.md#location-options) setting when recursing into subfolders
- Respects your rule order - safer, less magic, less surprises.
- (organize v1 tried to be clever. v2 now works your config file from top to bottom)
- [Jinja2 template engine for placeholders](docs/rules.md#templates-and-placeholders).
- Instant start. (does not need to gather all the files before starting)
- [Filters can now be excluded](docs/filters.md#how-to-exclude-filters).
- [Filter modes](docs/rules.md#rule-options): `all`, `any` and `none`.
- [Rule names](docs/rules.md#rule-options).
- new conflict resolution settings in [`move`](docs/actions.md#move),
[`copy`](docs/actions.md#copy) and [`rename`](docs/actions.md#rename) action:
- Options are `skip`, `overwrite`, `trash`, `rename_new` or `rename_existing`
- You can now define a custom `rename_template`.
- The [`duplicate`](docs/filters.md#duplicate) now supports several options on how to
distinguish between original and duplicate file.
- The [`python`](docs/actions.md#python) action can now be run in simulation.
- The [`shell`](docs/actions.md#shell) action now returns stdout and errorcode.
- Added filter [`empty`](docs/filters.md#empty) - find empty files and folders
- Added filter [`hash`](docs/filters.md#hash) - generate file hashes
- Added action [`symlink`](docs/actions.md#symlink) - generate symlinks
- Added action [`confirm`](docs/actions.md#confirm) - asks for confirmation
- Many small fixes and improvements!
### changed
- The `timezone` keyword for [`lastmodified`](docs/filters.md#lastmodified) and
[`created`](docs/filters.md#created) was removed. The timezone is
now the local timezone by default.
- The `filesize` filter was renamed to [`size`](docs/filters.md#size) and can now be
used to get directory sizes as well.
- The `filename` filter was renamed to [`name`](docs/filters.md#name) and can now be
used to get directory names as well.
- The [`size`](docs/filters.md#size) filter now returns multiple formats
### removed
- Glob syntax is gone from folders ([no longer needed](docs/locations.md))
- `"!"` folder exclude syntax is gone ([no longer needed](docs/locations.md))
## v1.10.1 (2021-04-21)
- Action `macos_tags` now supports colors and placeholders.
- Show full expanded path if folder is not found.
## v1.10.0 (2021-04-20)
- Add filter `mimetype`
- Add action `macos_tags`
- Support [`simplematch`](https://github.com/tfeldmann/simplematch) syntax in
`lename`-filter.
- Updated dependencies
- Because installing `textract` is quite hard on some platforms it is now an optional
dendency. Install it with `pip install organize-tool[textract]`
- This version needs python 3.6 minimum. Some dependencies that were simply backports
(thlib2, typing) are removed.
- Add timezones in created and last_modified filters (Thank you, @win0err!)
## v1.9.1 (2020-11-10)
- Add {env} variable
- Add {now} variable
## v1.9 (2020-06-12)
- Add filter `Duplicate`.
## v1.8.2 (2020-04-03)
- Fix a bug in the filename filter config parsing algorithm with digits-only filenames.
## v1.8.1 (2020-03-28)
- Flatten filter and action lists to allow enhanced config file configuration (Thanks to @rawdamedia!)
- Add support for multiline content filters (Thanks to @zor-el!)
## v1.8.0 (2020-03-04)
- Added action `Delete`.
- Added filter `FileContent`.
- Python 3.4 is officially deprecated and no longer supported.
- `--config-file` command line option now supports `~` for user folder and expansion
oenvironment variables
- Added `years`, `months`, `weeks` and `seconds` parameter to filter `created` and
`stmodified`
## v1.7.0 (2019-11-26)
- Added filter `Exif` to filter by image exif data.
- Placeholder variable properties are now case insensitve.
## v1.6.2 (2019-11-22)
- Fix `Rename` action (`'PosixPath' object has no attribute 'items'`).
- Use type hints everywhere.
## v1.6.1 (2019-10-25)
- Shows a warning for missing folders instead of raising an exception.
## v1.6 (2019-08-19)
- Added filter: `Python`
- Added filter: `FileSize`
- The organize module can now be run directly: `python3 -m organize`
- Various code simplifications and speedups.
- Fixes an issue with globstring file exclusion.
- Remove `clint` dependency as it is no longer maintained.
- Added various integration tests
- The "~~ SIMULATION ~~"-banner now takes up the whole terminal width
## v1.5.3 (2019-08-01)
- Filename filter now supports lists.
## v1.5.2 (2019-07-29)
- Environment variables in folder pathes are now expanded (syntax `$name` or `${name}`
a additionally `%name%` on windows).
F example this allows the usage of e.g. `%public/Desktop%` in windows.
## v1.5.1 (2019-07-23)
- New filter "Created" to filter by creation date.
- Fixes issue #39 where globstrings don't work most of the time.
- Integration test for issue #39
- Support indented config files
## v1.5 (2019-07-17)
- Fixes issue #31 where the {path} variable always resolves to the source path
- Updated dependencies
- Exclude changelog and readme from published wheel
## v1.4.5 (2019-07-03)
- Filter and Actions names are now case-insensitive
## v1.4.4 (2019-07-02)
- Fixes issues #36 with umlauts in config file on windows
## v1.4.3 (2019-06-05)
- Use safe YAML loader to fix a deprecation warning. (Thanks mope1!)
- Better error message if a folder does not exist. (Again thanks mope1!)
- Fix example code in documentation for LastModified filter.
- Custom config file locations (given by cmd line argument or environment variable).
- `config --debug` now shows the full path to the config file.
## v1.4.2 (2018-11-14)
- Fixes a bug with command line arguments in the `$EDITOR` environment
viable.
- Fixes a bug where an empty config wouldn't show the correct error message.
- Fix binary wheel creation in setup.py by using environment markers
## v1.4.1 (2018-10-05)
- A custom separator `counter_separator` can now be set in the actions Move,
Cy and Rename.
## v1.4 (2018-09-21)
- Fixes a bug where glob wildcards are not detected correctly
- Adds support for excluding folders and files via glob syntax.
- Makes sure that files are only handled once per rule.
## v1.3 (2018-07-06)
- Glob support in folder configuration.
- New variable {relative_path} is now available in actions.
## v1.2 (2018-03-19)
- Shows the relative path to files in subfolders.
## v1.1 (2018-03-13)
- Removes the colon from extension filter output so `{extension.lower}` now
rurns `'png'` instead of `'.png'`.
## v1.0 (2018-03-13)
- Initial release.
organize-3.3.0/Dockerfile 0000664 0000000 0000000 00000001303 14721113403 0015316 0 ustar 00root root 0000000 0000000 FROM python:3.11-slim as base
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
PYTHONUNBUFFERED=1 \
VIRTUAL_ENV="/venv"
ENV PATH="${VIRTUAL_ENV}/bin:$PATH"
WORKDIR /app
FROM base as pydeps
RUN pip install "poetry==1.7.1" && \
python -m venv ${VIRTUAL_ENV}
COPY pyproject.toml poetry.lock ./
RUN poetry install --only=main --no-interaction
FROM base as final
RUN apt update && \
apt install -y exiftool poppler-utils && \
rm -rf /var/lib/apt/lists/*
ENV ORGANIZE_CONFIG=/config/config.yml \
ORGANIZE_EXIFTOOL_PATH=exiftool
RUN mkdir /config && mkdir /data
COPY --from=pydeps ${VIRTUAL_ENV} ${VIRTUAL_ENV}
COPY ./organize ./organize
ENTRYPOINT ["python", "-m", "organize"]
CMD ["--help"]
organize-3.3.0/LICENSE.txt 0000664 0000000 0000000 00000002065 14721113403 0015155 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) Thomas Feldmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
organize-3.3.0/README.md 0000664 0000000 0000000 00000020707 14721113403 0014614 0 ustar 00root root 0000000 0000000
---
organize - The file management automation tool
Full documentation at Read the docs
## v3 is now available
The new version should be *much* faster and fix a lot of bugs. It also comes with
a some new actions, filters and options.
If you encounter any other bugs or problems during the migration, please reach out!
- [See the changelog](https://tfeldmann.github.io/organize/changelog/)
- [Migration guide](https://tfeldmann.github.io/organize/migrating/#migrating-from-v2-to-v3)
## About
Your desktop is a mess? You cannot find anything in your downloads and
documents? Sorting and renaming all these files by hand is too tedious?
Time to automate it once and benefit from it forever.
**organize** is a command line, open-source alternative to apps like Hazel (macOS)
or File Juggler (Windows).
### People use this for:
- Sorting and tagging pictures into various folder structures based on EXIF data
- Sorting and renaming PDF invoices based on file content
- Removing incomplete downloads from their ~/Downloads
- Cleaning up their ~/Desktop from unused files
- Freeing up disk space by removing duplicates
- Automating various business processes
- and many more
## Features
Some highlights include:
- Safe moving, renaming, copying of files and folders with conflict resolution options.
- Fast duplicate file detection.
- Exif tags extraction.
- Categorization via text extracted from PDF, DOCX and many more.
- Powerful template engine.
- Inline python and shell commands as filters and actions for maximum flexibility.
- Everything can be simulated before touching your files.
- Works on macOS, Windows and Linux.
- Free and open source software.
## Getting started
### Installation
Only python 3.9+ is needed.
Install it via your package manager or from [python.org](https://python.org).
Installation is done via pip. Note that the package name is `organize-tool`:
```bash
pip install -U organize-tool
```
This command can also be used to update to the newest version. Now you can run `organize --help` to check if the installation was successful.
### Create your first rule
In your shell, run `organize new` and then `organize edit` to edit the configuration:
```yaml
rules:
- name: "Find PDFs"
locations:
- ~/Downloads
subfolders: true
filters:
- extension: pdf
actions:
- echo: "Found PDF!"
```
> If you have problems editing the configuration you can run `organize show --reveal` to reveal the configuration folder in your file manager. You can then edit the `config.yaml` in your favourite editor.
save your config file and run:
```sh
organize run
```
You will see a list of all `.pdf` files you have in your downloads folder (+ subfolders).
For now we only show the text `Found PDF!` for each file, but this will change soon...
(If it shows `Nothing to do` you simply don't have any pdfs in your downloads folder).
Run `organize edit` again and add a `move`-action to your rule:
```yml
actions:
- echo: "Found PDF!"
- move: ~/Documents/PDFs/
```
Now run `organize sim` to see what would happen without touching your files.
You will see that your pdf-files would be moved over to your `Documents/PDFs` folder.
Congratulations, you just automated your first task. You can now run `organize run`
whenever you like and all your pdfs are a bit more organized. It's that easy.
> There is so much more. You want to rename / copy files, run custom shell- or python scripts, match names with regular expressions or use placeholder variables? organize has you covered. Have a look at the advanced usage example below!
## Example rules
Here are some examples of simple organization and cleanup rules. Modify to your needs!
Move all invoices, orders or purchase documents into your documents folder:
```yaml
rules:
- name: "Sort my invoices and receipts"
locations: ~/Downloads
subfolders: true
filters:
- extension: pdf
- name:
contains:
- Invoice
- Order
- Purchase
case_sensitive: false
actions:
- move: ~/Documents/Shopping/
```
Recursively delete all empty directories:
```yaml
rules:
- name: "Recursively delete all empty directories"
locations:
- path: ~/Downloads
targets: dirs
subfolders: true
filters:
- empty
actions:
- delete
```
You'll find many more examples in the full documentation.
## Command line interface
```txt
organize - The file management automation tool.
Usage:
organize run [options] []
organize sim [options] []
organize new []
organize edit []
organize check []
organize debug []
organize show [--path|--reveal] []
organize list
organize docs
organize --version
organize --help
Commands:
run Organize your files.
sim Simulate organizing your files.
new Creates a new config.
edit Edit the config file with $EDITOR.
check Check whether the config file is valid.
debug Shows the raw config parsing steps.
show Print the config to stdout.
Use --reveal to reveal the file in your file manager
Use --path to show the path to the file
list Lists config files found in the default locations.
docs Open the documentation.
Options:
A config name or path to a config file
-W --working-dir The working directory
-F --format (default|jsonl) The output format [Default: default]
-T --tags Tags to run (eg. "initial,release")
-S --skip-tags Tags to skip
-h --help Show this help page.
```
## Other donation options:
ETH:
```
0x8924a060CD533699E230C5694EC95b26BC4168E7
```
BTC:
```
39vpniiZk8qqGB2xEqcDjtWxngFCCdWGjY
```
organize-3.3.0/docs/ 0000775 0000000 0000000 00000000000 14721113403 0014257 5 ustar 00root root 0000000 0000000 organize-3.3.0/docs/actions.md 0000664 0000000 0000000 00000022215 14721113403 0016243 0 ustar 00root root 0000000 0000000 # Actions
This page shows the specifics of each action. For basic action usage and options have a
look at the [Rules](rules.md) section.
## confirm
::: organize.actions.Confirm
**Examples**
Confirm before deleting a duplicate
```yaml
rules:
- name: "Delete duplicates with confirmation"
locations:
- ~/Downloads
- ~/Documents
filters:
- not empty
- duplicate
- name
actions:
- confirm: "Delete {name}?"
- trash
```
## copy
::: organize.actions.Copy
**Examples:**
Copy all pdfs into `~/Desktop/somefolder/` and keep filenames
```yaml
rules:
- locations: ~/Desktop
filters:
- extension: pdf
actions:
- copy: "~/Desktop/somefolder/"
```
Use a placeholder to copy all .pdf files into a "PDF" folder and all .jpg files into a "JPG" folder. Existing files will be overwritten.
```yaml
rules:
- locations: ~/Desktop
filters:
- extension:
- pdf
- jpg
actions:
- copy:
dest: "~/Desktop/{extension.upper()}/"
on_conflict: overwrite
```
Use a placeholder to copy all .pdf files into a "PDF" folder and all .jpg files into a "JPG" folder. If two files share the same file name and are duplicates, the duplicate will be skipped. If they aren't duplicates, the second file will be renamed.
```yaml
rules:
- locations: ~/Desktop
filters:
- extension:
- pdf
- jpg
actions:
- copy:
dest: "~/Desktop/{extension.upper()}/"
on_conflict: deduplicate
```
Copy into the folder `Invoices`. Keep the filename but do not overwrite existing files.
To prevent overwriting files, an index is added to the filename, so `somefile.jpg` becomes `somefile 2.jpg`.
The counter separator is `' '` by default, but can be changed using the `counter_separator` property.
```yaml
rules:
- locations: ~/Desktop/Invoices
filters:
- extension:
- pdf
actions:
- copy:
dest: "~/Documents/Invoices/"
on_conflict: "rename_new"
rename_template: "{name} {counter}{extension}"
```
## delete
::: organize.actions.delete.Delete
**Examples:**
Delete old downloads.
```yaml
rules:
- locations: "~/Downloads"
filters:
- lastmodified:
days: 365
- extension:
- png
- jpg
actions:
- delete
```
Delete all empty subfolders
```yaml
rules:
- name: Delete all empty subfolders
locations:
- path: "~/Downloads"
max_depth: null
targets: dirs
filters:
- empty
actions:
- delete
```
## echo
::: organize.actions.Echo
**Examples:**
```yaml
rules:
- name: "Find files older than a year"
locations: ~/Desktop
filters:
- lastmodified:
days: 365
actions:
- echo: "Found old file"
```
Prints "Hello World!" and filepath for each file on the desktop:
```yaml
rules:
- locations:
- ~/Desktop
actions:
- echo: "Hello World! {path}"
```
This will print something like `Found a ZIP: "backup"` for each file on your desktop
```yaml
rules:
- locations:
- ~/Desktop
filters:
- extension
- name
actions:
- echo: 'Found a {extension.upper()}: "{name}"'
```
Show the `{relative_path}` and `{path}` of all files in '~/Downloads', '~/Desktop' and their subfolders:
```yaml
rules:
- locations:
- path: ~/Desktop
max_depth: null
- path: ~/Downloads
max_depth: null
actions:
- echo: "Path: {path}"
- echo: "Relative: {relative_path}"
```
## hardlink
::: organize.actions.Hardlink
## macos_tags
::: organize.actions.MacOSTags
**Examples:**
```yaml
rules:
- name: "add a single tag"
locations: "~/Documents/Invoices"
filters:
- name:
startswith: "Invoice"
- extension: pdf
actions:
- macos_tags: Invoice
```
Adding multiple tags ("Invoice" and "Important")
```yaml
rules:
- locations: "~/Documents/Invoices"
filters:
- name:
startswith: "Invoice"
- extension: pdf
actions:
- macos_tags:
- Important
- Invoice
```
Specify tag colors
```yaml
rules:
- locations: "~/Documents/Invoices"
filters:
- name:
startswith: "Invoice"
- extension: pdf
actions:
- macos_tags:
- Important (green)
- Invoice (purple)
```
Add a templated tag with color
```yaml
rules:
- locations: "~/Documents/Invoices"
filters:
- created
actions:
- macos_tags:
- Year-{created.year} (red)
```
## move
::: organize.actions.Move
**Examples:**
Move all pdfs and jpgs from the desktop into the folder "~/Desktop/media/". Filenames are not changed.
```yaml
rules:
- locations: ~/Desktop
filters:
- extension:
- pdf
- jpg
actions:
- move: "~/Desktop/media/"
```
Use a placeholder to move all .pdf files into a "PDF" folder and all .jpg files into a
"JPG" folder. Existing files will be overwritten.
```yaml
rules:
- locations: ~/Desktop
filters:
- extension:
- pdf
- jpg
actions:
- move:
dest: "~/Desktop/{extension.upper()}/"
on_conflict: "overwrite"
```
Move pdfs into the folder `Invoices`. Keep the filename but do not overwrite existing files. To prevent overwriting files, an index is added to the filename, so `somefile.jpg` becomes `somefile 2.jpg`.
```yaml
rules:
- locations: ~/Desktop/Invoices
filters:
- extension:
- pdf
actions:
- move:
dest: "~/Documents/Invoices/"
on_conflict: "rename_new"
rename_template: "{name} {counter}{extension}"
```
## python
::: organize.actions.Python
**Examples:**
A basic example that shows how to get the current file path and do some printing in a
for loop. The `|` is yaml syntax for defining a string literal spanning multiple lines.
```yaml
rules:
- locations: "~/Desktop"
actions:
- python: |
print('The path of the current file is %s' % path)
for _ in range(5):
print('Heyho, its me from the loop')
```
```yaml
rules:
- name: "You can access filter data"
locations: ~/Desktop
filters:
- regex: '^(?P.*)\.(?P.*)$'
actions:
- python: |
print('Name: %s' % regex["name"])
print('Extension: %s' % regex["extension"])
```
Running in simulation and [yaml aliases](rules.md#advanced-aliases):
```yaml
my_python_script: &script |
print("Hello World!")
print(path)
rules:
- name: "Run in simulation and yaml alias"
locations:
- ~/Desktop/
actions:
- python:
code: *script
run_in_simulation: yes
```
You have access to all the python magic -- do a google search for each
filename starting with an underscore:
```yaml
rules:
- locations: ~/Desktop
filters:
- name:
startswith: "_"
actions:
- python: |
import webbrowser
webbrowser.open('https://www.google.com/search?q=%s' % name)
```
## rename
::: organize.actions.Rename
**Examples:**
```yaml
rules:
- name: "Convert all .PDF file extensions to lowercase (.pdf)"
locations: "~/Desktop"
filters:
- name
- extension: PDF
actions:
- rename: "{name}.pdf"
```
```yaml
rules:
- name: "Convert **all** file extensions to lowercase"
locations: "~/Desktop"
filters:
- name
- extension
actions:
- rename: "{name}.{extension.lower()}"
```
## shell
::: organize.actions.Shell
**Examples:**
```yaml
rules:
- name: "On macOS: Open all pdfs on your desktop"
locations: "~/Desktop"
filters:
- extension: pdf
actions:
- shell: 'open "{path}"'
```
## symlink
::: organize.actions.Symlink
## trash
::: organize.actions.Trash
**Examples:**
```yaml
rules:
- name: Move all JPGs and PNGs on the desktop which are older than one year into the trash
locations: "~/Desktop"
filters:
- lastmodified:
years: 1
mode: older
- extension:
- png
- jpg
actions:
- trash
```
## write
::: organize.actions.Write
**Examples**
```yaml
rules:
- name: "Record file sizes"
locations: ~/Downloads
filters:
- size
actions:
- write:
outfile: "./sizes.txt"
text: "{size.traditional} -- {relative_path}"
mode: "append"
clear_before_first_write: true
```
This will create a file `sizes.txt` in the current working folder which contains the
filesizes of everything in the `~/Downloads` folder:
```
2.9 MB -- SIM7600.pdf
1.0 MB -- Bildschirmfoto 2022-07-05 um 10.43.16.png
5.9 MB -- Albumcover.png
51.2 KB -- Urlaubsantrag 2022-04-19.pdf
1.8 MB -- ETH_USB_HUB_HAT.pdf
2.1 MB -- ArduinoDUE_V02g_sch.pdf
...
```
You can use templates both in the text as well as in the textfile parameter:
```yaml
rules:
- name: "File sizes by extension"
locations: ~/Downloads
filters:
- size
- extension
actions:
- write:
outfile: "./sizes.{extension}.txt"
text: "{size.traditional} -- {relative_path}"
mode: "prepend"
clear_before_first_write: true
```
This will separate the filesizes by extension.
organize-3.3.0/docs/changelog.md 0000664 0000000 0000000 00000000112 14721113403 0016522 0 ustar 00root root 0000000 0000000 {%
include-markdown "../CHANGELOG.md"
rewrite-relative-urls=true
%}
organize-3.3.0/docs/configuration.md 0000664 0000000 0000000 00000004251 14721113403 0017452 0 ustar 00root root 0000000 0000000 # Configuration
## Editing the configuration
organize has a default config file if no other file is given.
To edit the default configuration file:
```sh
organize edit # opens in $EDITOR
organize edit --editor=vim
EDITOR=code organize edit
```
To open the folder containing the configuration file:
```sh
organize show
organize show --path # show the full path to the default config
```
To check your configuration run:
```sh
organize check
organize check --debug # check with debug output
```
## Running and simulating
To run / simulate the default config file:
```sh
organize sim
organize run
```
To run / simulate a specific config file:
```shell
organize sim [FILE]
organize run [FILE]
```
Optionally you can specify the working directory like this:
```shell
organize sim [FILE] --working-dir=~/Documents
```
## Running specific rules of your config
You can tag your rules like this:
```yml
rules:
- name: My first rule
actions:
- echo: "Hello world"
tags:
- debug
- fast
```
Then use the command line options `--tags` and `--skip-tags` so select the rules you
want to run. The options take a comma-separated list of tags:
```
organize sim --tags=debug,foo --skip-tags=slow
```
Special tags:
- Rules tagged with the special tag `always` will always run
(except if `--skip-tags=always` is specified)
- Rules tagged with the special tag `never` will never run
(except if ' `--tags=never` is specified)
## Environment variables
- `ORGANIZE_CONFIG` - The path to the default config file.
- `ORGANIZE_EXIFTOOL_PATH` - Path to the `exiftool` executable (Default: `""`)
- `ORGANIZE_NORMALIZE_UNICODE` - Whether to normalize strings to NFC unicode form for comparisons (Default `"1"`)
- `NO_COLOR` - if this is set, the output is not colored.
- `EDITOR` - The editor used to edit the config file.
## Parallelize jobs
To speed up organizing you can run multiple organize processes simultaneously like this
(linux / macOS):
```shell
organize run config_1.yaml & \
organize run config_2.yaml & \
organize run config_3.yaml &
```
Make sure that the config files are independent from each other, meaning that no rule
depends on another rule in another config file.
organize-3.3.0/docs/docker.md 0000664 0000000 0000000 00000002473 14721113403 0016056 0 ustar 00root root 0000000 0000000 # Using the organize docker image
The organize docker image comes preinstalled with `exiftool` and `pdftotext` as well as
all the python dependencies set up and ready to go.
!!! danger
As organize is mainly used for moving files around you have to be careful about your
volume mounts and paths. **If you move a file to a folder which is not persisted
it is gone as soon as the container is stopped!**
## Building the image
`cd` into the organize folder (containing the `Dockerfile`) and build the image:
```sh
docker build -t organize .
```
The image is now tagged as `organize`. Now you can test the image by running
```sh
docker run organize
```
This will show the organize usage help text.
## Running
Let's create a basic config file `docker-conf.yml`:
```yml
rules:
- locations: /data
actions:
- echo: "Found file: {path}"
```
We can now run mount the config file to the container path `/config/config.yml`. The current directory is mounted to `/data` so we have some files present.
We can now start the container:
```sh
docker run -v ./docker-conf.yml:/config/config.yml -v .:/data organize run
```
### Passing the config file from stdin
Instead of mounting the config file into the container you can also pass it from stdin:
```sh
docker run -i organize check --stdin < ./docker-conf.yml
```
organize-3.3.0/docs/filters.md 0000664 0000000 0000000 00000034575 14721113403 0016267 0 ustar 00root root 0000000 0000000 # Filters
This page shows the specifics of each filter.
## - How to exclude filters -
To exclude a filter, prefix the filter name with **not** (e.g. `"not empty"`,
`"not extension": jpg`, etc).
!!! note
If you want to exclude all filters you can set the rule's `filter_mode` to `none`.
Example:
```yaml
rules:
# using filter_mode
- locations: ~/Desktop
filter_mode: "none" # <- excludes all
filters:
- empty
- name:
endswith: "2022"
actions:
- echo: "{name}"
# Exclude a single filter
- locations: ~/Desktop
filters:
- not extension: jpg # <- matches all non-jpgs
- name:
startswith: "Invoice"
- not empty # <- matches files with content
actions:
- echo: "{name}"
```
## created
::: organize.filters.Created
**Examples:**
Show all files on your desktop created at least 10 days ago
```yaml
rules:
- name: Show all files on your desktop created at least 10 days ago
locations: "~/Desktop"
filters:
- created:
days: 10
actions:
- echo: "Was created at least 10 days ago"
```
Show all files on your desktop which were created within the last 5 hours
```yaml
rules:
- name: Show all files on your desktop which were created within the last 5 hours
locations: "~/Desktop"
filters:
- created:
hours: 5
mode: newer
actions:
- echo: "Was created within the last 5 hours"
```
Sort pdfs by year of creation
```yaml
rules:
- name: Sort pdfs by year of creation
locations: "~/Documents"
filters:
- extension: pdf
- created
actions:
- move: "~/Documents/PDF/{created.year}/"
```
Formatting the creation date
```yaml
rules:
- name: Display the creation date
locations: "~/Documents"
filters:
- extension: pdf
- created
actions:
- echo: "ISO Format: {created.strftime('%Y-%m-%d')}"
- echo: "As timestamp: {created.timestamp() | int}"
```
## date_added
::: organize.filters.DateAdded
Works the same way as [`created`](#created) and [`lastmodified`](#lastmodified).
** Examples **
```yaml
rules:
- name: Show the date the file was added to the folder
locations: "~/Desktop"
filters:
- date_added
actions:
- echo: "Date added: {date_added.strftime('%Y-%m-%d')}"
```
## date_lastused
::: organize.filters.DateLastUsed
Works the same way as [`created`](#created) and [`lastmodified`](#lastmodified).
** Examples **
```yaml
rules:
- name: Show the date the file was added to the folder
locations: "~/Desktop"
filters:
- date_lastused
actions:
- echo: "Date last used: {date_lastused.strftime('%Y-%m-%d')}"
```
## duplicate
::: organize.filters.Duplicate
**Examples:**
Show all duplicate files in your desktop and download folder (and their subfolders)
```yaml
rules:
- name: Show all duplicate files in your desktop and download folder (and their subfolders)
locations:
- ~/Desktop
- ~/Downloads
subfolders: true
filters:
- duplicate
actions:
- echo: "{path} is a duplicate of {duplicate.original}"
```
Check for duplicated files between Desktop and a Zip file, select original by creation date
```yaml
rules:
- name: "Check for duplicated files between Desktop and a Zip file, select original by creation date"
locations:
- ~/Desktop
- zip://~/Desktop/backup.zip
filters:
- duplicate:
detect_original_by: "created"
actions:
- echo: "Duplicate found!"
```
## empty
::: organize.filters.Empty
**Examples:**
Recursively delete empty folders
```yaml
rules:
- targets: dirs
locations:
- path: ~/Desktop
max_depth: null
filters:
- empty
actions:
- delete
```
## exif
::: organize.filters.Exif
Show available EXIF data of your pictures
```yaml
rules:
- name: "Show available EXIF data of your pictures"
locations:
- path: ~/Pictures
max_depth: null
filters:
- exif
actions:
- echo: "{exif}"
```
Copy all images which contain GPS information while keeping subfolder structure:
```yaml
rules:
- name: "GPS demo"
locations:
- path: ~/Pictures
max_depth: null
filters:
- exif: gps.gpsdate
actions:
- copy: ~/Pictures/with_gps/{relative_path}/
```
Filter by camera manufacturer
```yaml
rules:
- name: "Filter by camera manufacturer"
locations:
- path: ~/Pictures
max_depth: null
filters:
- exif:
image.model: Nikon D3200
actions:
- move: "~/Pictures/My old Nikon/"
```
Sort images by camera manufacturer. This will create folders for each camera model
(for example "Nikon D3200", "iPhone 6s", "iPhone 5s", "DMC-GX80") and move the pictures
accordingly:
```yaml
rules:
- name: "camera sort"
locations:
- path: ~/Pictures
max_depth: null
filters:
- extension: jpg
- exif: image.model
actions:
- move: "~/Pictures/{exif.image.model}/"
```
## extension
::: organize.filters.Extension
**Examples:**
Match a single file extension
```yaml
rules:
- name: "Match a single file extension"
locations: "~/Desktop"
filters:
- extension: png
actions:
- echo: "Found PNG file: {path}"
```
Match multiple file extensions
```yaml
rules:
- name: "Match multiple file extensions"
locations: "~/Desktop"
filters:
- extension:
- .jpg
- jpeg
actions:
- echo: "Found JPG file: {path}"
```
Make all file extensions lowercase
```yaml
rules:
- name: "Make all file extensions lowercase"
locations: "~/Desktop"
filters:
- extension
actions:
- rename: "{path.stem}.{extension.lower()}"
```
Using extension lists ([yaml aliases](rules.md#advanced-aliases)
```yaml
img_ext: &img
- png
- jpg
- tiff
audio_ext: &audio
- mp3
- wav
- ogg
rules:
- name: "Using extension lists"
locations: "~/Desktop"
filters:
- extension:
- *img
- *audio
actions:
- echo: "Found media file: {path}"
```
## filecontent
::: organize.filters.FileContent
**Examples:**
Show the content of all your PDF files
```yaml
rules:
- name: "Show the content of all your PDF files"
locations: ~/Documents
filters:
- extension: pdf
- filecontent
actions:
- echo: "{filecontent}"
```
Match an invoice with a regular expression and sort by customer
```yaml
rules:
- name: "Match an invoice with a regular expression and sort by customer"
locations: "~/Desktop"
filters:
- filecontent: 'Invoice.*Customer (?P\w+)'
actions:
- move: "~/Documents/Invoices/{filecontent.customer}/"
```
Exampe to filter the filename with respect to a valid date code.
The filename should start with `--`.
Regex:
1. creates a placeholder variable containing the year
2. allows only years which start with 20 and are followed by 2 numbers
3. months can only have as first digit 0 or 1 and must be followed by a number
4. days can only have 0, 1,2 or 3 and must followed by number
Note: Filter is not perfect but still.
```yaml
rules:
- locations: ~/Desktop
filters:
- regex: '(?P20\d{2})-[01]\d-[0123]\d.*'
actions:
- echo: "Year: {regex.year}"
```
!!! note
If you have trouble getting the filecontent filter to work, have a look at the
[installation hints](textract-hints.md)
## hash
::: organize.filters.Hash
**Examples:**
Show the hashes of your files:
```yaml
rules:
- name: "Show the hashes and size of your files"
locations: "~/Desktop"
filters:
- hash
- size
actions:
- echo: "{hash} {size.decimal}"
```
## lastmodified
::: organize.filters.LastModified
**Examples:**
```yaml
rules:
- name: "Show all files on your desktop last modified at least 10 days ago"
locations: "~/Desktop"
filters:
- lastmodified:
days: 10
actions:
- echo: "Was modified at least 10 days ago"
```
Show all files on your desktop which were modified within the last 5 hours:
```yaml
rules:
- locations: "~/Desktop"
filters:
- lastmodified:
hours: 5
mode: newer
actions:
- echo: "Was modified within the last 5 hours"
```
Sort pdfs by year of last modification
```yaml
rules:
- name: "Sort pdfs by year of last modification"
locations: "~/Documents"
filters:
- extension: pdf
- lastmodified
actions:
- move: "~/Documents/PDF/{lastmodified.year}/"
```
Formatting the last modified date
```yaml
rules:
- name: Formatting the lastmodified date
locations: "~/Documents"
filters:
- extension: pdf
- lastmodified
actions:
- echo: "ISO Format: {lastmodified.strftime('%Y-%m-%d')}"
- echo: "As timestamp: {lastmodified.timestamp() | int}"
```
## macos_tags
::: organize.filters.MacOSTags
**Examples:**
```yaml
rules:
- name: "Only files with a red macOS tag"
locations: "~/Downloads"
filters:
- macos_tags: "* (red)"
actions:
- echo: "File with red tag"
```
```yaml
rules:
- name: "All files tagged 'Invoice' (any color)"
locations: "~/Downloads"
filters:
- macos_tags: "Invoice (*)"
actions:
- echo: "Invoice found"
```
```yaml
rules:
- name: "All files with a tag 'Invoice' (any color) or with a green tag"
locations: "~/Downloads"
filters:
- macos_tags:
- "Invoice (*)"
- "* (green)"
actions:
- echo: "Match found!"
```
```yaml
rules:
- name: "Listing file tags"
locations: "~/Downloads"
filters:
- macos_tags
actions:
- echo: "{macos_tags}"
```
## mimetype
::: organize.filters.MimeType
**Examples:**
Show MIME types
```yaml
rules:
- name: "Show MIME types"
locations: "~/Downloads"
filters:
- mimetype
actions:
- echo: "{mimetype}"
```
Filter by 'image' mimetype
```yaml
rules:
- name: "Filter by 'image' mimetype"
locations: "~/Downloads"
filters:
- mimetype: image
actions:
- echo: "This file is an image: {mimetype}"
```
Filter by specific MIME type
```yaml
rules:
- name: Filter by specific MIME type
locations: "~/Desktop"
filters:
- mimetype: application/pdf
actions:
- echo: "Found a PDF file"
```
Filter by multiple specific MIME types
```yaml
rules:
- name: Filter by multiple specific MIME types
locations: "~/Music"
filters:
- mimetype:
- application/pdf
- audio/midi
actions:
- echo: "Found Midi or PDF."
```
## name
::: organize.filters.Name
**Examples:**
Match all files starting with 'Invoice':
```yaml
rules:
- locations: "~/Desktop"
filters:
- name:
startswith: Invoice
actions:
- echo: "This is an invoice"
```
Match all files starting with 'A' end containing the string 'hole'
(case insensitive):
```yaml
rules:
- locations: "~/Desktop"
filters:
- name:
startswith: A
contains: hole
case_sensitive: false
actions:
- echo: "Found a match."
```
Match all files starting with 'A' or 'B' containing '5' or '6' and ending with
'\_end':
```yaml
rules:
- locations: "~/Desktop"
filters:
- name:
startswith:
- "A"
- "B"
contains:
- "5"
- "6"
endswith: _end
case_sensitive: false
actions:
- echo: "Found a match."
```
## python
::: organize.filters.Python
**Examples:**
```yaml
rules:
- name: A file name reverser.
locations: ~/Documents
filters:
- extension
- python: |
return {"reversed_name": path.stem[::-1]}
actions:
- rename: "{python.reversed_name}.{extension}"
```
A filter for odd student numbers. Assuming the folder `~/Students` contains
the files `student-01.jpg`, `student-01.txt`, `student-02.txt` and
`student-03.txt` this rule will print
`"Odd student numbers: student-01.txt"` and
`"Odd student numbers: student-03.txt"`
```yaml
rules:
- name: "Filter odd student numbers"
locations: ~/Students/
filters:
- python: |
return int(path.stem.split('-')[1]) % 2 == 1
actions:
- echo: "Odd student numbers: {path.name}"
```
Advanced usecase. You can access data from previous filters in your python code.
This can be used to match files and capturing names with a regular expression
and then renaming the files with the output of your python script.
```yaml
rules:
- name: "Access placeholders in python filter"
locations: files
filters:
- extension: txt
- regex: (?P\w+)-(?P\w+)\..*
- python: |
emails = {
"Betts": "dbetts@mail.de",
"Cornish": "acornish@google.com",
"Bean": "dbean@aol.com",
"Frey": "l-frey@frey.org",
}
if regex.lastname in emails: # get emails from wherever
return {"mail": emails[regex.lastname]}
actions:
- rename: "{python.mail}.txt"
```
Result:
- `Devonte-Betts.txt` becomes `dbetts@mail.de.txt`
- `Alaina-Cornish.txt` becomes `acornish@google.com.txt`
- `Dimitri-Bean.txt` becomes `dbean@aol.com.txt`
- `Lowri-Frey.txt` becomes `l-frey@frey.org.txt`
- `Someunknown-User.txt` remains unchanged because the email is not found
## regex
::: organize.filters.Regex
**Examples:**
Match an invoice with a regular expression:
```yaml
rules:
- locations: "~/Desktop"
filters:
- regex: '^RG(\d{12})-sig\.pdf$'
actions:
- move: "~/Documents/Invoices/1und1/"
```
Match and extract data from filenames with regex named groups:
This is just like the previous example but we rename the invoice using
the invoice number extracted via the regular expression and the named
group `the_number`.
```yaml
rules:
- locations: ~/Desktop
filters:
- regex: '^RG(?P\d{12})-sig\.pdf$'
actions:
- move: ~/Documents/Invoices/1und1/{regex.the_number}.pdf
```
## size
::: organize.filters.Size
**Examples:**
Trash big downloads:
```yaml
rules:
- locations: "~/Downloads"
targets: files
filters:
- size: "> 0.5 GB"
actions:
- trash
```
Move all JPEGS bigger > 1MB and <10 MB. Search all subfolders and keep the
original relative path.
```yaml
rules:
- locations:
- path: "~/Pictures"
max_depth: null
filters:
- extension:
- jpg
- jpeg
- size: ">1mb, <10mb"
actions:
- move: "~/Pictures/sorted/{relative_path}/"
```
organize-3.3.0/docs/img/ 0000775 0000000 0000000 00000000000 14721113403 0015033 5 ustar 00root root 0000000 0000000 organize-3.3.0/docs/img/organize-v3.jpg 0000664 0000000 0000000 00000755706 14721113403 0017725 0 ustar 00root root 0000000 0000000 JFIF ` ` dICC_PROFILE Tlcms0 mntrRGB XYZ % acspAPPL -lcms desc >cprt H Lwtpt chad ,rXYZ bXYZ gXYZ rTRC gTRC bTRC chrm 0 $mluc enUS " s R G B I E C 6 1 9 6 6 - 2 . 1 mluc enUS 0 N o c o p y r i g h t , u s e f r e e l yXYZ -sf32 B % nXYZ o 8 XYZ $ XYZ b para ff
Y
[chrm T{ L &f