#1 2009-05-24 02:47

Yogui
Member
Registered: 2007-09-27
Posts: 41

Rearrange and Rename Folder Name Artist Album Pascal Script

Hi,

I’ve been searching for info to make a Pascal script (or something else) to rearrange folders names that contains music albums. Sorry I don’t have a clue how to do it. sad

The resulting mask is always the same:

…<Artist>\<Year>~<Album>

<Year> is the 4 Numbers year i.e. “1988”
<Album> is the album Name with comments in brackets i.e. “My Album Name (Disc 02)”

A few Examples to clarify:

A.    Name: “David Coverdale & Whitesnake\David Coverdale & Whitesnake-Restless Heart (1997)”
ReName to: “David Coverdale & Whitesnake\1997~ Restless Heart”

B.    Name: “Seltaeb Eht\Seltaeb Eht-Rockin' At The Star Club-1962”
ReName to: “Seltaeb Eht\1962~Rockin' At The Star Club”

C.    Name: “White Stripes\White Stripes-Live At London, Forum (06 12.2001)”
ReName to: “White Stripes\2001~Live At London, Forum (06 12)”

D.    Name: “Yawning Man\Yawning Man-Rock Formations”
ReName to: “Yawning Man\1900~Rock Formations”

E.    Name: “Van Halen\Van Halen Live Right Here, Right Now 1993 CD 1”
ReName to: “Van Halen\1993~Live Right Here, Right Now (Disc 01)”

What I understand it should happen is:

1.    String matching the <Artist> parent folder name is deleted.
This topic seems to be the closest to this kind of request, but I need to delete not append.
http://www.den4b.com/forum/viewtopic.php?id=604

2.    If a 4 Numbers String (between 1900 and 2100) is found is moved to the beginning and a tilde is inserted after it. If such string is not found “1900~” is inserted instead, for later fix.

