use of com.chimbori.hermitcrab.schema.manifest.Manifest in project lite-apps by chimbori.
the class PaletteExtractor method extractPaletteIfMissing.
private static void extractPaletteIfMissing() throws IOException {
Gson gson = GsonInstance.getPrettyPrinter();
File[] liteAppDirs = FilePaths.LITE_APPS_SRC_DIR.listFiles();
for (File liteAppDirectory : liteAppDirs) {
if (!liteAppDirectory.isDirectory()) {
// Probably a temporary file, like .DS_Store.
continue;
}
String appName = liteAppDirectory.getName();
File manifestJsonFile = new File(liteAppDirectory, FilePaths.MANIFEST_JSON_FILE_NAME);
if (!manifestJsonFile.exists()) {
throw new MissingManifestException(appName);
}
// Create an entry for this Lite App to be put in the directory index file.
Manifest manifest = gson.fromJson(new FileReader(manifestJsonFile), Manifest.class);
if (manifest.themeColor.equals("#") || manifest.secondaryColor.equals("#")) {
System.out.println("manifest: " + manifest.name);
File iconsDirectory = new File(liteAppDirectory, FilePaths.ICONS_DIR_NAME);
iconsDirectory.mkdirs();
File iconFile = new File(iconsDirectory, IconFile.FAVICON_FILE.fileName);
// Extract the color from the icon (either newly downloaded, or from existing icon).
if (iconFile.exists()) {
ColorExtractor.Color themeColor = ColorExtractor.getDominantColor(ImageIO.read(iconFile));
if (themeColor != null) {
// Overwrite the dummy values already inserted, if we are able to extract real values.
manifest.themeColor = themeColor.toString();
manifest.secondaryColor = themeColor.darken(0.9f).toString();
FileUtils.writeFile(manifestJsonFile, gson.toJson(manifest));
}
}
}
}
}
use of com.chimbori.hermitcrab.schema.manifest.Manifest in project lite-apps by chimbori.
the class Scaffolder method createScaffolding.
/**
* The Library Data JSON file (containing metadata about all Lite Apps) is used as the basis for
* generating scaffolding for the Lite App manifests.
*/
private static void createScaffolding(String startUrl, String appName) throws IOException, Scraper.ManifestUnavailableException {
File liteAppDirectoryRoot = new File(FilePaths.LITE_APPS_SRC_DIR, appName);
Manifest manifest;
File manifestJsonFile = new File(liteAppDirectoryRoot, FilePaths.MANIFEST_JSON_FILE_NAME);
// If the manifest.json exists, read it before modifying, else create a new JSON object.
if (manifestJsonFile.exists()) {
manifest = GsonInstance.getPrettyPrinter().fromJson(new FileReader(manifestJsonFile), Manifest.class);
} else {
Log.i("Creating new Lite App “%s”", appName);
// Create the root directory if it doesn’t exist yet.
liteAppDirectoryRoot.mkdirs();
// Scrape the Web looking for RSS & Atom feeds, theme colors, and site metadata.
Log.i("Fetching %s…", startUrl);
Scraper scraper = new Scraper(startUrl).fetch();
manifest = scraper.extractManifest();
// Constant fields, same for all apps.
manifest.manifestVersion = CURRENT_MANIFEST_VERSION;
manifest.lang = LANG_EN;
// Fields that can be populated from the data provided on the command-line.
manifest.name = appName;
manifest.startUrl = startUrl;
manifest.manifestUrl = String.format(MANIFEST_URL_TEMPLATE, URLEncoder.encode(appName, "UTF-8").replace("+", "%20"));
// Empty fields that must be manually populated.
manifest.priority = 10;
manifest.tags = Collections.singletonList("TODO");
// Put the icon JSON entry even if we don’t manage to fetch an icon successfully.
// This way, we can avoid additional typing, and the validator will check for the presence
// of the file anyway (and fail as expected).
manifest.icon = IconFile.FAVICON_FILE;
File iconsDirectory = new File(liteAppDirectoryRoot, FilePaths.ICONS_DIR_NAME);
iconsDirectory.mkdirs();
File iconFile = new File(iconsDirectory, IconFile.FAVICON_FILE.fileName);
String remoteIconUrl = scraper.extractIconUrl();
if (!iconFile.exists() && remoteIconUrl != null && !remoteIconUrl.isEmpty()) {
Log.i("Fetching icon from %s…", remoteIconUrl);
URL iconUrl = null;
try {
iconUrl = new URL(remoteIconUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
}
if (iconUrl != null) {
try (InputStream inputStream = iconUrl.openStream()) {
Files.copy(inputStream, iconFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
// But still continue with the rest of the manifest generation.
}
}
}
// Extract the color from the icon (either newly downloaded, or from existing icon).
if (iconFile.exists()) {
ColorExtractor.Color themeColor = ColorExtractor.getDominantColor(ImageIO.read(iconFile));
if (themeColor != null) {
// Overwrite the dummy values already inserted, if we are able to extract real values.
manifest.themeColor = themeColor.toString();
manifest.secondaryColor = themeColor.darken(0.9f).toString();
} else {
// Insert a placeholder for theme_color and secondary_color so we don’t have to
// type it in manually, but put invalid values so that the validator will catch it
// in case we forget to replace with valid values.
manifest.themeColor = "#";
manifest.secondaryColor = "#";
}
} else {
// Insert a placeholder for theme_color and secondary_color so we don’t have to
// type it in manually, but put invalid values so that the validator will catch it
// in case we forget to replace with valid values.
manifest.themeColor = "#";
manifest.secondaryColor = "#";
}
}
// Write the output manifest.
System.out.println(manifest);
FileUtils.writeFile(manifestJsonFile, GsonInstance.getPrettyPrinter().toJson(manifest));
}
use of com.chimbori.hermitcrab.schema.manifest.Manifest in project lite-apps by chimbori.
the class Scraper method extractManifest.
public Manifest extractManifest() throws ManifestUnavailableException {
Manifest manifest = new Manifest();
if (doc == null) {
// Fetch failed or never fetched.
throw new ManifestUnavailableException();
}
// First try to get the Site’s name (not just the current page’s title) via OpenGraph tags.
manifest.name = doc.select("meta[property=og:site_name]").attr("content");
if (manifest.name == null || manifest.name.isEmpty()) {
// But if the page isn’t using OpenGraph tags, then fallback to using the current page’s title.
manifest.name = doc.select("title").text();
}
manifest.themeColor = doc.select("meta[name=theme-color]").attr("content");
manifest.hermitBookmarks = findBookmarkableLinks();
manifest.hermitFeeds = findAtomAndRssFeeds();
manifest.relatedApplications = findRelatedApps();
return manifest;
}
use of com.chimbori.hermitcrab.schema.manifest.Manifest in project lite-apps by chimbori.
the class TagsCollector method updateTagsJson.
public static void updateTagsJson() throws IOException {
Gson gson = GsonInstance.getPrettyPrinter();
// Read the list of all known tags from the tags.json file. In case we discover any new tags,
// we will add them to this file, taking care not to overwrite those that already exist.
LibraryTagsList tagsGson = LibraryTagsList.fromGson(gson, new FileReader(FilePaths.LITE_APPS_TAGS_JSON));
Map<String, LibraryTag> globalTags = new HashMap<>();
File[] liteAppDirs = FilePaths.LITE_APPS_SRC_DIR.listFiles();
for (File liteAppDirectory : liteAppDirs) {
if (!liteAppDirectory.isDirectory()) {
// Probably a temporary file, like .DS_Store.
continue;
}
File manifestJsonFile = new File(liteAppDirectory, FilePaths.MANIFEST_JSON_FILE_NAME);
if (!manifestJsonFile.exists()) {
throw new MissingManifestException(liteAppDirectory.getName());
}
Manifest manifest;
try {
manifest = gson.fromJson(new FileReader(manifestJsonFile), Manifest.class);
} catch (JsonSyntaxException e) {
System.err.println("Failed to parse JSON: " + liteAppDirectory.getName());
throw e;
}
// For all tags applied to this manifest, check if they exist in the global tags list.
if (manifest.tags != null) {
for (String tagName : manifest.tags) {
LibraryTag tag = globalTags.get(tagName);
if (tag == null) {
// If this is the first time we are seeing this tag, create a new JSONArray to hold its contents.
LibraryTag newTag = new LibraryTag(tagName);
globalTags.put(tagName, newTag);
tagsGson.addTag(newTag);
}
}
}
}
// Write the tags to JSON
FileUtils.writeFile(FilePaths.LITE_APPS_TAGS_JSON, tagsGson.toJson(gson));
}
use of com.chimbori.hermitcrab.schema.manifest.Manifest in project lite-apps by chimbori.
the class LibraryGenerator method generateLibraryData.
/**
* Individual manifest.json files do not contain any information about the organization of the
* Lite Apps in the Library (e.g. categories, order within category, whether it should be
* displayed or not. This metadata is stored in a separate index.json file. To minimize
* duplication & to preserve a single source of truth, this file does not contain actual URLs
* or anything about a Lite App other than its name (same as the directory name).
* <p>
* This generator tool combines the basic organizational metadata from index.json & detailed
* Lite Apps data from * / manifest.json files. It outputs the Library Data JSON file,
* which is used as the basis for generating the Hermit Library page at
* https://hermit.chimbori.com/library.
*/
public static void generateLibraryData() throws IOException {
Gson gson = GsonInstance.getPrettyPrinter();
// Read the list of all known tags from the tags.json file. In case we discover any new tags,
// we will add them to this file, taking care not to overwrite those that already exist.
LibraryTagsList globalTags = LibraryTagsList.fromGson(gson, new FileReader(FilePaths.LITE_APPS_TAGS_JSON));
Library outputLibrary = new Library(globalTags);
File[] liteAppDirs = FilePaths.LITE_APPS_SRC_DIR.listFiles();
for (File liteAppDirectory : liteAppDirs) {
if (!liteAppDirectory.isDirectory()) {
// Probably a temporary file, like .DS_Store.
continue;
}
File iconsDirectory = new File(liteAppDirectory, FilePaths.ICONS_DIR_NAME);
String appName = liteAppDirectory.getName();
File manifestJsonFile = new File(liteAppDirectory, FilePaths.MANIFEST_JSON_FILE_NAME);
if (!manifestJsonFile.exists()) {
throw new MissingManifestException(appName);
}
// Create an entry for this Lite App to be put in the directory index file.
Manifest manifest = gson.fromJson(new FileReader(manifestJsonFile), Manifest.class);
LibraryApp outputApp = new LibraryApp();
outputApp.url = manifest.startUrl;
outputApp.name = appName;
outputApp.theme_color = manifest.themeColor;
outputApp.priority = manifest.priority;
// Set user-agent from the settings stored in the Lite App’s manifest.json.
String userAgent = manifest.hermitSettings != null ? manifest.hermitSettings.userAgent : null;
if (USER_AGENT_DESKTOP.equals(userAgent)) {
outputApp.user_agent = USER_AGENT_DESKTOP;
}
outputLibrary.addAppToCategories(outputApp, manifest.tags);
// Resize the icon to be suitable for the Web, and copy it to the Web-accessible icons directory.
File thumbnailImage = new File(FilePaths.LIBRARY_ICONS_DIR, appName + FilePaths.ICON_EXTENSION);
if (!thumbnailImage.exists()) {
Thumbnails.of(new File(iconsDirectory, IconFile.FAVICON_FILE.fileName)).outputQuality(1.0f).useOriginalFormat().size(LIBRARY_ICON_SIZE, LIBRARY_ICON_SIZE).imageType(BufferedImage.TYPE_INT_ARGB).toFile(thumbnailImage);
}
}
FileUtils.writeFile(FilePaths.LIBRARY_JSON, outputLibrary.toJson(gson));
}
Aggregations