topbanner_forum
  *

avatar image

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
  • Thursday November 14, 2024, 12:44 am
  • Proudly celebrating 15+ years online.
  • Donate now to become a lifetime supporting member of the site and get a non-expiring license key for all of our programs.
  • donate

Author Topic: Request: Ahk script to extract archive to subfolder of current directory  (Read 9578 times)

chashnniel

  • Member
  • Joined in 2018
  • **
  • default avatar
  • Posts: 127
    • View Profile
    • Donate to Member
sorry to post in here.
   Im new here so i have no rights to post a topic, also my English is not so well.
i know there are many great developers here and i got an ideal (maybe someone already did this)
   Hope you guys can make an AKH script to do this:
when i press ALT+Win+Lbutton on a zip/rar etc file. it automatic extract it to the current folder.  But what i need is:
   if the zip file contains one folder or one file in it, then just extract it (like extract it here)
   if the zip file contains several files but not in a folder, then it creates a folder (based on zip_name) for it. (like what extract to xxx folder do)

thus i don't have to check each downloaded zip file whether there is a folder in it. then: right click - choose 7zip - and choose action
and i think it would help TC a lot
« Last Edit: November 11, 2018, 09:55 PM by Deozaan »

Curt

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 7,566
    • View Profile
    • Donate to Member
I know nothing about coding, but instinctively I think your request is much too big for a person. It must be a job for the .zip authoring companies. One problem is the huge number of different extension libraries - larger companies can handle such a task, but how should a private, sparetime coder?

Zip (file format)w

4wd

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 5,644
    • View Profile
    • Donate to Member
Not really Curt, there's a couple of options:
1. Extract the archive to a temporary folder, check the contents, move to the final destination - probably the easiest since you're going to extract anyway.
2. Use 7-Zip, (library or command line version), to get a list of the contents, determine type, and then either create a destination folder or extract to the destination directly as necessary.

Curt

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 7,566
    • View Profile
    • Donate to Member
^ you may need to read his post more closely; I believe chashnniel is saying your options takes far too much work...


skwire

  • Global Moderator
  • Joined in 2005
  • *****
  • Posts: 5,287
    • View Profile
    • Donate to Member
^ you may need to read his post more closely; I believe chashnniel is saying your options takes far too much work...

Curt, the options/scenarios the OP wants can easily be handled in programming.  Furthermore, I agree with 4wd, and would have suggested the same two methods.

KodeZwerg

  • Honorary Member
  • Joined in 2018
  • **
  • Posts: 718
    • View Profile
    • Donate to Member
If a teamproject is possible, i could offer the part where files get extracted (zip) without need to decompress to temp folder.
I could integrate full zip function inside own app, so checking if there is a file in root of archive aint a pain to me.
I could do a CLI, like first parameter is zip filename and second root of destination folder.
The hotkey part, how to get archive filename, how decide destination name, there i am clueless.
Okay, as destination root i could easy extract archives path, but still no idea how to get a archive filename just by pressing some keys.

If such is helpful, let me know.

4wd

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 5,644
    • View Profile
    • Donate to Member
If a teamproject is possible, i could offer the part where files get extracted (zip) without need to decompress to temp folder.

A temporary folder created in the destination folder is the easiest method:

