Bug XBMC.Extract
#16
It is a binary add-on you have to build and install, it is not available in repositories. It should ship with the installer or as a separate system repo entry
Reply
#17
Hi all.

I'm seeing the same issue as user @henricos in post #15 above (https://forum.kodi.tv/showthread.php?tid...pid2681718) but with vthe fs.libarchive binary add-on.

According to reports from users on Android and Windows, and local tests on Windows, XBMC:Extract() doesn't work anymore on Kodi 18 to extract RAR files. I've had to switch to use vfs.libarchive for that special combination:

python:

kodi_major_version = int(xbmc.getInfoLabel('System.BuildVersion').split('.')[0])
if ext == 'rar' and kodi_major_version >= 18:
    src = 'archive' + '://' + quote_plus(compressed_file) + '/'
    (cdirs, cfiles) = xbmcvfs.listdir(src)
    for cfile in cfiles:
        fsrc = '%s%s' % (src, cfile)
        xbmcvfs.copy(fsrc, workdir + cfile)
else:
    xbmc.executebuiltin("XBMC.Extract(%s, %s)" % (
        compressed_file.encode("utf-8"),
        workdir.encode("utf-8")), True)

Problem is no automatic dependency resolution is triggered such that vfs.libarchive gets activated if I add a:

xml:
<import addon="vfs.libarchive" version="1.0.0"/>

line to the <requires> block on addon.xml

and a

"The dependency on vfs.libarchive version 1.0.0 could not be satisfied"

error message is show on the UI. Users need to activate such add-on manually.

What I'm doing wrong?
Reply
#18
you're not doing anything wrong, binary components need to be explicitly enabled by user for (perceived?) security reasons.
Reply
#19
(2018-03-06, 09:43)spiff Wrote: you're not doing anything wrong, binary components need to be explicitly enabled by user for (perceived?) security reasons.
Thanks a lot for your reply.
Reply
#20
I'm not sure I understand the syntax xbmcvfs is looking for in this case.

If I have a file:
python:

/path/to/file/myfile.zip

And the archive contains one compressed file:
python:

myfile.abc

Then to extract the file to '/path/to/file', I've tried unsuccessfully the following:
python:

from urllib import quote_plus as url_quote
dirs_in_dir, files_in_dir = xbmcvfs.listdir(url_quote('archive://path/to/file/myfile.zip'))
#Returns
#dirs_in_dir=
#files_in_dir=['myfile.abc']
success = xbmcvfs.copy(url_quote('archive://path/to/file/myfile.zip/')+'myfile.abc','/path/to/file/myfile.abc')
#success = 0

xbmcvfs will return the contents of the archive just fine, but it looks like the syntax to the contained files and folders needs to be something else?  Debug logs dont contain any hints

Edit:  I also tried to copy your example code directly, but it also fails:
python:

    print 'Web test'
    from urllib import quote_plus as url_quote
    path = url_quote(directory_from)
    (dirs, files) = xbmcvfs.listdir('archive://%s' % (path))
    src = 'archive://' + path + '/' + files[0]
    dest = os.path.join(directory_to,files[0])
    print('copy %s to %s' %(src, dest))
    success = xbmcvfs.copy(src, dest)
    print success

#Returns
#...
#NOTICE: ADDON: vfs.libarchive v1.0.0 installed
#...
#DEBUG: Web test
#DEBUG: copy archive://%2FUsers%2F...%2Ftemp_iagl%2Ffilename.zip/filename.md to /Users/.../temp_iagl/filename.md
#DEBUG: 0
Reply
#21
(2018-07-27, 01:22)zachmorris Wrote:
Code:

#DEBUG: copy archive:///Users/.../temp_iagl/filename.zip/filename.md to /Users/.../temp_iagl/filename.md

I looked into this. The archive:// protocol encodes the archive into the hostname, so this URL should be:

Code:

archive://%2FUsers%2F...%2Ftemp_iagl%2FAction+Fighter+%281989%29%28Firebird+Software%29%5B128K%5D.zip/filename.md

However due to this line, vfs.libarchive tries the read the file "filename.md?cache=no", which fails.

Removing the "?cache=no" causes Kodi to properly extract/copy the file.

@spiff ideas?
RetroPlayer releases: https://github.com/garbear/xbmc/releases

Donations: eigendude.eth
Reply
#22
?cache=no is not used by vfs.libarchive / archive urls.
Reply
#23
Then the code I linked above should be updated I think.
RetroPlayer releases: https://github.com/garbear/xbmc/releases

Donations: eigendude.eth
Reply
#24
OK, I think I've figured this out.  Just documenting my findings for anyone else that is stuck on this.

