mediathekplugin.Database.java Source code

Java tutorial

Introduction

Here is the source code for mediathekplugin.Database.java

Source

/*
 * Copyright Michael Keppler
 *
 * 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 3 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/>.
 */
package mediathekplugin;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;

import org.apache.commons.lang.StringUtils;

import devplugin.Channel;
import devplugin.Plugin;
import devplugin.Program;

public class Database {
    /** The logger for this class */
    private static final Logger LOG = Logger.getLogger(Database.class.getName());

    /**
     * tag content in the XML file
     */
    private static final String STRING_PATTERN = "([^<]*)";
    /**
     * pattern for a single line
     */
    private static final Pattern ITEM_PATTERN = Pattern.compile("(?s)" // match also the line terminator
            + ".*" // skip beginning
            + matchField("Sender") + ".*" + matchField("Thema") + ".*" + matchField("Titel") + ".*"
            + matchField("Url") + ".*"); // skip end
    /**
     * association of programs and file lines for each channel group
     */
    private HashMap<String, HashMap<Long, ArrayList<Integer>>> mChannelItems = new HashMap<String, HashMap<Long, ArrayList<Integer>>>();

    /**
     * marker for channel map, if a channel does not exist in TV-Browser
     */
    private static final Object NON_EXISTING_CHANNEL = new Object();
    /**
     * mapping of mediathek channel names to our channels, used for speedup
     */
    private HashMap<String, Object> mNameMapping = new HashMap<String, Object>(20);
    private CRC32 mCRC = new CRC32();
    private String mFileName;

    public Database(final String fileName) {
        mFileName = fileName;
        readFile();
    }

    private static String matchField(String name) {
        return Pattern.quote("<" + name + ">") + STRING_PATTERN + Pattern.quote("</" + name + ">");
    }

    private void readFile() {
        int programCount = 0;
        int byteCount = 0;
        if (StringUtils.isEmpty(mFileName)) {
            String separator = System.getProperty("file.separator");
            mFileName = System.getProperty("user.home") + separator + ".mediathek" + separator + ".filme";
        }
        File file = new File(mFileName);
        if (!file.canRead()) {
            return;
        }
        try {
            mChannelItems = new HashMap<String, HashMap<Long, ArrayList<Integer>>>(mChannelItems.size());
            BufferedReader in = new BufferedReader(new FileReader(mFileName));
            String lineEncoded;
            while ((lineEncoded = in.readLine()) != null) {
                String line = new String(lineEncoded.getBytes(), "UTF-8");

                Matcher itemMatcher = ITEM_PATTERN.matcher(line);
                if (itemMatcher.find()) {
                    String channelName = unifyChannelName(itemMatcher.group(1));
                    Channel channel = findChannel(channelName);
                    if (channel != null) {
                        HashMap<Long, ArrayList<Integer>> programs = mChannelItems.get(channelName);
                        if (programs == null) {
                            programs = new HashMap<Long, ArrayList<Integer>>(500);
                            mChannelItems.put(channelName, programs);
                        }
                        String topic = itemMatcher.group(2).trim();
                        long key = getKey(topic);
                        // store the URLs byte offset inside the file
                        ArrayList<Integer> list = programs.get(key);
                        if (list == null) {
                            list = new ArrayList<Integer>();
                            programs.put(key, list);
                        }
                        programCount++;
                        list.add(byteCount);
                    }
                }
                byteCount += lineEncoded.length() + 1;
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        LOG.info("Found " + programCount + " programs in Mediathek");
    }

    private String unifyChannelName(String channelName) {
        if (channelName.equalsIgnoreCase("Ard.Podcast")) {
            channelName = "Ard";
        }
        if (channelName.equalsIgnoreCase("Arte.DE")) {
            channelName = "Arte";
        }
        if (channelName.equalsIgnoreCase("Arte.FR")) {
            channelName = "Arte";
        }
        String result = channelName.toLowerCase();
        return result;
    }

    private long getKey(String topic) {
        mCRC.reset();
        mCRC.update(topic.getBytes());
        return mCRC.getValue();
    }

    private Channel findChannel(final String mediathekChannelName) {
        Object result = mNameMapping.get(mediathekChannelName);
        if (result == NON_EXISTING_CHANNEL) {
            return null;
        }
        if (result == null) {
            Channel[] allChannels = Plugin.getPluginManager().getSubscribedChannels();
            for (Channel channel : allChannels) {
                if (channel.getName().equalsIgnoreCase(mediathekChannelName)
                        || StringUtils.startsWithIgnoreCase(channel.getName(), mediathekChannelName + " ")) {
                    mNameMapping.put(mediathekChannelName, channel);
                    return channel;
                }
                String namePart = StringUtils.substringBetween(channel.getName(), "(", ")");
                if (StringUtils.isNotEmpty(namePart)) {
                    mNameMapping.put(mediathekChannelName, channel);
                    return channel;
                }
            }
            mNameMapping.put(mediathekChannelName, NON_EXISTING_CHANNEL);
            LOG.info("Ignored Mediathek channel: " + mediathekChannelName);
            return null;
        }
        return (Channel) result;
    }

    public ArrayList<MediathekProgramItem> getMediathekPrograms(final Program program) {
        ArrayList<MediathekProgramItem> result = new ArrayList<MediathekProgramItem>();
        String channelName = unifyChannelName(program.getChannel().getName());
        HashMap<Long, ArrayList<Integer>> programsMap = mChannelItems.get(channelName);
        // search parts in brackets like for ARD
        if (programsMap == null && channelName.contains("(")) {
            String bracketPart = StringUtils.substringBetween(channelName, "(", ")");
            programsMap = mChannelItems.get(bracketPart);
        }
        // search for partial name, if full name is not found
        if (programsMap == null && channelName.contains(" ")) {
            String firstPart = StringUtils.substringBefore(channelName, " ");
            programsMap = mChannelItems.get(firstPart);
        }
        if (programsMap == null) {
            for (Entry<String, HashMap<Long, ArrayList<Integer>>> entry : mChannelItems.entrySet()) {
                if (StringUtils.startsWithIgnoreCase(channelName, entry.getKey())) {
                    programsMap = entry.getValue();
                    break;
                }
            }
        }
        if (programsMap == null) {
            return result;
        }
        String title = program.getTitle();
        ArrayList<Integer> programs = programsMap.get(getKey(title));
        if (programs == null && title.endsWith(")") && title.contains("(")) {
            String newTitle = StringUtils.substringBeforeLast(title, "(").trim();
            programs = programsMap.get(getKey(newTitle));
        }
        if (programs == null && title.endsWith("...")) {
            String newTitle = title.substring(0, title.length() - 3).trim();
            programs = programsMap.get(getKey(newTitle));
        }
        if (programs == null) {
            return result;
        }
        try {
            RandomAccessFile file = new RandomAccessFile(new File(mFileName), "r");
            for (Integer byteOffset : programs) {
                file.seek(byteOffset);
                String lineEncoded = file.readLine();
                String line = new String(lineEncoded.getBytes(), "UTF-8");
                Matcher itemMatcher = ITEM_PATTERN.matcher(line);
                if (itemMatcher.find()) {
                    String itemTitle = itemMatcher.group(3).trim();
                    String itemUrl = itemMatcher.group(4).trim();
                    result.add(new MediathekProgramItem(itemTitle, itemUrl, null));
                }
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }
}