Compare commits

...

16 Commits
v3.0 ... master

3 changed files with 117 additions and 10 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
dist/

47
README.md Normal file
View File

@ -0,0 +1,47 @@
# shunt-tags
Script to rename filenames in a certain way.
`shunt_tags` shunt tags to the end of filenames, transforming `[RELEASEGROUP] Title - Episode [CRC32].mkv` into `Title - Episode [RELEASEGROUP CRC32].mkv`, in order to improve alphabetical sort ordering. The original goal has expanded into a large number of transforms with a comprehensive test suite.
## Usage
```
Usage:
shunt_tags [OPTIONS]
Options:
-y --accept Apply updates without prompting. (false)
-d --directory DIR Set directory. (pwd)
--display table|dump|none Choose display mode. ('table')
-n --dry-run Display proposed updates and exit. (false)
--help, --usage Display this message
--interactive Prompt whether to apply updates. (true)
-q --quiet Quiet mode hides scanning progress. (false)
-qq --quiet2 Equivalent to "-q --display none"
-r --recursive Apply to subdirectories. (false)
--test-suite Run test suite and exit
--undo Display an undo script
```
## Changelog
2018-09-30 v3.1.0
- Apply titlecasing for all-lowercase filenames
- Support quirks for `[a-s]` filenames
- Fix an issue with running `shunt-tags` from the current working directory
2017-10-22 v3.0
- Rewritten in PHP
- Feature: Many more features now available via command-line arguments
2017-04-05 v2.0
- Rewritten in bash, now requires linux ports of `rren` and `pause`
- Feature: Support `--graphical` argument to relaunch itself under `xfce4-terminal`
201?-??-?? v1.5
- Support additional filename transforms
2015-01-17 v1.0
- Initial public release
- Written in batch, requires `rren` in path

View File

@ -2,7 +2,7 @@
<?php
/**
* Copyright (2017) The shunt_tags author(s)
* Copyright (2017-2018) The shunt_tags author(s)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -64,7 +64,7 @@ function fixup($input) {
} while (! array_key_exists($tmp, $seen));
return $tmp;
};
// Some files using underscore instead of space
// Except - preserve "G_P", that's a known sub group
// Iterate until fixed point
@ -85,6 +85,11 @@ function fixup($input) {
$tmp = preg_replace('~([^p])v2\b~i', '\1 [v2] ', $tmp); // They could be part of the episode number - pull them out - BUT don't pull out "PV2"
$tmp = preg_replace('~([^p])v3\b~i', '\1 [v3] ', $tmp);
$tmp = preg_replace('~([^p])v4\b~i', '\1 [v4] ', $tmp);
if (strpos($tmp, '[a-s]') !== false) {
// This sub group puts a team member username in the filename
$tmp = preg_replace('~\\b(rs2|pball)\\b~', '[\1]', $tmp);
}
// Remove nesting
$drop_nested_tags = function($tmp) {
@ -154,12 +159,7 @@ function fixup($input) {
return $tmp;
});
/*
// Move tags from middle to end
$tmp = $fixed_point_iterate($tmp, function($tmp) {
return preg_replace('~([^\[\]]+)(\[[^\]]+?\])([^\[\]]+)~', '\1\3\2', $tmp);
});
*/
// Cleanup commas inside tags ( [720p,Bluray] => [720p Bluray] )
$tmp = preg_replace_callback('~\[(.+)\]~', function($matches) { return str_replace(',', ' ', $matches[0]); }, $tmp);
@ -224,6 +224,59 @@ function fixup($input) {
// There's always a space before the tag
$tmp = preg_replace('~([^ ])\[~', '\1 [', $tmp);
// Title-case for sections (delimited by -/~)
$fix_title_cases = function($str) {
// First section: all words titlecase except the/and/or unless first word
$titlecase = function($str) {
$words = explode(" ", $str);
for($i = 0; $i < count($words); ++$i) {
if (strlen($words[$i]) == 0) {
continue;
}
if (
$i == 0 ||
!in_array($words[$i], ['and', 'or', 'of', 'on', 'the', 'in', 'no', 'a'])
) {
$words[$i][0] = strtoupper($words[$i][0]);
}
}
return implode(" ", $words);
};
// Second section: enforce first character uppercase if not already
$weaktitlecase = function($str) {
if (!ctype_upper($str[0])) {
$str[0] = strtoupper($str[0]);
}
return $str;
};
// Only process up to the first [ (if one exists)
$spos = strpos($str, '[');
$consider = substr($str, 0, $spos);
$sections = preg_split('~( - | \~ )~', $consider, -1, PREG_SPLIT_DELIM_CAPTURE);
#var_dump($sections);
#die();
for($i = 0; $i < count($sections); $i += 2) {
if (strlen($sections[$i]) == 0) {
continue;
}
if ($i == 0) {
$sections[$i] = $titlecase($sections[$i]);
} else {
$sections[$i] = $weaktitlecase($sections[$i]);
}
}
return implode("", $sections).substr($str, $spos);
};
$tmp = $fix_title_cases($tmp);
// Special fixups:
// Fixup [Saiyan]BrollY, that's a sub group
$tmp = str_replace('SaiyanBrollY', '[Saiyan]BrollY', $tmp);
@ -252,6 +305,12 @@ function fixup($input) {
function tests() {
$tests = [
"[a-s]_you're_under_arrest_-_07_-_strike_man_~_defender_of_justice__rs2_[54AEE83C].mkv"
=> "You're Under Arrest - 07 - Strike man ~ Defender of justice [a-s rs2 54AEE83C].mkv"
,
"[a-s]_a_certain_scientific_railgun_-_17_-_tsuzuri's_summer_vacation__pball_[1080p_bd-rip][2C2AE93D].mkv"
=> "A Certain Scientific Railgun - 17 - Tsuzuri's summer vacation [a-s pball 1080p BD 2C2AE93D].mkv"
,
'[gg]_Valvrave_the_Liberator_-_12_[F9F3F5C5].mkv'
=> 'Valvrave the Liberator - 12 [gg F9F3F5C5].mkv'
,
@ -445,7 +504,7 @@ function findFilesNeedingReplacement($basedir, $recursive, $quiet) {
$fname = $file->getFilename();
if (! preg_match("~\.(?:mkv|mp4|avi|ogm|ogv)$~", $fname)) {
if (! preg_match("~\\.(?:mkv|mp4|avi|ogm|ogv)$~", $fname)) {
continue;
}
@ -543,7 +602,7 @@ EOD;
function main($argv) {
$recursive = false;
$directory = __DIR__;
$directory = getcwd(); // __DIR__;
$dryrun = false;
$shouldprompt = true;
$displaymode = "table";