Skip to content

Commit

Permalink
feat : re-implement flowerpot (#5226)
Browse files Browse the repository at this point in the history
  • Loading branch information
MrSluffy authored Jan 30, 2025
1 parent 9a81ca7 commit 0696240
Show file tree
Hide file tree
Showing 91 changed files with 17,779 additions and 7 deletions.
40 changes: 40 additions & 0 deletions flowerpot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# The `flowerpot` ruleset format

> Keeping beautiful things organized.
## Basic overview

We want to be able to provide an automatic categorization of apps into folders and tabs and needed a fitting file format for storing rules in a compact but human-readable way. This is what flowerpot is, a simple format for rule lists which is easy to read and equally easy to parse from code. Repurposing the general ideas of this format for other uses is also easily possible.

## Format

Flowerpot files are built as a line delimited list of rules. Except for metadata related rules/tags, most rules are filters. The parser identifies rules by the leading character.

### Supported rules

| Identifier | Rule | Description | Notes |
|:----------:|------------------|-------------------------------------|---------------------------------------------------------|
| | Package | Package name filter | Version 1 only supports full package names as filter |
| `#` | Comment | Comment | |
| `$` | Version | Version tag (integer) | Must be the first non-comment item, can only occur once |
| `:` | IntentAction | Intent action to filter by | |
| `;` | IntentCategory | Intent category to filter by | Tested in combination with the `MAIN` action |
| `&` | CodeRule | Rule which has been defined in code | Accepts arguments seperated by `|` |

### File names

Each file is a ruleset for one category, and the name of the file represents the name (codename) of that category. Flowerpot files have no file extension. You are advised to use uppercase (snake case) filenames spelling out the English name of the category.

### Versioning

Versions are identified by an incrementing integer value and accompanied by codenames. Codenames are given alphabetically and should be the name of a flower (I encourage everyone to use names of pink flowers, if possible).

#### Current Version

The format is currently at version 1 (`azalea`). This is the initial version of flowerpot.

> Azalea - A beautiful pink flower, known in China as "thinking of home bush" (sixiang shu).
#### Past versions

There are no past versions of flowerpot yet.
29 changes: 29 additions & 0 deletions flowerpot/lawnchair_specifics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## Categories

```python
{
"HEALTH_AND_FITNESS": ["HEALTH_AND_FITNESS", "MEDICAL"],
"KNOWLEDGE_AND_REFERENCE": ["EDUCATION", "BOOKS_AND_REFERENCE", "WEATHER"],
"NEWS": ["NEWS_AND_MAGAZINES"],
"ENTERTAINMENT": ["ENTERTAINMENT", "MUSIC_AND_AUDIO", "VIDEO_PLAYERS"],
"MUSIC": ["MUSIC_AND_AUDIO"],
"LIFESTYLE": ["LIFESTYLE", "BEAUTY"],
"PHOTOGRAPHY": ["PHOTOGRAPHY"],
"BUSINESS_AND_PRODUCTIVITY": ["PRODUCTIVITY", "BUSINESS"],
"TOOLS": ["TOOLS"],
"FINANCE": ["FINANCE"],
"COMMUNICATION": ["COMMUNCICATION"],
"SOCIAL": ["SOCIAL"],
"TRAVEL_AND_NAVIGATION": ["MAPS_AND_NAVIGATION", "TRAVEL_AND_LOCAL"],
"GAME": ["GAME"], # Actually identified by isGame manifest tag
"FOOD_AND_DRINK": ["FOOD_AND_DRINK"],
"PERSONALIZATION": ["PERSONALIZATION"], # Additionally identify icon packs by manifest
"SHOPPING": ["SHOPPING"]
}
```

The base package name lists are built by scraping the Play Store using `playstore.py`, these lists are then merged into our categories using `merge.py`, together with static template files for base rules.

## Manually adding a rule

If you want to manually add a rule to one of Lawnchair's rulesets you can simply add it to one of the static templates in the `templates/` directory. Create one with a categories name if none exists yet.
69 changes: 69 additions & 0 deletions flowerpot/merge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# This file is part of Lawnchair Launcher.
#
# Lawnchair Launcher is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Lawnchair Launcher 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Lawnchair Launcher. If not, see <https://www.gnu.org/licenses/>.

from pathlib import Path
import shutil
import time
import sys

CATEGORY_MAP = {
"HEALTH_AND_FITNESS": ["HEALTH_AND_FITNESS", "MEDICAL"],
"KNOWLEDGE_AND_REFERENCE": ["EDUCATION", "BOOKS_AND_REFERENCE", "WEATHER"],
"NEWS": ["NEWS_AND_MAGAZINES"],
"ENTERTAINMENT": ["ENTERTAINMENT", "MUSIC_AND_AUDIO", "VIDEO_PLAYERS", "MUSIC_AND_AUDIO"],
"MUSIC": ["MUSIC_AND_AUDIO"],
"LIFESTYLE": ["LIFESTYLE", "BEAUTY", "SHOPPING"],
"PHOTOGRAPHY": ["PHOTOGRAPHY"],
"BUSINESS_AND_PRODUCTIVITY": ["PRODUCTIVITY", "BUSINESS", "FINANCE"],
"TOOLS": ["TOOLS", "VIDEO_PLAYERS"],
"COMMUNICATION": ["COMMUNICATION", "SOCIAL"],
"TRAVEL_AND_NAVIGATION": ["MAPS_AND_NAVIGATION", "TRAVEL_AND_LOCAL"],
"GAME": ["GAME"], # Actually identified by isGame manifest tag which not all apps have :(
"FOOD_AND_DRINK": ["FOOD_AND_DRINK"],
"PERSONALIZATION": ["PERSONALIZATION"] # Additionally identify icon packs by manifest
}

IN_PATH = "playstore"
OUT_PATH = "../lawnchair/assets/flowerpot/"
TEMPLATE_PATH = "templates"
FORMAT_VERSION = "1"
FORMAT_VERSION_HUMAN = "azalea"

out_p = Path(OUT_PATH)
if out_p.exists():
shutil.rmtree(out_p)

try:
out_p.mkdir()
except OSError:
print ("Creation of the directory %s failed" % OUT_PATH)

for category in CATEGORY_MAP.keys():
with open("%s/%s" % (OUT_PATH, category), "a+") as out:
out.write("# generated at %s using %s\n" % (time.ctime(), sys.argv[0]))
out.write("# format: flowerpot-%s (%s)\n" % (FORMAT_VERSION, FORMAT_VERSION_HUMAN))
out.write("# specs: https://del.dog/flowerpot\n")
out.write("$%s\n" % FORMAT_VERSION)
template = Path("%s/%s" % (TEMPLATE_PATH, category))
if template.exists():
out.write("# STATIC TEMPLATE\n")
out.write(template.read_text())
for origin in CATEGORY_MAP[category]:
input = Path("%s/%s" % (IN_PATH, origin))
if input.exists():
out.write("# %s\n" % origin)
out.write(input.read_text())
else:
print("No input file found for %s" % origin)
Loading

0 comments on commit 0696240

Please sign in to comment.