3.    If a String like CD, C D etc is found followed by a number is placed at the end in the format “(Disc ##)” where the number is padded with ceros.

Thanks in advance for any help. big_smile

Cheers, Yogui.

Offline

#2 2009-06-04 00:03

prologician
Member
Registered: 2009-01-30
Posts: 84

Re: Rearrange and Rename Folder Name Artist Album Pascal Script

That's some tall order... little wonder no one's responded to this. The nice thing is, it seems like you have a good idea already of what needs to be done. Just need the extra little tidbit to get the final push done.

As hinted by your list of items, it might be good to break this into three different problems... one that removes the artist, one that picks out the date, and one that handles the CD numbering. And probably various amounts of cleaning up in between, for sanity.

I looked at the first problem, mainly because you gave a link. That was some good research you did, since you're right, it's very nearly what you need. I changed only one line from krtek's script, and it accomplishes the first item of your list:

var 
  Path, SubFolders : TStringsArray;
  Depth : Integer;
begin
  if not WideFileExists(FilePath) then
  begin
    SetLength(SubFolders,0);
    Path:=WideSplitString(FilePath,'\');
    WideScanDirForFolders(FilePath, SubFolders ,True, False, False);
    Depth:=Length(Path);
    If (Depth>1) and (Length(SubFolders)=0) then
      FileName := WideReplaceStr(Path[Depth-1],Path[Depth-2],'');
  end;
end.

As I said before... there needs some cleanup. With the five examples you gave, there is always one character between the artist and album title... whether that's a space or a hyphen. This can be cleared up using a Delete filter (at least, in these cases).

For your second bullet point, you can almost handle it with a regular expression.... except for that "if there is no year, use 1900 as the year" case. So, a second PascalScript to handle it.

begin
  if (Length(MatchesRegEx(FileName, '(19|20)\d{2}', false)) > 0) then
    FileName := ReplaceRegEx(FileName, '^(.*)(19|20)(\d{2})(.*)$', '$2$3~$1$4', false, true)
  else
    FileName := '1900~' + FileName;
end.

Like before, more cleaning up is necessary here. This time it's a bit more complicated, due to empty parentheses, floating periods, and other stuff. hmm

The last problem, I haven't even looked at.... mainly because this somehow seems harder (for example, what exactly is meant by "etc" in your description). Depending on the answer to that question, it might be doable to address this one with a RegEx filter alone. smile

Last edited by prologician (2009-06-04 00:05)

Offline

#3 2009-06-04 13:32

Yogui
Member
Registered: 2007-09-27
Posts: 41

Re: Rearrange and Rename Folder Name Artist Album Pascal Script

Thanks a Lot for the Scripts prologician  big_smile

I haven't use them much yet but with a few renaming tests they seems to work great !!!

They look kind of miracle scrips to me cause I still can't understand them but they do work Lol. tongue

I'll clarify the 3rd point hopefully a RegEx is enough.

I've only gave one example before (and a bad explanation roll):

E.    Name: “Van Halen\Van Halen Live Right Here, Right Now 1993 CD 1”
ReName to: “Van Halen\1993~Live Right Here, Right Now (Disc 01)”

these are some more examples with the same parent folder:

F.    Name: “Van Halen\Van Halen Live Right Here, Right Now 1993 CD1”
ReName to: “Van Halen\1993~Live Right Here, Right Now (Disc 01)”

G.    Name: “Van Halen\Van Halen Live Right Here, Right Now 1993 VOL 1”
ReName to: “Van Halen\1993~Live Right Here, Right Now (Vol 01)”

H.    Name: “Van Halen\Van Halen Live Right Here, Right Now 1993 VOL1”
ReName to: “Van Halen\1993~Live Right Here, Right Now (Vol 01)”

I.    Name: “Van Halen\Van Halen Live Right Here, Right Now 1993 Disc 1”
ReName to: “Van Halen\1993~Live Right Here, Right Now (Disc 01)”

J.    Name: “Van Halen\Van Halen Live Right Here, Right Now 1993 Disc1”
ReName to: “Van Halen\1993~Live Right Here, Right Now (Disc 01)”

Basically any of:

"Disc1", "Disc 1", "Disc01", "Disc01"

or

"CD1", "CD 1", "CD01", "CD 01"

any of them (should be only one in the Folder Name) is replaced for:

(Disc 01)

Also with:
"Vol1", "Vol 1", "Vol01", "Vol 01"

any of them (should be only one in the Folder Name) is replaced for:

(Vol 01)

And again same for 2,3 etc till 9 (or even better 99)

Probably there are other variations but hopefully I'll be able to add them later if required.

This should cover a +90% of the cases.

Thanks Again, Yogui.

Offline

#4 2009-06-04 13:45

Yogui
Member
Registered: 2007-09-27
Posts: 41

Re: Rearrange and Rename Folder Name Artist Album Pascal Script

I was playing with the rules and found that for instance:

"Blue Note\Best Of The Blue Note Years 1998-2005"

Gets renamed to:

"Blue Note\2005~Best Of The Blue Note Years 1998-"

Is not wrong (I actually didn't mention it before)

Could something be added to the pascal to get it renamed to:

Blue Note\2005~Best Of The Blue Note Years 1998-2005

Basically if two or more #### (years) exist the greatest one becomes the year at the beginning and is not deleted form the name.

Hopefully I'm not making it too hard. roll

Thanks, Yogui.

Last edited by Yogui (2009-06-04 13:46)

Offline

#5 2009-06-04 21:16

prologician
Member
Registered: 2009-01-30
Posts: 84

Re: Rearrange and Rename Folder Name Artist Album Pascal Script

The example you just gave (the Blue Note one) also points out another problem, where the artist's name could be part of the album title... and that breaks the first script, because it removes ALL instances of the artist's name. So, going back and revising such. Since nearly every example so far shows the artist's name (the redundant one to be removed) as appearing first, I'm adjusting it so that this is what gets removed.

var 
  Path, SubFolders : TStringsArray;
  Depth : Integer;
begin
  if not WideFileExists(FilePath) then
  begin
    SetLength(SubFolders,0);
    Path:=WideSplitString(FilePath,'\');
    WideScanDirForFolders(FilePath, SubFolders, True, False, False);
    Depth:=Length(Path);
    If (Depth>1) and (Length(SubFolders)=0) then
      FileName := ReplaceRegEx(Path[Depth-1], '^(.*?)' + Path[Depth-2] + '(.*)$', '$1$2', false, true);
  end;
end.

To make the scripts less magical, I'll give a shot to explain them... smile The "WideFileExists(FilePath)" is being used here to distinguish a file from a folder. Since we only want to rename folders, "WideFileExists(FilePath)" should return false to indicate that the thing in question is not a file. krtek then goes on to get the file's full path and break it up into parts (on Windows machines, folders along the path are separated by '\' characters). The "WideScanDirForFolders(FilePath, SubFolders, True, False, False)" part is then used to look and see if there are any folders inside the folder we're looking at. If there are any folders inside, or the current folder is at the root of the drive, then we don't rename anything. Otherwise, the script removes the first instance of the artist's name from the current folder's name.

The changes regarding the year make the script a ~little~ more complicated, but I don't think it's too bad. smile

begin
  if (Length(MatchesRegEx(FileName, '(19|20)\d{2}', false)) > 0) then
  begin
    if (Length(MatchesRegEx(FileName, '(19|20)\d{2}\D+(19|20)\d{2}', false)) > 0) then
      FileName := ReplaceRegEx(FileName, '^(.*)(19|20)(\d{2})(.*?)$', '$2$3~$1$2$3$4', false, true)
    else
      FileName := ReplaceRegEx(FileName, '^(.*)(19|20)(\d{2})(.*)$', '$2$3~$1$4', false, true)
  end
  else
    FileName := '1900~' + FileName;
end.

For entertainment purposes, I'll write out what this script does, so you can understand it better.

if there is at least one year in the title:
  if there are at least two years in the title:
    Take the last year in the filename, and append it to the start of the filename...
    otherwise (there is only one year), move that year to the start of the filename.
  otherwise (there is no year at all), append "1900~" to the start.

Hopefully that sheds some light on what that script is doing. wink

As far as your third bullet point, I think I understand it well enough now to give it a good shot. smile Like with the years, it's largely a regular expression thing. The difference here is that we want to have a name in question only match once, if it can at all. Fortunately, with some carefully written regular expressions and ordering them right, it's workable. smile Here's the four RegEx filters that I cooked up.

Expression: ^(.*)(CD|Disc)\s?(\d{2,})(.*)$
Replace: $1$4 (Disc $3)

Expression: ^(.*)(CD|Disc)\s?(\d)(\D.*)?$
Replace: $1$4 (Disc 0$3)

Expression: ^(.*)Vol\s?(\d{2,})(.*)$
Replace: $1$3 (Vol $2)

Expression: ^(.*)Vol\s?(\d)(\D.*)?$
Replace: $1$3 (Vol 0$2)

If you look at these, the first pair handles the CD/Disc case, and the second pair handles the Vol case. And first and third regular expressions are nearly identical, as are the second and fourth. smile I'll go through the Vol cases, just because the explanation will be easier.

RegEx 3 tries to match "Vol" and then two or more digits following (and maybe a space in between... that's the \s? part). Since this will need no padding, we just grab what we can, and append (Vol ##) at the end.

In a similar spirit, RegEx 4 tries to match "Vol", but it tries to match only one digit (this makes sure that there is no overlap with RegEx 3... and also ensures that if RegEx 3 trips, that RegEx 4 will not. This is where ordering is important... you can't swap 3 and 4.) Since only one digit is allowed here, it requires padding... thus, we append (Vol 0#) in this case.

And of course... more cleanup filters after all this mayhem. tongue

Offline

#6 2009-06-04 22:37

Yogui
Member
Registered: 2007-09-27
Posts: 41

Re: Rearrange and Rename Folder Name Artist Album Pascal Script

Pure Gold... Lol Thanks big_smile

I've only added spaces between the i.e. "$1 $2" then a Rule to Replace Double Spaces for Single ones, and clean up ie "~-" for "~" etc.

and... one more variation.

K.    Name: “Van Halen\Van Halen Live Right Here, Right Now 1993 Vol I”
ReName to: “Van Halen\1993~Live Right Here, Right Now (Vol 01)”

L.    Name: “Van Halen\Van Halen Live Right Here, Right Now 1993 Vol IV”
ReName to: “Van Halen\1993~Live Right Here, Right Now (Vol 04)”

M.    Name: “Van Halen\Van Halen Live Right Here, Right Now 1993 Vol X”
ReName to: “Van Halen\1993~Live Right Here, Right Now (Vol 10)”

Seems like we'll need

I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|XIII|XIV|XV|XVI|XVII|XVIII|XIX|XX

Lets Stop there roll

and of course 1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20
or
01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20

Probably should be a Non Case Sense rule

Thanks for yor help! big_smile

Offline

#7 2009-06-05 04:08

prologician
Member
Registered: 2009-01-30
Posts: 84

Re: Rearrange and Rename Folder Name Artist Album Pascal Script

<LOL> As the problems get addressed, you're just piling on more, aren't you? wink Ah, well, it's summer vacation for me. Exercises like this keep things fun. smile

Although writing an abbreviated Roman numeral parser might be easier, it might be beneficial to others who need a full-blown Roman numeral parser to handle everything. So, I'm gonna take this latter route, in spite of it not necessarily being easy. tongue

There's also the situation in this case, where we want to tie the number to the word "Vol". We don't want to change an album title like "I Like Roses" to "1 Like Roses," for example. tongue

With a lil bit of legwork, I did come across an already-written parser, available at http://www.blackwasp.co.uk/RomanToNumber.aspx (only that this thingy is written in... I guess Java or C++ or something). I'll port this to PascalScript, so that it handles what you're aiming for. smile (I'll post my ported version in a subsequent post....) In any case, this Roman-to-Arabic numeral script should go directly before the two Vol ## regular expressions, so that it changes from "Vol IV" to "Vol 4", and then can be adjusted appropriately. smile

Offline

#8 2009-06-07 04:30

prologician
Member
Registered: 2009-01-30
Posts: 84

Re: Rearrange and Rename Folder Name Artist Album Pascal Script

Uuuuuuuugh. I didn't realize just how much of a pain Roman numerals really are. This algorithm really makes you appreciate simple Arabic numerals and their universality in modern life.

This script SHOULD do what you want it to, but it's long, and I'm not 100% convinced it's bug-free. But give it a shot. Place it before the two VOL ## regular expressions for this thing to do its magic. Also, be aware that it appends a blank space at the end of the name which will need some cleaning up (This was to guarantee that the last character of the Roman numeral was not the last in the entire name... there's a regular expression which sorta counts on this).

{Roman Numeral Converter
Ported from http://www.blackwasp.co.uk/RomanToNumber.aspx
Retrieved June 5, 2009}

const
  I = 1;
  V = 5;
  X = 10;
  L = 50;
  C = 100;
  D = 500;
  M = 1000;
  ZERO = 'N';
  ALL_NUMERALS = 'IVXLCDM';
  SUBTRACTIVE = 'IXC';

function ParseNumeral(const numeral: WideChar): Integer;
var
  enum: Array of Integer;
  index: Integer;
begin
  setlength(enum, length(ALL_NUMERALS));
  enum[0] := I;
  enum[1] := V;
  enum[2] := X;
  enum[3] := L;
  enum[4] := C;
  enum[5] := D;
  enum[6] := M;
  
  index := WidePos(numeral, ALL_NUMERALS);
  if (index > 0) then
    result := enum[index - 1];
end;


// Converts a Roman numerals value into an integer
function RomanToNumber(const roman: WideString): Integer;
var
  count: Integer;
  last: WideChar;
  index: Integer;
  ptr: Integer;
  values: Array of Integer;
  maxDigit: Integer;
  numeral: WideChar;
  digit: Integer;
  nextDigit: Integer;
  nextNumeral: WideChar;
begin
  // Rule 7
  roman := WideTrim(WideUpperCase(roman));
  if roman = ZERO then
    exit;
  
  // Rule 4
  if (Length(WideSplitString(roman, 'V')) > 2) or
    (Length(WideSplitString(roman, 'L')) > 2) or
    (Length(WideSplitString(roman, 'D')) > 2) then
  begin
    result := -4;
    exit;
  end;
  
  // Rule 1
  count := 1;
  last := 'Z';
  for index := 1 to WideLength(roman) do
  begin
    // Valid character?
    if WidePos(roman[index], ALL_NUMERALS) = 0 then
    begin
      result := -8;
      exit;
    end;
    
    // Duplicate?
    if (roman[index] = last) then
    begin
      count := count + 1;
      if (count = 4) then
      begin
        result := -1;
        exit;
      end
    end
    else
    begin
      count := 1;
      last := roman[index];
    end
  end;
  
  // Create an ArrayList containing the values
  SetLength(values, WideLength(roman));
  count := 0;
  maxDigit := M;
  for ptr := 1 to WideLength(roman) do
  begin
    // Base value of digit
    numeral := roman[ptr];
    digit := ParseNumeral(numeral);
    
    if (digit > maxDigit) then
    begin
      result := -3;
      exit
    end;
    
    // Next digit
    nextDigit := 0;
    if (ptr < WideLength(roman)) then
    begin
      nextNumeral := roman[ptr + 1];
      nextDigit := ParseNumeral(nextNumeral);
      
      if (nextDigit > digit) then
      begin
        if (WidePos(numeral, SUBTRACTIVE) = 0) or
          (nextDigit > (digit * 10)) or
          (Length(WideSplitString(roman, numeral)) > 3) then
        begin
          result := -3;
          exit
        end;
        
        maxDigit := digit - 1;
        digit := nextDigit - digit;
        ptr := ptr + 1;
      end
    end;
    
    values[count] := digit;
    count := count + 1;
  end;
  
  // Rule 5
  for index := 0 to (count - 2) do
  begin
    if (values[index] < values[index + 1]) then
    begin
      result := -5;
      exit
    end
  end;
  
  // Rule 2
  result := 0;
  for index := 0 to (count - 1) do
    result := result + values[index];
end;

var
  matches: TStringsArray;
  index: Integer;
  romannum: WideString;
  arabicnum: Integer;
begin
  filename := filename + ' ';
  matches := MatchesRegEx(filename, '[^a-z]vol\s[' + ALL_NUMERALS + ']+[^a-z]', false);
  for index := 0 to (length(matches) - 1) do
  begin
    romannum := WideCopy(matches[index], 6, WideLength(matches[index]) - 6);
    arabicnum := RomanToNumber(romannum);
    if (arabicnum > 0) then
      filename := WideReplaceText(filename, matches[index], WideCopy(matches[index], 0, 5) + IntToStr(arabicnum) + WideCopy(matches[index], WideLength(matches[index]), 1));
  end
end.

Just short of 170 lines. I need a break... *~_~*

Offline

#9 2009-06-07 09:40

prologician
Member
Registered: 2009-01-30
Posts: 84

Re: Rearrange and Rename Folder Name Artist Album Pascal Script

For the sake of completeness and for posterity's sake, I've spent a few minutes porting the Number --> Roman Numeral algorithm, also available from the same source as above. Thankfully, it's a LOT shorter. My only irritation is that I couldn't find an easy clean way to define a constant array (I know I can do it cleanly in C...)

{Roman Numeral Generator
Ported from http://www.blackwasp.co.uk/NumberToRoman.aspx
Retrieved June 6, 2009}

// Converts an integer value into Roman numerals
function NumberToRoman(number: Integer): String;
var
  values: Array[0..12] of Integer;
  numerals: Array[0..12] of String;
  i: Integer;
begin
  // Validate
  if (number < 0) or (number > 3999) then
    exit;
  
  if (number = 0) then
  begin
    result := 'N';
    exit;
  end;
  
  // Set up key numerals and numeral pairs
  values[0] := 1000;
  values[1] := 900;
  values[2] := 500;
  values[3] := 400;
  for i := 0 to 3 do
  begin
    values[i + 4] := values[i] / 10;
    values[i + 8] := values[i] / 100;
  end;
  values[12] := 1;
  
  numerals[0] := 'M';
  numerals[1] := 'CM';
  numerals[2] := 'D';
  numerals[3] := 'CD';
  numerals[4] := 'C';
  numerals[5] := 'XC';
  numerals[6] := 'L';
  numerals[7] := 'XL';
  numerals[8] := 'X';
  numerals[9] := 'IX';
  numerals[10] := 'V';
  numerals[11] := 'IV';
  numerals[12] := 'I';

  // Loop through each of the values to diminish the number
  for i := 0 to 12 do
  begin
    // If the number being converted is less than the test value, append
    // the corresponding numeral or numeral pair to the resultant string
    while (number >= values[i]) do
    begin
      number := number - values[i];
      result := result + numerals[i];
    end
  end
end;

begin
  filename := NumberToRoman(strtoint(filename));
end.

Offline

#10 2009-06-07 16:08

Yogui
Member
Registered: 2007-09-27
Posts: 41

Re: Rearrange and Rename Folder Name Artist Album Pascal Script

Hi prologician,

Thanks for your solution seems powerful.

As per my test, the 1st version of your Roman Numeral algorithm function worked, the 2nd returns blank names.

Also, I've searched on the forum for a clean up reg ex with no luck...

I'm learning Reg Ex... tongue but could not do all I want.

so I'll pile an easy one

I like to get ride of All pair of chars like:

"~-" or "()" or "(-" or "_)" or "[)" or ",," or "~~"

My Reg Ex 101 points me towards

Expression: (.|)[-|_|,|=|\s|\(|\)|\{|\}|\[|\]][-|_|,|=|\s|\(|\)|\{|\}|\[|\]](.|)
Replace: $1 $2

And then for the ones that have "~" which I like to keep

Expression: (.)[~][-|_|,|=|\s|\(|\)|\{|\}|\[|\]](.)
Replace: $1~$2

Expression: (.)[-|_|,|=|\s|\(|\)|\{|\}|\[|\]][~](.)
Replace: $1~$2

Something like this:
"()AAA-_BBB~_CCC=~DDD[]FFF{}GGG  HHH~ III[].txt"

Renames to:
" AAA BBB~_CCC=~DDD FFF GGG HHH~ III .txt"

There is a Space a the beginning which I don't want

Chances are that there is a much better ways to do it... My 101 can't reach them yet smile

May be handy (and easier to update) to somehow declare a variable:

DirtyCharsList := -_()[]{},

To call later

Any help appreciated. big_smile

Cheers, Yogui.

Offline

Board footer

Powered by FluxBB