Compare commits
14 Commits
Author | SHA1 | Date |
---|---|---|
Harvey Tindall | 38facc0adc | |
Harvey Tindall | b53a6d4006 | |
Harvey Tindall | 8e070dbe2a | |
dependabot[bot] | d34cf0c40d | |
Harvey Tindall | 6ec214f644 | |
Harvey Tindall | a4feaa5d64 | |
Harvey Tindall | 237c575441 | |
Harvey Tindall | 9185b59d16 | |
Harvey Tindall | 43c0631f9b | |
Harvey Tindall | 3d10a8fe06 | |
Harvey Tindall | 8d265879cc | |
Harvey Tindall | a38045cefb | |
Harvey Tindall | d5609f3870 | |
Harvey Tindall | f2966ef810 |
|
@ -0,0 +1,27 @@
|
|||
FROM python:3.8.2-buster AS build
|
||||
|
||||
COPY . /opt/build
|
||||
|
||||
RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
|
||||
|
||||
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
|
||||
|
||||
RUN cd /opt/build \
|
||||
&& rm -rf dist \
|
||||
&& apt install nodejs \
|
||||
&& ~/.poetry/bin/poetry update \
|
||||
&& pip install libsass \
|
||||
&& python scss/get_node_deps.py \
|
||||
&& python scss/compile.py -y \
|
||||
&& python mail/generate.py -y \
|
||||
&& ~/.poetry/bin/poetry build -f wheel
|
||||
|
||||
FROM python:3.8.2-buster
|
||||
|
||||
COPY --from=build /opt/build/dist /opt/dist
|
||||
|
||||
RUN pip install /opt/dist/*.whl
|
||||
|
||||
RUN sed -i 's#id="pwrJfPath" placeholder="Folder"#id="pwrJfPath" value="/jf" disabled#g' /usr/local/lib/python3.8/site-packages/jellyfin_accounts/data/templates/setup.html
|
||||
|
||||
CMD [ "python3.8", "/usr/local/bin/jf-accounts", "-d", "/data" ]
|
92
README.md
92
README.md
|
@ -1,90 +1,6 @@
|
|||
# ![jellyfin-accounts](https://raw.githubusercontent.com/hrfee/jellyfin-accounts/bs5/images/jellyfin-accounts-banner-wide.svg)
|
||||
## 👀 ➡️: Try [jfa-go](https://github.com/hrfee/jfa-go), a rewrite in Go. It's faster and has more features.
|
||||
###### I won't be updating this version any more, and switching should be easy.
|
||||
|
||||
A basic account management system for [Jellyfin](https://github.com/jellyfin/jellyfin).
|
||||
* Provides a web interface for creating/sending invites
|
||||
* Sends out emails when a user requests a password reset
|
||||
* Uses a basic python jellyfin API client for communication with the server.
|
||||
* Uses [Flask](https://github.com/pallets/flask), [HTTPAuth](https://github.com/miguelgrinberg/Flask-HTTPAuth), [itsdangerous](https://github.com/pallets/itsdangerous), and [Waitress](https://github.com/Pylons/waitress)
|
||||
* Frontend uses [Bootstrap](https://v5.getbootstrap.com)
|
||||
* Password resets are handled using smtplib, requests, and [jinja](https://github.com/pallets/jinja)
|
||||
## Interface
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/hrfee/jellyfin-accounts/main/images/jfa.gif" width="100%"></img>
|
||||
</p>
|
||||
**please don't open any new issues.**
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/hrfee/jellyfin-accounts/main/images/admin.png" width="48%" style="margin-right: 1.5%;" alt="Admin page"></img>
|
||||
<img src="https://raw.githubusercontent.com/hrfee/jellyfin-accounts/main/images/create.png" width="48%" style="margin-left: 1.5%;" alt="Account creation page"></img>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
## Get it
|
||||
### Requirements
|
||||
|
||||
* This should work anywhere Python does, i've tried to not use anything OS-specific. Drop an issue if there's a problem, of course.
|
||||
```
|
||||
* python >= 3.6
|
||||
* flask
|
||||
* flask_httpauth
|
||||
* jinja2
|
||||
* requests
|
||||
* itsdangerous
|
||||
* passlib
|
||||
* pyOpenSSL
|
||||
* waitress
|
||||
* pytz
|
||||
* python-dateutil
|
||||
* watchdog
|
||||
* packaging
|
||||
```
|
||||
### Install
|
||||
|
||||
Usually as simple as:
|
||||
```
|
||||
pip install jellyfin-accounts
|
||||
```
|
||||
If not, or if you want to use docker, see [install](https://github.com/hrfee/jellyfin-accounts/wiki/Install).
|
||||
|
||||
## Usage
|
||||
* Passing no arguments will run the server
|
||||
```
|
||||
usage: jf-accounts [-h] [-c CONFIG] [-d DATA] [--host HOST] [-p PORT] [-g]
|
||||
|
||||
jellyfin-accounts
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-c CONFIG, --config CONFIG
|
||||
specifies path to configuration file.
|
||||
-d DATA, --data DATA specifies directory to store data in. defaults to
|
||||
~/.jf-accounts.
|
||||
--host HOST address to host web ui on.
|
||||
-p PORT, --port PORT port to host web ui on.
|
||||
-g, --get_defaults tool to grab a JF users policy (access, perms, etc.)
|
||||
and homescreen layout and output it as json to be used
|
||||
as a user template.
|
||||
```
|
||||
## Setup
|
||||
#### New user template
|
||||
* You may want to restrict a user from accessing certain libraries (e.g 4K Movies), display their account on the login screen by default, or set a default homecrseen layout. Jellyfin stores these settings in the user's policy, configuration and displayPreferences.
|
||||
* Make a temporary account and configure it, then in the web UI, go into "Settings => Set new account defaults". Choose the account, and its configuration will be stored for future use.
|
||||
#### Emails/Password Resets
|
||||
* When someone initiates forget password on Jellyfin, a file named `passwordreset*.json` is created in its configuration directory. This directory is monitored and when created, the program reads the username, expiry time and PIN, puts it into a template and sends it to whatever address is specified in `emails.json`.
|
||||
* **The default forget password popup references the `passwordreset*.json` file created. This is confusing for users, so a quick fix is to edit the `MessageForgotPasswordFileCreated` string in Jellyfin's language folder.**
|
||||
* Currently, jellyfin-accounts supports generic SSL/TLS or STARTTLS secured SMTP, and the [mailgun](https://mailgun.com) REST API.
|
||||
* Email html is created using [mjml](https://mjml.io), and [jinja](https://github.com/pallets/jinja) templating is used. If you wish to create your own, ensure you use the same jinja expressions (`{{ pin }}`, etc.) as used in `data/email.mjml` or `invite-email.mjml`, and also create plain text versions for legacy email clients.
|
||||
|
||||
### Configuration
|
||||
* Note: Make sure to put this behind a reverse proxy with HTTPS.
|
||||
|
||||
On first run, access the setup wizard at `0.0.0.0:8056`. When finished, restart the program.
|
||||
|
||||
The configuration is stored at `~/.jf-accounts/config.ini`. Settings can be changed through the web UI, or by manually editing the file.
|
||||
|
||||
For detailed descriptions of each setting, see [setup](https://github.com/hrfee/jellyfin-accounts/wiki/Setup).
|
||||
|
||||
### Donations
|
||||
I strongly suggest you send your money to [Jellyfin](https://opencollective.com/jellyfin) or a good charity, but for those who want to help me out, a Paypal link is below.
|
||||
|
||||
[Donate](https://www.paypal.me/hrfee)
|
||||
You can find the old README [here](https://github.com/hrfee/jellyfin-accounts/blob/main/README.old.md).
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
# ![jellyfin-accounts](https://raw.githubusercontent.com/hrfee/jellyfin-accounts/bs5/images/jellyfin-accounts-banner-wide.svg)
|
||||
|
||||
|
||||
A basic account management system for [Jellyfin](https://github.com/jellyfin/jellyfin).
|
||||
* Provides a web interface for creating/sending invites
|
||||
* Sends out emails when a user requests a password reset
|
||||
* Uses a basic python jellyfin API client for communication with the server.
|
||||
* Uses [Flask](https://github.com/pallets/flask), [HTTPAuth](https://github.com/miguelgrinberg/Flask-HTTPAuth), [itsdangerous](https://github.com/pallets/itsdangerous), and [Waitress](https://github.com/Pylons/waitress)
|
||||
* Frontend uses [Bootstrap](https://v5.getbootstrap.com)
|
||||
* Password resets are handled using smtplib, requests, and [jinja](https://github.com/pallets/jinja)
|
||||
## Interface
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/hrfee/jellyfin-accounts/main/images/jfa.gif" width="100%"></img>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/hrfee/jellyfin-accounts/main/images/admin.png" width="48%" style="margin-right: 1.5%;" alt="Admin page"></img>
|
||||
<img src="https://raw.githubusercontent.com/hrfee/jellyfin-accounts/main/images/create.png" width="48%" style="margin-left: 1.5%;" alt="Account creation page"></img>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
## Get it
|
||||
### Requirements
|
||||
|
||||
* This should work anywhere Python does, i've tried to not use anything OS-specific. Drop an issue if there's a problem, of course.
|
||||
```
|
||||
* python >= 3.6
|
||||
* flask
|
||||
* flask_httpauth
|
||||
* jinja2
|
||||
* requests
|
||||
* itsdangerous
|
||||
* passlib
|
||||
* pyOpenSSL
|
||||
* waitress
|
||||
* pytz
|
||||
* python-dateutil
|
||||
* watchdog
|
||||
* packaging
|
||||
```
|
||||
### Install
|
||||
|
||||
Usually as simple as:
|
||||
```
|
||||
pip install jellyfin-accounts
|
||||
```
|
||||
If not, or if you want to use docker, see [install](https://github.com/hrfee/jellyfin-accounts/wiki/Install).
|
||||
|
||||
## Usage
|
||||
* Passing no arguments will run the server
|
||||
```
|
||||
usage: jf-accounts [-h] [-c CONFIG] [-d DATA] [--host HOST] [-p PORT] [-g]
|
||||
|
||||
jellyfin-accounts
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-c CONFIG, --config CONFIG
|
||||
specifies path to configuration file.
|
||||
-d DATA, --data DATA specifies directory to store data in. defaults to
|
||||
~/.jf-accounts.
|
||||
--host HOST address to host web ui on.
|
||||
-p PORT, --port PORT port to host web ui on.
|
||||
-g, --get_defaults tool to grab a JF users policy (access, perms, etc.)
|
||||
and homescreen layout and output it as json to be used
|
||||
as a user template.
|
||||
```
|
||||
## Setup
|
||||
#### New user template
|
||||
* You may want to restrict a user from accessing certain libraries (e.g 4K Movies), display their account on the login screen by default, or set a default homecrseen layout. Jellyfin stores these settings in the user's policy, configuration and displayPreferences.
|
||||
* Make a temporary account and configure it, then in the web UI, go into "Settings => Set new account defaults". Choose the account, and its configuration will be stored for future use.
|
||||
#### Emails/Password Resets
|
||||
* When someone initiates forget password on Jellyfin, a file named `passwordreset*.json` is created in its configuration directory. This directory is monitored and when created, the program reads the username, expiry time and PIN, puts it into a template and sends it to whatever address is specified in `emails.json`.
|
||||
* **The default forget password popup references the `passwordreset*.json` file created. This is confusing for users, so a quick fix is to edit the `MessageForgotPasswordFileCreated` string in Jellyfin's language folder.**
|
||||
* Currently, jellyfin-accounts supports generic SSL/TLS or STARTTLS secured SMTP, and the [mailgun](https://mailgun.com) REST API.
|
||||
* Email html is created using [mjml](https://mjml.io), and [jinja](https://github.com/pallets/jinja) templating is used. If you wish to create your own, ensure you use the same jinja expressions (`{{ pin }}`, etc.) as used in `data/email.mjml` or `invite-email.mjml`, and also create plain text versions for legacy email clients.
|
||||
|
||||
### Configuration
|
||||
* Note: Make sure to put this behind a reverse proxy with HTTPS.
|
||||
|
||||
On first run, access the setup wizard at `0.0.0.0:8056`. When finished, restart the program.
|
||||
|
||||
The configuration is stored at `~/.jf-accounts/config.ini`. Settings can be changed through the web UI, or by manually editing the file.
|
||||
|
||||
For detailed descriptions of each setting, see [setup](https://github.com/hrfee/jellyfin-accounts/wiki/Setup).
|
||||
|
||||
### Donations
|
||||
I strongly suggest you send your money to [Jellyfin](https://opencollective.com/jellyfin) or a good charity, but for those who want to help me out, a Paypal link is below.
|
||||
|
||||
[Donate](https://www.paypal.me/hrfee)
|
|
@ -1,5 +1,7 @@
|
|||
# Runs it!
|
||||
__version__ = "0.3.7"
|
||||
__version__ = "0.3.9"
|
||||
|
||||
print("Note: jellyfin-accounts has been deprecated. Try jfa-go, a rewrite thats fast, portable, and has more features. Find it at\nhttps://github.com/hrfee/jfa-go\n")
|
||||
|
||||
import secrets
|
||||
import configparser
|
||||
|
@ -72,7 +74,7 @@ else:
|
|||
|
||||
# Temp config so logger knows whether to use debug mode or not
|
||||
temp_config = configparser.RawConfigParser()
|
||||
temp_config.read(config_path)
|
||||
temp_config.read(str(config_path.resolve()))
|
||||
|
||||
|
||||
def create_log(name):
|
||||
|
@ -98,7 +100,8 @@ config = Config(config_path, secrets.token_urlsafe(16), data_dir, local_dir, log
|
|||
|
||||
web_log = create_log("waitress")
|
||||
if not first_run:
|
||||
email_log = create_log("emails")
|
||||
email_log = create_log("email")
|
||||
pwr_log = create_log("pwr")
|
||||
auth_log = create_log("auth")
|
||||
|
||||
if args.host is not None:
|
||||
|
@ -185,6 +188,7 @@ def resp(success=True, code=500):
|
|||
r.status_code = code
|
||||
return r
|
||||
|
||||
app = Flask(__name__, root_path=str(local_dir))
|
||||
|
||||
def main():
|
||||
if args.install:
|
||||
|
@ -290,8 +294,6 @@ def main():
|
|||
success = True
|
||||
|
||||
else:
|
||||
global app
|
||||
app = Flask(__name__, root_path=str(local_dir))
|
||||
app.config["DEBUG"] = config.getboolean("ui", "debug")
|
||||
app.config["SECRET_KEY"] = secrets.token_urlsafe(16)
|
||||
app.config["JSON_SORT_KEYS"] = False
|
||||
|
@ -328,7 +330,7 @@ def main():
|
|||
jellyfin_accounts.pw_reset.start()
|
||||
|
||||
pwr = threading.Thread(target=start_pwr, daemon=True)
|
||||
log.info("Starting email thread")
|
||||
log.info("Starting password reset thread")
|
||||
pwr.start()
|
||||
|
||||
def signal_handler(sig, frame):
|
||||
|
|
|
@ -21,16 +21,19 @@ function checkEmailRadio() {
|
|||
document.getElementById('emailCommonArea').style.display = '';
|
||||
document.getElementById('emailSMTPArea').style.display = '';
|
||||
document.getElementById('emailMailgunArea').style.display = 'none';
|
||||
document.getElementById('notificationsEnabled').checked = true;
|
||||
} else if (document.getElementById('emailMailgunRadio').checked) {
|
||||
document.getElementById('emailCommonArea').style.display = '';
|
||||
document.getElementById('emailSMTPArea').style.display = 'none';
|
||||
document.getElementById('emailMailgunArea').style.display = '';
|
||||
document.getElementById('notificationsEnabled').checked = true;
|
||||
} else if (document.getElementById('emailDisabledRadio').checked) {
|
||||
document.getElementById('emailCommonArea').style.display = 'none';
|
||||
document.getElementById('emailSMTPArea').style.display = 'none';
|
||||
document.getElementById('emailMailgunArea').style.display = 'none';
|
||||
document.getElementById('emailNextButton').href = '#page-8';
|
||||
document.getElementById('valBackButton').href = '#page-4';
|
||||
document.getElementById('notificationsEnabled').checked = false;
|
||||
};
|
||||
};
|
||||
var emailRadios = ['emailDisabledRadio', 'emailSMTPRadio', 'emailMailgunRadio'];
|
||||
|
@ -165,6 +168,7 @@ document.getElementById('submitButton').onclick = function() {
|
|||
if (document.getElementById('emailDisabledRadio').checked) {
|
||||
config['password_resets']['enabled'] = 'false';
|
||||
config['invite_emails']['enabled'] = 'false';
|
||||
config['notificatons']['enabled'] = 'false';
|
||||
} else {
|
||||
if (document.getElementById('emailSMTPRadio').checked) {
|
||||
if (document.getElementById('emailSSL_TLS').checked) {
|
||||
|
|
|
@ -651,11 +651,11 @@ document.getElementById('openDefaultsWizard').onclick = function() {
|
|||
for (user of users) {
|
||||
let radio = document.createElement('div');
|
||||
radio.classList.add('radio');
|
||||
let checked = 'checked';
|
||||
if (first) {
|
||||
const checked = 'checked';
|
||||
first = false;
|
||||
} else {
|
||||
const checked = '';
|
||||
checked = '';
|
||||
};
|
||||
radio.innerHTML =
|
||||
`<label><input type="radio" name="defaultRadios" id="default_${user['name']}" style="margin-right: 1rem;" ${checked}>${user['name']}</label>`;
|
||||
|
|
|
@ -61,6 +61,7 @@ class Jellyfin:
|
|||
self.version = version
|
||||
self.device = device
|
||||
self.deviceId = deviceId
|
||||
self.authenticated = False
|
||||
self.timeout = cacheMinutes * 60
|
||||
self.userCacheAge = time.time() - self.timeout - 1
|
||||
self.userCachePublicAge = self.userCacheAge
|
||||
|
@ -80,10 +81,10 @@ class Jellyfin:
|
|||
"X-Emby-Authorization": self.auth,
|
||||
}
|
||||
try:
|
||||
self.info = requests.get(self.server + "/System/Info/Public").json()
|
||||
self.info = requests.get(f"{self.server}/System/Info/Public").json()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def reloadCache(self):
|
||||
""" Forces a reload of the user caches """
|
||||
self.userCachePublicAge = time.time() - self.timeout - 1
|
||||
|
@ -107,7 +108,7 @@ class Jellyfin:
|
|||
"""
|
||||
if public is True:
|
||||
if (time.time() - self.userCachePublicAge) >= self.timeout:
|
||||
response = requests.get(self.server + "/emby/Users/Public").json()
|
||||
response = requests.get(f"{self.server}/Users/Public").json()
|
||||
self.userCachePublic = response
|
||||
self.userCachePublicAge = time.time()
|
||||
else:
|
||||
|
@ -117,7 +118,7 @@ class Jellyfin:
|
|||
):
|
||||
if (time.time() - self.userCacheAge) >= self.timeout:
|
||||
response = requests.get(
|
||||
self.server + "/emby/Users",
|
||||
f"{self.server}/Users",
|
||||
headers=self.header,
|
||||
params={"Username": self.username, "Pw": self.password},
|
||||
)
|
||||
|
@ -125,7 +126,7 @@ class Jellyfin:
|
|||
response = response.json()
|
||||
self.userCache = response
|
||||
self.userCacheAge = time.time()
|
||||
else:
|
||||
elif response.status_code == 401:
|
||||
try:
|
||||
self.authenticate(self.username, self.password)
|
||||
return self.getUsers(username, userId, public)
|
||||
|
@ -161,12 +162,10 @@ class Jellyfin:
|
|||
:param username: Plaintext username.
|
||||
:param password: Plaintext password.
|
||||
"""
|
||||
self.username = username
|
||||
self.password = password
|
||||
response = requests.post(
|
||||
self.server + "/emby/Users/AuthenticateByName",
|
||||
f"{self.server}/Users/AuthenticateByName",
|
||||
headers=self.header,
|
||||
params={"Username": self.username, "Pw": self.password},
|
||||
params={"Username": username, "Pw": password},
|
||||
)
|
||||
if response.status_code == 200:
|
||||
json = response.json()
|
||||
|
@ -180,8 +179,11 @@ class Jellyfin:
|
|||
self.auth += f", Token={self.accessToken}"
|
||||
self.header["X-Emby-Authorization"] = self.auth
|
||||
self.info = requests.get(
|
||||
self.server + "/System/Info", headers=self.header
|
||||
f"{self.server}/System/Info", headers=self.header
|
||||
).json()
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.authenticated = True
|
||||
return True
|
||||
else:
|
||||
raise self.AuthenticationError
|
||||
|
@ -194,7 +196,7 @@ class Jellyfin:
|
|||
:param policy: User policy in dictionary form.
|
||||
"""
|
||||
return requests.post(
|
||||
self.server + "/Users/" + userId + "/Policy",
|
||||
f"{self.server}/Users/" + userId + "/Policy",
|
||||
headers=self.header,
|
||||
params=policy,
|
||||
)
|
||||
|
@ -204,7 +206,7 @@ class Jellyfin:
|
|||
if user["Name"] == username:
|
||||
raise self.UserExistsError
|
||||
response = requests.post(
|
||||
self.server + "/emby/Users/New",
|
||||
f"{self.server}/Users/New",
|
||||
headers=self.header,
|
||||
params={"Name": username, "Password": password},
|
||||
)
|
||||
|
@ -222,7 +224,7 @@ class Jellyfin:
|
|||
else:
|
||||
param = ""
|
||||
views = requests.get(
|
||||
self.server + "/Users/" + userId + "/Views" + param, headers=self.header
|
||||
f"{self.server}/Users/" + userId + "/Views" + param, headers=self.header
|
||||
).json()["Items"]
|
||||
orderedViews = []
|
||||
for library in views:
|
||||
|
@ -236,7 +238,7 @@ class Jellyfin:
|
|||
:param configuration: Configuration to write in dictionary form.
|
||||
"""
|
||||
resp = requests.post(
|
||||
self.server + "/Users/" + userId + "/Configuration",
|
||||
f"{self.server}/Users/" + userId + "/Configuration",
|
||||
headers=self.header,
|
||||
params=configuration,
|
||||
)
|
||||
|
|
|
@ -6,7 +6,7 @@ from watchdog.events import FileSystemEventHandler
|
|||
from jellyfin_accounts.email import Mailgun, Smtp
|
||||
from jellyfin_accounts.web_api import jf
|
||||
from jellyfin_accounts import config, data_store
|
||||
from jellyfin_accounts import email_log as log
|
||||
from jellyfin_accounts import pwr_log as log
|
||||
|
||||
|
||||
class Watcher:
|
||||
|
|
|
@ -441,7 +441,7 @@ def modifyConfig():
|
|||
temp_config = configparser.RawConfigParser(
|
||||
comment_prefixes="/", allow_no_value=True
|
||||
)
|
||||
temp_config.read(config_path)
|
||||
temp_config.read(str(config_path.resolve()))
|
||||
for section in data:
|
||||
if section in temp_config and 'restart-program' not in section:
|
||||
for item in data[section]:
|
||||
|
|
|
@ -1,13 +1,39 @@
|
|||
import subprocess
|
||||
import shutil
|
||||
import os
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
"-y", "--yes", help="use assumed node bin directory.", action="store_true"
|
||||
)
|
||||
|
||||
|
||||
def runcmd(cmd):
|
||||
if os.name == "nt":
|
||||
return subprocess.check_output(cmd, shell=True)
|
||||
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
|
||||
return proc.communicate()
|
||||
|
||||
local_path = Path(__file__).resolve().parent
|
||||
node_bin = local_path.parent / 'node_modules' / '.bin'
|
||||
out = runcmd("npm bin")
|
||||
|
||||
try:
|
||||
node_bin = Path(out[0].decode('utf-8').rstrip())
|
||||
except:
|
||||
node_bin = Path(out.decode('utf-8').rstrip())
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.yes:
|
||||
print(f"assuming npm bin directory \"{node_bin}\". Is this correct?")
|
||||
if input("[yY/nN]: ").lower() == "n":
|
||||
node_bin = local_path.parent / 'node_modules' / '.bin'
|
||||
print(f"this? \"{node_bin}\"")
|
||||
if input("[yY/nN]: ").lower() == "n":
|
||||
node_bin = input("input bin directory: ")
|
||||
|
||||
for mjml in [f for f in local_path.iterdir() if f.is_file() and 'mjml' in f.suffix]:
|
||||
print(f'Compiling {mjml.name}')
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,18 +1,18 @@
|
|||
[[package]]
|
||||
category = "dev"
|
||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
name = "appdirs"
|
||||
version = "1.4.4"
|
||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.4.4"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Classes Without Boilerplate"
|
||||
name = "attrs"
|
||||
version = "19.3.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "19.3.0"
|
||||
|
||||
[package.extras]
|
||||
azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
|
||||
|
@ -21,12 +21,12 @@ docs = ["sphinx", "zope.interface"]
|
|||
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "The uncompromising code formatter."
|
||||
name = "black"
|
||||
version = "19.10b0"
|
||||
description = "The uncompromising code formatter."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
version = "19.10b0"
|
||||
|
||||
[package.dependencies]
|
||||
appdirs = "*"
|
||||
|
@ -41,72 +41,72 @@ typed-ast = ">=1.4.0"
|
|||
d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
name = "certifi"
|
||||
version = "2020.6.20"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2020.6.20"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
name = "cffi"
|
||||
version = "1.14.1"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.14.0"
|
||||
|
||||
[package.dependencies]
|
||||
pycparser = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Universal encoding detector for Python 2 and 3"
|
||||
name = "chardet"
|
||||
version = "3.0.4"
|
||||
description = "Universal encoding detector for Python 2 and 3"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "3.0.4"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Composable command line interface toolkit"
|
||||
name = "click"
|
||||
version = "7.1.2"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "7.1.2"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
name = "cryptography"
|
||||
version = "3.2"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
|
||||
version = "2.9.2"
|
||||
|
||||
[package.dependencies]
|
||||
cffi = ">=1.8,<1.11.3 || >1.11.3"
|
||||
six = ">=1.4.1"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0)", "sphinx-rtd-theme"]
|
||||
docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"]
|
||||
docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
|
||||
idna = ["idna (>=2.1)"]
|
||||
pep8test = ["flake8", "flake8-import-order", "pep8-naming"]
|
||||
test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"]
|
||||
pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["pytest (>=3.6.0,!=3.9.0,!=3.9.1,!=3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A simple framework for building complex web applications."
|
||||
name = "flask"
|
||||
version = "1.1.2"
|
||||
description = "A simple framework for building complex web applications."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "1.1.2"
|
||||
|
||||
[package.dependencies]
|
||||
Jinja2 = ">=2.10.1"
|
||||
Werkzeug = ">=0.15"
|
||||
click = ">=5.1"
|
||||
itsdangerous = ">=0.24"
|
||||
Jinja2 = ">=2.10.1"
|
||||
Werkzeug = ">=0.15"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
|
||||
|
@ -114,47 +114,47 @@ docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-
|
|||
dotenv = ["python-dotenv"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Basic and Digest HTTP authentication for Flask routes"
|
||||
name = "flask-httpauth"
|
||||
version = "4.1.0"
|
||||
description = "Basic and Digest HTTP authentication for Flask routes"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "4.1.0"
|
||||
|
||||
[package.dependencies]
|
||||
Flask = "*"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Lightweight in-process concurrent programming"
|
||||
name = "greenlet"
|
||||
version = "0.4.16"
|
||||
description = "Lightweight in-process concurrent programming"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.4.16"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
name = "idna"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "2.10"
|
||||
|
||||
[[package]]
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
category = "main"
|
||||
description = "Various helpers to pass data to untrusted environments and back."
|
||||
name = "itsdangerous"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "1.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "itsdangerous"
|
||||
version = "1.1.0"
|
||||
description = "Various helpers to pass data to untrusted environments and back."
|
||||
category = "main"
|
||||
description = "A very fast and expressive template engine."
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "2.11.2"
|
||||
description = "A very fast and expressive template engine."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "2.11.2"
|
||||
|
||||
[package.dependencies]
|
||||
MarkupSafe = ">=0.23"
|
||||
|
@ -163,62 +163,62 @@ MarkupSafe = ">=0.23"
|
|||
i18n = ["Babel (>=0.8)"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Sass for Python: A straightforward binding of libsass for Python."
|
||||
name = "libsass"
|
||||
version = "0.20.0"
|
||||
description = "Sass for Python: A straightforward binding of libsass for Python."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.20.0"
|
||||
|
||||
[package.dependencies]
|
||||
six = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Safely add untrusted strings to HTML/XML markup."
|
||||
name = "markupsafe"
|
||||
version = "1.1.1"
|
||||
description = "Safely add untrusted strings to HTML/XML markup."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
|
||||
version = "1.1.1"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "MessagePack (de)serializer."
|
||||
name = "msgpack"
|
||||
version = "1.0.0"
|
||||
description = "MessagePack (de)serializer."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.0.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Transition packgage for pynvim"
|
||||
name = "neovim"
|
||||
version = "0.3.1"
|
||||
description = "Transition packgage for pynvim"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.3.1"
|
||||
|
||||
[package.dependencies]
|
||||
pynvim = ">=0.3.1"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Core utilities for Python packages"
|
||||
name = "packaging"
|
||||
version = "20.4"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "20.4"
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = ">=2.0.2"
|
||||
six = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "comprehensive password hashing framework supporting over 30 schemes"
|
||||
name = "passlib"
|
||||
version = "1.7.2"
|
||||
description = "comprehensive password hashing framework supporting over 30 schemes"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.7.2"
|
||||
|
||||
[package.extras]
|
||||
argon2 = ["argon2-cffi (>=18.2.0)"]
|
||||
|
@ -227,47 +227,47 @@ build_docs = ["sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)", "cloud-spthem
|
|||
totp = ["cryptography"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
name = "pathspec"
|
||||
version = "0.8.0"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "0.8.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "File system general utilities"
|
||||
name = "pathtools"
|
||||
version = "0.1.2"
|
||||
description = "File system general utilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.1.2"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Cross-platform lib for process and system monitoring in Python."
|
||||
name = "psutil"
|
||||
version = "5.7.2"
|
||||
description = "Cross-platform lib for process and system monitoring in Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "5.7.2"
|
||||
|
||||
[package.extras]
|
||||
test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "C parser in Python"
|
||||
name = "pycparser"
|
||||
version = "2.20"
|
||||
description = "C parser in Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "2.20"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Python client to neovim"
|
||||
name = "pynvim"
|
||||
version = "0.4.1"
|
||||
description = "Python client to neovim"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.4.1"
|
||||
|
||||
[package.dependencies]
|
||||
greenlet = "*"
|
||||
|
@ -278,12 +278,12 @@ pyuv = ["pyuv (>=1.0.0)"]
|
|||
test = ["pytest (>=3.4.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python wrapper module around the OpenSSL library"
|
||||
name = "pyopenssl"
|
||||
version = "19.1.0"
|
||||
description = "Python wrapper module around the OpenSSL library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "19.1.0"
|
||||
|
||||
[package.dependencies]
|
||||
cryptography = ">=2.8"
|
||||
|
@ -294,47 +294,47 @@ docs = ["sphinx", "sphinx-rtd-theme"]
|
|||
test = ["flaky", "pretend", "pytest (>=3.0.1)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python parsing module"
|
||||
name = "pyparsing"
|
||||
version = "2.4.7"
|
||||
description = "Python parsing module"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
version = "2.4.7"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Extensions to the standard Python datetime module"
|
||||
name = "python-dateutil"
|
||||
version = "2.8.1"
|
||||
description = "Extensions to the standard Python datetime module"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
version = "2.8.1"
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.5"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "World timezone definitions, modern and historical"
|
||||
name = "pytz"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2020.1"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Alternative regular expression module, to replace re."
|
||||
name = "regex"
|
||||
description = "World timezone definitions, modern and historical"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "2020.7.14"
|
||||
description = "Alternative regular expression module, to replace re."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2020.7.14"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python HTTP for Humans."
|
||||
name = "requests"
|
||||
version = "2.24.0"
|
||||
description = "Python HTTP for Humans."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "2.24.0"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
|
@ -344,75 +344,75 @@ urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
|
|||
|
||||
[package.extras]
|
||||
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
|
||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
name = "six"
|
||||
version = "1.15.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
version = "1.15.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "tasks runner for python projects"
|
||||
name = "taskipy"
|
||||
version = "1.2.1"
|
||||
description = "tasks runner for python projects"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6,<4.0"
|
||||
version = "1.2.1"
|
||||
|
||||
[package.dependencies]
|
||||
toml = ">=0.10.0,<0.11.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
name = "toml"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.10.1"
|
||||
|
||||
[[package]]
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "typed-ast"
|
||||
version = "1.4.1"
|
||||
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
||||
category = "dev"
|
||||
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
||||
name = "typed-ast"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.4.1"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
name = "urllib3"
|
||||
version = "1.25.10"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
version = "1.25.9"
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotlipy (>=0.6.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
|
||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Waitress WSGI server"
|
||||
name = "waitress"
|
||||
version = "1.4.4"
|
||||
description = "Waitress WSGI server"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
version = "1.4.4"
|
||||
|
||||
[package.extras]
|
||||
docs = ["Sphinx (>=1.8.1)", "docutils", "pylons-sphinx-themes (>=1.0.9)"]
|
||||
testing = ["pytest", "pytest-cover", "coverage (>=5.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Filesystem events monitoring"
|
||||
name = "watchdog"
|
||||
version = "0.10.3"
|
||||
description = "Filesystem events monitoring"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.10.3"
|
||||
|
||||
[package.dependencies]
|
||||
pathtools = ">=0.1.1"
|
||||
|
@ -421,20 +421,21 @@ pathtools = ">=0.1.1"
|
|||
watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "The comprehensive WSGI web application library."
|
||||
name = "werkzeug"
|
||||
version = "1.0.1"
|
||||
description = "The comprehensive WSGI web application library."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "1.0.1"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"]
|
||||
watchdog = ["watchdog"]
|
||||
|
||||
[metadata]
|
||||
content-hash = "1c2741c9be187d9d0be662509fb4a87f5978e5f44420e5049a20504824c29a59"
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.6"
|
||||
content-hash = "1c2741c9be187d9d0be662509fb4a87f5978e5f44420e5049a20504824c29a59"
|
||||
|
||||
[metadata.files]
|
||||
appdirs = [
|
||||
|
@ -454,34 +455,34 @@ certifi = [
|
|||
{file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"},
|
||||
]
|
||||
cffi = [
|
||||
{file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-win32.whl", hash = "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-win_amd64.whl", hash = "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793"},
|
||||
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e"},
|
||||
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-win32.whl", hash = "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b"},
|
||||
{file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"},
|
||||
{file = "cffi-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:66dd45eb9530e3dde8f7c009f84568bc7cac489b93d04ac86e3111fb46e470c2"},
|
||||
{file = "cffi-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:4f53e4128c81ca3212ff4cf097c797ab44646a40b42ec02a891155cd7a2ba4d8"},
|
||||
{file = "cffi-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:833401b15de1bb92791d7b6fb353d4af60dc688eaa521bd97203dcd2d124a7c1"},
|
||||
{file = "cffi-1.14.1-cp27-cp27m-win32.whl", hash = "sha256:26f33e8f6a70c255767e3c3f957ccafc7f1f706b966e110b855bfe944511f1f9"},
|
||||
{file = "cffi-1.14.1-cp27-cp27m-win_amd64.whl", hash = "sha256:b87dfa9f10a470eee7f24234a37d1d5f51e5f5fa9eeffda7c282e2b8f5162eb1"},
|
||||
{file = "cffi-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:effd2ba52cee4ceff1a77f20d2a9f9bf8d50353c854a282b8760ac15b9833168"},
|
||||
{file = "cffi-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bac0d6f7728a9cc3c1e06d4fcbac12aaa70e9379b3025b27ec1226f0e2d404cf"},
|
||||
{file = "cffi-1.14.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d6033b4ffa34ef70f0b8086fd4c3df4bf801fee485a8a7d4519399818351aa8e"},
|
||||
{file = "cffi-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8416ed88ddc057bab0526d4e4e9f3660f614ac2394b5e019a628cdfff3733849"},
|
||||
{file = "cffi-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:892daa86384994fdf4856cb43c93f40cbe80f7f95bb5da94971b39c7f54b3a9c"},
|
||||
{file = "cffi-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:c991112622baee0ae4d55c008380c32ecfd0ad417bcd0417ba432e6ba7328caa"},
|
||||
{file = "cffi-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:fcf32bf76dc25e30ed793145a57426064520890d7c02866eb93d3e4abe516948"},
|
||||
{file = "cffi-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f960375e9823ae6a07072ff7f8a85954e5a6434f97869f50d0e41649a1c8144f"},
|
||||
{file = "cffi-1.14.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a6d28e7f14ecf3b2ad67c4f106841218c8ab12a0683b1528534a6c87d2307af3"},
|
||||
{file = "cffi-1.14.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:cda422d54ee7905bfc53ee6915ab68fe7b230cacf581110df4272ee10462aadc"},
|
||||
{file = "cffi-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:4a03416915b82b81af5502459a8a9dd62a3c299b295dcdf470877cb948d655f2"},
|
||||
{file = "cffi-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:4ce1e995aeecf7cc32380bc11598bfdfa017d592259d5da00fc7ded11e61d022"},
|
||||
{file = "cffi-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e23cb7f1d8e0f93addf0cae3c5b6f00324cccb4a7949ee558d7b6ca973ab8ae9"},
|
||||
{file = "cffi-1.14.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ddff0b2bd7edcc8c82d1adde6dbbf5e60d57ce985402541cd2985c27f7bec2a0"},
|
||||
{file = "cffi-1.14.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f90c2267101010de42f7273c94a1f026e56cbc043f9330acd8a80e64300aba33"},
|
||||
{file = "cffi-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:3cd2c044517f38d1b577f05927fb9729d3396f1d44d0c659a445599e79519792"},
|
||||
{file = "cffi-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fa72a52a906425416f41738728268072d5acfd48cbe7796af07a923236bcf96"},
|
||||
{file = "cffi-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:267adcf6e68d77ba154334a3e4fc921b8e63cbb38ca00d33d40655d4228502bc"},
|
||||
{file = "cffi-1.14.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d3148b6ba3923c5850ea197a91a42683f946dba7e8eb82dfa211ab7e708de939"},
|
||||
{file = "cffi-1.14.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:98be759efdb5e5fa161e46d404f4e0ce388e72fbf7d9baf010aff16689e22abe"},
|
||||
{file = "cffi-1.14.1-cp38-cp38-win32.whl", hash = "sha256:6923d077d9ae9e8bacbdb1c07ae78405a9306c8fd1af13bfa06ca891095eb995"},
|
||||
{file = "cffi-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:b1d6ebc891607e71fd9da71688fcf332a6630b7f5b7f5549e6e631821c0e5d90"},
|
||||
{file = "cffi-1.14.1.tar.gz", hash = "sha256:b2a2b0d276a136146e012154baefaea2758ef1f56ae9f4e01c612b0831e0bd2f"},
|
||||
]
|
||||
chardet = [
|
||||
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
|
||||
|
@ -492,25 +493,28 @@ click = [
|
|||
{file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
|
||||
]
|
||||
cryptography = [
|
||||
{file = "cryptography-2.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e"},
|
||||
{file = "cryptography-2.9.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b"},
|
||||
{file = "cryptography-2.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c447cf087cf2dbddc1add6987bbe2f767ed5317adb2d08af940db517dd704365"},
|
||||
{file = "cryptography-2.9.2-cp27-cp27m-win32.whl", hash = "sha256:f118a95c7480f5be0df8afeb9a11bd199aa20afab7a96bcf20409b411a3a85f0"},
|
||||
{file = "cryptography-2.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:c4fd17d92e9d55b84707f4fd09992081ba872d1a0c610c109c18e062e06a2e55"},
|
||||
{file = "cryptography-2.9.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d0d5aeaedd29be304848f1c5059074a740fa9f6f26b84c5b63e8b29e73dfc270"},
|
||||
{file = "cryptography-2.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e4014639d3d73fbc5ceff206049c5a9a849cefd106a49fa7aaaa25cc0ce35cf"},
|
||||
{file = "cryptography-2.9.2-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:96c080ae7118c10fcbe6229ab43eb8b090fccd31a09ef55f83f690d1ef619a1d"},
|
||||
{file = "cryptography-2.9.2-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:e993468c859d084d5579e2ebee101de8f5a27ce8e2159959b6673b418fd8c785"},
|
||||
{file = "cryptography-2.9.2-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:88c881dd5a147e08d1bdcf2315c04972381d026cdb803325c03fe2b4a8ed858b"},
|
||||
{file = "cryptography-2.9.2-cp35-cp35m-win32.whl", hash = "sha256:651448cd2e3a6bc2bb76c3663785133c40d5e1a8c1a9c5429e4354201c6024ae"},
|
||||
{file = "cryptography-2.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:726086c17f94747cedbee6efa77e99ae170caebeb1116353c6cf0ab67ea6829b"},
|
||||
{file = "cryptography-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:091d31c42f444c6f519485ed528d8b451d1a0c7bf30e8ca583a0cac44b8a0df6"},
|
||||
{file = "cryptography-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:bb1f0281887d89617b4c68e8db9a2c42b9efebf2702a3c5bf70599421a8623e3"},
|
||||
{file = "cryptography-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:18452582a3c85b96014b45686af264563e3e5d99d226589f057ace56196ec78b"},
|
||||
{file = "cryptography-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:22e91636a51170df0ae4dcbd250d318fd28c9f491c4e50b625a49964b24fe46e"},
|
||||
{file = "cryptography-2.9.2-cp38-cp38-win32.whl", hash = "sha256:844a76bc04472e5135b909da6aed84360f522ff5dfa47f93e3dd2a0b84a89fa0"},
|
||||
{file = "cryptography-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5"},
|
||||
{file = "cryptography-2.9.2.tar.gz", hash = "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229"},
|
||||
{file = "cryptography-3.2-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:9a8580c9afcdcddabbd064c0a74f337af74ff4529cdf3a12fa2e9782d677a2e5"},
|
||||
{file = "cryptography-3.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7ef41304bf978f33cfb6f43ca13bb0faac0c99cda33693aa20ad4f5e34e8cb8f"},
|
||||
{file = "cryptography-3.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:87c2fffd61e934bc0e2c927c3764c20b22d7f5f7f812ee1a477de4c89b044ca6"},
|
||||
{file = "cryptography-3.2-cp27-cp27m-win32.whl", hash = "sha256:6e8a3c7c45101a7eeee93102500e1b08f2307c717ff553fcb3c1127efc9b6917"},
|
||||
{file = "cryptography-3.2-cp27-cp27m-win_amd64.whl", hash = "sha256:52a47e60953679eea0b4d490ca3c241fb1b166a7b161847ef4667dfd49e7699d"},
|
||||
{file = "cryptography-3.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:6a8f64ed096d13f92d1f601a92d9fd1f1025dc73a2ca1ced46dcf5e0d4930943"},
|
||||
{file = "cryptography-3.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:3e17d02941c0f169c5b877597ca8be895fca0e5e3eb882526a74aa4804380a98"},
|
||||
{file = "cryptography-3.2-cp35-abi3-macosx_10_10_x86_64.whl", hash = "sha256:d1cbc3426e6150583b22b517ef3720036d7e3152d428c864ff0f3fcad2b97591"},
|
||||
{file = "cryptography-3.2-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:22f8251f68953553af4f9c11ec5f191198bc96cff9f0ac5dd5ff94daede0ee6d"},
|
||||
{file = "cryptography-3.2-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:f2aa3f8ba9e2e3fd49bd3de743b976ab192fbf0eb0348cebde5d2a9de0090a9f"},
|
||||
{file = "cryptography-3.2-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:9a07e6d255053674506091d63ab4270a119e9fc83462c7ab1dbcb495b76307af"},
|
||||
{file = "cryptography-3.2-cp35-cp35m-win32.whl", hash = "sha256:f0e3986f6cce007216b23c490f093f35ce2068f3c244051e559f647f6731b7ae"},
|
||||
{file = "cryptography-3.2-cp35-cp35m-win_amd64.whl", hash = "sha256:284e275e3c099a80831f9898fb5c9559120d27675c3521278faba54e584a7832"},
|
||||
{file = "cryptography-3.2-cp36-abi3-win32.whl", hash = "sha256:f01c9116bfb3ad2831e125a73dcd957d173d6ddca7701528eff1e7d97972872c"},
|
||||
{file = "cryptography-3.2-cp36-abi3-win_amd64.whl", hash = "sha256:bd80bc156d3729b38cb227a5a76532aef693b7ac9e395eea8063ee50ceed46a5"},
|
||||
{file = "cryptography-3.2-cp36-cp36m-win32.whl", hash = "sha256:8f0fd8b0751d75c4483c534b209e39e918f0d14232c0d8a2a76e687f64ced831"},
|
||||
{file = "cryptography-3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:8a0866891326d3badb17c5fd3e02c926b635e8923fa271b4813cd4d972a57ff3"},
|
||||
{file = "cryptography-3.2-cp37-cp37m-win32.whl", hash = "sha256:57b8c1ed13b8aa386cabbfde3be175d7b155682470b0e259fecfe53850967f8a"},
|
||||
{file = "cryptography-3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:88069392cd9a1e68d2cfd5c3a2b0d72a44ef3b24b8977a4f7956e9e3c4c9477a"},
|
||||
{file = "cryptography-3.2-cp38-cp38-win32.whl", hash = "sha256:fb70a4cedd69dc52396ee114416a3656e011fb0311fca55eb55c7be6ed9c8aef"},
|
||||
{file = "cryptography-3.2-cp38-cp38-win_amd64.whl", hash = "sha256:e15ac84dcdb89f92424cbaca4b0b34e211e7ce3ee7b0ec0e4f3c55cee65fae5a"},
|
||||
{file = "cryptography-3.2.tar.gz", hash = "sha256:e4789b84f8dedf190148441f7c5bfe7244782d9cbb194a36e17b91e7d3e1cca9"},
|
||||
]
|
||||
flask = [
|
||||
{file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"},
|
||||
|
@ -735,11 +739,17 @@ typed-ast = [
|
|||
{file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"},
|
||||
{file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"},
|
||||
{file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"},
|
||||
{file = "typed_ast-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92c325624e304ebf0e025d1224b77dd4e6393f18aab8d829b5b7e04afe9b7a2c"},
|
||||
{file = "typed_ast-1.4.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d648b8e3bf2fe648745c8ffcee3db3ff903d0817a01a12dd6a6ea7a8f4889072"},
|
||||
{file = "typed_ast-1.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fac11badff8313e23717f3dada86a15389d0708275bddf766cca67a84ead3e91"},
|
||||
{file = "typed_ast-1.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:0d8110d78a5736e16e26213114a38ca35cb15b6515d535413b090bd50951556d"},
|
||||
{file = "typed_ast-1.4.1-cp39-cp39-win32.whl", hash = "sha256:b52ccf7cfe4ce2a1064b18594381bccf4179c2ecf7f513134ec2f993dd4ab395"},
|
||||
{file = "typed_ast-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:3742b32cf1c6ef124d57f95be609c473d7ec4c14d0090e5a5e05a15269fb4d0c"},
|
||||
{file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
|
||||
]
|
||||
urllib3 = [
|
||||
{file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"},
|
||||
{file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"},
|
||||
{file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"},
|
||||
{file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},
|
||||
]
|
||||
waitress = [
|
||||
{file = "waitress-1.4.4-py2.py3-none-any.whl", hash = "sha256:3d633e78149eb83b60a07dfabb35579c29aac2d24bb803c18b26fb2ab1a584db"},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "jellyfin-accounts"
|
||||
version = "0.3.7"
|
||||
version = "0.3.9"
|
||||
readme = "README.md"
|
||||
description = "A simple account management system for Jellyfin"
|
||||
authors = ["Harvey Tindall <harveyltindall@gmail.com>"]
|
||||
|
|
|
@ -2,14 +2,40 @@
|
|||
import sass
|
||||
import subprocess
|
||||
import shutil
|
||||
import os
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
"-y", "--yes", help="use assumed node bin directory.", action="store_true"
|
||||
)
|
||||
|
||||
|
||||
def runcmd(cmd):
|
||||
if os.name == "nt":
|
||||
return subprocess.check_output(cmd, shell=True)
|
||||
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
|
||||
return proc.communicate()
|
||||
|
||||
local_path = Path(__file__).resolve().parent
|
||||
node_bin = local_path.parent / 'node_modules' / '.bin'
|
||||
out = runcmd("npm bin")
|
||||
|
||||
try:
|
||||
node_bin = Path(out[0].decode('utf-8').rstrip())
|
||||
except:
|
||||
node_bin = Path(out.decode('utf-8').rstrip())
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.yes:
|
||||
print(f"assuming npm bin directory \"{node_bin}\". Is this correct?")
|
||||
if input("[yY/nN]: ").lower() == "n":
|
||||
node_bin = local_path.parent / 'node_modules' / '.bin'
|
||||
print(f"this? \"{node_bin}\"")
|
||||
if input("[yY/nN]: ").lower() == "n":
|
||||
node_bin = input("input bin directory: ")
|
||||
|
||||
for bsv in [d for d in local_path.iterdir() if 'bs' in d.name]:
|
||||
scss = bsv / f'{bsv.name}-jf.scss'
|
||||
|
@ -21,7 +47,11 @@ for bsv in [d for d in local_path.iterdir() if 'bs' in d.name]:
|
|||
precision=6))
|
||||
if css.exists():
|
||||
print(f'{bsv.name}: Compiled.')
|
||||
runcmd(f'{str((node_bin / "postcss").resolve())} {str(css.resolve())} --replace --use autoprefixer')
|
||||
# postcss only excepts forwards slashes? weird.
|
||||
cssPath = str(css.resolve())
|
||||
if os.name == 'nt':
|
||||
cssPath = cssPath.replace('\\', '/')
|
||||
runcmd(f'{str((node_bin / "postcss").resolve())} {cssPath} --replace --use autoprefixer')
|
||||
print(f'{bsv.name}: Prefixed.')
|
||||
runcmd(f'{str((node_bin / "cleancss").resolve())} --level 1 --format breakWith=lf --output {str(min_css.resolve())} {str(css.resolve())}')
|
||||
if min_css.exists():
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def runcmd(cmd):
|
||||
if os.name == "nt":
|
||||
return subprocess.check_output(cmd, shell=True)
|
||||
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
|
||||
return proc.communicate()
|
||||
|
||||
|
||||
print('Installing npm packages')
|
||||
|
||||
root_path = Path(__file__).parents[1]
|
||||
runcmd(f'npm install --prefix {root_path}')
|
||||
if os.name == 'nt':
|
||||
root_path /= 'node_modules'
|
||||
runcmd(f'npm install')
|
||||
|
||||
if (root_path / 'node_modules' / 'cleancss').exists():
|
||||
print(f'Installed successfully in {str((root_path / "node_modules").resolve())}.')
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue