7 Commits

Author SHA1 Message Date
237c575441 make jfa-go mention bigger
you should try it out.
2020-08-18 14:34:26 +01:00
9185b59d16 Dockerfile builds from source
Uses multi-stage build, like jfa-go. I'm hoping this'll shrink the image
aswell.
2020-08-17 12:07:28 +01:00
43c0631f9b add non interactive modes to build scripts 2020-08-17 11:45:42 +01:00
3d10a8fe06 fix email generation on windows 2020-08-04 18:14:39 +01:00
8d265879cc actually fixed windows scss build 2020-08-04 18:12:18 +01:00
a38045cefb potential fixes for windows
hopefully fixes scss and email generation on windows by fixing runcmd()
and (optionally) reading npm bin location from the 'npm bin' command.
also, config path is cast to string before being passed to configparser.
2020-08-04 01:29:29 +01:00
d5609f3870 update readme, fix setup.js setting toggle 2020-08-02 02:33:34 +01:00
11 changed files with 182 additions and 79 deletions

27
Dockerfile Normal file
View File

@@ -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" ]

View File

@@ -1,5 +1,9 @@
### 👀 ➡️: Have a look at [jfa-go](https://github.com/hrfee/jfa-go), a rewrite in Go. Identical look and features but might be faster.
this version likely won't get too many more updates, so i recommend you switch.
# ![jellyfin-accounts](https://raw.githubusercontent.com/hrfee/jellyfin-accounts/bs5/images/jellyfin-accounts-banner-wide.svg) # ![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). A basic account management system for [Jellyfin](https://github.com/jellyfin/jellyfin).
* Provides a web interface for creating/sending invites * Provides a web interface for creating/sending invites
* Sends out emails when a user requests a password reset * Sends out emails when a user requests a password reset

View File

