Page 2 of 3

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 26 Aug 2014 19:34
by highend
Why the question mark before "folder"? I interpret it as limiting "anything from the beginning of the string" to 0 or 1 occurrences (lazy)
Personal habit. I tend to "design" regexes not being greedy. I've had a lot of cases where I had issues leaving out the "lazy operator (?)" As long as you don't have any issues with it, leave it out.

An example:
Regex: ^.*?folder\.jpg\|
D:\folder.jpg|D:\Temp\folder.jpg|D:\Temp\subfolder\folder.jpg|
This will match only on the first folder (with the trailing |)

Regex: ^.*folder\.jpg\|
This will match _all_ folders.

Create a Search for folders without a certain file

Posted: 26 Aug 2014 20:47
by Jeff Bellune
@highend:

Code: Select all

    $iTunesFolder = "<curpath>";
    $folders = folderreport("dirs", "r", $iTunesFolder, "r", , "<crlf>");
    $files = folderreport("files", "r", $iTunesFolder, "r", , "<crlf>");

    $matches = regexmatches($files, "^.*?folder\.jpg$", "<crlf>");
    if ($matches) {
        $foldersToExclude = "";
        foreach($match, $matches, "<crlf>") {
            if (strpos(report("{attr}", $match), "s") != -1){ // Ignore folder.jpg with system attribute
                $foldersToExclude = $foldersToExclude . getpathcomponent($match, "path") . "|";
            }
        }
    }
    $folders = regexreplace(replacelist($folders, $foldersToExclude, "", "|"), "^\\.*?$");
    paperfolder("iTunes", formatlist($folders, "dents", "<crlf>"), "<crlf>");
In my tests, both the new, faster version of the iTunes/folder.jpg script and original version of that script return all of the folders, regardless of whether or not they contain a standard folder.jpg file. I think it's because $foldersToExclude never gets set by anything other than a $match that has the system attribute. When the If test evaluates as true, the variable gets set, but when it evaluates as false it doesn't. There's no command outside of the if-then block (but still within the foreach block) that modifies $foldersToExclude.

I think I fixed that, but I ran into another problem. Many CDs consist of 2 or more discs (e.g., "The Best Of The Doors [Disc 1]" and "The Best Of The Doors [Disc 2]"), or different CDs are named similarly -- Greatest Hits, Greatest Hits Vol.2 (e.g., Elton John or Linda Ronstadt), The Traveling Wilburys, Vol. 1, The Traveling Wilburys, Vol. 3, and so on. If one of these discs has artwork but the other doesn't, then the regexreplace command truncates the path of the folder we want to keep to just the different characters at the end of the string. For example, "...\Greatest Hits Vol.2" becomes "Vol.2". Obviously, such a folder doesn't exist.

What's the best way to fix these issues?

Thanks,
Jeff

Create a Search for folders without a certain file

Posted: 26 Aug 2014 20:52
by Jeff Bellune
@Don,

Is it time to move this into the Scripting forum?

Cheers,
Jeff

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 26 Aug 2014 21:20
by highend
My current goal is to find all the folders in my iTunes Music folder that do not contain album art in the form of folder.jpg, except in the cases where folder.jpg has the system attribute
1. If a folder contains a file name folder.jpg, don't list that folder?
2. Exception: If the folder.jpg has the system attribute, list it?

If these are true you'd only need to change the
!= -1 to == -1 in the if clause.

Can you give me a real world example for your second issue?
Which folders should I create exactly and which of them should have a folder.jpg with / without "s" attribute in them to recreate the problem?
Because atm with my limited test folder hierarchy everything works as expected.

Create a Search for folders without a certain file

Posted: 26 Aug 2014 21:40
by Jeff Bellune
highend wrote:1. If a folder contains a file name folder.jpg, don't list that folder?
2. Exception: If the folder.jpg has the system attribute, list it?

If these are true you'd only need to change the
!= -1 to == -1 in the if clause.
They are true, and that's a much better way to fix it!
highend wrote:Can you give me a real world example for your second issue?
Which folders should I create exactly and which of them should have a folder.jpg with / without "s" attribute in them to recreate the problem?
Because atm with my limited test folder hierarchy everything works as expected.
This folder exists in F:\My Music\iTunes Music:
"Linda Ronstadt"

Inside of F:\My Music\iTunes Music\Linda Ronstadt are these three folders:
"Greatest Hits"
"Greatest Hits Vol.2"
"Lush Life"

Inside each of those three folders are several .flac and .m4a files, but most importantly, "Greatest Hits" and "Lush Life" contain a "folder.jpg" file. "Greatest Hits Vol.2" does not.

When I run the script, the only folder returned is "Greatest Hits Vol. 2", which is the proper result. But because "Greatest Hits" was excluded, the folder name that gets passed to the paperfolder function is "Vol.2". Since a folder named "Vol.2" doesn't exist, the new paper folder is empty.

Does that give you enough information? Let me know if I need to provide more details.

