v1.0.2: multi-episode rename (S01E01-E02), VERSION file, docs
Made-with: Cursor
This commit is contained in:
Binary file not shown.
@@ -7,7 +7,7 @@ A **native Linux** GUI for mass renaming files. Inspired by [Bulk Rename Utility
|
|||||||
- **GUI** – Structure renames with rule panels; no command line needed.
|
- **GUI** – Structure renames with rule panels; no command line needed.
|
||||||
- **Preview** – See “Original → New name” for every file before committing.
|
- **Preview** – See “Original → New name” for every file before committing.
|
||||||
- **Multiple rules** – Combine rules (order: Replace → Regex → Insert → Remove → Case → Numbering → Episode renumber → Prefix/Suffix). Enable only the rules you need.
|
- **Multiple rules** – Combine rules (order: Replace → Regex → Insert → Remove → Case → Numbering → Episode renumber → Prefix/Suffix). Enable only the rules you need.
|
||||||
- **Episode renumbering** – Replace episode numbers (e.g. `S01E05 - Title` → `S01E01 - Title`) while keeping season and title. Start number and zero-padding configurable.
|
- **Episode renumbering** – Replace episode numbers (e.g. `S01E05 - Title` → `S01E01 - Title`) while keeping season and title. Multi-episode files like `S01E05-E06` become `S01E01-E02` (range length preserved). Start, step, and zero-padding configurable.
|
||||||
- **Replace / Regex** – Plain text find/replace or full regex with capture groups.
|
- **Replace / Regex** – Plain text find/replace or full regex with capture groups.
|
||||||
- **Insert / Remove** – Insert text at start/end/position; remove text, digits, or first/last N characters.
|
- **Insert / Remove** – Insert text at start/end/position; remove text, digits, or first/last N characters.
|
||||||
- **Case** – Title Case, UPPER, lower, Sentence case.
|
- **Case** – Title Case, UPPER, lower, Sentence case.
|
||||||
@@ -62,6 +62,10 @@ Sort order is the current list order (alphabetical by filename). Reorder files i
|
|||||||
3. Enable **9. CSV mapping**, click **Browse…** and select the CSV.
|
3. Enable **9. CSV mapping**, click **Browse…** and select the CSV.
|
||||||
4. Only rows that match a current filename in the folder are renamed; others are unchanged. You can combine with other rules (CSV is applied in rule order).
|
4. Only rows that match a current filename in the folder are renamed; others are unchanged. You can combine with other rules (CSV is applied in rule order).
|
||||||
|
|
||||||
|
## Gear Lever (AppImage updates)
|
||||||
|
|
||||||
|
To have [Gear Lever](https://github.com/mijorus/gearlever) see new releases when we push them and update the AppImage from there, see **[docs/GEARLEVER.md](docs/GEARLEVER.md)** for configuration (custom update URL for Gitea, or static URL).
|
||||||
|
|
||||||
## AppImage (distribution)
|
## AppImage (distribution)
|
||||||
|
|
||||||
To build a portable AppImage:
|
To build a portable AppImage:
|
||||||
|
|||||||
+9
-1
@@ -54,9 +54,17 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "=== Building AppImage (requires appimagetool) ==="
|
echo "=== Building AppImage (requires appimagetool) ==="
|
||||||
|
# Optional: set VERSION when building for release so update info is embedded (for Gear Lever etc.)
|
||||||
|
# e.g. VERSION=v1.0.1 ./build_appimage.sh
|
||||||
|
GITEA_RELEASES="http://brassnet.ddns.net:33983/Dawnsorrow/HS-Rename/releases"
|
||||||
|
UPDATE_INFO=""
|
||||||
|
if [[ -n "${VERSION:-}" ]]; then
|
||||||
|
UPDATE_INFO="-u url|${GITEA_RELEASES}/download/${VERSION}/HSRename.AppImage"
|
||||||
|
fi
|
||||||
if command -v appimagetool &>/dev/null; then
|
if command -v appimagetool &>/dev/null; then
|
||||||
OUT="${APP_NAME}.AppImage"
|
OUT="${APP_NAME}.AppImage"
|
||||||
appimagetool "$APPDIR" "$OUT"
|
# shellcheck disable=SC2086
|
||||||
|
appimagetool $UPDATE_INFO "$APPDIR" "$OUT"
|
||||||
echo "Done: $OUT"
|
echo "Done: $OUT"
|
||||||
else
|
else
|
||||||
echo "AppDir is ready at $APPDIR/"
|
echo "AppDir is ready at $APPDIR/"
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# Using HSRename with Gear Lever
|
||||||
|
|
||||||
|
[Gear Lever](https://github.com/mijorus/gearlever) can manage and update the HSRename AppImage. Because releases are hosted on **Gitea** (not GitHub), use one of the options below.
|
||||||
|
|
||||||
|
## Option 1: Custom update URL (recommended to try first)
|
||||||
|
|
||||||
|
Gitea uses the same release path style as GitHub:
|
||||||
|
`/owner/repo/releases/download/{tag}/{filename}`
|
||||||
|
|
||||||
|
1. Open **Gear Lever** and add the HSRename AppImage (drag & drop or **Add**).
|
||||||
|
2. Select the HSRename entry and open **Update** / **Custom update URL** (or the equivalent in your Gear Lever version).
|
||||||
|
3. Try this URL pattern (with a wildcard for the tag):
|
||||||
|
```
|
||||||
|
http://brassnet.ddns.net:33983/Dawnsorrow/HS-Rename/releases/download/*/HSRename.AppImage
|
||||||
|
```
|
||||||
|
4. If Gear Lever accepts it (e.g. field turns green or validates), it may use the Gitea releases page to resolve the latest tag and offer updates when you push new releases.
|
||||||
|
5. Use **Check for updates** / **List updates** to see if it detects new versions.
|
||||||
|
|
||||||
|
If your Gear Lever only supports GitHub-style URLs and rejects this, use Option 2.
|
||||||
|
|
||||||
|
## Option 2: Static URL (manual update link)
|
||||||
|
|
||||||
|
If the wildcard URL does not work:
|
||||||
|
|
||||||
|
1. In Gear Lever, add HSRename and set **Update** to **Static URL**.
|
||||||
|
2. Paste the **direct download URL** of the current release, for example:
|
||||||
|
- **v1.0.1:**
|
||||||
|
`http://brassnet.ddns.net:33983/Dawnsorrow/HS-Rename/releases/download/v1.0.1/HSRename.AppImage`
|
||||||
|
3. When a new version is released (e.g. v1.0.2), open the [releases page](http://brassnet.ddns.net:33983/Dawnsorrow/HS-Rename/releases), open the new release, right‑click **HSRename.AppImage** → **Copy link address**, then in Gear Lever set the Static URL to that new link and run **Update**.
|
||||||
|
|
||||||
|
So: Gear Lever will only “see” updates if you change the Static URL to the new release’s download link when you want to update.
|
||||||
|
|
||||||
|
## Option 3: CLI (if you use Gear Lever from the terminal)
|
||||||
|
|
||||||
|
After adding the AppImage in Gear Lever, you can set the update URL from the command line:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set custom update URL (try the wildcard pattern)
|
||||||
|
gearlever --set-update-url /path/to/HSRename.AppImage "http://brassnet.ddns.net:33983/Dawnsorrow/HS-Rename/releases/download/*/HSRename.AppImage"
|
||||||
|
|
||||||
|
# Check for updates
|
||||||
|
gearlever --list-updates
|
||||||
|
|
||||||
|
# Apply update
|
||||||
|
gearlever --update /path/to/HSRename.AppImage
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `/path/to/HSRename.AppImage` with the actual path where Gear Lever stores the AppImage.
|
||||||
|
|
||||||
|
## Release download URL pattern
|
||||||
|
|
||||||
|
For any release tag `vX.Y.Z`, the direct download URL is:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://brassnet.ddns.net:33983/Dawnsorrow/HS-Rename/releases/download/vX.Y.Z/HSRename.AppImage
|
||||||
|
```
|
||||||
|
|
||||||
|
So when we push a new release (e.g. v1.0.2), that new tag’s URL is what Gear Lever needs (either via the wildcard in Option 1 or by pasting the new URL in Option 2).
|
||||||
+33
-7
@@ -201,14 +201,14 @@ class NumberingRule(Rule):
|
|||||||
return stem, ext
|
return stem, ext
|
||||||
|
|
||||||
|
|
||||||
# Episode renumber: match SxxExx or similar, replace episode number only, keep title
|
# Episode renumber: match SxxExx or SxxExx-Eyy, replace episode block; keep title
|
||||||
@dataclass
|
@dataclass
|
||||||
class EpisodeRenumberRule(Rule):
|
class EpisodeRenumberRule(Rule):
|
||||||
start: int = 1
|
start: int = 1
|
||||||
step: int = 1
|
step: int = 1
|
||||||
padding: int = 2
|
padding: int = 2
|
||||||
# Pattern: group 1 = prefix (e.g. "S01E"), group 2 = episode digits, group 3 = rest (title)
|
# Group 1 = prefix (e.g. "S01E"), 2 = first ep digits, 3 = full "-E06" or None, 4 = second ep if range, 5 = rest (title)
|
||||||
pattern: str = r"(.*?[Ss]\d+[Ee])(\d+)(.*)"
|
pattern: str = r"(.*?[Ss]\d+[Ee])(\d+)(-[Ee](\d+))?(.*)"
|
||||||
|
|
||||||
def apply(
|
def apply(
|
||||||
self,
|
self,
|
||||||
@@ -224,10 +224,36 @@ class EpisodeRenumberRule(Rule):
|
|||||||
return stem, ext
|
return stem, ext
|
||||||
if not m:
|
if not m:
|
||||||
return stem, ext
|
return stem, ext
|
||||||
prefix, _old_ep, rest = m.group(1), m.group(2), m.group(3)
|
prefix, old_first_s, range_dash_e, old_second_s, rest = (
|
||||||
ep_num = self.start + index * self.step
|
m.group(1),
|
||||||
ep_str = str(ep_num).zfill(max(1, self.padding))
|
m.group(2),
|
||||||
new_stem = f"{prefix}{ep_str}{rest}"
|
m.group(3),
|
||||||
|
m.group(4),
|
||||||
|
m.group(5),
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
old_first = int(old_first_s)
|
||||||
|
except ValueError:
|
||||||
|
return stem, ext
|
||||||
|
span = 1
|
||||||
|
if old_second_s is not None:
|
||||||
|
try:
|
||||||
|
old_second = int(old_second_s)
|
||||||
|
except ValueError:
|
||||||
|
return stem, ext
|
||||||
|
span = old_second - old_first + 1
|
||||||
|
if span < 1:
|
||||||
|
span = 1
|
||||||
|
ep_new_first = self.start + index * self.step
|
||||||
|
pad = max(1, self.padding)
|
||||||
|
e1 = str(ep_new_first).zfill(pad)
|
||||||
|
if span <= 1:
|
||||||
|
new_stem = f"{prefix}{e1}{rest}"
|
||||||
|
else:
|
||||||
|
ep_new_last = ep_new_first + span - 1
|
||||||
|
e2 = str(ep_new_last).zfill(pad)
|
||||||
|
# Match common style: S01E01-E02 (second block uses E again)
|
||||||
|
new_stem = f"{prefix}{e1}-E{e2}{rest}"
|
||||||
return new_stem, ext
|
return new_stem, ext
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -285,7 +285,10 @@ class EpisodeRenumberRuleWidget(QWidget):
|
|||||||
layout.addRow("First episode number:", self.start)
|
layout.addRow("First episode number:", self.start)
|
||||||
layout.addRow("Step:", self.step)
|
layout.addRow("Step:", self.step)
|
||||||
layout.addRow("Zero-pad width:", self.padding)
|
layout.addRow("Zero-pad width:", self.padding)
|
||||||
info = QLabel("Matches patterns like S01E05 - Title or Show 1x03 - Title. Episode number is replaced; title is kept.")
|
info = QLabel(
|
||||||
|
"Matches S01E05 - Title (single) or S01E05-E06 - Title (two-part). "
|
||||||
|
"Ranges keep their length: S01E01-E02, S01E03-E04, … Order follows the file list / table sort."
|
||||||
|
)
|
||||||
info.setWordWrap(True)
|
info.setWordWrap(True)
|
||||||
layout.addRow(info)
|
layout.addRow(info)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user