mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-25 11:43:44 +03:00
added doc, docs, gif preview, file update form
This commit is contained in:
parent
a7dcfb4540
commit
2a9d0d7011
9
akarpov/files/forms.py
Normal file
9
akarpov/files/forms.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from django import forms
|
||||
|
||||
from akarpov.files.models import File
|
||||
|
||||
|
||||
class FileForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = File
|
||||
fields = ["name", "private", "description"]
|
|
@ -35,6 +35,10 @@ class File(TimeStampedModel, ShortLink):
|
|||
description = TextField(blank=True, null=True)
|
||||
file_type = CharField(max_length=255, null=True, blank=True)
|
||||
|
||||
@property
|
||||
def file_name(self):
|
||||
return self.file.path.split("/")[-1]
|
||||
|
||||
@property
|
||||
def file_image_url(self):
|
||||
if self.preview:
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
previews = {
|
||||
"application": {
|
||||
"zip": application.zip.view,
|
||||
"doc": application.doc.view,
|
||||
"docx": application.docx.view,
|
||||
},
|
||||
"audio": {
|
||||
"aac": audio.basic.view,
|
||||
|
@ -18,6 +20,7 @@
|
|||
"png": image.basic.view,
|
||||
"avif": image.basic.view,
|
||||
"bmp": image.basic.view,
|
||||
"gif": image.gif.view,
|
||||
},
|
||||
"text": {"css": text.common.view, "plain": text.plain.view, "csv": text.csv.view},
|
||||
}
|
||||
|
@ -32,4 +35,7 @@
|
|||
"avif": image.basic.view,
|
||||
"bmp": image.basic.view,
|
||||
"mov": video.basic.view,
|
||||
"doc": application.doc.view,
|
||||
"docx": application.docx.view,
|
||||
"gif": image.gif.view,
|
||||
} | source_code
|
||||
|
|
|
@ -1 +1 @@
|
|||
from . import zip # noqa
|
||||
from . import doc, docx, zip # noqa
|
||||
|
|
16
akarpov/files/previews/application/doc.py
Normal file
16
akarpov/files/previews/application/doc.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
import textract
|
||||
|
||||
from akarpov.files.models import File
|
||||
|
||||
|
||||
def view(file: File):
|
||||
static = ""
|
||||
content = ""
|
||||
text = (
|
||||
textract.process(file.file.path, extension="doc", output_encoding="utf8")
|
||||
.decode("utf8")
|
||||
.replace("\t", " ")
|
||||
)
|
||||
for line in text.split("\n"):
|
||||
content += f"<p class='mt-1'>{line}</p>"
|
||||
return static, content
|
16
akarpov/files/previews/application/docx.py
Normal file
16
akarpov/files/previews/application/docx.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
import textract
|
||||
|
||||
from akarpov.files.models import File
|
||||
|
||||
|
||||
def view(file: File):
|
||||
static = ""
|
||||
content = ""
|
||||
text = (
|
||||
textract.process(file.file.path, extension="docx", output_encoding="utf8")
|
||||
.decode("utf8")
|
||||
.replace("\t", " ")
|
||||
)
|
||||
for line in text.split("\n"):
|
||||
content += f"<p class='mt-1'>{line}</p>"
|
||||
return static, content
|
|
@ -1 +1 @@
|
|||
from . import basic # noqa
|
||||
from . import basic, gif # noqa
|
||||
|
|
29
akarpov/files/previews/image/gif.py
Normal file
29
akarpov/files/previews/image/gif.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
from akarpov.files.models import File
|
||||
|
||||
|
||||
def view(file: File):
|
||||
static = ""
|
||||
content = (
|
||||
f"""
|
||||
<div class="col-auto">
|
||||
<img class="img-fluid" src="{file.file.url}" rel:animated_src="{file.file.url}"
|
||||
rel:auto_play="1" rel:rubbable="1" />
|
||||
</div>
|
||||
"""
|
||||
+ r"""
|
||||
<script type="text/javascript" src="/static/js/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/libgif.js"></script>
|
||||
<script type="text/javascript">
|
||||
$('img').each(function (img_tag) {
|
||||
if (/.*\.gif/.test(img_tag.src)) {
|
||||
var rub = new SuperGif({ gif: img_tag } );
|
||||
rub.load(function(){
|
||||
console.log('oh hey, now the gif is loaded');
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
"""
|
||||
)
|
||||
|
||||
return static, content
|
|
@ -48,15 +48,15 @@ def view(file: File):
|
|||
reader = csv.reader(csvfile, dialect)
|
||||
content = get_csv_table(reader)
|
||||
except UnicodeDecodeError:
|
||||
rawdata = open("file.csv", "rb").read()
|
||||
rawdata = open(file.file.path, "rb").read()
|
||||
enc = chardet.detect(rawdata)
|
||||
print(enc)
|
||||
with open(file.file.path, newline="", encoding=enc["encoding"]) as csvfile:
|
||||
dialect = csv.Sniffer().sniff(csvfile.read(1024))
|
||||
csvfile.seek(0)
|
||||
reader = csv.reader(csvfile, dialect)
|
||||
content = get_csv_table(reader)
|
||||
except Exception as e:
|
||||
content = "couldn't parse csv file"
|
||||
logger.error(e)
|
||||
static = ""
|
||||
return static, content
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
MyChunkedUploadView,
|
||||
TopFolderView,
|
||||
delete_file_view,
|
||||
file_update,
|
||||
files_view,
|
||||
folder_view,
|
||||
)
|
||||
|
@ -23,6 +24,7 @@
|
|||
"api/chunked_upload/", MyChunkedUploadView.as_view(), name="api_chunked_upload"
|
||||
),
|
||||
path("<str:slug>", files_view, name="view"),
|
||||
path("<str:slug>/update", file_update, name="update"),
|
||||
path("<str:slug>/delete", delete_file_view, name="delete"),
|
||||
path("f/<str:slug>", folder_view, name="folder"),
|
||||
]
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import os
|
||||
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse
|
||||
from django.views.generic import DetailView, ListView, RedirectView
|
||||
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
|
||||
from django.views.generic.base import TemplateView
|
||||
|
||||
from akarpov.contrib.chunked_upload.exceptions import ChunkedUploadError
|
||||
|
@ -12,6 +13,7 @@
|
|||
ChunkedUploadCompleteView,
|
||||
ChunkedUploadView,
|
||||
)
|
||||
from akarpov.files.forms import FileForm
|
||||
from akarpov.files.models import File, Folder
|
||||
from akarpov.files.previews import extensions, previews
|
||||
|
||||
|
@ -32,6 +34,22 @@ def get_context_data(self, **kwargs):
|
|||
return contex
|
||||
|
||||
|
||||
class FileUpdateView(LoginRequiredMixin, UpdateView):
|
||||
model = File
|
||||
form_class = FileForm
|
||||
|
||||
def get_object(self):
|
||||
file = get_object_or_404(File, slug=self.kwargs["slug"])
|
||||
if file.user != self.request.user:
|
||||
raise PermissionDenied
|
||||
return file
|
||||
|
||||
template_name = "files/form.html"
|
||||
|
||||
|
||||
file_update = FileUpdateView.as_view()
|
||||
|
||||
|
||||
class FileView(DetailView):
|
||||
template_name = "files/view.html"
|
||||
model = File
|
||||
|
|
988
akarpov/static/js/libgif.js
Normal file
988
akarpov/static/js/libgif.js
Normal file
|
@ -0,0 +1,988 @@
|
|||
/*
|
||||
SuperGif
|
||||
|
||||
Example usage:
|
||||
|
||||
<img src="./example1_preview.gif" rel:animated_src="./example1.gif" width="360" height="360" rel:auto_play="1" />
|
||||
|
||||
<script type="text/javascript">
|
||||
$$('img').each(function (img_tag) {
|
||||
if (/.*\.gif/.test(img_tag.src)) {
|
||||
var rub = new SuperGif({ gif: img_tag } );
|
||||
rub.load();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
Image tag attributes:
|
||||
|
||||
rel:animated_src - If this url is specified, it's loaded into the player instead of src.
|
||||
This allows a preview frame to be shown until animated gif data is streamed into the canvas
|
||||
|
||||
rel:auto_play - Defaults to 1 if not specified. If set to zero, a call to the play() method is needed
|
||||
|
||||
Constructor options args
|
||||
|
||||
gif Required. The DOM element of an img tag.
|
||||
loop_mode Optional. Setting this to false will force disable looping of the gif.
|
||||
auto_play Optional. Same as the rel:auto_play attribute above, this arg overrides the img tag info.
|
||||
max_width Optional. Scale images over max_width down to max_width. Helpful with mobile.
|
||||
on_end Optional. Add a callback for when the gif reaches the end of a single loop (one iteration). The first argument passed will be the gif HTMLElement.
|
||||
loop_delay Optional. The amount of time to pause (in ms) after each single loop (iteration).
|
||||
draw_while_loading Optional. Determines whether the gif will be drawn to the canvas whilst it is loaded.
|
||||
show_progress_bar Optional. Only applies when draw_while_loading is set to true.
|
||||
|
||||
Instance methods
|
||||
|
||||
// loading
|
||||
load( callback ) Loads the gif specified by the src or rel:animated_src sttributie of the img tag into a canvas element and then calls callback if one is passed
|
||||
load_url( src, callback ) Loads the gif file specified in the src argument into a canvas element and then calls callback if one is passed
|
||||
|
||||
// play controls
|
||||
play - Start playing the gif
|
||||
pause - Stop playing the gif
|
||||
move_to(i) - Move to frame i of the gif
|
||||
move_relative(i) - Move i frames ahead (or behind if i < 0)
|
||||
|
||||
// getters
|
||||
get_canvas The canvas element that the gif is playing in. Handy for assigning event handlers to.
|
||||
get_playing Whether or not the gif is currently playing
|
||||
get_loading Whether or not the gif has finished loading/parsing
|
||||
get_auto_play Whether or not the gif is set to play automatically
|
||||
get_length The number of frames in the gif
|
||||
get_current_frame The index of the currently displayed frame of the gif
|
||||
|
||||
For additional customization (viewport inside iframe) these params may be passed:
|
||||
c_w, c_h - width and height of canvas
|
||||
vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport
|
||||
|
||||
A bonus: few articles to understand what is going on
|
||||
http://enthusiasms.org/post/16976438906
|
||||
http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
|
||||
http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546
|
||||
|
||||
*/
|
||||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
} else {
|
||||
root.SuperGif = factory();
|
||||
}
|
||||
}(this, function () {
|
||||
// Generic functions
|
||||
var bitsToNum = function (ba) {
|
||||
return ba.reduce(function (s, n) {
|
||||
return s * 2 + n;
|
||||
}, 0);
|
||||
};
|
||||
|
||||
var byteToBitArr = function (bite) {
|
||||
var a = [];
|
||||
for (var i = 7; i >= 0; i--) {
|
||||
a.push( !! (bite & (1 << i)));
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
// Stream
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
// Make compiler happy.
|
||||
var Stream = function (data) {
|
||||
this.data = data;
|
||||
this.len = this.data.length;
|
||||
this.pos = 0;
|
||||
|
||||
this.readByte = function () {
|
||||
if (this.pos >= this.data.length) {
|
||||
throw new Error('Attempted to read past end of stream.');
|
||||
}
|
||||
if (data instanceof Uint8Array)
|
||||
return data[this.pos++];
|
||||
else
|
||||
return data.charCodeAt(this.pos++) & 0xFF;
|
||||
};
|
||||
|
||||
this.readBytes = function (n) {
|
||||
var bytes = [];
|
||||
for (var i = 0; i < n; i++) {
|
||||
bytes.push(this.readByte());
|
||||
}
|
||||
return bytes;
|
||||
};
|
||||
|
||||
this.read = function (n) {
|
||||
var s = '';
|
||||
for (var i = 0; i < n; i++) {
|
||||
s += String.fromCharCode(this.readByte());
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
this.readUnsigned = function () { // Little-endian.
|
||||
var a = this.readBytes(2);
|
||||
return (a[1] << 8) + a[0];
|
||||
};
|
||||
};
|
||||
|
||||
var lzwDecode = function (minCodeSize, data) {
|
||||
// TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String?
|
||||
var pos = 0; // Maybe this streaming thing should be merged with the Stream?
|
||||
var readCode = function (size) {
|
||||
var code = 0;
|
||||
for (var i = 0; i < size; i++) {
|
||||
if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) {
|
||||
code |= 1 << i;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return code;
|
||||
};
|
||||
|
||||
var output = [];
|
||||
|
||||
var clearCode = 1 << minCodeSize;
|
||||
var eoiCode = clearCode + 1;
|
||||
|
||||
var codeSize = minCodeSize + 1;
|
||||
|
||||
var dict = [];
|
||||
|
||||
var clear = function () {
|
||||
dict = [];
|
||||
codeSize = minCodeSize + 1;
|
||||
for (var i = 0; i < clearCode; i++) {
|
||||
dict[i] = [i];
|
||||
}
|
||||
dict[clearCode] = [];
|
||||
dict[eoiCode] = null;
|
||||
|
||||
};
|
||||
|
||||
var code;
|
||||
var last;
|
||||
|
||||
while (true) {
|
||||
last = code;
|
||||
code = readCode(codeSize);
|
||||
|
||||
if (code === clearCode) {
|
||||
clear();
|
||||
continue;
|
||||
}
|
||||
if (code === eoiCode) break;
|
||||
|
||||
if (code < dict.length) {
|
||||
if (last !== clearCode) {
|
||||
dict.push(dict[last].concat(dict[code][0]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (code !== dict.length) throw new Error('Invalid LZW code.');
|
||||
dict.push(dict[last].concat(dict[last][0]));
|
||||
}
|
||||
output.push.apply(output, dict[code]);
|
||||
|
||||
if (dict.length === (1 << codeSize) && codeSize < 12) {
|
||||
// If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long.
|
||||
codeSize++;
|
||||
}
|
||||
}
|
||||
|
||||
// I don't know if this is technically an error, but some GIFs do it.
|
||||
//if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.');
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
// The actual parsing; returns an object with properties.
|
||||
var parseGIF = function (st, handler) {
|
||||
handler || (handler = {});
|
||||
|
||||
// LZW (GIF-specific)
|
||||
var parseCT = function (entries) { // Each entry is 3 bytes, for RGB.
|
||||
var ct = [];
|
||||
for (var i = 0; i < entries; i++) {
|
||||
ct.push(st.readBytes(3));
|
||||
}
|
||||
return ct;
|
||||
};
|
||||
|
||||
var readSubBlocks = function () {
|
||||
var size, data;
|
||||
data = '';
|
||||
do {
|
||||
size = st.readByte();
|
||||
data += st.read(size);
|
||||
} while (size !== 0);
|
||||
return data;
|
||||
};
|
||||
|
||||
var parseHeader = function () {
|
||||
var hdr = {};
|
||||
hdr.sig = st.read(3);
|
||||
hdr.ver = st.read(3);
|
||||
if (hdr.sig !== 'GIF') throw new Error('Not a GIF file.'); // XXX: This should probably be handled more nicely.
|
||||
hdr.width = st.readUnsigned();
|
||||
hdr.height = st.readUnsigned();
|
||||
|
||||
var bits = byteToBitArr(st.readByte());
|
||||
hdr.gctFlag = bits.shift();
|
||||
hdr.colorRes = bitsToNum(bits.splice(0, 3));
|
||||
hdr.sorted = bits.shift();
|
||||
hdr.gctSize = bitsToNum(bits.splice(0, 3));
|
||||
|
||||
hdr.bgColor = st.readByte();
|
||||
hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64
|
||||
if (hdr.gctFlag) {
|
||||
hdr.gct = parseCT(1 << (hdr.gctSize + 1));
|
||||
}
|
||||
handler.hdr && handler.hdr(hdr);
|
||||
};
|
||||
|
||||
var parseExt = function (block) {
|
||||
var parseGCExt = function (block) {
|
||||
var blockSize = st.readByte(); // Always 4
|
||||
var bits = byteToBitArr(st.readByte());
|
||||
block.reserved = bits.splice(0, 3); // Reserved; should be 000.
|
||||
block.disposalMethod = bitsToNum(bits.splice(0, 3));
|
||||
block.userInput = bits.shift();
|
||||
block.transparencyGiven = bits.shift();
|
||||
|
||||
block.delayTime = st.readUnsigned();
|
||||
|
||||
block.transparencyIndex = st.readByte();
|
||||
|
||||
block.terminator = st.readByte();
|
||||
|
||||
handler.gce && handler.gce(block);
|
||||
};
|
||||
|
||||
var parseComExt = function (block) {
|
||||
block.comment = readSubBlocks();
|
||||
handler.com && handler.com(block);
|
||||
};
|
||||
|
||||
var parsePTExt = function (block) {
|
||||
// No one *ever* uses this. If you use it, deal with parsing it yourself.
|
||||
var blockSize = st.readByte(); // Always 12
|
||||
block.ptHeader = st.readBytes(12);
|
||||
block.ptData = readSubBlocks();
|
||||
handler.pte && handler.pte(block);
|
||||
};
|
||||
|
||||
var parseAppExt = function (block) {
|
||||
var parseNetscapeExt = function (block) {
|
||||
var blockSize = st.readByte(); // Always 3
|
||||
block.unknown = st.readByte(); // ??? Always 1? What is this?
|
||||
block.iterations = st.readUnsigned();
|
||||
block.terminator = st.readByte();
|
||||
handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block);
|
||||
};
|
||||
|
||||
var parseUnknownAppExt = function (block) {
|
||||
block.appData = readSubBlocks();
|
||||
// FIXME: This won't work if a handler wants to match on any identifier.
|
||||
handler.app && handler.app[block.identifier] && handler.app[block.identifier](block);
|
||||
};
|
||||
|
||||
var blockSize = st.readByte(); // Always 11
|
||||
block.identifier = st.read(8);
|
||||
block.authCode = st.read(3);
|
||||
switch (block.identifier) {
|
||||
case 'NETSCAPE':
|
||||
parseNetscapeExt(block);
|
||||
break;
|
||||
default:
|
||||
parseUnknownAppExt(block);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
var parseUnknownExt = function (block) {
|
||||
block.data = readSubBlocks();
|
||||
handler.unknown && handler.unknown(block);
|
||||
};
|
||||
|
||||
block.label = st.readByte();
|
||||
switch (block.label) {
|
||||
case 0xF9:
|
||||
block.extType = 'gce';
|
||||
parseGCExt(block);
|
||||
break;
|
||||
case 0xFE:
|
||||
block.extType = 'com';
|
||||
parseComExt(block);
|
||||
break;
|
||||
case 0x01:
|
||||
block.extType = 'pte';
|
||||
parsePTExt(block);
|
||||
break;
|
||||
case 0xFF:
|
||||
block.extType = 'app';
|
||||
parseAppExt(block);
|
||||
break;
|
||||
default:
|
||||
block.extType = 'unknown';
|
||||
parseUnknownExt(block);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
var parseImg = function (img) {
|
||||
var deinterlace = function (pixels, width) {
|
||||
// Of course this defeats the purpose of interlacing. And it's *probably*
|
||||
// the least efficient way it's ever been implemented. But nevertheless...
|
||||
var newPixels = new Array(pixels.length);
|
||||
var rows = pixels.length / width;
|
||||
var cpRow = function (toRow, fromRow) {
|
||||
var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width);
|
||||
newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels));
|
||||
};
|
||||
|
||||
// See appendix E.
|
||||
var offsets = [0, 4, 2, 1];
|
||||
var steps = [8, 8, 4, 2];
|
||||
|
||||
var fromRow = 0;
|
||||
for (var pass = 0; pass < 4; pass++) {
|
||||
for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) {
|
||||
cpRow(toRow, fromRow)
|
||||
fromRow++;
|
||||
}
|
||||
}
|
||||
|
||||
return newPixels;
|
||||
};
|
||||
|
||||
img.leftPos = st.readUnsigned();
|
||||
img.topPos = st.readUnsigned();
|
||||
img.width = st.readUnsigned();
|
||||
img.height = st.readUnsigned();
|
||||
|
||||
var bits = byteToBitArr(st.readByte());
|
||||
img.lctFlag = bits.shift();
|
||||
img.interlaced = bits.shift();
|
||||
img.sorted = bits.shift();
|
||||
img.reserved = bits.splice(0, 2);
|
||||
img.lctSize = bitsToNum(bits.splice(0, 3));
|
||||
|
||||
if (img.lctFlag) {
|
||||
img.lct = parseCT(1 << (img.lctSize + 1));
|
||||
}
|
||||
|
||||
img.lzwMinCodeSize = st.readByte();
|
||||
|
||||
var lzwData = readSubBlocks();
|
||||
|
||||
img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData);
|
||||
|
||||
if (img.interlaced) { // Move
|
||||
img.pixels = deinterlace(img.pixels, img.width);
|
||||
}
|
||||
|
||||
handler.img && handler.img(img);
|
||||
};
|
||||
|
||||
var parseBlock = function () {
|
||||
var block = {};
|
||||
block.sentinel = st.readByte();
|
||||
|
||||
switch (String.fromCharCode(block.sentinel)) { // For ease of matching
|
||||
case '!':
|
||||
block.type = 'ext';
|
||||
parseExt(block);
|
||||
break;
|
||||
case ',':
|
||||
block.type = 'img';
|
||||
parseImg(block);
|
||||
break;
|
||||
case ';':
|
||||
block.type = 'eof';
|
||||
handler.eof && handler.eof(block);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unknown block: 0x' + block.sentinel.toString(16)); // TODO: Pad this with a 0.
|
||||
}
|
||||
|
||||
if (block.type !== 'eof') setTimeout(parseBlock, 0);
|
||||
};
|
||||
|
||||
var parse = function () {
|
||||
parseHeader();
|
||||
setTimeout(parseBlock, 0);
|
||||
};
|
||||
|
||||
parse();
|
||||
};
|
||||
|
||||
var SuperGif = function ( opts ) {
|
||||
var options = {
|
||||
//viewport position
|
||||
vp_l: 0,
|
||||
vp_t: 0,
|
||||
vp_w: null,
|
||||
vp_h: null,
|
||||
//canvas sizes
|
||||
c_w: null,
|
||||
c_h: null
|
||||
};
|
||||
for (var i in opts ) { options[i] = opts[i] }
|
||||
if (options.vp_w && options.vp_h) options.is_vp = true;
|
||||
|
||||
var stream;
|
||||
var hdr;
|
||||
|
||||
var loadError = null;
|
||||
var loading = false;
|
||||
|
||||
var transparency = null;
|
||||
var delay = null;
|
||||
var disposalMethod = null;
|
||||
var disposalRestoreFromIdx = null;
|
||||
var lastDisposalMethod = null;
|
||||
var frame = null;
|
||||
var lastImg = null;
|
||||
|
||||
var playing = true;
|
||||
var forward = true;
|
||||
|
||||
var ctx_scaled = false;
|
||||
|
||||
var frames = [];
|
||||
var frameOffsets = []; // elements have .x and .y properties
|
||||
|
||||
var gif = options.gif;
|
||||
if (typeof options.auto_play == 'undefined')
|
||||
options.auto_play = (!gif.getAttribute('rel:auto_play') || gif.getAttribute('rel:auto_play') == '1');
|
||||
|
||||
var onEndListener = (options.hasOwnProperty('on_end') ? options.on_end : null);
|
||||
var loopDelay = (options.hasOwnProperty('loop_delay') ? options.loop_delay : 0);
|
||||
var overrideLoopMode = (options.hasOwnProperty('loop_mode') ? options.loop_mode : 'auto');
|
||||
var drawWhileLoading = (options.hasOwnProperty('draw_while_loading') ? options.draw_while_loading : true);
|
||||
var showProgressBar = drawWhileLoading ? (options.hasOwnProperty('show_progress_bar') ? options.show_progress_bar : true) : false;
|
||||
var progressBarHeight = (options.hasOwnProperty('progressbar_height') ? options.progressbar_height : 25);
|
||||
var progressBarBackgroundColor = (options.hasOwnProperty('progressbar_background_color') ? options.progressbar_background_color : 'rgba(255,255,255,0.4)');
|
||||
var progressBarForegroundColor = (options.hasOwnProperty('progressbar_foreground_color') ? options.progressbar_foreground_color : 'rgba(255,0,22,.8)');
|
||||
|
||||
var clear = function () {
|
||||
transparency = null;
|
||||
delay = null;
|
||||
lastDisposalMethod = disposalMethod;
|
||||
disposalMethod = null;
|
||||
frame = null;
|
||||
};
|
||||
|
||||
// XXX: There's probably a better way to handle catching exceptions when
|
||||
// callbacks are involved.
|
||||
var doParse = function () {
|
||||
try {
|
||||
parseGIF(stream, handler);
|
||||
}
|
||||
catch (err) {
|
||||
doLoadError('parse');
|
||||
}
|
||||
};
|
||||
|
||||
var doText = function (text) {
|
||||
toolbar.innerHTML = text; // innerText? Escaping? Whatever.
|
||||
toolbar.style.visibility = 'visible';
|
||||
};
|
||||
|
||||
var setSizes = function(w, h) {
|
||||
canvas.width = w * get_canvas_scale();
|
||||
canvas.height = h * get_canvas_scale();
|
||||
toolbar.style.minWidth = ( w * get_canvas_scale() ) + 'px';
|
||||
|
||||
tmpCanvas.width = w;
|
||||
tmpCanvas.height = h;
|
||||
tmpCanvas.style.width = w + 'px';
|
||||
tmpCanvas.style.height = h + 'px';
|
||||
tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0);
|
||||
};
|
||||
|
||||
var setFrameOffset = function(frame, offset) {
|
||||
if (!frameOffsets[frame]) {
|
||||
frameOffsets[frame] = offset;
|
||||
return;
|
||||
}
|
||||
if (typeof offset.x !== 'undefined') {
|
||||
frameOffsets[frame].x = offset.x;
|
||||
}
|
||||
if (typeof offset.y !== 'undefined') {
|
||||
frameOffsets[frame].y = offset.y;
|
||||
}
|
||||
};
|
||||
|
||||
var doShowProgress = function (pos, length, draw) {
|
||||
if (draw && showProgressBar) {
|
||||
var height = progressBarHeight;
|
||||
var left, mid, top, width;
|
||||
if (options.is_vp) {
|
||||
if (!ctx_scaled) {
|
||||
top = (options.vp_t + options.vp_h - height);
|
||||
height = height;
|
||||
left = options.vp_l;
|
||||
mid = left + (pos / length) * options.vp_w;
|
||||
width = canvas.width;
|
||||
} else {
|
||||
top = (options.vp_t + options.vp_h - height) / get_canvas_scale();
|
||||
height = height / get_canvas_scale();
|
||||
left = (options.vp_l / get_canvas_scale() );
|
||||
mid = left + (pos / length) * (options.vp_w / get_canvas_scale());
|
||||
width = canvas.width / get_canvas_scale();
|
||||
}
|
||||
//some debugging, draw rect around viewport
|
||||
if (false) {
|
||||
if (!ctx_scaled) {
|
||||
var l = options.vp_l, t = options.vp_t;
|
||||
var w = options.vp_w, h = options.vp_h;
|
||||
} else {
|
||||
var l = options.vp_l/get_canvas_scale(), t = options.vp_t/get_canvas_scale();
|
||||
var w = options.vp_w/get_canvas_scale(), h = options.vp_h/get_canvas_scale();
|
||||
}
|
||||
ctx.rect(l,t,w,h);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
else {
|
||||
top = (canvas.height - height) / (ctx_scaled ? get_canvas_scale() : 1);
|
||||
mid = ((pos / length) * canvas.width) / (ctx_scaled ? get_canvas_scale() : 1);
|
||||
width = canvas.width / (ctx_scaled ? get_canvas_scale() : 1 );
|
||||
height /= ctx_scaled ? get_canvas_scale() : 1;
|
||||
}
|
||||
|
||||
ctx.fillStyle = progressBarBackgroundColor;
|
||||
ctx.fillRect(mid, top, width - mid, height);
|
||||
|
||||
ctx.fillStyle = progressBarForegroundColor;
|
||||
ctx.fillRect(0, top, mid, height);
|
||||
}
|
||||
};
|
||||
|
||||
var doLoadError = function (originOfError) {
|
||||
var drawError = function () {
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.fillRect(0, 0, options.c_w ? options.c_w : hdr.width, options.c_h ? options.c_h : hdr.height);
|
||||
ctx.strokeStyle = 'red';
|
||||
ctx.lineWidth = 3;
|
||||
ctx.moveTo(0, 0);
|
||||
ctx.lineTo(options.c_w ? options.c_w : hdr.width, options.c_h ? options.c_h : hdr.height);
|
||||
ctx.moveTo(0, options.c_h ? options.c_h : hdr.height);
|
||||
ctx.lineTo(options.c_w ? options.c_w : hdr.width, 0);
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
loadError = originOfError;
|
||||
hdr = {
|
||||
width: gif.width,
|
||||
height: gif.height
|
||||
}; // Fake header.
|
||||
frames = [];
|
||||
drawError();
|
||||
};
|
||||
|
||||
var doHdr = function (_hdr) {
|
||||
hdr = _hdr;
|
||||
setSizes(hdr.width, hdr.height)
|
||||
};
|
||||
|
||||
var doGCE = function (gce) {
|
||||
pushFrame();
|
||||
clear();
|
||||
transparency = gce.transparencyGiven ? gce.transparencyIndex : null;
|
||||
delay = gce.delayTime;
|
||||
disposalMethod = gce.disposalMethod;
|
||||
// We don't have much to do with the rest of GCE.
|
||||
};
|
||||
|
||||
var pushFrame = function () {
|
||||
if (!frame) return;
|
||||
frames.push({
|
||||
data: frame.getImageData(0, 0, hdr.width, hdr.height),
|
||||
delay: delay
|
||||
});
|
||||
frameOffsets.push({ x: 0, y: 0 });
|
||||
};
|
||||
|
||||
var doImg = function (img) {
|
||||
if (!frame) frame = tmpCanvas.getContext('2d');
|
||||
|
||||
var currIdx = frames.length;
|
||||
|
||||
//ct = color table, gct = global color table
|
||||
var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists?
|
||||
|
||||
/*
|
||||
Disposal method indicates the way in which the graphic is to
|
||||
be treated after being displayed.
|
||||
|
||||
Values : 0 - No disposal specified. The decoder is
|
||||
not required to take any action.
|
||||
1 - Do not dispose. The graphic is to be left
|
||||
in place.
|
||||
2 - Restore to background color. The area used by the
|
||||
graphic must be restored to the background color.
|
||||
3 - Restore to previous. The decoder is required to
|
||||
restore the area overwritten by the graphic with
|
||||
what was there prior to rendering the graphic.
|
||||
|
||||
Importantly, "previous" means the frame state
|
||||
after the last disposal of method 0, 1, or 2.
|
||||
*/
|
||||
if (currIdx > 0) {
|
||||
if (lastDisposalMethod === 3) {
|
||||
// Restore to previous
|
||||
// If we disposed every frame including first frame up to this point, then we have
|
||||
// no composited frame to restore to. In this case, restore to background instead.
|
||||
if (disposalRestoreFromIdx !== null) {
|
||||
frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0);
|
||||
} else {
|
||||
frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height);
|
||||
}
|
||||
} else {
|
||||
disposalRestoreFromIdx = currIdx - 1;
|
||||
}
|
||||
|
||||
if (lastDisposalMethod === 2) {
|
||||
// Restore to background color
|
||||
// Browser implementations historically restore to transparent; we do the same.
|
||||
// http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079
|
||||
frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height);
|
||||
}
|
||||
}
|
||||
// else, Undefined/Do not dispose.
|
||||
// frame contains final pixel data from the last frame; do nothing
|
||||
|
||||
//Get existing pixels for img region after applying disposal method
|
||||
var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height);
|
||||
|
||||
//apply color table colors
|
||||
img.pixels.forEach(function (pixel, i) {
|
||||
// imgData.data === [R,G,B,A,R,G,B,A,...]
|
||||
if (pixel !== transparency) {
|
||||
imgData.data[i * 4 + 0] = ct[pixel][0];
|
||||
imgData.data[i * 4 + 1] = ct[pixel][1];
|
||||
imgData.data[i * 4 + 2] = ct[pixel][2];
|
||||
imgData.data[i * 4 + 3] = 255; // Opaque.
|
||||
}
|
||||
});
|
||||
|
||||
frame.putImageData(imgData, img.leftPos, img.topPos);
|
||||
|
||||
if (!ctx_scaled) {
|
||||
ctx.scale(get_canvas_scale(),get_canvas_scale());
|
||||
ctx_scaled = true;
|
||||
}
|
||||
|
||||
// We could use the on-page canvas directly, except that we draw a progress
|
||||
// bar for each image chunk (not just the final image).
|
||||
if (drawWhileLoading) {
|
||||
ctx.drawImage(tmpCanvas, 0, 0);
|
||||
drawWhileLoading = options.auto_play;
|
||||
}
|
||||
|
||||
lastImg = img;
|
||||
};
|
||||
|
||||
var player = (function () {
|
||||
var i = -1;
|
||||
var iterationCount = 0;
|
||||
|
||||
var showingInfo = false;
|
||||
var pinned = false;
|
||||
|
||||
/**
|
||||
* Gets the index of the frame "up next".
|
||||
* @returns {number}
|
||||
*/
|
||||
var getNextFrameNo = function () {
|
||||
var delta = (forward ? 1 : -1);
|
||||
return (i + delta + frames.length) % frames.length;
|
||||
};
|
||||
|
||||
var stepFrame = function (amount) { // XXX: Name is confusing.
|
||||
i = i + amount;
|
||||
|
||||
putFrame();
|
||||
};
|
||||
|
||||
var step = (function () {
|
||||
var stepping = false;
|
||||
|
||||
var completeLoop = function () {
|
||||
if (onEndListener !== null)
|
||||
onEndListener(gif);
|
||||
iterationCount++;
|
||||
|
||||
if (overrideLoopMode !== false || iterationCount < 0) {
|
||||
doStep();
|
||||
} else {
|
||||
stepping = false;
|
||||
playing = false;
|
||||
}
|
||||
};
|
||||
|
||||
var doStep = function () {
|
||||
stepping = playing;
|
||||
if (!stepping) return;
|
||||
|
||||
stepFrame(1);
|
||||
var delay = frames[i].delay * 10;
|
||||
if (!delay) delay = 100; // FIXME: Should this even default at all? What should it be?
|
||||
|
||||
var nextFrameNo = getNextFrameNo();
|
||||
if (nextFrameNo === 0) {
|
||||
delay += loopDelay;
|
||||
setTimeout(completeLoop, delay);
|
||||
} else {
|
||||
setTimeout(doStep, delay);
|
||||
}
|
||||
};
|
||||
|
||||
return function () {
|
||||
if (!stepping) setTimeout(doStep, 0);
|
||||
};
|
||||
}());
|
||||
|
||||
var putFrame = function () {
|
||||
var offset;
|
||||
i = parseInt(i, 10);
|
||||
|
||||
if (i > frames.length - 1){
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if (i < 0){
|
||||
i = 0;
|
||||
}
|
||||
|
||||
offset = frameOffsets[i];
|
||||
|
||||
tmpCanvas.getContext("2d").putImageData(frames[i].data, offset.x, offset.y);
|
||||
ctx.globalCompositeOperation = "copy";
|
||||
ctx.drawImage(tmpCanvas, 0, 0);
|
||||
};
|
||||
|
||||
var play = function () {
|
||||
playing = true;
|
||||
step();
|
||||
};
|
||||
|
||||
var pause = function () {
|
||||
playing = false;
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
init: function () {
|
||||
if (loadError) return;
|
||||
|
||||
if ( ! (options.c_w && options.c_h) ) {
|
||||
ctx.scale(get_canvas_scale(),get_canvas_scale());
|
||||
}
|
||||
|
||||
if (options.auto_play) {
|
||||
step();
|
||||
}
|
||||
else {
|
||||
i = 0;
|
||||
putFrame();
|
||||
}
|
||||
},
|
||||
step: step,
|
||||
play: play,
|
||||
pause: pause,
|
||||
playing: playing,
|
||||
move_relative: stepFrame,
|
||||
current_frame: function() { return i; },
|
||||
length: function() { return frames.length },
|
||||
move_to: function ( frame_idx ) {
|
||||
i = frame_idx;
|
||||
putFrame();
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
var doDecodeProgress = function (draw) {
|
||||
doShowProgress(stream.pos, stream.data.length, draw);
|
||||
};
|
||||
|
||||
var doNothing = function () {};
|
||||
/**
|
||||
* @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency.
|
||||
* Note that this means that the text will be unsynchronized with the progress bar on non-frames;
|
||||
* but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly.
|
||||
*/
|
||||
var withProgress = function (fn, draw) {
|
||||
return function (block) {
|
||||
fn(block);
|
||||
doDecodeProgress(draw);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
var handler = {
|
||||
hdr: withProgress(doHdr),
|
||||
gce: withProgress(doGCE),
|
||||
com: withProgress(doNothing),
|
||||
// I guess that's all for now.
|
||||
app: {
|
||||
// TODO: Is there much point in actually supporting iterations?
|
||||
NETSCAPE: withProgress(doNothing)
|
||||
},
|
||||
img: withProgress(doImg, true),
|
||||
eof: function (block) {
|
||||
//toolbar.style.display = '';
|
||||
pushFrame();
|
||||
doDecodeProgress(false);
|
||||
if ( ! (options.c_w && options.c_h) ) {
|
||||
canvas.width = hdr.width * get_canvas_scale();
|
||||
canvas.height = hdr.height * get_canvas_scale();
|
||||
}
|
||||
player.init();
|
||||
loading = false;
|
||||
if (load_callback) {
|
||||
load_callback(gif);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var init = function () {
|
||||
var parent = gif.parentNode;
|
||||
|
||||
var div = document.createElement('div');
|
||||
canvas = document.createElement('canvas');
|
||||
ctx = canvas.getContext('2d');
|
||||
toolbar = document.createElement('div');
|
||||
|
||||
tmpCanvas = document.createElement('canvas');
|
||||
|
||||
div.width = canvas.width = gif.width;
|
||||
div.height = canvas.height = gif.height;
|
||||
toolbar.style.minWidth = gif.width + 'px';
|
||||
|
||||
div.className = 'jsgif';
|
||||
toolbar.className = 'jsgif_toolbar';
|
||||
div.appendChild(canvas);
|
||||
div.appendChild(toolbar);
|
||||
|
||||
parent.insertBefore(div, gif);
|
||||
parent.removeChild(gif);
|
||||
|
||||
if (options.c_w && options.c_h) setSizes(options.c_w, options.c_h);
|
||||
initialized=true;
|
||||
};
|
||||
|
||||
var get_canvas_scale = function() {
|
||||
var scale;
|
||||
if (options.max_width && hdr && hdr.width > options.max_width) {
|
||||
scale = options.max_width / hdr.width;
|
||||
}
|
||||
else {
|
||||
scale = 1;
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
var canvas, ctx, toolbar, tmpCanvas;
|
||||
var initialized = false;
|
||||
var load_callback = false;
|
||||
|
||||
var load_setup = function(callback) {
|
||||
if (loading) return false;
|
||||
if (callback) load_callback = callback;
|
||||
else load_callback = false;
|
||||
|
||||
loading = true;
|
||||
frames = [];
|
||||
clear();
|
||||
disposalRestoreFromIdx = null;
|
||||
lastDisposalMethod = null;
|
||||
frame = null;
|
||||
lastImg = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return {
|
||||
// play controls
|
||||
play: player.play,
|
||||
pause: player.pause,
|
||||
move_relative: player.move_relative,
|
||||
move_to: player.move_to,
|
||||
|
||||
// getters for instance vars
|
||||
get_playing : function() { return playing },
|
||||
get_canvas : function() { return canvas },
|
||||
get_canvas_scale : function() { return get_canvas_scale() },
|
||||
get_loading : function() { return loading },
|
||||
get_auto_play : function() { return options.auto_play },
|
||||
get_length : function() { return player.length() },
|
||||
get_current_frame: function() { return player.current_frame() },
|
||||
load_url: function(src,callback){
|
||||
if (!load_setup(callback)) return;
|
||||
|
||||
var h = new XMLHttpRequest();
|
||||
// new browsers (XMLHttpRequest2-compliant)
|
||||
h.open('GET', src, true);
|
||||
|
||||
if ('overrideMimeType' in h) {
|
||||
h.overrideMimeType('text/plain; charset=x-user-defined');
|
||||
}
|
||||
|
||||
// old browsers (XMLHttpRequest-compliant)
|
||||
else if ('responseType' in h) {
|
||||
h.responseType = 'arraybuffer';
|
||||
}
|
||||
|
||||
// IE9 (Microsoft.XMLHTTP-compliant)
|
||||
else {
|
||||
h.setRequestHeader('Accept-Charset', 'x-user-defined');
|
||||
}
|
||||
|
||||
h.onloadstart = function() {
|
||||
// Wait until connection is opened to replace the gif element with a canvas to avoid a blank img
|
||||
if (!initialized) init();
|
||||
};
|
||||
h.onload = function(e) {
|
||||
if (this.status != 200) {
|
||||
doLoadError('xhr - response');
|
||||
}
|
||||
// emulating response field for IE9
|
||||
if (!('response' in this)) {
|
||||
this.response = new VBArray(this.responseText).toArray().map(String.fromCharCode).join('');
|
||||
}
|
||||
var data = this.response;
|
||||
if (data.toString().indexOf("ArrayBuffer") > 0) {
|
||||
data = new Uint8Array(data);
|
||||
}
|
||||
|
||||
stream = new Stream(data);
|
||||
setTimeout(doParse, 0);
|
||||
};
|
||||
h.onprogress = function (e) {
|
||||
if (e.lengthComputable) doShowProgress(e.loaded, e.total, true);
|
||||
};
|
||||
h.onerror = function() { doLoadError('xhr'); };
|
||||
h.send();
|
||||
},
|
||||
load: function (callback) {
|
||||
this.load_url(gif.getAttribute('rel:animated_src') || gif.src,callback);
|
||||
},
|
||||
load_raw: function(arr, callback) {
|
||||
if (!load_setup(callback)) return;
|
||||
if (!initialized) init();
|
||||
stream = new Stream(arr);
|
||||
setTimeout(doParse, 0);
|
||||
},
|
||||
set_frame_offset: setFrameOffset
|
||||
};
|
||||
};
|
||||
|
||||
return SuperGif;
|
||||
}));
|
|
@ -114,7 +114,7 @@
|
|||
</div>
|
||||
</main>
|
||||
<footer class="row bg-light py-1 mt-auto text-center">
|
||||
<div class="col"> Writen by sanspie, find source code <a href="https://github.com/Alexander-D-Karpov/akarpov">here</a> </div>
|
||||
<div class="col"> Writen by <a href="/about">sanspie</a>, find source code <a href="https://github.com/Alexander-D-Karpov/akarpov">here</a> </div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
|
20
akarpov/templates/files/form.html
Normal file
20
akarpov/templates/files/form.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block title %}editing file on akarpov{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form class="pt-2" enctype="multipart/form-data" method="POST" id="designer-form">
|
||||
{% csrf_token %}
|
||||
{{ form.media }}
|
||||
{% for field in form %}
|
||||
{{ field|as_crispy_field }}
|
||||
{% endfor %}
|
||||
<div class="mt-4 flex justify-end space-x-4">
|
||||
<button class="btn btn-secondary" type="submit" id="submit">
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -8,7 +8,12 @@
|
|||
|
||||
{% block content %}
|
||||
<div class="row m-2">
|
||||
<h1 class="fs-1 text-break mb-4">{{ file.name }}</h1>
|
||||
<h1 class="fs-1 text-break mb-4">{{ file.name }}
|
||||
{% if has_perm %}
|
||||
<a class="justify-content-center" href="{% url 'files:update' file.slug %}">
|
||||
<i style="color:black" class="bi bi-pen fs-6"></i></a>
|
||||
{% endif %}
|
||||
</h1>
|
||||
<div class="col-md-4 col-sm-6 col-xs-auto mb-5">
|
||||
{% if not has_perm %}
|
||||
<p>Uploaded by: <a href="{% url 'users:detail' file.user.username %}">
|
||||
|
@ -17,6 +22,7 @@
|
|||
{% endif %}
|
||||
<p class="mt-2">Last updated: {{ file.modified|date:"d.m.Y" }} {{ file.modified|time:"H:i" }}</p>
|
||||
<p>File size: {{ file.file_size | filesizeformat }}</p>
|
||||
<p>File name: {{ file.file_name }}</p>
|
||||
{% if file.file_type %}
|
||||
<p>File type: {{ file.file_type }}</p>
|
||||
{% endif %}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
apt-get update
|
||||
apt-get install -y poppler-utils libfile-mimeinfo-perl ghostscript libsecret-1-0 zlib1g-dev libjpeg-dev imagemagick libmagic1 libreoffice inkscape xvfb
|
||||
apt-get install -y libxml2-dev libxslt1-dev antiword unrtf pstotext tesseract-ocr flac lame libmad0 libsox-fmt-mp3 sox swig
|
||||
wget https://github.com/jgraph/drawio-desktop/releases/download/v13.0.3/draw.io-amd64-13.0.3.deb
|
||||
dpkg -i draw.io-amd64-13.0.3.deb
|
||||
rm draw.io-amd64-13.0.3.deb
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
SpectacularSwaggerView,
|
||||
)
|
||||
|
||||
from akarpov.about.views import about_view
|
||||
from akarpov.tools.shortener.views import redirect_view
|
||||
|
||||
urlpatterns = [
|
||||
|
@ -20,6 +21,7 @@
|
|||
path(settings.ADMIN_URL, admin.site.urls),
|
||||
# User management
|
||||
path("users/", include("akarpov.users.urls", namespace="users")),
|
||||
path("about", about_view),
|
||||
path("about/", include("akarpov.about.urls", namespace="about")),
|
||||
path("files/", include("akarpov.files.urls", namespace="files")),
|
||||
path("music/", include("akarpov.music.urls", namespace="music")),
|
||||
|
|
520
poetry.lock
generated
520
poetry.lock
generated
|
@ -213,6 +213,21 @@ files = [
|
|||
{file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argcomplete"
|
||||
version = "1.10.3"
|
||||
description = "Bash tab completion for argparse"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "argcomplete-1.10.3-py2.py3-none-any.whl", hash = "sha256:d8ea63ebaec7f59e56e7b2a386b1d1c7f1a7ae87902c9ee17d377eaa557f06fa"},
|
||||
{file = "argcomplete-1.10.3.tar.gz", hash = "sha256:a37f522cf3b6a34abddfedb61c4546f60023b3799b22d1cd971eacdc0861530a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
test = ["coverage", "flake8", "pexpect", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "argon2-cffi"
|
||||
version = "21.3.0"
|
||||
|
@ -423,6 +438,26 @@ files = [
|
|||
{file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "beautifulsoup4"
|
||||
version = "4.8.2"
|
||||
description = "Screen-scraping library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "beautifulsoup4-4.8.2-py2-none-any.whl", hash = "sha256:e1505eeed31b0f4ce2dbb3bc8eb256c04cc2b3b72af7d551a4ab6efd5cbe5dae"},
|
||||
{file = "beautifulsoup4-4.8.2-py3-none-any.whl", hash = "sha256:9fbb4d6e48ecd30bcacc5b63b94088192dcda178513b2ae3c394229f8911b887"},
|
||||
{file = "beautifulsoup4-4.8.2.tar.gz", hash = "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
soupsieve = ">=1.2"
|
||||
|
||||
[package.extras]
|
||||
html5lib = ["html5lib"]
|
||||
lxml = ["lxml"]
|
||||
|
||||
[[package]]
|
||||
name = "billiard"
|
||||
version = "3.6.4.0"
|
||||
|
@ -691,14 +726,14 @@ tests = ["async-timeout", "coverage (>=4.5,<5.0)", "pytest", "pytest-asyncio", "
|
|||
|
||||
[[package]]
|
||||
name = "chardet"
|
||||
version = "5.1.0"
|
||||
description = "Universal encoding detector for Python 3"
|
||||
version = "3.0.4"
|
||||
description = "Universal encoding detector for Python 2 and 3"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "chardet-5.1.0-py3-none-any.whl", hash = "sha256:362777fb014af596ad31334fde1e8c327dfdb076e1960d1694662d46a6917ab9"},
|
||||
{file = "chardet-5.1.0.tar.gz", hash = "sha256:0d62712b956bc154f85fb0a266e2a3c5913c2967e00348701b32411d6def31e5"},
|
||||
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
|
||||
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -863,6 +898,17 @@ files = [
|
|||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "compressed-rtf"
|
||||
version = "1.0.6"
|
||||
description = "Compressed Rich Text Format (RTF) compression and decompression package"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "compressed_rtf-1.0.6.tar.gz", hash = "sha256:c1c827f1d124d24608981a56e8b8691eb1f2a69a78ccad6440e7d92fde1781dd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constantly"
|
||||
version = "15.1.0"
|
||||
|
@ -1049,31 +1095,31 @@ dev = ["polib"]
|
|||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "40.0.1"
|
||||
version = "40.0.2"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "cryptography-40.0.1-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:918cb89086c7d98b1b86b9fdb70c712e5a9325ba6f7d7cfb509e784e0cfc6917"},
|
||||
{file = "cryptography-40.0.1-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9618a87212cb5200500e304e43691111570e1f10ec3f35569fdfcd17e28fd797"},
|
||||
{file = "cryptography-40.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a4805a4ca729d65570a1b7cac84eac1e431085d40387b7d3bbaa47e39890b88"},
|
||||
{file = "cryptography-40.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63dac2d25c47f12a7b8aa60e528bfb3c51c5a6c5a9f7c86987909c6c79765554"},
|
||||
{file = "cryptography-40.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0a4e3406cfed6b1f6d6e87ed243363652b2586b2d917b0609ca4f97072994405"},
|
||||
{file = "cryptography-40.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1e0af458515d5e4028aad75f3bb3fe7a31e46ad920648cd59b64d3da842e4356"},
|
||||
{file = "cryptography-40.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d8aa3609d337ad85e4eb9bb0f8bcf6e4409bfb86e706efa9a027912169e89122"},
|
||||
{file = "cryptography-40.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cf91e428c51ef692b82ce786583e214f58392399cf65c341bc7301d096fa3ba2"},
|
||||
{file = "cryptography-40.0.1-cp36-abi3-win32.whl", hash = "sha256:650883cc064297ef3676b1db1b7b1df6081794c4ada96fa457253c4cc40f97db"},
|
||||
{file = "cryptography-40.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:a805a7bce4a77d51696410005b3e85ae2839bad9aa38894afc0aa99d8e0c3160"},
|
||||
{file = "cryptography-40.0.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cd033d74067d8928ef00a6b1327c8ea0452523967ca4463666eeba65ca350d4c"},
|
||||
{file = "cryptography-40.0.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d36bbeb99704aabefdca5aee4eba04455d7a27ceabd16f3b3ba9bdcc31da86c4"},
|
||||
{file = "cryptography-40.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:32057d3d0ab7d4453778367ca43e99ddb711770477c4f072a51b3ca69602780a"},
|
||||
{file = "cryptography-40.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f5d7b79fa56bc29580faafc2ff736ce05ba31feaa9d4735048b0de7d9ceb2b94"},
|
||||
{file = "cryptography-40.0.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7c872413353c70e0263a9368c4993710070e70ab3e5318d85510cc91cce77e7c"},
|
||||
{file = "cryptography-40.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:28d63d75bf7ae4045b10de5413fb1d6338616e79015999ad9cf6fc538f772d41"},
|
||||
{file = "cryptography-40.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6f2bbd72f717ce33100e6467572abaedc61f1acb87b8d546001328d7f466b778"},
|
||||
{file = "cryptography-40.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cc3a621076d824d75ab1e1e530e66e7e8564e357dd723f2533225d40fe35c60c"},
|
||||
{file = "cryptography-40.0.1.tar.gz", hash = "sha256:2803f2f8b1e95f614419926c7e6f55d828afc614ca5ed61543877ae668cc3472"},
|
||||
{file = "cryptography-40.0.2-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:8f79b5ff5ad9d3218afb1e7e20ea74da5f76943ee5edb7f76e56ec5161ec782b"},
|
||||
{file = "cryptography-40.0.2-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:05dc219433b14046c476f6f09d7636b92a1c3e5808b9a6536adf4932b3b2c440"},
|
||||
{file = "cryptography-40.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4df2af28d7bedc84fe45bd49bc35d710aede676e2a4cb7fc6d103a2adc8afe4d"},
|
||||
{file = "cryptography-40.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dcca15d3a19a66e63662dc8d30f8036b07be851a8680eda92d079868f106288"},
|
||||
{file = "cryptography-40.0.2-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a04386fb7bc85fab9cd51b6308633a3c271e3d0d3eae917eebab2fac6219b6d2"},
|
||||
{file = "cryptography-40.0.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:adc0d980fd2760c9e5de537c28935cc32b9353baaf28e0814df417619c6c8c3b"},
|
||||
{file = "cryptography-40.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d5a1bd0e9e2031465761dfa920c16b0065ad77321d8a8c1f5ee331021fda65e9"},
|
||||
{file = "cryptography-40.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a95f4802d49faa6a674242e25bfeea6fc2acd915b5e5e29ac90a32b1139cae1c"},
|
||||
{file = "cryptography-40.0.2-cp36-abi3-win32.whl", hash = "sha256:aecbb1592b0188e030cb01f82d12556cf72e218280f621deed7d806afd2113f9"},
|
||||
{file = "cryptography-40.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:b12794f01d4cacfbd3177b9042198f3af1c856eedd0a98f10f141385c809a14b"},
|
||||
{file = "cryptography-40.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:142bae539ef28a1c76794cca7f49729e7c54423f615cfd9b0b1fa90ebe53244b"},
|
||||
{file = "cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:956ba8701b4ffe91ba59665ed170a2ebbdc6fc0e40de5f6059195d9f2b33ca0e"},
|
||||
{file = "cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f01c9863da784558165f5d4d916093737a75203a5c5286fde60e503e4276c7a"},
|
||||
{file = "cryptography-40.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3daf9b114213f8ba460b829a02896789751626a2a4e7a43a28ee77c04b5e4958"},
|
||||
{file = "cryptography-40.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48f388d0d153350f378c7f7b41497a54ff1513c816bcbbcafe5b829e59b9ce5b"},
|
||||
{file = "cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c0764e72b36a3dc065c155e5b22f93df465da9c39af65516fe04ed3c68c92636"},
|
||||
{file = "cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cbaba590180cba88cb99a5f76f90808a624f18b169b90a4abb40c1fd8c19420e"},
|
||||
{file = "cryptography-40.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7a38250f433cd41df7fcb763caa3ee9362777fdb4dc642b9a349721d2bf47404"},
|
||||
{file = "cryptography-40.0.2.tar.gz", hash = "sha256:c33c0d32b8594fa647d2e01dbccc303478e16fdd7cf98652d5b3ed11aa5e5c99"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -1812,6 +1858,17 @@ files = [
|
|||
{file = "docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "docx2txt"
|
||||
version = "0.8"
|
||||
description = "A pure python-based utility to extract text and images from docx files."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "docx2txt-0.8.tar.gz", hash = "sha256:2c06d98d7cfe2d3947e5760a57d924e3ff07745b379c8737723922e7009236e5"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "drf-spectacular"
|
||||
version = "0.26.1"
|
||||
|
@ -1836,6 +1893,17 @@ uritemplate = ">=2.0.0"
|
|||
offline = ["drf-spectacular-sidecar"]
|
||||
sidecar = ["drf-spectacular-sidecar"]
|
||||
|
||||
[[package]]
|
||||
name = "ebcdic"
|
||||
version = "1.1.1"
|
||||
description = "Additional EBCDIC codecs"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "ebcdic-1.1.1-py2.py3-none-any.whl", hash = "sha256:33b4cb729bc2d0bf46cc1847b0e5946897cb8d3f53520c5b9aa5fa98d7e735f1"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "executing"
|
||||
version = "1.2.0"
|
||||
|
@ -1851,6 +1919,25 @@ files = [
|
|||
[package.extras]
|
||||
tests = ["asttokens", "littleutils", "pytest", "rich"]
|
||||
|
||||
[[package]]
|
||||
name = "extract-msg"
|
||||
version = "0.29.0"
|
||||
description = "Extracts emails and attachments saved in Microsoft Outlook's .msg files"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "extract_msg-0.29.0-py2.py3-none-any.whl", hash = "sha256:a8885dc385d0c88c4b87fb2a573727c0115cd2ef5157956cf183878f940eef28"},
|
||||
{file = "extract_msg-0.29.0.tar.gz", hash = "sha256:ae6ce5f78fddb582350cb49bbf2776eadecdbf3c74b7a305dced42bd187a5401"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
compressed-rtf = ">=1.0.6"
|
||||
ebcdic = ">=1.1.1"
|
||||
imapclient = "2.1.0"
|
||||
olefile = ">=0.46"
|
||||
tzlocal = ">=2.1"
|
||||
|
||||
[[package]]
|
||||
name = "factory-boy"
|
||||
version = "3.2.1"
|
||||
|
@ -2328,6 +2415,25 @@ files = [
|
|||
{file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imapclient"
|
||||
version = "2.1.0"
|
||||
description = "Easy-to-use, Pythonic and complete IMAP client library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "IMAPClient-2.1.0-py2.py3-none-any.whl", hash = "sha256:3eeb97b9aa8faab0caa5024d74bfde59408fbd542781246f6960873c7bf0dd01"},
|
||||
{file = "IMAPClient-2.1.0.zip", hash = "sha256:60ba79758cc9f13ec910d7a3df9acaaf2bb6c458720d9a02ec33a41352fd1b99"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
six = "*"
|
||||
|
||||
[package.extras]
|
||||
doc = ["sphinx"]
|
||||
test = ["mock (>=1.3.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "incremental"
|
||||
version = "22.10.0"
|
||||
|
@ -2686,6 +2792,99 @@ files = [
|
|||
six = "*"
|
||||
tornado = {version = "*", markers = "python_version > \"2.7\""}
|
||||
|
||||
[[package]]
|
||||
name = "lxml"
|
||||
version = "4.9.2"
|
||||
description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*"
|
||||
files = [
|
||||
{file = "lxml-4.9.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2"},
|
||||
{file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892"},
|
||||
{file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a"},
|
||||
{file = "lxml-4.9.2-cp27-cp27m-win32.whl", hash = "sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de"},
|
||||
{file = "lxml-4.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3"},
|
||||
{file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50"},
|
||||
{file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975"},
|
||||
{file = "lxml-4.9.2-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c"},
|
||||
{file = "lxml-4.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a"},
|
||||
{file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4"},
|
||||
{file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4"},
|
||||
{file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7"},
|
||||
{file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184"},
|
||||
{file = "lxml-4.9.2-cp310-cp310-win32.whl", hash = "sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda"},
|
||||
{file = "lxml-4.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab"},
|
||||
{file = "lxml-4.9.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9"},
|
||||
{file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf"},
|
||||
{file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380"},
|
||||
{file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92"},
|
||||
{file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1"},
|
||||
{file = "lxml-4.9.2-cp311-cp311-win32.whl", hash = "sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33"},
|
||||
{file = "lxml-4.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd"},
|
||||
{file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0"},
|
||||
{file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e"},
|
||||
{file = "lxml-4.9.2-cp35-cp35m-win32.whl", hash = "sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df"},
|
||||
{file = "lxml-4.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5"},
|
||||
{file = "lxml-4.9.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53"},
|
||||
{file = "lxml-4.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7"},
|
||||
{file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe"},
|
||||
{file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c"},
|
||||
{file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1"},
|
||||
{file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e"},
|
||||
{file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74"},
|
||||
{file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38"},
|
||||
{file = "lxml-4.9.2-cp36-cp36m-win32.whl", hash = "sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5"},
|
||||
{file = "lxml-4.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3"},
|
||||
{file = "lxml-4.9.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03"},
|
||||
{file = "lxml-4.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941"},
|
||||
{file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726"},
|
||||
{file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b"},
|
||||
{file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894"},
|
||||
{file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45"},
|
||||
{file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e"},
|
||||
{file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b"},
|
||||
{file = "lxml-4.9.2-cp37-cp37m-win32.whl", hash = "sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe"},
|
||||
{file = "lxml-4.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9"},
|
||||
{file = "lxml-4.9.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8"},
|
||||
{file = "lxml-4.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24"},
|
||||
{file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889"},
|
||||
{file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f"},
|
||||
{file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03"},
|
||||
{file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c"},
|
||||
{file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f"},
|
||||
{file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457"},
|
||||
{file = "lxml-4.9.2-cp38-cp38-win32.whl", hash = "sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b"},
|
||||
{file = "lxml-4.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7"},
|
||||
{file = "lxml-4.9.2-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1"},
|
||||
{file = "lxml-4.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140"},
|
||||
{file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4"},
|
||||
{file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf"},
|
||||
{file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947"},
|
||||
{file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5"},
|
||||
{file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5"},
|
||||
{file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2"},
|
||||
{file = "lxml-4.9.2-cp39-cp39-win32.whl", hash = "sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1"},
|
||||
{file = "lxml-4.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f"},
|
||||
{file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c"},
|
||||
{file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a"},
|
||||
{file = "lxml-4.9.2-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419"},
|
||||
{file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05"},
|
||||
{file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f"},
|
||||
{file = "lxml-4.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9"},
|
||||
{file = "lxml-4.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5"},
|
||||
{file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746"},
|
||||
{file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7"},
|
||||
{file = "lxml-4.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409"},
|
||||
{file = "lxml-4.9.2.tar.gz", hash = "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
cssselect = ["cssselect (>=0.7)"]
|
||||
html5 = ["html5lib"]
|
||||
htmlsoup = ["BeautifulSoup4"]
|
||||
source = ["Cython (>=0.29.7)"]
|
||||
|
||||
[[package]]
|
||||
name = "markdown"
|
||||
version = "3.4.3"
|
||||
|
@ -3078,16 +3277,27 @@ rsa = ["cryptography (>=3.0.0)"]
|
|||
signals = ["blinker (>=1.4.0)"]
|
||||
signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"]
|
||||
|
||||
[[package]]
|
||||
name = "olefile"
|
||||
version = "0.46"
|
||||
description = "Python package to parse, read and write Microsoft OLE2 files (Structured Storage or Compound Document, Microsoft Office)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
{file = "olefile-0.46.zip", hash = "sha256:133b031eaf8fd2c9399b78b8bc5b8fcbe4c31e85295749bb17a87cba8f3c3964"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.0"
|
||||
version = "23.1"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
|
||||
{file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
|
||||
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
|
||||
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3118,6 +3328,28 @@ files = [
|
|||
{file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pdfminer-six"
|
||||
version = "20191110"
|
||||
description = "PDF parser and analyzer"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pdfminer.six-20191110-py2.py3-none-any.whl", hash = "sha256:ca2ca58f3ac66a486bce53a6ddba95dc2b27781612915fa41c444790ba9cd2a8"},
|
||||
{file = "pdfminer.six-20191110.tar.gz", hash = "sha256:141a53ec491bee6d45bf9b2c7f82601426fb5d32636bcf6b9c8a8f3b6431fea6"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
chardet = {version = "*", markers = "python_version > \"3.0\""}
|
||||
pycryptodome = "*"
|
||||
six = "*"
|
||||
sortedcontainers = "*"
|
||||
|
||||
[package.extras]
|
||||
dev = ["nose", "tox"]
|
||||
docs = ["sphinx", "sphinx-argparse"]
|
||||
|
||||
[[package]]
|
||||
name = "pexpect"
|
||||
version = "4.8.0"
|
||||
|
@ -3510,6 +3742,49 @@ files = [
|
|||
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pycryptodome"
|
||||
version = "3.17"
|
||||
description = "Cryptographic library for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
{file = "pycryptodome-3.17-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:2c5631204ebcc7ae33d11c43037b2dafe25e2ab9c1de6448eb6502ac69c19a56"},
|
||||
{file = "pycryptodome-3.17-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:04779cc588ad8f13c80a060b0b1c9d1c203d051d8a43879117fe6b8aaf1cd3fa"},
|
||||
{file = "pycryptodome-3.17-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:f812d58c5af06d939b2baccdda614a3ffd80531a26e5faca2c9f8b1770b2b7af"},
|
||||
{file = "pycryptodome-3.17-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:9453b4e21e752df8737fdffac619e93c9f0ec55ead9a45df782055eb95ef37d9"},
|
||||
{file = "pycryptodome-3.17-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:121d61663267f73692e8bde5ec0d23c9146465a0d75cad75c34f75c752527b01"},
|
||||
{file = "pycryptodome-3.17-cp27-cp27m-win32.whl", hash = "sha256:ba2d4fcb844c6ba5df4bbfee9352ad5352c5ae939ac450e06cdceff653280450"},
|
||||
{file = "pycryptodome-3.17-cp27-cp27m-win_amd64.whl", hash = "sha256:87e2ca3aa557781447428c4b6c8c937f10ff215202ab40ece5c13a82555c10d6"},
|
||||
{file = "pycryptodome-3.17-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f44c0d28716d950135ff21505f2c764498eda9d8806b7c78764165848aa419bc"},
|
||||
{file = "pycryptodome-3.17-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:5a790bc045003d89d42e3b9cb3cc938c8561a57a88aaa5691512e8540d1ae79c"},
|
||||
{file = "pycryptodome-3.17-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:d086d46774e27b280e4cece8ab3d87299cf0d39063f00f1e9290d096adc5662a"},
|
||||
{file = "pycryptodome-3.17-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:5587803d5b66dfd99e7caa31ed91fba0fdee3661c5d93684028ad6653fce725f"},
|
||||
{file = "pycryptodome-3.17-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:e7debd9c439e7b84f53be3cf4ba8b75b3d0b6e6015212355d6daf44ac672e210"},
|
||||
{file = "pycryptodome-3.17-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ca1ceb6303be1282148f04ac21cebeebdb4152590842159877778f9cf1634f09"},
|
||||
{file = "pycryptodome-3.17-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:dc22cc00f804485a3c2a7e2010d9f14a705555f67020eb083e833cabd5bd82e4"},
|
||||
{file = "pycryptodome-3.17-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80ea8333b6a5f2d9e856ff2293dba2e3e661197f90bf0f4d5a82a0a6bc83a626"},
|
||||
{file = "pycryptodome-3.17-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c133f6721fba313722a018392a91e3c69d3706ae723484841752559e71d69dc6"},
|
||||
{file = "pycryptodome-3.17-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:333306eaea01fde50a73c4619e25631e56c4c61bd0fb0a2346479e67e3d3a820"},
|
||||
{file = "pycryptodome-3.17-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:1a30f51b990994491cec2d7d237924e5b6bd0d445da9337d77de384ad7f254f9"},
|
||||
{file = "pycryptodome-3.17-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:909e36a43fe4a8a3163e9c7fc103867825d14a2ecb852a63d3905250b308a4e5"},
|
||||
{file = "pycryptodome-3.17-cp35-abi3-win32.whl", hash = "sha256:a3228728a3808bc9f18c1797ec1179a0efb5068c817b2ffcf6bcd012494dffb2"},
|
||||
{file = "pycryptodome-3.17-cp35-abi3-win_amd64.whl", hash = "sha256:9ec565e89a6b400eca814f28d78a9ef3f15aea1df74d95b28b7720739b28f37f"},
|
||||
{file = "pycryptodome-3.17-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:e1819b67bcf6ca48341e9b03c2e45b1c891fa8eb1a8458482d14c2805c9616f2"},
|
||||
{file = "pycryptodome-3.17-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:f8e550caf52472ae9126953415e4fc554ab53049a5691c45b8816895c632e4d7"},
|
||||
{file = "pycryptodome-3.17-pp27-pypy_73-win32.whl", hash = "sha256:afbcdb0eda20a0e1d44e3a1ad6d4ec3c959210f4b48cabc0e387a282f4c7deb8"},
|
||||
{file = "pycryptodome-3.17-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a74f45aee8c5cc4d533e585e0e596e9f78521e1543a302870a27b0ae2106381e"},
|
||||
{file = "pycryptodome-3.17-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38bbd6717eac084408b4094174c0805bdbaba1f57fc250fd0309ae5ec9ed7e09"},
|
||||
{file = "pycryptodome-3.17-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f68d6c8ea2974a571cacb7014dbaada21063a0375318d88ac1f9300bc81e93c3"},
|
||||
{file = "pycryptodome-3.17-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8198f2b04c39d817b206ebe0db25a6653bb5f463c2319d6f6d9a80d012ac1e37"},
|
||||
{file = "pycryptodome-3.17-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3a232474cd89d3f51e4295abe248a8b95d0332d153bf46444e415409070aae1e"},
|
||||
{file = "pycryptodome-3.17-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4992ec965606054e8326e83db1c8654f0549cdb26fce1898dc1a20bc7684ec1c"},
|
||||
{file = "pycryptodome-3.17-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53068e33c74f3b93a8158dacaa5d0f82d254a81b1002e0cd342be89fcb3433eb"},
|
||||
{file = "pycryptodome-3.17-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:74794a2e2896cd0cf56fdc9db61ef755fa812b4a4900fa46c49045663a92b8d0"},
|
||||
{file = "pycryptodome-3.17.tar.gz", hash = "sha256:bce2e2d8e82fcf972005652371a3e8731956a0c1fbb719cc897943b3695ad91b"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydotplus"
|
||||
version = "2.0.2"
|
||||
|
@ -3561,14 +3836,14 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.14.0"
|
||||
version = "2.15.0"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"},
|
||||
{file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"},
|
||||
{file = "Pygments-2.15.0-py3-none-any.whl", hash = "sha256:77a3299119af881904cd5ecd1ac6a66214b6e9bed1f2db16993b54adede64094"},
|
||||
{file = "Pygments-2.15.0.tar.gz", hash = "sha256:f7e36cffc4c517fbc252861b9a6e4644ca0e5abadf9a113c72d1358ad09b9500"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -3757,14 +4032,14 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.3.0"
|
||||
version = "7.3.1"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytest-7.3.0-py3-none-any.whl", hash = "sha256:933051fa1bfbd38a21e73c3960cebdad4cf59483ddba7696c48509727e17f201"},
|
||||
{file = "pytest-7.3.0.tar.gz", hash = "sha256:58ecc27ebf0ea643ebfdf7fb1249335da761a00c9f955bcd922349bcb68ee57d"},
|
||||
{file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"},
|
||||
{file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -3797,20 +4072,23 @@ testing = ["Django", "django-configurations (>=2.0)"]
|
|||
|
||||
[[package]]
|
||||
name = "pytest-sugar"
|
||||
version = "0.9.6"
|
||||
version = "0.9.7"
|
||||
description = "pytest-sugar is a plugin for pytest that changes the default look and feel of pytest (e.g. progressbar, show tests that fail instantly)."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pytest-sugar-0.9.6.tar.gz", hash = "sha256:c4793495f3c32e114f0f5416290946c316eb96ad5a3684dcdadda9267e59b2b8"},
|
||||
{file = "pytest_sugar-0.9.6-py2.py3-none-any.whl", hash = "sha256:30e5225ed2b3cc988a8a672f8bda0fc37bcd92d62e9273937f061112b3f2186d"},
|
||||
{file = "pytest-sugar-0.9.7.tar.gz", hash = "sha256:f1e74c1abfa55f7241cf7088032b6e378566f16b938f3f08905e2cf4494edd46"},
|
||||
{file = "pytest_sugar-0.9.7-py2.py3-none-any.whl", hash = "sha256:8cb5a4e5f8bbcd834622b0235db9e50432f4cbd71fef55b467fe44e43701e062"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
packaging = ">=14.1"
|
||||
pytest = ">=2.9"
|
||||
termcolor = ">=1.1.0"
|
||||
packaging = ">=21.3"
|
||||
pytest = ">=6.2.0"
|
||||
termcolor = ">=2.1.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["black", "flake8", "pre-commit"]
|
||||
|
||||
[[package]]
|
||||
name = "python-crontab"
|
||||
|
@ -3873,6 +4151,22 @@ files = [
|
|||
[package.extras]
|
||||
twisted = ["Twisted"]
|
||||
|
||||
[[package]]
|
||||
name = "python-pptx"
|
||||
version = "0.6.21"
|
||||
description = "Generate and manipulate Open XML PowerPoint (.pptx) files"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "python-pptx-0.6.21.tar.gz", hash = "sha256:7798a2aaf89563565b3c7120c0acfe9aff775db0db3580544e3bf4840c2e378f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
lxml = ">=3.1.0"
|
||||
Pillow = ">=3.3.2"
|
||||
XlsxWriter = ">=0.5.7"
|
||||
|
||||
[[package]]
|
||||
name = "python-slugify"
|
||||
version = "7.0.0"
|
||||
|
@ -3934,6 +4228,21 @@ files = [
|
|||
{file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytz-deprecation-shim"
|
||||
version = "0.1.0.post0"
|
||||
description = "Shims to make deprecation of pytz easier"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
||||
files = [
|
||||
{file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"},
|
||||
{file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
tzdata = {version = "*", markers = "python_version >= \"3.6\""}
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0"
|
||||
|
@ -4164,14 +4473,14 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (
|
|||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
version = "1.12.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
|
||||
files = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
{file = "six-1.12.0-py2.py3-none-any.whl", hash = "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c"},
|
||||
{file = "six-1.12.0.tar.gz", hash = "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4198,6 +4507,41 @@ files = [
|
|||
{file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sortedcontainers"
|
||||
version = "2.4.0"
|
||||
description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"},
|
||||
{file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "soupsieve"
|
||||
version = "2.4"
|
||||
description = "A modern CSS selector implementation for Beautiful Soup."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "soupsieve-2.4-py3-none-any.whl", hash = "sha256:49e5368c2cda80ee7e84da9dbe3e110b70a4575f196efb74e51b94549d921955"},
|
||||
{file = "soupsieve-2.4.tar.gz", hash = "sha256:e28dba9ca6c7c00173e34e4ba57448f0688bb681b7c5e8bf4971daafc093d69a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "speechrecognition"
|
||||
version = "3.8.1"
|
||||
description = "Library for performing speech recognition, with support for several engines and APIs, online and offline."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "SpeechRecognition-3.8.1-py2.py3-none-any.whl", hash = "sha256:4d8f73a0c05ec70331c3bacaa89ecc06dfa8d9aba0899276664cda06ab597e8e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sphinx"
|
||||
version = "6.1.3"
|
||||
|
@ -4350,22 +4694,20 @@ test = ["pytest"]
|
|||
|
||||
[[package]]
|
||||
name = "spotipy"
|
||||
version = "2.23.0"
|
||||
version = "2.16.0"
|
||||
description = "A light weight Python library for the Spotify Web API"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "spotipy-2.23.0-py2-none-any.whl", hash = "sha256:da850fbf62faaa05912132d2886c293a5fbbe8350d0821e7208a6a2fdd6a0079"},
|
||||
{file = "spotipy-2.23.0-py3-none-any.whl", hash = "sha256:6bf8b963c10d0a3e51037e4baf92e29732dee36b2a1f1b7dcc8cd5771e662a5b"},
|
||||
{file = "spotipy-2.23.0.tar.gz", hash = "sha256:0dfafe08239daae6c16faa68f60b5775d40c4110725e1a7c545ad4c7fb66d4e8"},
|
||||
{file = "spotipy-2.16.0-py2-none-any.whl", hash = "sha256:800330badc1b953417dace1532a586220d35b2240eb2e538e883e19e6bf1b53d"},
|
||||
{file = "spotipy-2.16.0-py3-none-any.whl", hash = "sha256:9d07b8948c30d8a338805440797263749ccad07c22009f9b3112aa2bcb2ebcea"},
|
||||
{file = "spotipy-2.16.0.tar.gz", hash = "sha256:315eadd1248053ed336b4d3adbf2e3c32895fdbb0cfcd170542c848c8fd45649"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
redis = ">=3.5.3"
|
||||
requests = ">=2.25.0"
|
||||
six = ">=1.15.0"
|
||||
urllib3 = ">=1.26.0"
|
||||
requests = ">=2.20.0"
|
||||
six = ">=1.10.0"
|
||||
|
||||
[package.extras]
|
||||
doc = ["Sphinx (>=1.5.2)"]
|
||||
|
@ -4448,6 +4790,33 @@ files = [
|
|||
{file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textract"
|
||||
version = "1.6.5"
|
||||
description = "extract text from any document. no muss. no fuss."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "textract-1.6.5-py3-none-any.whl", hash = "sha256:0accd78ec42864e3e3827f9ef798ced9aac4727b664303b724a198fed73fa438"},
|
||||
{file = "textract-1.6.5.tar.gz", hash = "sha256:68f0f09056885821e6c43d8538987518daa94057c306679f2857cc5ee66ad850"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
argcomplete = ">=1.10.0,<1.11.0"
|
||||
beautifulsoup4 = ">=4.8.0,<4.9.0"
|
||||
chardet = ">=3.0.0,<4.0.0"
|
||||
docx2txt = ">=0.8,<1.0"
|
||||
extract-msg = "<=0.29"
|
||||
"pdfminer.six" = "20191110"
|
||||
python-pptx = ">=0.6.18,<0.7.0"
|
||||
six = ">=1.12.0,<1.13.0"
|
||||
SpeechRecognition = ">=3.8.1,<3.9.0"
|
||||
xlrd = ">=1.2.0,<1.3.0"
|
||||
|
||||
[package.extras]
|
||||
pocketsphinx = ["pocketsphinx (==0.1.15)"]
|
||||
|
||||
[[package]]
|
||||
name = "tinycss2"
|
||||
version = "1.2.1"
|
||||
|
@ -4688,6 +5057,25 @@ files = [
|
|||
{file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzlocal"
|
||||
version = "4.3"
|
||||
description = "tzinfo object for the local timezone"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "tzlocal-4.3-py3-none-any.whl", hash = "sha256:b44c4388f3d34f25862cfbb387578a4d70fec417649da694a132f628a23367e2"},
|
||||
{file = "tzlocal-4.3.tar.gz", hash = "sha256:3f21d09e1b2aa9f2dacca12da240ca37de3ba5237a93addfd6d593afe9073355"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pytz-deprecation-shim = "*"
|
||||
tzdata = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[package.extras]
|
||||
devenv = ["black", "check-manifest", "flake8", "pyroma", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"]
|
||||
|
||||
[[package]]
|
||||
name = "uritemplate"
|
||||
version = "4.1.1"
|
||||
|
@ -5029,6 +5417,30 @@ files = [
|
|||
{file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xlrd"
|
||||
version = "1.2.0"
|
||||
description = "Library for developers to extract data from Microsoft Excel (tm) spreadsheet files"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
{file = "xlrd-1.2.0-py2.py3-none-any.whl", hash = "sha256:e551fb498759fa3a5384a94ccd4c3c02eb7c00ea424426e212ac0c57be9dfbde"},
|
||||
{file = "xlrd-1.2.0.tar.gz", hash = "sha256:546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xlsxwriter"
|
||||
version = "3.1.0"
|
||||
description = "A Python module for creating Excel XLSX files."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "XlsxWriter-3.1.0-py3-none-any.whl", hash = "sha256:b70a147d36235d1ee835cfd037396f789db1f76740a0e5c917d54137169341de"},
|
||||
{file = "XlsxWriter-3.1.0.tar.gz", hash = "sha256:02913b50b74c00f165933d5da3e3a02cab4204cb4932722a1b342c5c71034122"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xvfbwrapper"
|
||||
version = "0.2.9"
|
||||
|
@ -5213,4 +5625,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "580bc9d748f65b25b9de3554c49e5c05a9cb3fccc60ce411b8f953ab70f2c14f"
|
||||
content-hash = "5127a61d6308ff9b884ea4cfb0e9ce7fd8cdf01525b2462b8e3a91a9a71e00e6"
|
||||
|
|
|
@ -78,7 +78,6 @@ pytube = "^12.1.3"
|
|||
ytmusicapi = "^0.25.2"
|
||||
pydub = "^0.25.1"
|
||||
python-mpd2 = "^3.0.5"
|
||||
spotipy = "^2.22.1"
|
||||
yandex-music = "^2.0.1"
|
||||
pyjwt = "^2.6.0"
|
||||
rawpy = "^0.18.0"
|
||||
|
@ -86,7 +85,8 @@ xvfbwrapper = "^0.2.9"
|
|||
vtk = "^9.2.6"
|
||||
ffmpeg-python = "^0.2.0"
|
||||
cairosvg = "^2.7.0"
|
||||
chardet = "^5.1.0"
|
||||
textract = "^1.6.5"
|
||||
spotipy = "2.16"
|
||||
|
||||
|
||||
[build-system]
|
||||
|
|
Loading…
Reference in New Issue
Block a user