Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mikf
GitHub Repository: mikf/gallery-dl
Path: blob/master/gallery_dl/postprocessor/zip.py
8753 views
1
# -*- coding: utf-8 -*-
2
3
# Copyright 2018-2022 Mike Fährmann
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License version 2 as
7
# published by the Free Software Foundation.
8
9
"""Store files in ZIP archives"""
10
11
from .common import PostProcessor
12
from .. import util
13
import zipfile
14
import os
15
16
17
class ZipPP(PostProcessor):
18
19
COMPRESSION_ALGORITHMS = {
20
"store": zipfile.ZIP_STORED,
21
"zip" : zipfile.ZIP_DEFLATED,
22
"bzip2": zipfile.ZIP_BZIP2,
23
"lzma" : zipfile.ZIP_LZMA,
24
}
25
26
def __init__(self, job, options):
27
PostProcessor.__init__(self, job)
28
self.delete = not options.get("keep-files", False)
29
self.files = options.get("files")
30
ext = "." + options.get("extension", "zip")
31
algorithm = options.get("compression", "store")
32
if algorithm not in self.COMPRESSION_ALGORITHMS:
33
self.log.warning(
34
"unknown compression algorithm '%s'; falling back to 'store'",
35
algorithm)
36
algorithm = "store"
37
38
self.zfile = None
39
self.path = job.pathfmt.realdirectory[:-1]
40
self.args = (self.path + ext, "a",
41
self.COMPRESSION_ALGORITHMS[algorithm], True)
42
43
job.register_hooks({
44
"file": (self.write_safe if options.get("mode") == "safe" else
45
self.write_fast),
46
}, options)
47
job.hooks["finalize"].append(self.finalize)
48
49
def open(self):
50
try:
51
return zipfile.ZipFile(*self.args)
52
except FileNotFoundError:
53
os.makedirs(os.path.dirname(self.path))
54
return zipfile.ZipFile(*self.args)
55
56
def write(self, pathfmt, zfile):
57
# 'NameToInfo' is not officially documented, but it's available
58
# for all supported Python versions and using it directly is a lot
59
# faster than calling getinfo()
60
if self.files:
61
self.write_extra(pathfmt, zfile, self.files)
62
self.files = None
63
if pathfmt.filename not in zfile.NameToInfo:
64
zfile.write(pathfmt.temppath, pathfmt.filename)
65
pathfmt.delete = self.delete
66
67
def write_fast(self, pathfmt):
68
if self.zfile is None:
69
self.zfile = self.open()
70
self.write(pathfmt, self.zfile)
71
72
def write_safe(self, pathfmt):
73
with self.open() as zfile:
74
self.write(pathfmt, zfile)
75
76
def write_extra(self, pathfmt, zfile, files):
77
for path in map(util.expand_path, files):
78
if not os.path.isabs(path):
79
path = os.path.join(pathfmt.realdirectory, path)
80
try:
81
zfile.write(path, os.path.basename(path))
82
except OSError as exc:
83
self.log.warning(
84
"Unable to write %s to %s", path, zfile.filename)
85
self.log.debug("%s: %s", exc, exc.__class__.__name__)
86
pass
87
else:
88
if self.delete:
89
util.remove_file(path)
90
91
def finalize(self, pathfmt):
92
if self.zfile:
93
self.zfile.close()
94
95
if self.delete:
96
util.remove_directory(self.path)
97
98
if self.zfile and not self.zfile.NameToInfo:
99
# remove empty zip archive
100
util.remove_file(self.zfile.filename)
101
102
103
__postprocessor__ = ZipPP
104
105