com.oakesville.mythling.util.MythlingParser.java Source code

Java tutorial

Introduction

Here is the source code for com.oakesville.mythling.util.MythlingParser.java

Source

/**
 * Copyright 2015 Donald Oakes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.oakesville.mythling.util;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.oakesville.mythling.BuildConfig;
import com.oakesville.mythling.app.AppSettings;
import com.oakesville.mythling.app.Localizer;
import com.oakesville.mythling.media.Category;
import com.oakesville.mythling.media.Item;
import com.oakesville.mythling.media.MediaList;
import com.oakesville.mythling.media.MediaSettings.MediaType;
import com.oakesville.mythling.media.MediaSettings.SortType;
import com.oakesville.mythling.media.Movie;
import com.oakesville.mythling.media.Recording;
import com.oakesville.mythling.media.SearchResults;
import com.oakesville.mythling.media.Song;
import com.oakesville.mythling.media.StorageGroup;
import com.oakesville.mythling.media.TvEpisode;
import com.oakesville.mythling.media.TvShow;
import com.oakesville.mythling.media.Video;

import android.util.Log;

/**
 * Artist and title may be reversed for some folks
 * but the reversal will be counteracted so that they'll
 * be displayed in the same order as in the filename.
 */
public class MythlingParser implements MediaListParser {
    private static final String TAG = MythlingParser.class.getSimpleName();

    private AppSettings appSettings;
    private String json;

    public MythlingParser(AppSettings appSettings, String json) {
        this.appSettings = appSettings;
        this.json = json;
    }

    public MediaList parseMediaList(MediaType mediaType, Map<String, StorageGroup> storageGroups)
            throws JSONException, ParseException, ServiceException {
        MediaList mediaList = new MediaList();
        mediaList.setMediaType(mediaType);

        long startTime = System.currentTimeMillis();
        JSONObject list = new JSONObject(json);
        if (list.has("error"))
            throw new ServiceException(list.getString("error"));
        JSONObject summary = list.getJSONObject("summary");
        if (summary.has("mythTvVersion"))
            mediaList.setMythTvVersion(summary.getString("mythTvVersion"));
        mediaList.setRetrieveDate(summary.getString("date"));
        mediaList.setCount(summary.getString("count"));
        if (summary.has("base"))
            mediaList.setBasePath(summary.getString("base"));
        if (list.has("items")) {
            JSONArray its = list.getJSONArray("items");
            for (int i = 0; i < its.length(); i++) {
                JSONObject it = (JSONObject) its.get(i);
                Item item = buildItem(mediaList.getMediaType(), it, storageGroups);
                item.setPath("");
                mediaList.addItem(item);
            }
        }
        if (list.has("categories")) {
            JSONArray cats = list.getJSONArray("categories");
            for (int i = 0; i < cats.length(); i++) {
                JSONObject cat = (JSONObject) cats.get(i);
                mediaList.addCategory(buildCategory(mediaList.getMediaType(), cat, null, storageGroups));
            }
        }
        if (BuildConfig.DEBUG)
            Log.d(TAG, " -> media list parse time: " + (System.currentTimeMillis() - startTime) + " ms");

        SortType sortType = appSettings.getMediaSettings().getSortType();
        if ((mediaType == MediaType.movies || mediaType == MediaType.tvSeries)
                && (sortType == SortType.byDate || sortType == SortType.byRating)) {
            // media.php will have sorted by sortType within categories, but categories must be sorted by title
            startTime = System.currentTimeMillis();
            mediaList.sort(SortType.byTitle, false);
            if (BuildConfig.DEBUG)
                Log.d(TAG, " -> media list sort time: " + (System.currentTimeMillis() - startTime) + " ms");
        }

        return mediaList;
    }

    private Category buildCategory(MediaType type, JSONObject cat, Category parent,
            Map<String, StorageGroup> storageGroups) throws JSONException, ParseException {
        String name = cat.getString("name");
        Category category = parent == null ? new Category(name, type) : new Category(name, parent);
        if (cat.has("categories")) {
            JSONArray childs = cat.getJSONArray("categories");
            for (int i = 0; i < childs.length(); i++) {
                JSONObject childCat = (JSONObject) childs.get(i);
                category.addChild(buildCategory(type, childCat, category, storageGroups));
            }
        }
        if (cat.has("items")) {
            JSONArray its = cat.getJSONArray("items");
            for (int i = 0; i < its.length(); i++) {
                JSONObject it = (JSONObject) its.get(i);
                Item item = buildItem(type, it, storageGroups);
                item.setPath(category.getPath());
                category.addItem(item);
            }
        }
        return category;
    }