1. Extract contents to new temporary folder using 7-Zip command, (or library routines)
2. Get contents of temporary folder
3. Determine types of contents, (don't even need to do that, just count the number of items)
4. Contents:
 - If a single file/folder move it to the parent folder and delete the temporary folder
 - If multiple files/folders rename temporary folder to archive name sans extension
5. Go make a cup of coffee

Pretty easy in Powershell but not really any provision for a hotkey so simpler in AHK, AutoIT, or some other language.

Proof of concept (no error checking at all):
Code: PowerShell [Select]
  1. <#
  2.   Uses 7Zip4Powershell module: https://www.powershellgallery.com/packages/7Zip4Powershell/1.9.0
  3.  
  4. .\ExArc.ps1 <archive> <destination>
  5.  
  6. <archive> = full path to archive with quotes if necessary
  7. <destination> = destination path with no trailing \
  8. #>
  9.  
  10.  
  11. Param (
  12.   [string]$archive,
  13.   [string]$dest
  14. )
  15.  
  16. $tempdest = $dest + '\temp7zip'
  17. Expand-7Zip -ArchiveFileName $archive -TargetPath $tempdest
  18.  
  19. $items = Get-ChildItem -Path $tempdest
  20.  
  21. switch ($items.Count) {
  22.   1 {
  23.       Move-Item $items[0].FullName $dest
  24.       Remove-Item $tempdest -Recurse -Force
  25.     }
  26.   0 {
  27.       Write-Host "Ain't nuffin' there!"
  28.     }
  29.   default {
  30.     Rename-Item $tempdest ($dest + '\' + ([io.path]::GetFileNameWithoutExtension($archive)))
  31.     }
  32. }

BTW, referring to the OP I'm assuming TC = Total Commander which is what he wants it to work with, correct?

Maybe Total Commander has a Powershell interface, (see here)?

So, in theory, TC can set a hotkey that passes the selected objects, (archives), to a Powershell script that does the above for each file.

DISCLAIMER: I don't use Total Commander.

Using the info at that link apparently %L is a temp text file containing a list of selected files.  This will probably need tweaking, (not to mention checking for existing files/folders), to stop/redirect output, etc but it should be a start:

Command: PowerShell -NoProfile -NoExit -ExecutionPolicy Bypass -File "%COMMANDER_PATH%\TOOLs\CMDs\ExArc-TC.ps1"
Parameters: '% L'
Start Path:
Icon File: Powershell
Tooltip: Extract each archive

Code: PowerShell [Select]
  1. <#
  2.   *** REQUIRES ***
  3.     7Zip4Powershell module: https://www.powershellgallery.com/packages/7Zip4Powershell/1.9.0
  4.  
  5. .\ExArc-TC.ps1 <textfile>
  6.  
  7. <textfile> = list of archives: full path, one per line
  8. #>
  9.  
  10.  
  11. Param (
  12.   [string]$selFiles
  13. )
  14.  
  15. $files = Get-Content $selFiles
  16. ForEach ($file in $files) {
  17.   $dest = [io.path]::GetDirectoryName($file)
  18.   $tempdest = $dest + '\temp7zip'
  19.   Expand-7Zip -ArchiveFileName $file -TargetPath $tempdest
  20.  
  21.   $items = Get-ChildItem -Path $tempdest
  22.  
  23.   switch ($items.Count) {
  24.     1 {
  25.         Move-Item $items[0].FullName $dest
  26.         Remove-Item $tempdest -Recurse -Force
  27.       }
  28.     0 {
  29.         Write-Host "Ain't nuffin' there!"
  30.       }
  31.     default {
  32.       Rename-Item $tempdest ($dest + '\' + ([io.path]::GetFileNameWithoutExtension($file)))
  33.       }
  34.   }
  35. }
« Last Edit: November 13, 2018, 03:31 AM by 4wd »

chashnniel

  • Member
  • Joined in 2018
  • **
  • default avatar
  • Posts: 127
    • View Profile
    • Donate to Member
thx for your help!!! :Thmbsup: :Thmbsup:
after reading your comments. now let me make my request clear:  use hotkey+click to wisely extract a small size archive file.

@curt may concern it take much more time if  Extract the archive to a temporary folder. extraxt+move file mean double time. So i revise my request: I only use this way when i want to extract a small size file. As to extract a large size archive, i do it in the normal way(check the files manually then choose the right content menu to extract it).  In briefly, we focus on small size file. so @4wd s idea is OK for me.
 @KodeZwerg  ALT+Win+leftclick, i don't know whether ahk can get the files name when i click it, the point is how to know whether there is multi files in a archive. it seems you know how to do it.
@4wd thx for your hard work. but i don't know how to use it. i will google the powershell usage
sorry for my English

chashnniel

  • Member
  • Joined in 2018
  • **
  • default avatar
  • Posts: 127
    • View Profile
    • Donate to Member
I find a way to solve my problem
1. extract the file in a subfolder(its name based on the archive files name of course). (no matter there is multi files in it or not)
2. check files number in it(one or multi)
3. if multi       then nothing need to do
    if one         then use this AHK script rescue orphans  which can make a file/folder move to their parent dir.

i hope it can help you guys.

KodeZwerg

  • Honorary Member
  • Joined in 2018
  • **
  • Posts: 718
    • View Profile
    • Donate to Member
@Scripters, why dont use List command to get archive content to compare? Just my Idea to Script stuff where i aint have any idea at all :-]
At least that way i would go if i write a batch file.

@chashnniel For Zip fileformat that is easy action to get content. But as said, i have no idea on how to get Archive filename.

There exists some multipurpose CLI dearchivers that can list content, as more archive formats needed as more my first of all zip only variant would fail :-)

4wd

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 5,644
    • View Profile
    • Donate to Member
Since the ultimate point is to extract the contents of the archive I see no need to get the list of its contents before doing so, it adds unnecessary steps.

Only needed to find out if there was more than one object in the root of the archive.
If, after extraction, there was an already existing object of the same name then you can either rename, replace, or skip (and leave the extracted files in the temporary folder for comparison with the existing), which can be handled by a requester or a preset.

Like I said, there was no error checking in my script since it was just a sample of how easy it is to do.

Plus there was the reference to TC so the ultimate environment in which the script/program would be used was unknown.
« Last Edit: November 13, 2018, 06:00 PM by 4wd »

chashnniel

  • Member
  • Joined in 2018
  • **
  • default avatar
  • Posts: 127
    • View Profile
    • Donate to Member
i found another solution(maybe)
this AHK script 智能解压
seems can do it.
    But it is just a plugin, the author said it can be used as a independent script if i modify it. since i don't know how to code, anyone can help?
    @KodeZwerg How about add a content menu if it is hard to get the Archive filename through a hotket+click?

Nod5

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 1,169
    • View Profile
    • Donate to Member
Hi all. Here is an AutoHotkey prototype. I don't have time to make more of it right now. But maybe someone else takes this to the next level?

Code: Autohotkey [Select]
  1. ;Smarter unzip sketch
  2. ;by nod5  181114
  3.  
  4. ;note: only a sketch/prototype so far
  5. ;todo:
  6. ;- add error checks/handling:
  7. ;   1 unzip errors (paths to long, or whatever)
  8. ;   2 file/folder move errors:
  9. ;     - script currently silently avoids overwrite
  10. ;     - need to add code to prompt user: overwrite yes/no? and react accordingly
  11. ;- must test how reliable the unzip function performs if the zip file is huge, etcetera
  12. ;- notify user while processing (window, tooltip, etcetera)
  13. ;- prevent repeat commands while processing
  14. ;- replace crude F5 refresh with something better, maybe also reselect zip file after refresh
  15.  
  16. #IfWinActive ahk_exe explorer.exe
  17. !#Lbutton::
  18.  
  19. ;get first file in Explorer selection and verify that it is .zip
  20. clip := ClipToVar()
  21. Loop, parse, clip, `n, `r
  22. {
  23.   firstfile := A_LoopField
  24. }
  25. if !FileExist(firstfile) or (SubStr(firstfile,-3) != ".zip")
  26.   return
  27.  
  28. ;unzip to temporary folder
  29. SplitPath, firstfile, , folder, , zipname_noext
  30. tempfolder := folder "\temp_" A_Now
  31. FileCreateDir, % tempfolder
  32. Unzip(firstfile, tempfolder)
  33.  
  34. ;count unzipped files/folders recursively
  35. Loop, Files, % tempfolder "\*.*", FDR
  36. {
  37.   allcount := A_Index
  38.   onlyitem := A_LoopFilePath
  39. }
  40.  
  41. ;count unzipped files/folders at first level only
  42. Loop, Files, % tempfolder "\*.*", FD
  43. {
  44.   firstlevelcount := A_Index
  45.   firstlevelitem  := A_LoopFilePath
  46. }
  47.  
  48. ;case1: only one file/folder in whole zip
  49. if (allcount = 1)
  50. {
  51.   if InStr( FileExist(onlyitem), "D")
  52.   {
  53.     SplitPath, onlyitem, onlyfoldername
  54.     FileMoveDir, % onlyitem, % folder "\" onlyfoldername
  55.   }
  56.   else
  57.     FileMove   , % onlyitem, % folder
  58. }
  59.  
  60. ;case2: only one folder (and no files) at the first level in zip
  61. else if (firstlevelcount = 1) and InStr(FileExist(firstlevelitem), "D")
  62. {
  63.   SplitPath, firstlevelitem, firstlevelfoldername
  64.   FileMoveDir, % firstlevelitem, % folder "\" firstlevelfoldername
  65. }
  66.  
  67. ;case3: multiple files/folders at the first level in zip
  68. else
  69. {
  70.   FileMoveDir % tempfolder, % folder "\" zipname_noext
  71. }
  72.  
  73. ;cleanup temp folder
  74. FileRemoveDir, % tempfolder, 1
  75.  
  76. ;refresh Explorer to show results
  77. If WinActive("ahk_exe Explorer.exe")
  78.   Send {F5}
  79. return
  80.  
  81.  
  82. ;function: copy selection to clipboard to var
  83. ClipToVar() {
  84.   cliptemp := clipboardall ;backup
  85.   clipboard =
  86.   send ^c
  87.   clipwait, 1
  88.   clip := clipboard
  89.   clipboard := cliptemp    ;restore
  90.   return clip
  91. }
  92.  
  93.  
  94. ;function: unzip files to already existing folder
  95. ;zip file can have subfolders
  96. Unzip(zipfile, folder)
  97. {
  98.   psh := ComObjCreate("Shell.Application")
  99.   psh.Namespace(folder).CopyHere( psh.Namespace(zipfile).items, 4|16)
  100. }

chashnniel

  • Member
  • Joined in 2018
  • **
  • default avatar
  • Posts: 127
    • View Profile
    • Donate to Member
@Nod5 thx!!! what a decent script!
i just test it, it works like a charm :Thmbsup: :Thmbsup:
a little suggestion(since it is just a prototype), it overwrites(my mistake, it just skip the same file) the files by default if it is already existed in the current folder. maybe you can add a overwrite  confirm dialog.
« Last Edit: November 14, 2018, 11:36 PM by chashnniel »

Nod5

  • Supporting Member
  • Joined in 2006
  • **
  • Posts: 1,169
    • View Profile
    • Donate to Member
it overwrites the files by default if it is already existed in the current folder
I don't think it does, on the contrary in my (quick) tests it silently skips to unzip/move files if another file with the same name exists in the target path. But yes, a complete program should handle such cases by asking the user what to do. However that would take more time, which I don't have for this right now. But someone else might.