jonas.tool.saveForOffline.FaviconFetcher.java Source code

Java tutorial

Introduction

Here is the source code for jonas.tool.saveForOffline.FaviconFetcher.java

Source

/**
 This program 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 2 of the License, or
 (at your option) any later version.
    
 This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
    
 **/

/**
 This file is part of Save For Offline, an Android app which saves / downloads complete webpages for offine reading.
 **/

/**
 If you modify, redistribute, or write something based on this or parts of it, you MUST,
 I repeat, you MUST comply with the GPLv2+ license. This means that if you use or modify
 my code, you MUST release the source code of your modified version, if / when this is
 required under the terms of the license.
    
 If you cannot / do not want to do this, DO NOT USE MY CODE. Thanks.
    
 (I've added this message to to the source because it's been used in severeral proprietary
 closed source apps, which I don't want, and which is also a violation of the liense.)
 **/

/**
 Written by Jonas Czech (JonasCz, stackoverflow.com/users/4428462/JonasCz and github.com/JonasCz). (4428462jonascz/eafc4d1afq)
 **/

package jonas.tool.saveForOffline;

import org.jsoup.nodes.Document;

import java.io.File;
import com.squareup.okhttp.*;
import org.jsoup.select.*;
import java.util.*;
import org.jsoup.nodes.*;
import java.net.*;
import java.io.*;
import java.util.regex.*;
import android.graphics.*;
import org.jsoup.*;
import android.os.*;

public class FaviconFetcher {
    private static FaviconFetcher INSTANCE = new FaviconFetcher();
    private OkHttpClient client = new OkHttpClient();

    private final String[] htmlIconCssQueries = { "meta[property=\"og:image\"]",
            "meta[name=\"msapplication-TileImage\"]", "link[rel=\"icon\"]", "link[rel=\"shortcut icon\"]",
            "link[rel=\"apple-touch-icon\"]", "link[rel=\"apple-touch-icon-precomposed\"]", "img[alt=\"Logo\"]",
            "img[alt=\"logo\"]" };

    private final String[] hardcodedIconPaths = { "/favicon.ico", "/apple-touch-icon.png",
            "/apple-touch-icon-precomposed.png", };

    private FaviconFetcher() {
    }

    public static FaviconFetcher getInstance() {
        return INSTANCE;
    }

    public String getFaviconUrl(Document document) {
        List<String> potentialIcons = getPotentialFaviconUrls(document);
        return pickBestIconUrl(potentialIcons);
    }

    public List<String> getPotentialFaviconUrls(Document document) {
        List<String> iconUrls = new ArrayList<String>();
        HttpUrl base = HttpUrl.parse(document.baseUri());

        for (String cssQuery : htmlIconCssQueries) {
            for (Element e : document.select(cssQuery)) {
                if (e.hasAttr("href")) {
                    iconUrls.add(e.attr("href"));
                }

                if (e.hasAttr("content")) {
                    iconUrls.add(e.attr("content"));
                }

                if (e.hasAttr("src")) {
                    iconUrls.add(e.attr("src"));
                }
            }
        }

        for (String path : hardcodedIconPaths) {
            HttpUrl url = HttpUrl.parse("http://" + HttpUrl.parse(document.baseUri()).host() + path);
            iconUrls.add(url.toString());
        }

        for (ListIterator<String> i = iconUrls.listIterator(); i.hasNext();) {
            HttpUrl httpUrl = base.resolve(i.next());
            if (httpUrl != null) {
                i.set(httpUrl.toString());
            } else {
                i.remove();
            }
        }

        return iconUrls;

    }

    public String pickBestIconUrl(List<String> urls) {
        String bestIconUrl = null;
        int currentBestWidth = 0;

        for (String url : urls) {
            BitmapFactory.Options options = getBitmapDimensFromUrl(url);
            if (options != null && options.outHeight == options.outHeight) {
                if ((bestIconUrl != null) && (currentBestWidth <= options.outWidth)) {
                    bestIconUrl = url;
                    currentBestWidth = options.outWidth;
                } else if (bestIconUrl == null) {
                    bestIconUrl = url;
                    currentBestWidth = options.outWidth;
                }
            }
        }

        return bestIconUrl;
    }

    private BitmapFactory.Options getBitmapDimensFromUrl(String url) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;

        Request request = new Request.Builder().url(url).build();

        try {
            Response response = client.newCall(request).execute();
            InputStream is = response.body().byteStream();

            BitmapFactory.decodeStream(is, null, options);

            response.body().close();
            is.close();

            return options;

        } catch (IllegalArgumentException | IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}