    public SearchResults parseSearchResults(Map<String, StorageGroup> storageGroups)
            throws JSONException, ParseException, ServiceException {
        SearchResults searchResults = new SearchResults();

        long startTime = System.currentTimeMillis();
        JSONObject list = new JSONObject(json);
        if (list.has("error"))
            throw new ServiceException(list.getString("error"));

        JSONObject summary = list.getJSONObject("summary");
        if (summary.has("mythTvVersion"))
            searchResults.setMythTvVersion(summary.getString("mythTvVersion"));
        searchResults.setRetrieveDate(summary.getString("date"));
        searchResults.setQuery(summary.getString("query"));
        if (summary.has("videoBase"))
            searchResults.setVideoBase(summary.getString("videoBase"));
        if (summary.has("musicBase"))
            searchResults.setMusicBase(summary.getString("musicBase"));

        JSONArray vids = list.getJSONArray("videos");
        for (int i = 0; i < vids.length(); i++) {
            JSONObject vid = (JSONObject) vids.get(i);
            searchResults.addVideo(buildItem(MediaType.videos, vid, storageGroups));
        }

        JSONArray recordings = list.getJSONArray("recordings");
        for (int i = 0; i < recordings.length(); i++) {
            JSONObject recording = (JSONObject) recordings.get(i);
            recording.put("path", "");
            searchResults.addRecording(buildItem(MediaType.recordings, recording, storageGroups));
        }

        JSONArray tvShows = list.getJSONArray("liveTv");
        for (int i = 0; i < tvShows.length(); i++) {
            JSONObject tvShow = (JSONObject) tvShows.get(i);
            tvShow.put("path", "");
            searchResults.addLiveTvItem(buildItem(MediaType.liveTv, tvShow, storageGroups));
        }

        if (list.has("movies")) // if no videos categorization
        {
            JSONArray movies = list.getJSONArray("movies");
            for (int i = 0; i < movies.length(); i++) {
                JSONObject movie = (JSONObject) movies.get(i);
                searchResults.addMovie(buildItem(MediaType.movies, movie, storageGroups));
            }
        }

        if (list.has("tvSeries")) // if no videos categorization
        {
            JSONArray tvSeries = list.getJSONArray("tvSeries");
            for (int i = 0; i < tvSeries.length(); i++) {
                JSONObject tvSeriesItem = (JSONObject) tvSeries.get(i);
                searchResults.addTvSeriesItem(buildItem(MediaType.tvSeries, tvSeriesItem, storageGroups));
            }
        }

        if (list.has("songs")) {
            JSONArray songs = list.getJSONArray("songs");
            for (int i = 0; i < songs.length(); i++) {
                JSONObject song = (JSONObject) songs.get(i);
                searchResults.addSong(buildItem(MediaType.music, song, storageGroups));
            }
        }

        if (BuildConfig.DEBUG)
            Log.d(TAG, " -> search results parse time: " + (System.currentTimeMillis() - startTime) + " ms");

        return searchResults;
    }

    private Item buildItem(MediaType type, JSONObject jsonObj, Map<String, StorageGroup> storageGroups)
            throws JSONException, ParseException {
        Item item;
        if (type == MediaType.movies) {
            item = new Movie(jsonObj.getString("id"), jsonObj.getString("title"));
            if (storageGroups != null)
                item.setStorageGroup(storageGroups.get(appSettings.getVideoStorageGroup()));
            addVideoInfo((Video) item, jsonObj);
        } else if (type == MediaType.tvSeries) {
            item = new TvEpisode(jsonObj.getString("id"), jsonObj.getString("title"));
            if (storageGroups != null)
                item.setStorageGroup(storageGroups.get(appSettings.getVideoStorageGroup()));
            addVideoInfo((Video) item, jsonObj);
            if (jsonObj.has("season"))
                ((TvEpisode) item).setSeason(Integer.parseInt(jsonObj.getString("season")));
            if (jsonObj.has("episode"))
                ((TvEpisode) item).setEpisode(Integer.parseInt(jsonObj.getString("episode")));
        } else if (type == MediaType.videos) {
            item = new Video(jsonObj.getString("id"), jsonObj.getString("title"));
            if (storageGroups != null)
                item.setStorageGroup(storageGroups.get(appSettings.getVideoStorageGroup()));
            addVideoInfo((Video) item, jsonObj);
        } else if (type == MediaType.liveTv) {
            item = new TvShow(jsonObj.getString("id"), jsonObj.getString("title"));
            addProgramInfo((TvShow) item, jsonObj);
        } else if (type == MediaType.recordings) {
            item = new Recording(jsonObj.getString("id"), jsonObj.getString("title"));
            addProgramInfo((TvShow) item, jsonObj);
            if (jsonObj.has("recordId"))
                ((Recording) item).setRecordRuleId(jsonObj.getInt("recordId"));
            if (storageGroups != null && jsonObj.has("storageGroup"))
                item.setStorageGroup(storageGroups.get(jsonObj.getString("storageGroup")));
            if (jsonObj.has("recGroup"))
                ((Recording) item).setRecordingGroup(jsonObj.getString("recGroup"));
            if (jsonObj.has("internetRef"))
                ((Recording) item).setInternetRef(jsonObj.getString("internetRef"));
            if (jsonObj.has("recStatus")) {
                String recStatus = jsonObj.getString("recStatus");
                ((Recording) item).setRecorded(recStatus.equals("-3") || recStatus.equals("Recorded"));
            }
            if (jsonObj.has("season")) {
                String season = jsonObj.getString("season");
                ((Recording) item).setSeason(Integer.parseInt(season));
            }
            if (jsonObj.has("episode")) {
                String episode = jsonObj.getString("episode");
                ((Recording) item).setEpisode(Integer.parseInt(episode));
            }
        } else if (type == MediaType.music) {
            item = new Song(jsonObj.getString("id"), jsonObj.getString("title"));
            if (appSettings.isMusicArtAlbum())
                ((Song) item).setAlbumArt("cover.jpg"); // TODO: hardcoded
        } else {
            throw new IllegalArgumentException("Unsupported media type: " + type);
        }

        if (jsonObj.has("format"))
            item.setFormat(jsonObj.getString("format"));
        if (jsonObj.has("path"))
            item.setSearchPath(jsonObj.getString("path"));
        if (jsonObj.has("file"))
            item.setFileBase(jsonObj.getString("file"));
        if (jsonObj.has("subtitle"))
            item.setSubTitle(jsonObj.getString("subtitle"));
        if (jsonObj.has("transcoded"))
            item.setTranscoded("true".equalsIgnoreCase(jsonObj.getString("transcoded")));
        return item;
    }

