Skip to content

Commit

Permalink
package
Browse files Browse the repository at this point in the history
  • Loading branch information
e3rd committed Sep 3, 2024
1 parent a03a7d3 commit 1ff8ded
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 32 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Upload Python Package
on:
push:
tags:
- '[0-9]+\.[0-9]+\.[0-9]+'
- '[0-9]+\.[0-9]+\.[0-9]+-?rc\.?[0-9]+'

jobs:
pypi:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Replace media paths in README.md
run: sed -E 's#(\]\((asset/[a-zA-Z0-9._-]+))#](https://github.com/CZ-NIC/mininterface/blob/main/\2?raw=True#g' README.md | less > README.md.tmp && mv README.md.tmp README.md
- name: Build the package
run: python3 -m pip install --upgrade build && python3 -m build
- name: Publish package
uses: pypa/[email protected]
with:
password: ${{ secrets.PYPI_GITHUB_TOUCHTIMESTAMP }}
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export TAG := `grep version pyproject.toml | pz --search '"(\d+\.\d+\.\d+(?:rc\d+))?"'`

release:
git tag $(TAG)
git push origin $(TAG)
82 changes: 79 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,80 @@
XXX asi z toho můžu udělat package na pypi
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)

Krusader user action command
`python3 ...gui-touch/gui-touch.py %aList("Selected")%`
Change file timestamps with a dialog window.

![Gui window](asset/mininterface-gui.avif "Graphical interface")

GUI automatically fallback to a text interface when display is not available.

![Text interface](asset/textual.avif "Runs in the terminal")


# Installation

