|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
# coding: utf-8
|
|
|
|
|
#
|
|
|
|
|
# Copyright (C) 2019-2021 Alexandros Theodotou <alex at zrythm dot org>
|
|
|
|
|
#
|
|
|
|
|
# This file is part of Zrythm
|
|
|
|
|
#
|
|
|
|
|
# Zrythm is free software: you can redistribute it and/or modify
|
|
|
|
|
# it under the terms of the GNU Affero General Public License as published by
|
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
# (at your option) any later version.
|
|
|
|
|
#
|
|
|
|
|
# Zrythm is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU Affero General Public License for more details.
|
|
|
|
|
#
|
|
|
|
|
# This file incorporates work covered by the following copyright and
|
|
|
|
|
# permission notice:
|
|
|
|
|
#
|
|
|
|
|
# Copyright (C) 2017, 2018, 2019 GNUnet e.V.
|
|
|
|
|
#
|
|
|
|
|
# Copying and distribution of this file, with or without modification,
|
|
|
|
|
# are permitted in any medium without royalty provided the copyright
|
|
|
|
|
# notice and this notice are preserved. This file is offered as-is,
|
|
|
|
|
# without any warranty.
|
|
|
|
|
#
|
|
|
|
|
# ----
|
|
|
|
|
#
|
|
|
|
|
# This script runs the jinja2 templating engine on an input template-file
|
|
|
|
|
# using the specified locale for gettext translations, and outputs
|
|
|
|
|
# the resulting (HTML) ouptut-file.
|
|
|
|
|
#
|
|
|
|
|
# Note that the gettext files need to be prepared first. This script
|
|
|
|
|
# is thus to be invoked via the Makefile.
|
|
|
|
|
#
|
|
|
|
|
# We import unicode_literals until people have understood how unicode
|
|
|
|
|
# with bytes and strings changed in python2->python3.
|
|
|
|
|
|
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
import os
|
|
|
|
|
import os.path
|
|
|
|
|
import sys
|
|
|
|
|
import re
|
|
|
|
|
import gettext
|
|
|
|
|
import glob
|
|
|
|
|
import codecs
|
|
|
|
|
import jinja2
|
|
|
|
|
import i18nfix
|
|
|
|
|
import urllib3
|
|
|
|
|
import polib
|
|
|
|
|
import requests
|
|
|
|
|
import semver
|
|
|
|
|
|
|
|
|
|
# for news
|
|
|
|
|
import datetime
|
|
|
|
|
from dateutil.parser import parse
|
|
|
|
|
|
|
|
|
|
env = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
|
|
|
|
|
extensions=["jinja2.ext.i18n"],
|
|
|
|
|
lstrip_blocks=True,
|
|
|
|
|
trim_blocks=True,
|
|
|
|
|
undefined=jinja2.StrictUndefined,
|
|
|
|
|
autoescape=False)
|
|
|
|
|
# DEBUG OUTPUT:
|
|
|
|
|
if (os.getenv("DEBUG")):
|
|
|
|
|
print(sys.path)
|
|
|
|
|
|
|
|
|
|
# Note: also edit the Makefile when adding languages
|
|
|
|
|
langs_full = {
|
|
|
|
|
"af_ZA": "Afrikaans",
|
|
|
|
|
"ar": "العربية",
|
|
|
|
|
"cs": "Czech",
|
|
|
|
|
"da": "Dansk",
|
|
|
|
|
"de": "Deutsch",
|
|
|
|
|
"en": "English",
|
|
|
|
|
"en_GB": "English UK",
|
|
|
|
|
"el": "Ελληνικά",
|
|
|
|
|
"es": "Español",
|
|
|
|
|
"et": "Eeti",
|
|
|
|
|
"fi": "Suomi",
|
|
|
|
|
"fr": "Français",
|
|
|
|
|
"gd": "Gaelic",
|
|
|
|
|
"gl": "Galego",
|
|
|
|
|
"hi": "हिन्दी",
|
|
|
|
|
"it": "Italiano",
|
|
|
|
|
"ja": "日本語",
|
|
|
|
|
"ko": "한국어",
|
|
|
|
|
"nb_NO": "Bokmål",
|
|
|
|
|
"nl": "Nederlands",
|
|
|
|
|
"pl": "Polski",
|
|
|
|
|
"pt": "Português",
|
|
|
|
|
"pt_BR": "Português BR",
|
|
|
|
|
"ru": "Русский",
|
|
|
|
|
"sv": "Svenska",
|
|
|
|
|
"uk": "Українська",
|
|
|
|
|
"zh_Hans": "简体中文",
|
|
|
|
|
"zh_Hant": "繁體中文",
|
|
|
|
|
}
|
|
|
|
|
git_url = 'https://sr.ht/~alextee/zrythm'
|
|
|
|
|
feature_tracker = 'https://todo.sr.ht/~alextee/zrythm-feature'
|
|
|
|
|
bug_tracker = 'https://todo.sr.ht/~alextee/zrythm-bug'
|
|
|
|
|
pronunciation = 'ziˈrɪðəm'
|
|
|
|
|
releases_url = 'https://www.zrythm.org/releases/'
|
|
|
|
|
downloads_url = 'https://www.zrythm.org/downloads/'
|
|
|
|
|
aur_git_url = 'https://aur.archlinux.org/packages/zrythm-git/'
|
|
|
|
|
aur_stable_url = 'https://aur.archlinux.org/packages/zrythm/'
|
|
|
|
|
obs_package_url = 'https://software.opensuse.org//download.html?project=home%3Aalextee&package=zrythm'
|
|
|
|
|
copr_package_url = 'https://copr.fedorainfracloud.org/coprs/ycollet/linuxmao/package/zrythm/'
|
|
|
|
|
freshports_url = 'https://www.freshports.org/audio/zrythm/'
|
|
|
|
|
|
|
|
|
|
usd_to_gbp = 0.77
|
|
|
|
|
eur_to_gbp = 0.92
|
|
|
|
|
|
|
|
|
|
prev_month_earning = 100
|
|
|
|
|
|
|
|
|
|
# get monthly orders
|
|
|
|
|
orders_url = 'https://{}:{}@www.sendowl.com/api/v1/orders'.format(
|
|
|
|
|
os.getenv('SENDOWL_KEY'), os.getenv('SENDOWL_SECRET'))
|
|
|
|
|
headers = {
|
|
|
|
|
'Accept': 'application/json',
|
|
|
|
|
'Content-type': 'application/json',
|
|
|
|
|
'Accept-Charset': 'UTF-8',
|
|
|
|
|
}
|
|
|
|
|
payload = {
|
|
|
|
|
'from': datetime.datetime.utcnow().replace(day=1).strftime('%Y-%m-%d'),
|
|
|
|
|
'to': datetime.datetime.utcnow().strftime('%Y-%m-%d'),
|
|
|
|
|
'state': 'complete',
|
|
|
|
|
'per_page': '50',
|
|
|
|
|
}
|
|
|
|
|
r = requests.get(orders_url, params=payload, headers=headers)
|
|
|
|
|
if r.status_code == 200:
|
|
|
|
|
monthly_earning = 0
|
|
|
|
|
num_monthly_orders = 0
|
|
|
|
|
for _order in r.json():
|
|
|
|
|
num_monthly_orders += 1
|
|
|
|
|
order = _order['order']
|
|
|
|
|
if order['gateway'] == 'BitPay':
|
|
|
|
|
amount = float(order['settled_gross'])
|
|
|
|
|
amount -= amount / 100.0
|
|
|
|
|
else:
|
|
|
|
|
amount = float(order['settled_gross']) - float(order['settled_gateway_fee'])
|
|
|
|
|
if order['settled_currency'] == 'USD':
|
|
|
|
|
amount *= usd_to_gbp
|
|
|
|
|
print ('adding {} sendowl earnings'.format(amount))
|
|
|
|
|
monthly_earning += amount
|
|
|
|
|
else:
|
|
|
|
|
print (r.json())
|
|
|
|
|
|
|
|
|
|
# get paypal earnings
|
|
|
|
|
access_token_url = 'https://{}:{}@api.paypal.com/v1/oauth2/token'.format(
|
|
|
|
|
os.getenv('PAYPAL_CLIENT_ID'), os.getenv('PAYPAL_SECRET'))
|
|
|
|
|
headers = {
|
|
|
|
|
'Accept': 'application/json',
|
|
|
|
|
'Accept-Language': 'en_US',
|
|
|
|
|
}
|
|
|
|
|
payload = {
|
|
|
|
|
'grant_type': 'client_credentials',
|
|
|
|
|
}
|
|
|
|
|
r = requests.post(access_token_url, params=payload, headers=headers)
|
|
|
|
|
if r.status_code == 200:
|
|
|
|
|
access_token = r.json()['access_token']
|
|
|
|
|
transactions_url = 'https://api.paypal.com/v1/reporting/transactions'
|
|
|
|
|
headers = {
|
|
|
|
|
'Accept': 'application/json',
|
|
|
|
|
'Content-type': 'application/json',
|
|
|
|
|
'Accept-Charset': 'UTF-8',
|
|
|
|
|
'Authorization': 'Bearer ' + access_token,
|
|
|
|
|
}
|
|
|
|
|
payload = {
|
|
|
|
|
'start_date': datetime.datetime.utcnow().replace(day=1,tzinfo=datetime.timezone.utc).astimezone().replace(microsecond=0).isoformat(),
|
|
|
|
|
'end_date': datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).astimezone().replace(microsecond=0).isoformat(),
|
|
|
|
|
'transaction_status': 'S',
|
|
|
|
|
}
|
|
|
|
|
r = requests.get(transactions_url, params=payload, headers=headers)
|
|
|
|
|
if r.status_code == 200:
|
|
|
|
|
for _tx in r.json()['transaction_details']:
|
|
|
|
|
tx = _tx['transaction_info']
|
|
|
|
|
if 'transaction_subject' in tx and tx['transaction_subject'] == 'Zrythm subscription':
|
|
|
|
|
amount = float(tx['transaction_amount']['value'])
|
|
|
|
|
if 'fee_amound' in tx:
|
|
|
|
|
amount += float(tx['fee_amount']['value'])
|
|
|
|
|
if tx['transaction_amount']['currency_code'] == 'USD':
|
|
|
|
|
amount *= usd_to_gbp
|
|
|
|
|
if amount > 0:
|
|
|
|
|
print ('adding {} paypal subscription earnings'.format(amount))
|
|
|
|
|
monthly_earning += amount
|
|
|
|
|
elif 'invoice_id' not in tx and tx['transaction_event_code'] == 'T0000':
|
|
|
|
|
amount = float(tx['transaction_amount']['value'])
|
|
|
|
|
if 'fee_amound' in tx:
|
|
|
|
|
amount += float(tx['fee_amount']['value'])
|
|
|
|
|
if tx['transaction_amount']['currency_code'] == 'USD':
|
|
|
|
|
amount *= usd_to_gbp
|
|
|
|
|
elif tx['transaction_amount']['currency_code'] == 'EUR':
|
|
|
|
|
amount *= eur_to_gbp
|
|
|
|
|
if amount > 0:
|
|
|
|
|
print ('adding {} paypal custom donation earnings'.format(amount))
|
|
|
|
|
monthly_earning += amount
|
|
|
|
|
else:
|
|
|
|
|
print (r.json())
|
|
|
|
|
else:
|
|
|
|
|
print (r.json())
|
|
|
|
|
|
|
|
|
|
# get liberapay earnings
|
|
|
|
|
for lp_account in [ 'Zrythm', 'alextee' ]:
|
|
|
|
|
r = requests.get('https://liberapay.com/' + lp_account + '/public.json')
|
|
|
|
|
if r.status_code == 200:
|
|
|
|
|
amount = float(r.json()['receiving']['amount']) * 4.0
|
|
|
|
|
amount = float('%.2f' % amount)
|
|
|
|
|
print ('adding {} liberapay earnings'.format(amount))
|
|
|
|
|
monthly_earning += amount
|
|
|
|
|
else:
|
|
|
|
|
print (r.json())
|
|
|
|
|
|
|
|
|
|
# add opencollective earnings
|
|
|
|
|
r = requests.get("https://opencollective.com/zrythm.json")
|
|
|
|
|
if r.status_code == 200:
|
|
|
|
|
amount = float(r.json()['yearlyIncome']) / 1200.0
|
|
|
|
|
amount *= usd_to_gbp
|
|
|
|
|
amount = float('%.2f' % amount)
|
|
|
|
|
print ('adding {} opencollective earnings (estimated)'.format(amount))
|
|
|
|
|
monthly_earning += amount
|
|
|
|
|
else:
|
|
|
|
|
print (r.json())
|
|
|
|
|
|
|
|
|
|
monthly_earning_str = '{0:.2f}'.format(monthly_earning)
|
|
|
|
|
prev_month_earning_str = '{0:.2f}'.format(prev_month_earning)
|
|
|
|
|
prev_month_comparison_perc = '{0:.0f}'.format(100 * (monthly_earning / prev_month_earning))
|
|
|
|
|
|
|
|
|
|
# get latest version
|
|
|
|
|
from subprocess import check_output
|
|
|
|
|
versions = check_output('git ls-remote --tags https://git.zrythm.org/zrythm/zrythm | grep -o "refs/tags/v[0-9]*\.[0-9]*\.[0-9]*-alpha\.[0-9]*\.[0-9]*\.[0-9]*$" | sed -e "s/v//" | sort -r | grep -o "[^\/]*$"', shell=True).decode("utf-8").strip ()
|
|
|
|
|
latest_ver = "0.0.0"
|
|
|
|
|
for ver in versions.split('\n'):
|
|
|
|
|
if (semver.compare(ver, latest_ver) > 0):
|
|
|
|
|
latest_ver = ver
|
|
|
|
|
print ('normal version: ' + latest_ver)
|
|
|
|
|
version = latest_ver.replace ('-', '.')
|
|
|
|
|
print ('version: ' + version)
|
|
|
|
|
|
|
|
|
|
def check_url(url):
|
|
|
|
|
print ('checking ' + url + '...')
|
|
|
|
|
try:
|
|
|
|
|
with requests.get(url, stream=True) as response:
|
|
|
|
|
try:
|
|
|
|
|
response.raise_for_status()
|
|
|
|
|
except requests.exceptions.HTTPError:
|
|
|
|
|
print ('error fetching ' + url + ': ' + str (status))
|
|
|
|
|
exit (1)
|
|
|
|
|
except requests.exceptions.ConnectionError:
|
|
|
|
|
print ('error fetching ' + url + ': ' + str (status))
|
|
|
|
|
exit (1)
|
|
|
|
|
|
|
|
|
|
# verify that tarball and trials exist
|
|
|
|
|
print ('verifying release and trial packages...')
|
|
|
|
|
check_url (releases_url + 'zrythm-' + latest_ver + '.tar.xz')
|
|
|
|
|
check_url (downloads_url + 'zrythm-trial-' + version + '-installer.zip')
|
|
|
|
|
check_url (downloads_url + 'zrythm-trial-' + version + '-ms-setup.exe')
|
|
|
|
|
check_url (downloads_url + 'zrythm-trial-' + version + '-osx-installer.zip')
|
|
|
|
|
print ('done')
|
|
|
|
|
|
|
|
|
|
def url(x):
|
|
|
|
|
# TODO: look at the app root environment variable
|
|
|
|
|
# TODO: check if file exists
|
|
|
|
|
return "../" + x
|
|
|
|
|
|
|
|
|
|
screenshot = url('static/images/feb-20-2021.png')
|
|
|
|
|
|
|
|
|
|
class Plugin:
|
|
|
|
|
def __init__(self,name,is_img_static,img,summary,features):
|
|
|
|
|
self.name = name
|
|
|
|
|
self.is_img_static = is_img_static
|
|
|
|
|
self.img = img
|
|
|
|
|
self.summary = summary
|
|
|
|
|
self.features = features
|
|
|
|
|
|
|
|
|
|
for in_file in glob.glob("template/*.j2"):
|
|
|
|
|
name, ext = re.match(r"(.*)\.([^.]+)$", in_file.rstrip(".j2")).groups()
|
|
|
|
|
tmpl = env.get_template(in_file)
|
|
|
|
|
|
|
|
|
|
def self_localized(other_locale):
|
|
|
|
|
"""
|
|
|
|
|
Return URL for the current page in another locale.
|
|
|
|
|
"""
|
|
|
|
|
return "https://www.zrythm.org/" + other_locale + "/" + in_file.replace('template/', '').rstrip(".j2")
|
|
|
|
|
|
|
|
|
|
def url_localized(filename):
|
|
|
|
|
return "../" + locale + "/" + filename
|
|
|
|
|
|
|
|
|
|
def svg_localized(filename):
|
|
|
|
|
lf = filename + "." + locale + ".svg"
|
|
|
|
|
if locale == "en" or not os.path.isfile(lf):
|
|
|
|
|
return "../" + filename + ".svg"
|
|
|
|
|
else:
|
|
|
|
|
return "../" + lf
|
|
|
|
|
|
|
|
|
|
# remove fuzzies
|
|
|
|
|
for dirname, dirnames, filenames in os.walk('locale'):
|
|
|
|
|
for filename in filenames:
|
|
|
|
|
try: ext = filename.rsplit('.', 1)[1]
|
|
|
|
|
except: ext = ''
|
|
|
|
|
if ext == 'po':
|
|
|
|
|
po = polib.pofile(os.path.join(dirname, filename))
|
|
|
|
|
for entry in po.fuzzy_entries():
|
|
|
|
|
entry.msgstr = ''
|
|
|
|
|
if entry.msgid_plural: entry.msgstr_plural['0'] = ''
|
|
|
|
|
if entry.msgid_plural and '1' in entry.msgstr_plural: entry.msgstr_plural['1'] = ''
|
|
|
|
|
if entry.msgid_plural and '2' in entry.msgstr_plural: entry.msgstr_plural['2'] = ''
|
|
|
|
|
entry.flags.remove('fuzzy')
|
|
|
|
|
po.save()
|
|
|
|
|
|
|
|
|
|
for l in langs_full.keys():
|
|
|
|
|
locale = l
|
|
|
|
|
|
|
|
|
|
tr = gettext.translation("messages",
|
|
|
|
|
localedir="locale",
|
|
|
|
|
languages=[locale],
|
|
|
|
|
# only fallback to no translations for en
|
|
|
|
|
fallback= locale == 'en')
|
|
|
|
|
|
|
|
|
|
tr.gettext = i18nfix.wrap_gettext(tr.gettext)
|
|
|
|
|
_ = tr.gettext
|
|
|
|
|
|
|
|
|
|
env.install_gettext_translations(tr, newstyle=True)
|
|
|
|
|
|
|
|
|
|
# plugins
|
|
|
|
|
plugins = [
|
|
|
|
|
Plugin(
|
|
|
|
|
'ZChordz', True, 'zchordz-mar-21-2020.png',
|
|
|
|
|
_('ZChordz maps the chords of a minor or major scale to white keys'),
|
|
|
|
|
[ _('Major or minor scale'),
|
|
|
|
|
_('Velocity multiplier per note') ]),
|
|
|
|
|
Plugin(
|
|
|
|
|
'ZLFO', False,
|
|
|
|
|
'https://git.zrythm.org/alex/ZLFO/raw/branch/master/screenshots/2020_feb_12_zlfo.png',
|
|
|
|
|
_('ZLFO is a fully featured LFO for CV-based automation'),
|
|
|
|
|
[ _('Multi-oscillator with custom wave'),
|
|
|
|
|
_('Phase shift'),
|
|
|
|
|
_('Vertical/horizontal inversion'),
|
|
|
|
|
_('Step mode'),
|
|
|
|
|
_('Editable range'),
|
|
|
|
|
_('Sync to host or free-form') ]),
|
|
|
|
|
Plugin(
|
|
|
|
|
'ZSaw', True, 'zsaw-mar-21-2020.png',
|
|
|
|
|
_('ZSaw is a supersaw synth with 1 parameter'),
|
|
|
|
|
[ _('7 sawtooth oscillators'),
|
|
|
|
|
_('Single knob to control detune') ]),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
content = tmpl.render(lang=locale,
|
|
|
|
|
lang_full=langs_full[locale],
|
|
|
|
|
langs_full=langs_full,
|
|
|
|
|
url=url,
|
|
|
|
|
git_url=git_url,
|
|
|
|
|
aur_git_url=aur_git_url,
|
|
|
|
|
aur_stable_url=aur_stable_url,
|
|
|
|
|
freshports_url=freshports_url,
|
|
|
|
|
obs_package_url=obs_package_url,
|
|
|
|
|
copr_package_url=copr_package_url,
|
|
|
|
|
releases_url=releases_url,
|
|
|
|
|
downloads_url=downloads_url,
|
|
|
|
|
datetime_parse=parse,
|
|
|
|
|
num_monthly_orders=num_monthly_orders,
|
|
|
|
|
monthly_earning=monthly_earning,
|
|
|
|
|
monthly_earning_str=monthly_earning_str,
|
|
|
|
|
prev_month_earning_str=prev_month_earning_str,
|
|
|
|
|
prev_month_comparison_perc=prev_month_comparison_perc,
|
|
|
|
|
feature_tracker=feature_tracker,
|
|
|
|
|
bug_tracker=bug_tracker,
|
|
|
|
|
plugins=plugins,
|
|
|
|
|
version=version,
|
|
|
|
|
pronunciation=pronunciation,
|
|
|
|
|
self_localized=self_localized,
|
|
|
|
|
url_localized=url_localized,
|
|
|
|
|
svg_localized=svg_localized,
|
|
|
|
|
screenshot=screenshot,
|
|
|
|
|
filename=name + "." + ext)
|
|
|
|
|
out_name = "./rendered/" + locale + "/" + in_file.replace('template/', '').rstrip(".j2")
|
|
|
|
|
os.makedirs("./rendered/" + locale, exist_ok=True)
|
|
|
|
|
with codecs.open(out_name, "w", encoding='utf-8') as f:
|
|
|
|
|
f.write(content)
|