Search in sources :

Example 1 with Manifest

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));
                }
            }
        }
    }
}
Also used : Gson(com.google.gson.Gson) FileReader(java.io.FileReader) ColorExtractor(com.chimbori.common.ColorExtractor) Manifest(com.chimbori.hermitcrab.schema.manifest.Manifest) IconFile(com.chimbori.hermitcrab.schema.manifest.IconFile) File(java.io.File)

Example 2 with 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));
}
Also used : MalformedURLException(java.net.MalformedURLException) InputStream(java.io.InputStream) FileReader(java.io.FileReader) ColorExtractor(com.chimbori.common.ColorExtractor) IOException(java.io.IOException) Manifest(com.chimbori.hermitcrab.schema.manifest.Manifest) File(java.io.File) IconFile(com.chimbori.hermitcrab.schema.manifest.IconFile) URL(java.net.URL)

Example 3 with 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;
}
Also used : Manifest(com.chimbori.hermitcrab.schema.manifest.Manifest)

Example 4 with 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));
}
Also used : LibraryTag(com.chimbori.hermitcrab.schema.library.LibraryTag) JsonSyntaxException(com.google.gson.JsonSyntaxException) HashMap(java.util.HashMap) Gson(com.google.gson.Gson) FileReader(java.io.FileReader) LibraryTagsList(com.chimbori.hermitcrab.schema.library.LibraryTagsList) Manifest(com.chimbori.hermitcrab.schema.manifest.Manifest) File(java.io.File)

Example 5 with Manifest

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));
}
Also used : Gson(com.google.gson.Gson) FileReader(java.io.FileReader) Library(com.chimbori.hermitcrab.schema.library.Library) LibraryApp(com.chimbori.hermitcrab.schema.library.LibraryApp) LibraryTagsList(com.chimbori.hermitcrab.schema.library.LibraryTagsList) Manifest(com.chimbori.hermitcrab.schema.manifest.Manifest) File(java.io.File) IconFile(com.chimbori.hermitcrab.schema.manifest.IconFile)

Aggregations

Manifest (com.chimbori.hermitcrab.schema.manifest.Manifest)6 File (java.io.File)5 IconFile (com.chimbori.hermitcrab.schema.manifest.IconFile)4 FileReader (java.io.FileReader)4 Gson (com.google.gson.Gson)3 ColorExtractor (com.chimbori.common.ColorExtractor)2 LibraryTagsList (com.chimbori.hermitcrab.schema.library.LibraryTagsList)2 IOException (java.io.IOException)2 MalformedURLException (java.net.MalformedURLException)2 URL (java.net.URL)2 Library (com.chimbori.hermitcrab.schema.library.Library)1 LibraryApp (com.chimbori.hermitcrab.schema.library.LibraryApp)1 LibraryTag (com.chimbori.hermitcrab.schema.library.LibraryTag)1 RelatedApp (com.chimbori.hermitcrab.schema.manifest.RelatedApp)1 TestHelpers.assertIsURL (com.chimbori.liteapps.TestHelpers.assertIsURL)1 JsonSyntaxException (com.google.gson.JsonSyntaxException)1 InputStream (java.io.InputStream)1 HashMap (java.util.HashMap)1 Test (org.junit.Test)1