zip and rar files will (currently) not copy contents with the 'archive://' vfs url.  They will copy if you use the 'zip://' or the 'rar://' url

7z/bz2/gzip/xz/etc (all the formats that libarchive supports) will copy if you use the 'archive://' url

The contents of an rar/zip/7z etc will correctly be listed using xbmcvfs.listdir using 'archive://' regardless of the format.  The builtin xbmc.extract does not work with 'archive://', only 'zip://' and 'rar://'

@spiff
I'm not sure if this is the expected behavior?  I'd think extraction/copying would work on zip/rar files with libarchive since it also supports zip and rar.

Edit:  One thing I still cannot get to work is extracting / copying data a folder or file in a folder in a libarchive supported file.  xbmcvfs.copy will generate a file for a folder, but it's an invalid file.  Is there a valid method for extracting all files/folders within a libarchive supported file?


Test code:
python:

print('libarchive test')
import os
from urllib import quote_plus as url_quote
from kodi_six import xbmc, xbmcaddon, xbmcplugin, xbmcgui, xbmcvfs
directory_from = '/Users/xxx/Downloads/1941.zip'
directory_to = '/Users/xxx/Downloads/test/'
path = url_quote(directory_from)
print('Archive file test')
(dirs, files) = xbmcvfs.listdir('archive://%s' % (path))
print('Dirs and files')
print(dirs)
print(files)
src = os.path.join('archive://%s' % (path),files[0])
print(xbmcvfs.exists(src))
dest = os.path.join(directory_to,files[0])
print('Test copy from archive %s to %s' %(src, dest))
success = xbmcvfs.copy(src, dest)
print(success)
print('Copied file exists test from archive')
print(xbmcvfs.exists(dest))
print('Zip file test')
(dirs, files) = xbmcvfs.listdir('zip://%s' % (path))
print('Dirs and files')
print(dirs)
print(files)
src = os.path.join('zip://%s' % (path),files[0])
print(xbmcvfs.exists(src))
dest = os.path.join(directory_to,files[0])
print('Test copy from zip %s to %s' %(src, dest))
success = xbmcvfs.copy(src, dest)
print(success)
print('Copied file exists test from zip')
print(xbmcvfs.exists(dest))
print('Done.')
Returns:
xml:

13:42:32.338 T:123145461903360   DEBUG: libarchive test
13:42:32.419 T:123145461903360   DEBUG: Archive file test
13:42:32.428 T:123145461903360   DEBUG: Dirs and files
13:42:32.428 T:123145461903360   DEBUG:
13:42:32.429 T:123145461903360   DEBUG: ['41_09.rom', '41_18.rom', '41_19.rom', '41_32.rom', '41_gfx1.rom', '41_gfx3.rom', '41_gfx5.rom', '41_gfx7.rom', '41e_30.rom', '41e_31.rom', '41e_35.rom', '41e_36.rom']
13:42:32.429 T:123145461903360   DEBUG: 0
13:42:32.429 T:123145461903360   DEBUG: Test copy from archive archive://%2FUsers%2Fxxx%2FDownloads%2F1941.zip/41_09.rom to /Users/xxx/Downloads/test/41_09.rom
13:42:32.430 T:123145461903360   DEBUG: 0
13:42:32.430 T:123145461903360   DEBUG: Copied file exists test from archive
13:42:32.430 T:123145461903360   DEBUG: 0
13:42:32.430 T:123145461903360   DEBUG: Zip file test
13:42:32.432 T:123145461903360   DEBUG: Dirs and files
13:42:32.433 T:123145461903360   DEBUG:
13:42:32.433 T:123145461903360   DEBUG: ['41_09.rom', '41_18.rom', '41_19.rom', '41_32.rom', '41_gfx1.rom', '41_gfx3.rom', '41_gfx5.rom', '41_gfx7.rom', '41e_30.rom', '41e_31.rom', '41e_35.rom', '41e_36.rom']
13:42:32.433 T:123145461903360   DEBUG: 1
13:42:32.434 T:123145461903360   DEBUG: Test copy from zip zip://%2FUsers%2Fxxx%2FDownloads%2F1941.zip/41_09.rom to /Users/xxx/Downloads/test/41_09.rom
13:42:32.437 T:123145461903360   DEBUG: 1
13:42:32.438 T:123145461903360   DEBUG: Copied file exists test from zip
13:42:32.438 T:123145461903360   DEBUG: 1
13:42:32.438 T:123145461903360   DEBUG: Done.
Reply
#25
xbmc.extract is legacy code which i did not extend to support the new archive protocol. It could be done but copydir etc is preferable. The extract builtin was there to bypass some intermediate caching. Any such caching is now an implementation detail in libarchive and thus there is no need for a dedicated command.

