Merge branch 'YunoHost:master' into master
27
.github/workflows/main.yml
vendored
|
@ -9,10 +9,25 @@ jobs:
|
|||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: Check apps.json
|
||||
|
||||
- name: Check JSON validity for apps.json
|
||||
run: |
|
||||
python -m json.tool apps.json
|
||||
cat apps.json | jq >/dev/null
|
||||
|
||||
- name: Check all working apps have consistent app id / app url
|
||||
run: |
|
||||
FAULTY_APPS="false";
|
||||
for LINE in $(cat apps.json | jq -r 'to_entries[] | select ( .value.state=="working" ) | "\(.key)|\(.value.url)"')
|
||||
do
|
||||
APP=$(echo $LINE | awk -F'|' '{print $1}')
|
||||
URL_END=$(echo $LINE | awk -F'/' '{print $NF}')
|
||||
[ "$APP" == "$(echo $APP | tr [A-Z] [a-z])" ] || { FAULTY_APPS="true"; echo "$APP : app id should be lowercase" >&2; }
|
||||
[ "$URL_END" == "${APP}_ynh" ] || { FAULTY_APPS="true"; echo "$APP : the url should end with ${APP}_ynh" >&2; }
|
||||
done
|
||||
[ $FAULTY_APPS = "false" ]
|
||||
|
||||
- name: Check all working apps have a category
|
||||
run: |
|
||||
APPS_WITH_NO_CATEGORY=$(jq -e -r '.[] | select ( .state=="working" ) | select ( has("category") | not )' apps.json || true)
|
||||
[ "$APPS_WITH_NO_CATEGORY" == "" ] || { echo "Some working apps are missing a category: $APPS_WITH_NO_CATEGORY" >&2; false; }
|
||||
|
||||
|
|
51
README.md
|
@ -23,26 +23,36 @@ https://app.yunohost.org/default/.
|
|||
N.B.: The YunoHost project will **NOT** integrate in its catalog applications that are not
|
||||
based on free-software upstreams.
|
||||
|
||||
N.B.2: We strongly encourage you to transfer the ownership of your repository to
|
||||
the YunoHost-Apps organization on GitHub, such that the community will help you
|
||||
with keeping your app working and up to date with packaging evolutions.
|
||||
|
||||
To add your application to the catalog:
|
||||
* Fork this repository and edit the [apps.json](https://github.com/YunoHost/apps/tree/master/apps.json) file
|
||||
* Add your app's ID and git information at the right alphabetical place
|
||||
* Indicate the app's functioning state: `notworking`, `inprogress`, or `working`
|
||||
* *Do not* add the level entry by yourself. Our automatic test suite ("the CI") will handle it.
|
||||
* Indicate the app category, which you can pick from `categories.yml`
|
||||
* Indicate any anti-feature that your app may be subject to, see `antifeatures.yml` (or remove the `antifeatures` key if there's none)
|
||||
* Indicate if your app can be thought of as an alternative to popular proprietary services (or remove the `potential_alternative_to` key if there's none)
|
||||
* *Do not* add the `level` entry by yourself. Our automatic test suite ("the CI") will handle it.
|
||||
* Create a [Pull Request](https://github.com/YunoHost/apps/pulls/)
|
||||
|
||||
App example addition:
|
||||
```json
|
||||
"wallabag": {
|
||||
"url": "https://github.com/abeudin/wallabag_ynh",
|
||||
"state": "working"
|
||||
"your_app": {
|
||||
"antifeatures": [
|
||||
"deprecated-software"
|
||||
],
|
||||
"potential_alternative_to": [
|
||||
"YouTube"
|
||||
],
|
||||
"category": "pick_the_appropriate_category",
|
||||
"state": "working",
|
||||
"url": "https://github.com/YunoHost-Apps/your_app_ynh"
|
||||
}
|
||||
```
|
||||
|
||||
N.B.: We strongly encourage you to transfer the ownership of your repository to
|
||||
the YunoHost-Apps organization on GitHub, such that the community will help you
|
||||
with keeping your app working and up to date with packaging evolutions.
|
||||
|
||||
N.B.2: Implicitly, the catalog publishes the `HEAD` of branch `master`
|
||||
N.B: Implicitly, the catalog publishes the `HEAD` of branch `master`
|
||||
(this can be overwritten by adding keys `branch` and `revision`).
|
||||
Therefore, **be careful that any commit on the `master` branch will automatically be published**.
|
||||
**We strongly encourage you to develop in separate branches**, and only
|
||||
|
@ -50,28 +60,9 @@ merge changes that were carefully tested. Get in touch with the Apps group to
|
|||
obtain an access to the developer CI where you'll be able to test your app
|
||||
easily.
|
||||
|
||||
### Updating apps' level in the catalog
|
||||
### Updating apps levels in the catalog
|
||||
|
||||
App packagers should *not* manually set their apps' level. The levels of all the apps are automatically updated once per week on Friday.
|
||||
|
||||
#### Helper script
|
||||
|
||||
You can use the <code>add_or_update.py</code> Python script to add or update
|
||||
your app from one of the 2 JSON files.
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
./add_or_update.py apps.json [github/gitlab url OR app name [github/gitlab url OR app name [github/gitlab url OR app name ...]]]
|
||||
```
|
||||
|
||||
### How to help translating
|
||||
|
||||
Update on Nov. 2020: this part is broken / not maintained anymore for the
|
||||
moment...
|
||||
|
||||
We invite you to use [translate.yunohost.org](https://translate.yunohost.org/)
|
||||
instead of doing Pull Request for files in `locales` folder.
|
||||
App packagers should *not* manually set their apps' level. The levels of all the apps are automatically updated once per week on Friday, according to the results from the official app CI.
|
||||
|
||||
### Apps flagged as not-maintained
|
||||
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
from urllib2 import urlopen
|
||||
from urlparse import urlparse
|
||||
|
||||
states = {
|
||||
1: "notworking",
|
||||
2: "inprogress",
|
||||
3: "working",
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not len(sys.argv[1:]):
|
||||
print("I need a json file as first argument and a list of github urls")
|
||||
sys.exit(0)
|
||||
|
||||
if len(sys.argv[1:]) < 2:
|
||||
print("I need a list of github urls or app names after the json file")
|
||||
sys.exit(0)
|
||||
|
||||
if not os.path.exists(sys.argv[1]):
|
||||
print("The json file '%s' doesn't exist" % sys.argv[1])
|
||||
|
||||
content = json.load(open(sys.argv[1], "r"))
|
||||
|
||||
for url in sys.argv[2:]:
|
||||
if not url.startswith("http"):
|
||||
if url in content:
|
||||
url = content[url]["url"]
|
||||
else:
|
||||
print "App name '%s' not in %s" % (url, sys.argv[1])
|
||||
sys.exit(1)
|
||||
|
||||
if url.endswith("/"):
|
||||
url = url[:-1]
|
||||
|
||||
if url.endswith(".git"):
|
||||
url = url[:-len(".git")]
|
||||
|
||||
if not url.startswith("https://github.com"):
|
||||
sys.stderr.write("WARNING: url '%s' doesn't starts with https://github.com, we will try with gitlab api\n" % url)
|
||||
|
||||
owner, repo = filter(None, url.split("/"))[-2:]
|
||||
project_name = filter(None, url.split("/"))[-1].replace("_ynh", "")
|
||||
|
||||
if url.startswith("https://github.com"):
|
||||
git_data = json.load(urlopen("https://api.github.com/repos/%(owner)s/%(repo)s/commits" % {"owner": owner, "repo": repo}))
|
||||
revision = git_data[0]["sha"]
|
||||
else:
|
||||
parsed_uri = urlparse(url)
|
||||
base_url = '{uri.scheme}://{uri.netloc}/'.format(uri=parsed_uri)
|
||||
# Try with gitlab api
|
||||
git_data = json.load(urlopen("%(base_url)sapi/v4/projects/%(owner)s%%2F%(repo)s/repository/commits/HEAD" % {"base_url": base_url, "owner": owner, "repo": repo}))
|
||||
revision = git_data["id"]
|
||||
|
||||
if project_name not in content:
|
||||
content[project_name] = {}
|
||||
else:
|
||||
print("INFO: project already in '%s', I'm updating it" % sys.argv[1])
|
||||
|
||||
content[project_name]["url"] = url
|
||||
content[project_name]["revision"] = revision
|
||||
content[project_name]["branch"] = "master"
|
||||
|
||||
if sys.argv[1] == "official.json":
|
||||
content[project_name]["state"] = "validated"
|
||||
|
||||
else:
|
||||
got_state = False
|
||||
while not got_state:
|
||||
answer = input("Give me a state for this repository (digit or name) in:\n%s\n\nState: " % "\n".join(["%s: %s" % x for x in sorted(states.items(), key=lambda x: x[0])]) + "\n")
|
||||
|
||||
if answer in states:
|
||||
answer = states[answer]
|
||||
got_state = True
|
||||
elif answer in states.values():
|
||||
got_state = True
|
||||
else:
|
||||
print("Invalid state.\n")
|
||||
|
||||
content[project_name]["state"] = answer
|
||||
|
||||
open(sys.argv[1], "w").write("\n".join(json.dumps(content, indent=4, sort_keys=True).split(" \n")) + "\n")
|
||||
os.system("git diff")
|
54
apps.json
|
@ -23,7 +23,7 @@
|
|||
"category": "system_tools",
|
||||
"level": 7,
|
||||
"state": "working",
|
||||
"url": "https://github.com/YunoHost-Apps/2FAuth_ynh"
|
||||
"url": "https://github.com/YunoHost-Apps/2fauth_ynh"
|
||||
},
|
||||
"abantecart": {
|
||||
"category": "publishing",
|
||||
|
@ -343,6 +343,15 @@
|
|||
],
|
||||
"url": "https://github.com/YunoHost-Apps/bookstack_ynh"
|
||||
},
|
||||
"bookwyrm": {
|
||||
"category": "social_media",
|
||||
"state": "working",
|
||||
"maintained": true,
|
||||
"potential_alternative_to": [
|
||||
"ActivityPub"
|
||||
],
|
||||
"url": "https://github.com/YunoHost-Apps/bookwyrm_ynh"
|
||||
},
|
||||
"borg": {
|
||||
"category": "system_tools",
|
||||
"level": 6,
|
||||
|
@ -391,6 +400,17 @@
|
|||
],
|
||||
"url": "https://github.com/YunoHost-Apps/cachet_ynh"
|
||||
},
|
||||
"calckey": {
|
||||
"category": "social_media",
|
||||
"state": "working",
|
||||
"maintained": true,
|
||||
"potential_alternative_to": [
|
||||
"Twitter",
|
||||
"Mastodon",
|
||||
"Pleroma"
|
||||
],
|
||||
"url": "https://github.com/YunoHost-Apps/calckey_ynh"
|
||||
},
|
||||
"calibreweb": {
|
||||
"category": "reading",
|
||||
"level": 8,
|
||||
|
@ -662,7 +682,7 @@
|
|||
"category": "games",
|
||||
"level": 8,
|
||||
"state": "working",
|
||||
"url": "https://github.com/YunoHost-Apps/Cubiks-2048_ynh"
|
||||
"url": "https://github.com/YunoHost-Apps/cubiks-2048_ynh"
|
||||
},
|
||||
"cypht": {
|
||||
"category": "communication",
|
||||
|
@ -861,7 +881,7 @@
|
|||
],
|
||||
"url": "https://github.com/Jojo144/django_app_ynh"
|
||||
},
|
||||
"django_example_ynh": {
|
||||
"django_example": {
|
||||
"category": "dev",
|
||||
"level": 7,
|
||||
"state": "working",
|
||||
|
@ -2142,7 +2162,7 @@
|
|||
"level": 0,
|
||||
"revision": "a38a83fea289f77910fd98b34ea58eea5f5909db",
|
||||
"state": "notworking",
|
||||
"url": "https://github.com/YunoHost-Apps/LBCAlerte_ynh"
|
||||
"url": "https://github.com/YunoHost-Apps/lbcalerte_ynh"
|
||||
},
|
||||
"leed": {
|
||||
"category": "reading",
|
||||
|
@ -2685,6 +2705,7 @@
|
|||
"url": "https://github.com/YunoHost-Apps/modernpaste_ynh"
|
||||
},
|
||||
"mongo-express": {
|
||||
"branch": "main",
|
||||
"category": "system_tools",
|
||||
"state": "working",
|
||||
"subtags": [
|
||||
|
@ -3070,6 +3091,17 @@
|
|||
"state": "working",
|
||||
"url": "https://github.com/YunoHost-Apps/openproject_ynh"
|
||||
},
|
||||
"opensearch": {
|
||||
"category": "dev",
|
||||
"state": "working",
|
||||
"subtags": [
|
||||
"programming"
|
||||
],
|
||||
"potential_alternative_to": [
|
||||
"ElasticSearch"
|
||||
],
|
||||
"url": "https://github.com/YunoHost-Apps/opensearch_ynh"
|
||||
},
|
||||
"opensondage": {
|
||||
"category": "productivity_and_management",
|
||||
"level": 8,
|
||||
|
@ -3577,7 +3609,6 @@
|
|||
"potential_alternative_to": [
|
||||
"TikTok"
|
||||
],
|
||||
"state": "working",
|
||||
"url": "https://github.com/YunoHost-Apps/proxitok_ynh"
|
||||
},
|
||||
"psitransfer": {
|
||||
|
@ -3731,7 +3762,7 @@
|
|||
"remotestorage": {
|
||||
"category": "small_utilities",
|
||||
"state": "notworking",
|
||||
"url": "https://github.com/YunoHost-Apps/RemoteStorage_ynh"
|
||||
"url": "https://github.com/YunoHost-Apps/remotestorage_ynh"
|
||||
},
|
||||
"restic": {
|
||||
"category": "system_tools",
|
||||
|
@ -3998,7 +4029,7 @@
|
|||
"category": "small_utilities",
|
||||
"level": 7,
|
||||
"state": "working",
|
||||
"url": "https://github.com/YunoHost-Apps/Signaturepdf_ynh"
|
||||
"url": "https://github.com/YunoHost-Apps/signaturepdf_ynh"
|
||||
},
|
||||
"simple-hash-generator": {
|
||||
"category": "small_utilities",
|
||||
|
@ -4022,7 +4053,7 @@
|
|||
"subtags": [
|
||||
"websites"
|
||||
],
|
||||
"url": "https://github.com/YunoHost-Apps/SitemagicCMS_ynh"
|
||||
"url": "https://github.com/YunoHost-Apps/sitemagiccms_ynh"
|
||||
},
|
||||
"slingcode": {
|
||||
"category": "dev",
|
||||
|
@ -4166,6 +4197,11 @@
|
|||
"state": "notworking",
|
||||
"url": "https://github.com/YunoHost-Apps/staticwebapp_ynh"
|
||||
},
|
||||
"statping_ng": {
|
||||
"category": "system_tools",
|
||||
"state": "working",
|
||||
"url": "https://github.com/YunoHost-Apps/statping_ng_ynh"
|
||||
},
|
||||
"streama": {
|
||||
"category": "multimedia",
|
||||
"level": 6,
|
||||
|
@ -4586,7 +4622,7 @@
|
|||
"category": "multimedia",
|
||||
"level": 6,
|
||||
"state": "working",
|
||||
"url": "https://github.com/YunoHost-Apps/UMS_ynh"
|
||||
"url": "https://github.com/YunoHost-Apps/ums_ynh"
|
||||
},
|
||||
"unattended_upgrades": {
|
||||
"category": "system_tools",
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
import sys
|
||||
import json
|
||||
import requests
|
||||
|
||||
|
||||
def get_json(url, verify=True, token=None):
|
||||
|
||||
try:
|
||||
# Retrieve and load manifest
|
||||
if ".github" in url:
|
||||
r = requests.get(url, verify=verify, auth=token)
|
||||
else:
|
||||
r = requests.get(url, verify=verify)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
print("-> Error: unable to request %s, %s" % (url, e))
|
||||
return None
|
||||
except ValueError as e:
|
||||
print("-> Error: unable to decode JSON from %s : %s" % (url, e))
|
||||
return None
|
||||
|
||||
|
||||
def main(apps):
|
||||
for app_id, app_data in apps.items():
|
||||
url = app_data["url"]
|
||||
github_repo_name = url.split("/")[-1].replace("_ynh", "")
|
||||
|
||||
if app_id != github_repo_name:
|
||||
print "[%s] GitHub repo name is not coherent with app id: '%s' vs '%s' (%s)" % (app_id, app_id, url.split("/")[-1], url)
|
||||
|
||||
owner, repo_name = url.split("/")[-2:]
|
||||
|
||||
raw_url = "https://raw.githubusercontent.com/%s/%s/%s/manifest.json" % (
|
||||
owner, repo_name, app_data["revision"]
|
||||
)
|
||||
|
||||
manifest = get_json(raw_url)
|
||||
|
||||
if manifest is None:
|
||||
continue
|
||||
|
||||
manifest_id = manifest["id"]
|
||||
if app_id != manifest_id:
|
||||
print "[%s] manifest id is different from app id: '%s' vs '%s' (manifest_id" % (app_id, app_id, manifest_id)
|
||||
|
||||
if manifest_id != github_repo_name:
|
||||
print "[%s] manifest id is different from GitHub repo name: '%s' vs '%s' (%s)" % (app_id, manifest_id, url.split("/")[-1], url)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not sys.argv[1:]:
|
||||
print "Usage: python check_id_unicity.py list.json"
|
||||
sys.exit(1)
|
||||
|
||||
main(json.load(open(sys.argv[1])))
|
|
@ -213,6 +213,16 @@ def build_catalog():
|
|||
if "manifest" in app and "resources" in app["manifest"]:
|
||||
del app["manifest"]["resources"]
|
||||
|
||||
for appid, app in result_dict_with_manifest_v2.items():
|
||||
appid = appid.lower()
|
||||
if os.path.exists(f"logos/{appid}.png"):
|
||||
logo_hash = subprocess.check_output(["sha256sum", f"logos/{appid}.png"]).strip().decode("utf-8").split()[0]
|
||||
os.system(f"cp logos/{appid}.png builds/default/v3/logos/{logo_hash}.png")
|
||||
# FIXME: implement something to cleanup old logo stuf in the builds/.../logos/ folder somehow
|
||||
else:
|
||||
logo_hash = None
|
||||
app["logo_hash"] = logo_hash
|
||||
|
||||
os.system("mkdir -p ./builds/default/v3/")
|
||||
with open("builds/default/v3/apps.json", "w") as f:
|
||||
f.write(
|
||||
|
|
BIN
logos/adguardhome.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
logos/adminer.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
logos/aeneria.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
logos/agendav.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
logos/airsonic.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
logos/alltube.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
logos/ampache.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
logos/anarchism.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
logos/archivebox.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
logos/audiobookshelf.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
logos/backdrop.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
logos/baikal.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
logos/bazarr.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
logos/beehive.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
logos/biboumi.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
logos/bicbucstriim.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
logos/blogotext.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
logos/bludit.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
logos/bookstack.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
logos/borg.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
logos/borgserver.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
logos/cachet.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
logos/calibreweb.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
logos/castopod.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
logos/cinny.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
logos/civicrm_drupal7.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
logos/cockpit.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
logos/code-server.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
logos/codimd.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
logos/collabora.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
logos/commento.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
logos/concrete5.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
logos/converse.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
logos/conversejs.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
logos/couchpotato.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
logos/cowyo.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
logos/cryptpad.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
logos/cypht.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
logos/diagramsnet.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
logos/diaspora.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
logos/discourse.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
logos/dokuwiki.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
logos/dolibarr.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
logos/domoticz.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
logos/dotclear2.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
logos/droppy.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
logos/drupal.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
logos/drupal7.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
logos/duniter.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
logos/easyappointments.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
logos/ecko.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
logos/elabftw.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
logos/element.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
logos/emailpoubelle.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
logos/ethercalc.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
logos/etherpad_mypads.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
logos/excalidraw.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
logos/ffsync.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
logos/filebrowser.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
logos/firefly-iii.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
logos/flarum.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
logos/flood.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
logos/fluxbb.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
logos/focalboard.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
logos/framaforms.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
logos/freshrss.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
logos/friendica.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
logos/funkwhale.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
logos/ghost.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
logos/gitea.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
logos/gitlab-runner.png
Normal file
After Width: | Height: | Size: 9 KiB |
BIN
logos/gitlab.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
logos/glowingbear.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
logos/gogs.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
logos/gotify.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
logos/grafana.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
logos/grav.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
logos/grocy.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
logos/guacamole.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
logos/halcyon.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
logos/headphones.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
logos/hedgedoc.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
logos/hextris.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
logos/homeassistant.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
logos/horde.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
logos/hubzilla.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
logos/huginn.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
logos/humhub.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
logos/ihatemoney.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
logos/internetarchive.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
logos/invidious.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
logos/invoiceninja.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
logos/invoiceninja5.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
logos/jackett.png
Normal file
After Width: | Height: | Size: 3.7 KiB |