Install with a single command from [PyPi](https://pypi.org/project/touch-timestamp/).

```bash
pip install touch-timestamp
```

Or eventually add [eel](https://github.com/python-eel/Eel) to provide browser-like GUI window.

```bash
pip install touch-timestamp[eel]
```

![Browser interface](asset/eel-gui.avif "Eel interface")

# Docs

## Exact date

When invoked with file paths, the program sets their modification times to the specified time.

![Gui window](asset/mininterface-gui.avif "Graphical interface")

## Fetch the time from the file name

Should you end up with files that keep the date in the file name, use the `--from-name` parameter.

```bash
$ touch-timestamp 20240828_160619.heic --from-name True
Changed 2001-01-01T12:00:00 → 2024-08-28T16:06:19: 20240828_160619.heic
```

## Full help

Use the `--help` to see full options.

```bash
$ touch-timestamp --help
usage: Touch [-h] [--eel | --no-eel] [--from-name {True,False}|STR]
[[PATH [PATH ...]]]

╭─ positional arguments ─────────────────────────────────────────────────────╮
│ [[PATH [PATH ...]]] │
│ Files the modification date is to be changed. (default: ) │
╰────────────────────────────────────────────────────────────────────────────╯
╭─ options ──────────────────────────────────────────────────────────────────╮
│ -h, --help │
│ show this help message and exit
│ --eel, --no-eel │
│ Prefer Eel GUI. (Set the date as in a chromium browser.) (default: │
│ True) │
│ --from-name {True,False}|STR │
│ Fetch the modification time from the file names stem. Set the format │
│ as for `datetime.strptime` like '%Y%m%d_%H%M%S'. │
│ If set to True, the format will be auto-detected. │
│ If a file name does not match the format or the format cannot be │
│ auto-detected, the file remains unchanged. │
│ │
│ │
│ Ex: `--from-name True 20240827_154252.heic` → modification time = │
│ 27.8.2024 15:42 (default: False) │
╰────────────────────────────────────────────────────────────────────────────╯
```


## Krusader user action

To change the file timestamps easily from Krusader, import this [user action](extra/touch-timestamp-krusader-useraction.xml): `touch-timestamp %aList("Selected")%`
Binary file added asset/eel-gui.avif
Binary file not shown.
Binary file added asset/mininterface-gui.avif
Binary file not shown.
Binary file added asset/textual.avif
Binary file not shown.
12 changes: 12 additions & 0 deletions extra/touch-timestamp-krusader-useraction.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE KrusaderUserActions>
<KrusaderUserActions>
<action name="touch-timestamp">
<title>&amp;touch-timestamp</title>
<tooltip>touch-timestamp</tooltip>
<category>Files</category>
<description>%aList("Selected")%</description>
<command>touch-timestamp %aList("Selected")%</command>
<defaultshortcut>Alt+Shift+T</defaultshortcut>
</action>
</KrusaderUserActions>
29 changes: 0 additions & 29 deletions gui-touch.py

This file was deleted.

22 changes: 22 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "touch-timestamp"
version = "0.3.0"
description = "Change file timestamps with a dialog window."
authors = ["Edvard Rejthar <[email protected]>"]
license = "GPL-3.0-or-later"
homepage = "https://github.com/CZ-NIC/touch-timestamp"
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10"
mininterface = "*"

[tool.poetry.extras]
eel = ["eel"]

[tool.poetry.scripts]
touch-timestamp = "touch_timestamp.touch_timestamp:main"
File renamed without changes.
104 changes: 104 additions & 0 deletions touch_timestamp/touch_timestamp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env python3
from dataclasses import dataclass, field
from datetime import datetime
from os import utime
from pathlib import Path

import dateutil.parser
from mininterface import run
from tyro.conf import Positional

try:
from eel import expose, init, start
eel = True
except ImportError:
eel = None


DateFormat = str # Use type as of Python3.12


@dataclass
class Env:
files: Positional[list[Path]] = field(default_factory=list)
""" Files the modification date is to be changed. """

eel: bool = True
""" Prefer Eel GUI. (Set the date as in a chromium browser.) """

from_name: bool | DateFormat = False
"""
Fetch the modification time from the file names stem. Set the format as for `datetime.strptime` like '%Y%m%d_%H%M%S'.
If set to True, the format will be auto-detected.
If a file name does not match the format or the format cannot be auto-detected, the file remains unchanged.
Ex: `--from-name True 20240827_154252.heic` → modification time = 27.8.2024 15:42
"""


def set_files_timestamp(date, time, files: list[str]):
print("Touching files", date, time)
print(", ".join(str(f) for f in files))
if date and time:
time = dateutil.parser.parse(date + " " + time).timestamp()
[utime(f, (time, time)) for f in files]
return True


def run_eel(files):
@expose
def get_len_files():
return len(files)

@expose
def get_first_file_date():
return Path(files[0]).stat().st_mtime

@expose
def set_timestamp(date, time):
return set_files_timestamp(date, time, files)

init(Path(__file__).absolute().parent.joinpath('static'))
start('index.html', size=(330, 30), port=0, block=True)


def main():
m = run(Env, prog="Touch")

if m.env.from_name:
for p in m.env.files:
if m.env.from_name is True: # auto detection
try:
# 20240828_160619.heic -> "20240828 160619" -> "28.8."
dt = dateutil.parser.parse(p.stem.replace("_", ""))
except ValueError:
print(f"Cannot auto detect the date format: {p}")
continue
else:
try:
dt = datetime.strptime(p.stem, m.env.from_name)
except ValueError:
print(f"Does not match the format {m.env.from_name}: {p}")
continue
timestamp = int(dt.timestamp())
original = datetime.fromtimestamp(p.stat().st_mtime)
utime(str(p), (timestamp, timestamp))
print(f"Changed {original.isoformat()}{dt.isoformat()}: {p}")
elif eel and m.env.eel: # set exact date with eel
run_eel(m.env.files)
else: # set exact date with Mininterface
if len(m.env.files) > 1:
title = f"Touch {len(m.env.files)} files"
else:
title = f"Touch {m.env.files[0].name}"

with m:
m.title = title # NOTE: Changing title does not work
date = datetime.fromtimestamp(Path(m.env.files[0]).stat().st_mtime)
output = {title: {"date": str(date.date()), "time": str(date.time())}}
m.form(output)
set_files_timestamp(output["date"], output["time"], m.env.files)


if __name__ == "__main__":
main()

0 comments on commit 1ff8ded

Please sign in to comment.