    private void addProgramInfo(TvShow item, JSONObject jsonObj) throws JSONException, ParseException {
        item.setStartTime(Localizer.SERVICE_DATE_TIME_RAW_FORMAT
                .parse(item.getId().substring(item.getId().indexOf('~') + 1)));
        if (jsonObj.has("channel"))
            item.setChannelNumber(jsonObj.getString("channel"));
        if (jsonObj.has("callsign"))
            item.setCallsign(jsonObj.getString("callsign"));
        if (jsonObj.has("description"))
            item.setDescription(jsonObj.getString("description"));
        if (jsonObj.has("airdate")) {
            String ad = jsonObj.getString("airdate");
            if (ad.length() == 4) // year only (for movies)
                item.setOriginallyAired(Localizer.getYearFormat().parse(ad));
            else
                item.setOriginallyAired(Localizer.SERVICE_DATE_FORMAT.parse(ad));
        }
        if (jsonObj.has("endtime"))
            item.setEndTime(Localizer.SERVICE_DATE_TIME_RAW_FORMAT.parse(jsonObj.getString("endtime")));
        if (jsonObj.has("programStart"))
            item.setProgramStart(jsonObj.getString("programStart"));
        if (jsonObj.has("rating")) {
            // mythconverg stores program.stars and recorded.stars as a fraction of one
            Float rating = Float.parseFloat(jsonObj.getString("rating")) * 10;
            rating = (float) Math.round(rating) / 2;
            item.setRating(rating);
        }
    }

    private void addVideoInfo(Video item, JSONObject jsonObj) throws JSONException, ParseException {
        if (jsonObj.has("year"))
            item.setYear(Integer.parseInt(jsonObj.getString("year")));
        if (jsonObj.has("rating"))
            item.setRating(Float.parseFloat(jsonObj.getString("rating")) / 2);
        if (jsonObj.has("director"))
            item.setDirector(jsonObj.getString("director"));
        if (jsonObj.has("actors"))
            item.setActors(jsonObj.getString("actors"));
        if (jsonObj.has("summary"))
            item.setSummary(jsonObj.getString("summary"));
        if (jsonObj.has("artwork"))
            item.setArtwork(jsonObj.getString("artwork"));
        if (jsonObj.has("length"))
            item.setLength(Integer.parseInt(jsonObj.getString("length")) * 60);
        if (jsonObj.has("internetRef"))
            item.setInternetRef(jsonObj.getString("internetRef"));
        if (jsonObj.has("pageUrl"))
            item.setPageUrl(jsonObj.getString("pageUrl"));
    }

    public List<Item> parseQueue(MediaType type, Map<String, StorageGroup> storageGroups)
            throws JSONException, ParseException {
        List<Item> queue = new ArrayList<Item>();
        long startTime = System.currentTimeMillis();
        JSONObject list = new JSONObject(json);
        JSONArray vids = list.getJSONArray(type.toString());
        for (int i = 0; i < vids.length(); i++) {
            JSONObject vid = (JSONObject) vids.get(i);
            queue.add(buildItem(type, vid, storageGroups));
        }
        if (BuildConfig.DEBUG)
            Log.d(TAG, " -> (" + type + ") queue parse time: " + (System.currentTimeMillis() - startTime) + " ms");
        return queue;
    }
}