1 Commits

Author SHA1 Message Date
Bulk Renamer 76574e2bee v1.0.2: multi-episode rename (S01E01-E02), VERSION file, docs
Made-with: Cursor
2026-03-29 20:50:00 -05:00
7 changed files with 110 additions and 10 deletions
BIN
View File
Binary file not shown.
+5 -1
View File
@@ -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:
+1
View File
@@ -0,0 +1 @@
1.0.2
+9 -1
View File
@@ -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/"
+58
View File
@@ -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, rightclick **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 releases 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 tags URL is what Gear Lever needs (either via the wildcard in Option 1 or by pasting the new URL in Option 2).
+33 -7
View File
@@ -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
View File
@@ -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)