There is no reason why copying from archive urls should not work (not questioning your observations). I am on holiday until mid january, will look into it asap when i get back home and the backlog at work has been taken care of.
Reply
#26
Thanks.  I'm not able to find a copydir function in xbmcvfs, and I can't find a way to listdir for a folder within an archive (in order to try and copy files individually)
Reply
#27
found and fixed https://github.com/xbmc/xbmc/pull/15309
Reply
#28
Hello,

I'm using the below code to extract subtitles files from archive:

python:
      
       path = urllib.quote_plus(tempfile)
       (dirs, files) = xbmcvfs.listdir('archive://%s' % (path))
       for file in files:
           src = 'archive://' + path + '/' + file
           log( sys._getframe().f_code.co_name ,"file name: %s" % (file))
           dest = os.path.join(__temp__, files)
           log( sys._getframe().f_code.co_name ,"src: %s" % (src))
           log( sys._getframe().f_code.co_name ,"dest: %s" % (dest))
           xbmcvfs.copy(src, dest)

where tempfile = /storage/.kodi/userdata/addon_data/service.subtitles.zimuku/temp/subtitles.rar

and i get the below error:
ERROR: GetDirectory - Error getting archive://%2fstorage%2f.kodi%2fuserdata%2faddon_data%2fservice.subtitles.zimuku%2ftemp%2fsubtitles.rar/

I dont know what is wrong is my code ?
I checked and the rar file is located in /storage/.kodi/userdata/addon_data/service.subtitles.zimuku/temp/
I've enable vfs.libarchive (vfs.rar is disabled)

Thank you
Reply
#29
Hi, it seems you've got it working, but I still have one issue, using an automatic subtitles downloader (Legendas.tv). It uses zip files and the subtitle files are inside a directory inside the zip file. For accomplish it, it uses the zip:// protocol and xmbcvfs.listdir to get the list of zip file. The problem is: we cannot use listdir to get the list of directory inside the zip file (to recurse all directories inside the zip file). Below is an example of code and the error generated by it.

I didn't test the copydir yet, I was not planing on extract directory by directory to list all files (the idea would be to extract/copy only one choosen file from a complete list of what was found on the zip file). Would copydir be the only way? Is listdir limited to list the "root" dir inside the archive?

Example code, trying to listdir a directory found inside the zip file (using listdir on the zip itself first):

python:

import xmbcvfs
...
# Here the correctly and checked downloaded zip file url is
# zipprotocolpath = "zip://C:\Users\Username\AppData\Roaming\Kodi\userdata\addon_data\service.subtitles.legendastv\temp\Extracted\f63a57e12f72471ab5912f976776cc87.zip"
dirs, files = xmbcvfs.listdir( zipprotocolpath )  
for dir in dirs:
    # Here the first (correctly) found dir = "legendas_tv_20181109202013214"
    insidedirs, insidefiles = xmbcvfs.listdir( os.path.join( zipprotocolpath, dir ))
    # And that is where we get the GetZipList error

A piece from log, where states the error:

Code:
12:39:35.365 T:15704  NOTICE: ADDON: service.subtitles.legendastv v2.4.0 installed
12:39:35.365 T:15704  NOTICE: ADDON: vfs.rar v2.0.6 installed
...
12:46:01.076 T:13608   DEBUG: ### [Legendas.TV] - Opening URL: (http://legendas.tv/downloadarquivo/5be5ebf227fc8)
12:46:03.539 T:13608   DEBUG: CZipManager::GetZipList: failed to stat file zip://C%3a%5cUsers%5cUsername%5cAppData%5cRoaming%5cKodi%5cuserdata%5caddon_data%5cservice.subtitles.legendastv%5ctemp%5cExtracted%5cf63a57e12f72471ab5912f976776cc87.zip%5clegendas_tv_20181109202013214/
12:46:03.539 T:13608   ERROR: XFILE::CDirectory::GetDirectory - Error getting zip://C%3a%5cUsers%5cUsername%5cAppData%5cRoaming%5cKodi%5cuserdata%5caddon_data%5cservice.subtitles.legendastv%5ctemp%5cExtracted%5cf63a57e12f72471ab5912f976776cc87.zip%5clegendas_tv_20181109202013214/
Reply
#30
For zip files with Kodi 18, I'm still using xbmc.extract(src,dest) as it works fine
Reply

Logout Mark Read Team Forum Stats Members Help
XBMC.Extract0