Thanks,
Jeff

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 26 Aug 2014 22:42
by highend
Think I've got it...

Code: Select all

    $iTunesFolder = "<curpath>";
    $folders = folderreport("dirs", "r", $iTunesFolder, "r", , "<crlf>");
    $files = folderreport("files", "r", $iTunesFolder, "r", , "<crlf>");

    $matches = regexmatches($files, "^.*?folder\.jpg$", "<crlf>");
    if ($matches) {
        foreach($match, $matches, "<crlf>") {
            if (strpos(report("{attr}", $match), "s") == -1){ // Ignore folder.jpg with system attribute
                $folderToExclude = replacelist(getpathcomponent($match, "path"), "\|^|$|.|+|(|)|[|{", "\\|\^|\$|\.|\+|\(|\)|\[|\{" , "|");
                $folders = regexreplace($folders, "^.*?" . $folderToExclude . "$");
            }
        }
    }
    paperfolder("iTunes", formatlist($folders, "dents", "<crlf>"), "<crlf>");
Explanation:
$folderToExclude = replacelist(getpathcomponent($match, "path"), "\|^|$|.|+|(|)|[|{", "\\|\^|\$|\.|\+|\(|\)|\[|\{" , "|");
Looks difficult but it isn't :) There are a few chars that have a special meaning in regexes. They are called metacharacters.
These are:
\
^
$
.
|
?
*
+
(
)
[
{
So the replacelist() replaces all metacharacters with an escape char ("\"). This is necessary because in the next line we're replacing via regexreplace...
$folders = regexreplace($folders, "^.*?" . $folderToExclude . "$");
Because the regex selects all from the beginning of a path until the end of the line (remember, we're using "<crlf>" as dividers) you shouldn't have any problems with cut folder names.

Any questions?

Create a Search for folders without a certain file

Posted: 26 Aug 2014 22:54
by Jeff Bellune
So after the replacelist() command, will regexreplace operate on a string that looks like this:

Code: Select all

F:\\My Music\\iTunes Music\\Linda Ronstadt\\Greatest Hits Vol\. 2
?

EDIT: Answering my own question after stepping through the script: Yes.
NB: *If* "Greatest Hits Vol. 2" was to be excluded, *then* the regexreplace() command would work on the string as shown above. In the example I gave, only "Greatest Hits" and "Lush Life" would get replaced.

Cheers,
Jeff

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 26 Aug 2014 23:01
by highend
F:\\My Music\\iTunes Music\\Linda Ronstadt\\Greatest Hits Vol\.2
That's the search pattern.

Another example:
F:\My Music\iTunes Music\Linda Ronstadt\Greatest ^$.+()[{Hits Vol.2
Even such a folder name will be correctly removed from the $folders list. If we wouldn't escape all those metacharacters the regex wouldn't match and therefore the line not removed.

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 26 Aug 2014 23:13
by Jeff Bellune
I think that's got it for the iTunes case. I will test some more to make sure.

How does our discussion affect the general case, i.e., the first one you posted? It looks like adding a few tweaks that include the replacelist() command with metacharacter and escape character arguments will work. Maybe that should be my homework assignment? :D

Thank you,
Jeff

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 26 Aug 2014 23:28
by highend
It's 85% the same so replacing two lines in the foreach loop and doing the same replacelist for the $excludedFiles variable and it should fit a general purpose :)

Shouldn't take more than 5 minutes to get it working.

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 27 Aug 2014 00:25
by Jeff Bellune
Like this?

Code: Select all

    $excludedFiles = "BadFile.txt|BadFile.xys";
    $folders = folderreport("dirs", "r", "<curpath>", "r", , "<crlf>");
    $files = folderreport("files", "r", "<curpath>", "r", , "<crlf>");

    foreach($file, $excludedFiles) {
        $matches = regexmatches($files, "^.*?" . $file . "$", "<crlf>");
        if ($matches) {
            foreach($match, $matches, "<crlf>") {
                $folder = replacelist(getpathcomponent($match, "path"), "\|^|$|.|+|(|)|[|{", "\\|\^|\$|\.|\+|\(|\)|\[|\{" , "|");;
                $folders = regexreplace($folders, "^.*?" . $folder . "$");
            }
        }
    }
    $folders = formatlist($folders, "dents", "<crlf>");
    text $folders;
It passed 3 test scenarios, so I'm hoping it's good to go.

Cheers,
Jeff

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 27 Aug 2014 00:29
by highend
Add another variable for the starting folder and replace <curpath> with it. More flexible.
$matches = regexmatches($files, "^.*?" . $file . "$", "<crlf>");
replacelist() should be done here, too. If any of the files uses one of the metacharacters, regexmatches might miss them...

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 29 Aug 2014 16:19
by Jeff Bellune
Update:

The iTunes script had a flaw in its logic due to me providing incomplete information at the start. The script returned all of the artist\album folders like it should, but it also returned all of the artist folders as well. Since the artist folders never contain artwork, the script's output wasn't really usable for its intended purpose. Further, the iTunes Music folder also contains a Movie folder, which has video files, other files and many subfolders, and which never contains album art. So it needed to be excluded. Here's the modified script, and it works well:

Code: Select all

    $iTunesFolder = "<curpath>";
    $artistFolders = folderreport("dirs", "r", $iTunesFolder, , , "<crlf>");  //Get a list of folders, but not subfolders.
    $folders = folderreport("dirs", "r", $iTunesFolder, "r", , "<crlf>");  //Get a list of all folders, including subfolders.
    $files = folderreport("files", "r", $iTunesFolder, "r", , "<crlf>");  //Get a list of all files in all folders & subfolders.

    $matches = regexmatches($files, "^.*?folder\.jpg$", "<crlf>");  //Find all files named "folder.jpg"
    if ($matches) {                   
        foreach($match, $matches, "<crlf>") {
            if (strpos(report("{attr}", $match), "s") == -1){ // Ignore folder.jpg with system attribute
                $folderToExclude = replacelist(getpathcomponent($match, "path"), "\|^|$|.|+|(|)|[|{", "\\|\^|\$|\.|\+|\(|\)|\[|\{" , "|");
                $folders = regexreplace($folders, "^.*?" . $folderToExclude . "$");
            }
        }
    }
    //Now remove the artist folders from the list because only the album folders ever contain artwork.
    foreach($artist, $artistFolders, "<crlf>") {
        $folderToExclude = replacelist($artist, "\|^|$|.|+|(|)|[|{", "\\|\^|\$|\.|\+|\(|\)|\[|\{" , "|");
        $folders = regexreplace($folders, "^.*?" . $folderToExclude . "$");
    }
    //The "iTunes Music\Movies" folder has nonsense in it and never contains album art. Exclude it.
    $folders = regexreplace($folders, "F:\\Me\\Music\\iTunes\\iTunes Music\\Movies");
    paperfolder("iTunes", formatlist($folders, "dents", "<crlf>"), "<crlf>");
I wish I could highlight the changes, but the forum wouldn't recognize my font color changes inside of the code box.

Cheers,
Jeff

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 29 Aug 2014 18:11
by Jeff Bellune
And here's the updated general case:

Code: Select all

    $startingFolder = inputfolder("C:\", "Please select folder to search");
    $excludedFiles = input("Enter the file name(s) that should NOT be in any of the folders", "Include the extension and separate them with a pipe '|'. No wildcards!");
    $folders = folderreport("dirs", "r", $startingFolder, "r", , "<crlf>");
    $files = folderreport("files", "r", $startingFolder, "r", , "<crlf>");
    $metaCharacters = "\|*|^|$|.|+|(|)|[|{";
    $escapedCharacters = "\\|\*|\^|\$|\.|\+|\(|\)|\[|\{";
   
    foreach($file, $excludedFiles) {
        $cleanFile = replacelist(getpathcomponent($file, "file"), $metaCharacters, $escapedCharacters, "|");
        $matches = regexmatches($files, "^.*?" . $cleanFile . "$", "<crlf>");
        if ($matches) {
            foreach($match, $matches, "<crlf>") {
                $folder = replacelist(getpathcomponent($match, "path"), $metaCharacters, $escapedCharacters, "|");
                $folders = regexreplace($folders, "^.*?" . $folder . "$");
            }
        }
    }
    $folders = formatlist($folders, "dents", "<crlf>");
    text $folders;
Cheers,
Jeff

EDIT: Added variables to improve readability.

Re: Command Number for "Copy Containing Folder(s)"?

Posted: 03 Sep 2014 13:07
by highend
While I'm optimizing some of my scripts for speed...

Code: Select all

    $startingFolder = inputfolder("C:\", "Please select folder to search");
    $excludedFiles = input("Enter the file name(s) that should NOT be in any of the folders", "File must contain the extension but NOT the path! Separate all items with a pipe '|'. Wildcards are not allowed!");

    $folders = folderreport("dirs", "r", $startingFolder, "r", , "<crlf>");
    $files = folderreport("files", "r", $startingFolder, "r", , "<crlf>");
    $metaCharacters = "(\\|\*|\^|\$|\.|\+|\(|\)|\[|\{)";
    $escapedCharacters = "\$1";

    $excludedFiles = regexreplace($excludedFiles, $metaCharacters, $escapedCharacters);
    $matches = regexmatches($files, "^.*?(" . $excludedFiles . ")$", "<crlf>");

    if ($matches) {
        $pattern = regexreplace(formatlist(regexreplace($matches, "^(.*)(?=\\)(.*?)(\r?\n|$)", "$1|"), "dents"), $metaCharacters, $escapedCharacters);
        $folders = regexreplace($folders, "($pattern)");
    }
    $folders = formatlist($folders, "dents", "<crlf>");
    text $folders;
This version should be about 10 times faster than the previous one(s) that use a loop...