@@ -72,7 +72,7 @@ else:
# Temp config so logger knows whether to use debug mode or not # Temp config so logger knows whether to use debug mode or not
temp_config = configparser.RawConfigParser() temp_config = configparser.RawConfigParser()
temp_config.read(config_path) temp_config.read(str(config_path.resolve()))
def create_log(name): def create_log(name):
@@ -98,7 +98,8 @@ config = Config(config_path, secrets.token_urlsafe(16), data_dir, local_dir, log
web_log = create_log("waitress") web_log = create_log("waitress")
if not first_run: if not first_run:
email_log = create_log("emails") email_log = create_log("email")
pwr_log = create_log("pwr")
auth_log = create_log("auth") auth_log = create_log("auth")
if args.host is not None: if args.host is not None:
@@ -185,6 +186,7 @@ def resp(success=True, code=500):
r.status_code = code r.status_code = code
return r return r
app = Flask(__name__, root_path=str(local_dir))
def main(): def main():
if args.install: if args.install:
@@ -290,8 +292,6 @@ def main():
success = True success = True
else: else:
global app
app = Flask(__name__, root_path=str(local_dir))
app.config["DEBUG"] = config.getboolean("ui", "debug") app.config["DEBUG"] = config.getboolean("ui", "debug")
app.config["SECRET_KEY"] = secrets.token_urlsafe(16) app.config["SECRET_KEY"] = secrets.token_urlsafe(16)
app.config["JSON_SORT_KEYS"] = False app.config["JSON_SORT_KEYS"] = False
@@ -328,7 +328,7 @@ def main():
jellyfin_accounts.pw_reset.start() jellyfin_accounts.pw_reset.start()
pwr = threading.Thread(target=start_pwr, daemon=True) pwr = threading.Thread(target=start_pwr, daemon=True)
log.info("Starting email thread") log.info("Starting password reset thread")
pwr.start() pwr.start()
def signal_handler(sig, frame): def signal_handler(sig, frame):

View File

@@ -21,16 +21,19 @@ function checkEmailRadio() {
document.getElementById('emailCommonArea').style.display = ''; document.getElementById('emailCommonArea').style.display = '';
document.getElementById('emailSMTPArea').style.display = ''; document.getElementById('emailSMTPArea').style.display = '';
document.getElementById('emailMailgunArea').style.display = 'none'; document.getElementById('emailMailgunArea').style.display = 'none';
document.getElementById('notificationsEnabled').checked = true;
} else if (document.getElementById('emailMailgunRadio').checked) { } else if (document.getElementById('emailMailgunRadio').checked) {
document.getElementById('emailCommonArea').style.display = ''; document.getElementById('emailCommonArea').style.display = '';
document.getElementById('emailSMTPArea').style.display = 'none'; document.getElementById('emailSMTPArea').style.display = 'none';
document.getElementById('emailMailgunArea').style.display = ''; document.getElementById('emailMailgunArea').style.display = '';
document.getElementById('notificationsEnabled').checked = true;
} else if (document.getElementById('emailDisabledRadio').checked) { } else if (document.getElementById('emailDisabledRadio').checked) {
document.getElementById('emailCommonArea').style.display = 'none'; document.getElementById('emailCommonArea').style.display = 'none';
document.getElementById('emailSMTPArea').style.display = 'none'; document.getElementById('emailSMTPArea').style.display = 'none';
document.getElementById('emailMailgunArea').style.display = 'none'; document.getElementById('emailMailgunArea').style.display = 'none';
document.getElementById('emailNextButton').href = '#page-8'; document.getElementById('emailNextButton').href = '#page-8';
document.getElementById('valBackButton').href = '#page-4'; document.getElementById('valBackButton').href = '#page-4';
document.getElementById('notificationsEnabled').checked = false;
}; };
}; };
var emailRadios = ['emailDisabledRadio', 'emailSMTPRadio', 'emailMailgunRadio']; var emailRadios = ['emailDisabledRadio', 'emailSMTPRadio', 'emailMailgunRadio'];
@@ -165,6 +168,7 @@ document.getElementById('submitButton').onclick = function() {
if (document.getElementById('emailDisabledRadio').checked) { if (document.getElementById('emailDisabledRadio').checked) {
config['password_resets']['enabled'] = 'false'; config['password_resets']['enabled'] = 'false';
config['invite_emails']['enabled'] = 'false'; config['invite_emails']['enabled'] = 'false';
config['notificatons']['enabled'] = 'false';
} else { } else {
if (document.getElementById('emailSMTPRadio').checked) { if (document.getElementById('emailSMTPRadio').checked) {
if (document.getElementById('emailSSL_TLS').checked) { if (document.getElementById('emailSSL_TLS').checked) {

View File

@@ -61,6 +61,7 @@ class Jellyfin:
self.version = version self.version = version
self.device = device self.device = device
self.deviceId = deviceId self.deviceId = deviceId
self.authenticated = False
self.timeout = cacheMinutes * 60 self.timeout = cacheMinutes * 60
self.userCacheAge = time.time() - self.timeout - 1 self.userCacheAge = time.time() - self.timeout - 1
self.userCachePublicAge = self.userCacheAge self.userCachePublicAge = self.userCacheAge
@@ -80,10 +81,10 @@ class Jellyfin:
"X-Emby-Authorization": self.auth, "X-Emby-Authorization": self.auth,
} }
try: try:
self.info = requests.get(self.server + "/System/Info/Public").json() self.info = requests.get(f"{self.server}/System/Info/Public").json()
except: except:
pass pass
def reloadCache(self): def reloadCache(self):
""" Forces a reload of the user caches """ """ Forces a reload of the user caches """
self.userCachePublicAge = time.time() - self.timeout - 1 self.userCachePublicAge = time.time() - self.timeout - 1
@@ -107,7 +108,7 @@ class Jellyfin:
""" """
if public is True: if public is True:
if (time.time() - self.userCachePublicAge) >= self.timeout: 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.userCachePublic = response
self.userCachePublicAge = time.time() self.userCachePublicAge = time.time()
else: else:
@@ -117,7 +118,7 @@ class Jellyfin:
): ):
if (time.time() - self.userCacheAge) >= self.timeout: if (time.time() - self.userCacheAge) >= self.timeout:
response = requests.get( response = requests.get(
self.server + "/emby/Users", f"{self.server}/Users",
headers=self.header, headers=self.header,
params={"Username": self.username, "Pw": self.password}, params={"Username": self.username, "Pw": self.password},
) )
@@ -125,7 +126,7 @@ class Jellyfin:
response = response.json() response = response.json()
self.userCache = response self.userCache = response
self.userCacheAge = time.time() self.userCacheAge = time.time()
else: elif response.status_code == 401:
try: try:
self.authenticate(self.username, self.password) self.authenticate(self.username, self.password)
return self.getUsers(username, userId, public) return self.getUsers(username, userId, public)
@@ -161,12 +162,10 @@ class Jellyfin:
:param username: Plaintext username. :param username: Plaintext username.
:param password: Plaintext password. :param password: Plaintext password.
""" """
self.username = username
self.password = password
response = requests.post( response = requests.post(
self.server + "/emby/Users/AuthenticateByName", f"{self.server}/Users/AuthenticateByName",
headers=self.header, headers=self.header,
params={"Username": self.username, "Pw": self.password}, params={"Username": username, "Pw": password},
) )
if response.status_code == 200: if response.status_code == 200:
json = response.json() json = response.json()
@@ -180,8 +179,11 @@ class Jellyfin:
self.auth += f", Token={self.accessToken}" self.auth += f", Token={self.accessToken}"
self.header["X-Emby-Authorization"] = self.auth self.header["X-Emby-Authorization"] = self.auth
self.info = requests.get( self.info = requests.get(
self.server + "/System/Info", headers=self.header f"{self.server}/System/Info", headers=self.header
).json() ).json()
self.username = username
self.password = password
self.authenticated = True
return True return True
else: else:
raise self.AuthenticationError raise self.AuthenticationError
@@ -194,7 +196,7 @@ class Jellyfin:
:param policy: User policy in dictionary form. :param policy: User policy in dictionary form.
""" """
return requests.post( return requests.post(
self.server + "/Users/" + userId + "/Policy", f"{self.server}/Users/" + userId + "/Policy",
headers=self.header, headers=self.header,
params=policy, params=policy,
) )
@@ -204,7 +206,7 @@ class Jellyfin:
if user["Name"] == username: if user["Name"] == username:
raise self.UserExistsError raise self.UserExistsError
response = requests.post( response = requests.post(
self.server + "/emby/Users/New", f"{self.server}/Users/New",
headers=self.header, headers=self.header,
params={"Name": username, "Password": password}, params={"Name": username, "Password": password},
) )
@@ -222,7 +224,7 @@ class Jellyfin:
else: else:
param = "" param = ""
views = requests.get( views = requests.get(
self.server + "/Users/" + userId + "/Views" + param, headers=self.header f"{self.server}/Users/" + userId + "/Views" + param, headers=self.header
).json()["Items"] ).json()["Items"]
orderedViews = [] orderedViews = []
for library in views: for library in views:
@@ -236,7 +238,7 @@ class Jellyfin:
:param configuration: Configuration to write in dictionary form. :param configuration: Configuration to write in dictionary form.
""" """
resp = requests.post( resp = requests.post(
self.server + "/Users/" + userId + "/Configuration", f"{self.server}/Users/" + userId + "/Configuration",
headers=self.header, headers=self.header,
params=configuration, params=configuration,
) )

View File

@@ -6,7 +6,7 @@ from watchdog.events import FileSystemEventHandler
from jellyfin_accounts.email import Mailgun, Smtp from jellyfin_accounts.email import Mailgun, Smtp
from jellyfin_accounts.web_api import jf from jellyfin_accounts.web_api import jf
from jellyfin_accounts import config, data_store 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: class Watcher:

View File

@@ -441,7 +441,7 @@ def modifyConfig():
temp_config = configparser.RawConfigParser( temp_config = configparser.RawConfigParser(
comment_prefixes="/", allow_no_value=True comment_prefixes="/", allow_no_value=True
) )
temp_config.read(config_path) temp_config.read(str(config_path.resolve()))
for section in data: for section in data:
if section in temp_config and 'restart-program' not in section: if section in temp_config and 'restart-program' not in section:
for item in data[section]: for item in data[section]:

View File

@@ -1,13 +1,39 @@
import subprocess import subprocess
import shutil import shutil
import os
import argparse
from pathlib import Path from pathlib import Path
parser = argparse.ArgumentParser()
parser.add_argument(
"-y", "--yes", help="use assumed node bin directory.", action="store_true"
)
def runcmd(cmd): def runcmd(cmd):
if os.name == "nt":
return subprocess.check_output(cmd, shell=True)
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
return proc.communicate() return proc.communicate()
local_path = Path(__file__).resolve().parent 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]: for mjml in [f for f in local_path.iterdir() if f.is_file() and 'mjml' in f.suffix]:
print(f'Compiling {mjml.name}') print(f'Compiling {mjml.name}')

110
poetry.lock generated
View File

@@ -54,7 +54,7 @@ description = "Foreign Function Interface for Python calling C code."
name = "cffi" name = "cffi"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.14.0" version = "1.14.1"
[package.dependencies] [package.dependencies]
pycparser = "*" pycparser = "*"
@@ -81,17 +81,18 @@ description = "cryptography is a package which provides cryptographic recipes an
name = "cryptography" name = "cryptography"
optional = false optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
version = "2.9.2" version = "3.0"
[package.dependencies] [package.dependencies]
cffi = ">=1.8,<1.11.3 || >1.11.3" cffi = ">=1.8,<1.11.3 || >1.11.3"
six = ">=1.4.1" six = ">=1.4.1"
[package.extras] [package.extras]
docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0)", "sphinx-rtd-theme"] docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0,<3.1.0 || >3.1.0,<3.1.1 || >3.1.1)", "sphinx-rtd-theme"]
docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
idna = ["idna (>=2.1)"] idna = ["idna (>=2.1)"]
pep8test = ["flake8", "flake8-import-order", "pep8-naming"] pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"]
ssh = ["bcrypt (>=3.1.5)"]
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)"] 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)"]
[[package]] [[package]]
@@ -387,7 +388,7 @@ description = "HTTP library with thread-safe connection pooling, file post, and
name = "urllib3" name = "urllib3"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
version = "1.25.9" version = "1.25.10"
[package.extras] [package.extras]
brotli = ["brotlipy (>=0.6.0)"] brotli = ["brotlipy (>=0.6.0)"]
@@ -434,6 +435,7 @@ watchdog = ["watchdog"]
[metadata] [metadata]
content-hash = "1c2741c9be187d9d0be662509fb4a87f5978e5f44420e5049a20504824c29a59" content-hash = "1c2741c9be187d9d0be662509fb4a87f5978e5f44420e5049a20504824c29a59"
lock-version = "1.0"
python-versions = "^3.6" python-versions = "^3.6"
[metadata.files] [metadata.files]
@@ -454,34 +456,34 @@ certifi = [
{file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"},
] ]
cffi = [ cffi = [
{file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"}, {file = "cffi-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:66dd45eb9530e3dde8f7c009f84568bc7cac489b93d04ac86e3111fb46e470c2"},
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30"}, {file = "cffi-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:4f53e4128c81ca3212ff4cf097c797ab44646a40b42ec02a891155cd7a2ba4d8"},
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"}, {file = "cffi-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:833401b15de1bb92791d7b6fb353d4af60dc688eaa521bd97203dcd2d124a7c1"},
{file = "cffi-1.14.0-cp27-cp27m-win32.whl", hash = "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78"}, {file = "cffi-1.14.1-cp27-cp27m-win32.whl", hash = "sha256:26f33e8f6a70c255767e3c3f957ccafc7f1f706b966e110b855bfe944511f1f9"},
{file = "cffi-1.14.0-cp27-cp27m-win_amd64.whl", hash = "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793"}, {file = "cffi-1.14.1-cp27-cp27m-win_amd64.whl", hash = "sha256:b87dfa9f10a470eee7f24234a37d1d5f51e5f5fa9eeffda7c282e2b8f5162eb1"},
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e"}, {file = "cffi-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:effd2ba52cee4ceff1a77f20d2a9f9bf8d50353c854a282b8760ac15b9833168"},
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a"}, {file = "cffi-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bac0d6f7728a9cc3c1e06d4fcbac12aaa70e9379b3025b27ec1226f0e2d404cf"},
{file = "cffi-1.14.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff"}, {file = "cffi-1.14.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d6033b4ffa34ef70f0b8086fd4c3df4bf801fee485a8a7d4519399818351aa8e"},
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f"}, {file = "cffi-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8416ed88ddc057bab0526d4e4e9f3660f614ac2394b5e019a628cdfff3733849"},
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa"}, {file = "cffi-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:892daa86384994fdf4856cb43c93f40cbe80f7f95bb5da94971b39c7f54b3a9c"},
{file = "cffi-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5"}, {file = "cffi-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:c991112622baee0ae4d55c008380c32ecfd0ad417bcd0417ba432e6ba7328caa"},
{file = "cffi-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4"}, {file = "cffi-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:fcf32bf76dc25e30ed793145a57426064520890d7c02866eb93d3e4abe516948"},
{file = "cffi-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d"}, {file = "cffi-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f960375e9823ae6a07072ff7f8a85954e5a6434f97869f50d0e41649a1c8144f"},
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc"}, {file = "cffi-1.14.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a6d28e7f14ecf3b2ad67c4f106841218c8ab12a0683b1528534a6c87d2307af3"},
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac"}, {file = "cffi-1.14.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:cda422d54ee7905bfc53ee6915ab68fe7b230cacf581110df4272ee10462aadc"},
{file = "cffi-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f"}, {file = "cffi-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:4a03416915b82b81af5502459a8a9dd62a3c299b295dcdf470877cb948d655f2"},
{file = "cffi-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b"}, {file = "cffi-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:4ce1e995aeecf7cc32380bc11598bfdfa017d592259d5da00fc7ded11e61d022"},
{file = "cffi-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3"}, {file = "cffi-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e23cb7f1d8e0f93addf0cae3c5b6f00324cccb4a7949ee558d7b6ca973ab8ae9"},
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66"}, {file = "cffi-1.14.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ddff0b2bd7edcc8c82d1adde6dbbf5e60d57ce985402541cd2985c27f7bec2a0"},
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0"}, {file = "cffi-1.14.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f90c2267101010de42f7273c94a1f026e56cbc043f9330acd8a80e64300aba33"},
{file = "cffi-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f"}, {file = "cffi-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:3cd2c044517f38d1b577f05927fb9729d3396f1d44d0c659a445599e79519792"},
{file = "cffi-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26"}, {file = "cffi-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fa72a52a906425416f41738728268072d5acfd48cbe7796af07a923236bcf96"},
{file = "cffi-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd"}, {file = "cffi-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:267adcf6e68d77ba154334a3e4fc921b8e63cbb38ca00d33d40655d4228502bc"},
{file = "cffi-1.14.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55"}, {file = "cffi-1.14.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d3148b6ba3923c5850ea197a91a42683f946dba7e8eb82dfa211ab7e708de939"},
{file = "cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2"}, {file = "cffi-1.14.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:98be759efdb5e5fa161e46d404f4e0ce388e72fbf7d9baf010aff16689e22abe"},
{file = "cffi-1.14.0-cp38-cp38-win32.whl", hash = "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8"}, {file = "cffi-1.14.1-cp38-cp38-win32.whl", hash = "sha256:6923d077d9ae9e8bacbdb1c07ae78405a9306c8fd1af13bfa06ca891095eb995"},
{file = "cffi-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b"}, {file = "cffi-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:b1d6ebc891607e71fd9da71688fcf332a6630b7f5b7f5549e6e631821c0e5d90"},
{file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"}, {file = "cffi-1.14.1.tar.gz", hash = "sha256:b2a2b0d276a136146e012154baefaea2758ef1f56ae9f4e01c612b0831e0bd2f"},
] ]
chardet = [ chardet = [
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
@@ -492,25 +494,25 @@ click = [
{file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
] ]
cryptography = [ cryptography = [
{file = "cryptography-2.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e"}, {file = "cryptography-3.0-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:ab49edd5bea8d8b39a44b3db618e4783ef84c19c8b47286bf05dfdb3efb01c83"},
{file = "cryptography-2.9.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b"}, {file = "cryptography-3.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:124af7255ffc8e964d9ff26971b3a6153e1a8a220b9a685dc407976ecb27a06a"},
{file = "cryptography-2.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c447cf087cf2dbddc1add6987bbe2f767ed5317adb2d08af940db517dd704365"}, {file = "cryptography-3.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:51e40123083d2f946794f9fe4adeeee2922b581fa3602128ce85ff813d85b81f"},
{file = "cryptography-2.9.2-cp27-cp27m-win32.whl", hash = "sha256:f118a95c7480f5be0df8afeb9a11bd199aa20afab7a96bcf20409b411a3a85f0"}, {file = "cryptography-3.0-cp27-cp27m-win32.whl", hash = "sha256:dea0ba7fe6f9461d244679efa968d215ea1f989b9c1957d7f10c21e5c7c09ad6"},
{file = "cryptography-2.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:c4fd17d92e9d55b84707f4fd09992081ba872d1a0c610c109c18e062e06a2e55"}, {file = "cryptography-3.0-cp27-cp27m-win_amd64.whl", hash = "sha256:8ecf9400d0893836ff41b6f977a33972145a855b6efeb605b49ee273c5e6469f"},
{file = "cryptography-2.9.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d0d5aeaedd29be304848f1c5059074a740fa9f6f26b84c5b63e8b29e73dfc270"}, {file = "cryptography-3.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0c608ff4d4adad9e39b5057de43657515c7da1ccb1807c3a27d4cf31fc923b4b"},
{file = "cryptography-2.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e4014639d3d73fbc5ceff206049c5a9a849cefd106a49fa7aaaa25cc0ce35cf"}, {file = "cryptography-3.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:bec7568c6970b865f2bcebbe84d547c52bb2abadf74cefce396ba07571109c67"},
{file = "cryptography-2.9.2-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:96c080ae7118c10fcbe6229ab43eb8b090fccd31a09ef55f83f690d1ef619a1d"}, {file = "cryptography-3.0-cp35-abi3-macosx_10_10_x86_64.whl", hash = "sha256:0cbfed8ea74631fe4de00630f4bb592dad564d57f73150d6f6796a24e76c76cd"},
{file = "cryptography-2.9.2-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:e993468c859d084d5579e2ebee101de8f5a27ce8e2159959b6673b418fd8c785"}, {file = "cryptography-3.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:a09fd9c1cca9a46b6ad4bea0a1f86ab1de3c0c932364dbcf9a6c2a5eeb44fa77"},
{file = "cryptography-2.9.2-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:88c881dd5a147e08d1bdcf2315c04972381d026cdb803325c03fe2b4a8ed858b"}, {file = "cryptography-3.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:ce82cc06588e5cbc2a7df3c8a9c778f2cb722f56835a23a68b5a7264726bb00c"},
{file = "cryptography-2.9.2-cp35-cp35m-win32.whl", hash = "sha256:651448cd2e3a6bc2bb76c3663785133c40d5e1a8c1a9c5429e4354201c6024ae"}, {file = "cryptography-3.0-cp35-cp35m-win32.whl", hash = "sha256:9367d00e14dee8d02134c6c9524bb4bd39d4c162456343d07191e2a0b5ec8b3b"},
{file = "cryptography-2.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:726086c17f94747cedbee6efa77e99ae170caebeb1116353c6cf0ab67ea6829b"}, {file = "cryptography-3.0-cp35-cp35m-win_amd64.whl", hash = "sha256:384d7c681b1ab904fff3400a6909261cae1d0939cc483a68bdedab282fb89a07"},
{file = "cryptography-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:091d31c42f444c6f519485ed528d8b451d1a0c7bf30e8ca583a0cac44b8a0df6"}, {file = "cryptography-3.0-cp36-cp36m-win32.whl", hash = "sha256:4d355f2aee4a29063c10164b032d9fa8a82e2c30768737a2fd56d256146ad559"},
{file = "cryptography-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:bb1f0281887d89617b4c68e8db9a2c42b9efebf2702a3c5bf70599421a8623e3"}, {file = "cryptography-3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:45741f5499150593178fc98d2c1a9c6722df88b99c821ad6ae298eff0ba1ae71"},
{file = "cryptography-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:18452582a3c85b96014b45686af264563e3e5d99d226589f057ace56196ec78b"}, {file = "cryptography-3.0-cp37-cp37m-win32.whl", hash = "sha256:8ecef21ac982aa78309bb6f092d1677812927e8b5ef204a10c326fc29f1367e2"},
{file = "cryptography-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:22e91636a51170df0ae4dcbd250d318fd28c9f491c4e50b625a49964b24fe46e"}, {file = "cryptography-3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4b9303507254ccb1181d1803a2080a798910ba89b1a3c9f53639885c90f7a756"},
{file = "cryptography-2.9.2-cp38-cp38-win32.whl", hash = "sha256:844a76bc04472e5135b909da6aed84360f522ff5dfa47f93e3dd2a0b84a89fa0"}, {file = "cryptography-3.0-cp38-cp38-win32.whl", hash = "sha256:8713ddb888119b0d2a1462357d5946b8911be01ddbf31451e1d07eaa5077a261"},
{file = "cryptography-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5"}, {file = "cryptography-3.0-cp38-cp38-win_amd64.whl", hash = "sha256:bea0b0468f89cdea625bb3f692cd7a4222d80a6bdafd6fb923963f2b9da0e15f"},
{file = "cryptography-2.9.2.tar.gz", hash = "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229"}, {file = "cryptography-3.0.tar.gz", hash = "sha256:8e924dbc025206e97756e8903039662aa58aa9ba357d8e1d8fc29e3092322053"},
] ]
flask = [ flask = [
{file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"}, {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"},
@@ -738,8 +740,8 @@ typed-ast = [
{file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
] ]
urllib3 = [ urllib3 = [
{file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, {file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"},
{file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, {file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},
] ]
waitress = [ waitress = [
{file = "waitress-1.4.4-py2.py3-none-any.whl", hash = "sha256:3d633e78149eb83b60a07dfabb35579c29aac2d24bb803c18b26fb2ab1a584db"}, {file = "waitress-1.4.4-py2.py3-none-any.whl", hash = "sha256:3d633e78149eb83b60a07dfabb35579c29aac2d24bb803c18b26fb2ab1a584db"},

View File

@@ -2,14 +2,40 @@
import sass import sass
import subprocess import subprocess
import shutil import shutil
import os
import argparse
from pathlib import Path from pathlib import Path
parser = argparse.ArgumentParser()
parser.add_argument(
"-y", "--yes", help="use assumed node bin directory.", action="store_true"
)
def runcmd(cmd): def runcmd(cmd):
if os.name == "nt":
return subprocess.check_output(cmd, shell=True)
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
return proc.communicate() return proc.communicate()
local_path = Path(__file__).resolve().parent 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]: for bsv in [d for d in local_path.iterdir() if 'bs' in d.name]:
scss = bsv / f'{bsv.name}-jf.scss' 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)) precision=6))
if css.exists(): if css.exists():
print(f'{bsv.name}: Compiled.') 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.') 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())}') runcmd(f'{str((node_bin / "cleancss").resolve())} --level 1 --format breakWith=lf --output {str(min_css.resolve())} {str(css.resolve())}')
if min_css.exists(): if min_css.exists():

View File

@@ -1,17 +1,25 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import subprocess import subprocess
import os
from pathlib import Path from pathlib import Path
def runcmd(cmd): def runcmd(cmd):
if os.name == "nt":
return subprocess.check_output(cmd, shell=True)
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
return proc.communicate() return proc.communicate()
print('Installing npm packages') print('Installing npm packages')
root_path = Path(__file__).parents[1] 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(): if (root_path / 'node_modules' / 'cleancss').exists():
print(f'Installed successfully in {str((root_path / "node_modules").resolve())}.') print(f'Installed successfully in {str((root_path / "node_modules").resolve())}.')