Java tutorial
/* * Copyright 2014 Nicholas Liu * * 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 ca.zadrox.dota2esportticker.util; import android.content.AsyncTaskLoader; import android.content.Context; import android.net.Uri; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import ca.zadrox.dota2esportticker.data.http.match.model.Livestream; import ca.zadrox.dota2esportticker.data.http.match.model.Match; import ca.zadrox.dota2esportticker.data.http.match.model.Player; import ca.zadrox.dota2esportticker.data.http.match.model.RecentMatch; import ca.zadrox.dota2esportticker.data.http.match.model.Team; import ca.zadrox.dota2esportticker.data.http.match.model.Vod; /** * Created by Acco on 10/29/2014. */ public class MatchDetailLoader extends AsyncTaskLoader<Match> { private static final String BASE_URL = "http://www.gosugamers.net"; private final String TAG = MatchDetailLoader.class.getSimpleName(); Match mMatch; String mUrl; public MatchDetailLoader(Context context, String url) { super(context); mUrl = url; } @Override protected void onStopLoading() { cancelLoad(); } @Override public void deliverResult(Match data) { if (isReset()) { if (mMatch != null) { onReleaseResources(mMatch); } } super.deliverResult(data); } @Override protected void onReset() { super.onReset(); onStopLoading(); if (mMatch != null) { onReleaseResources(mMatch); mMatch = null; } } @Override public void onCanceled(Match data) { super.onCanceled(data); onReleaseResources(data); } @Override protected void onStartLoading() { if (mMatch != null) { deliverResult(mMatch); } else { forceLoad(); } } @Override public Match loadInBackground() { try { if (mMatch == null) { mMatch = new Match(); } OkHttpClient okHttpClient = new OkHttpClient(); String rawHtml = okHttpClient.newCall(new Request.Builder().url(mUrl).build()).execute().body() .string(); // try { // trimmedHtml = rawHtml.substring( // rawHtml.indexOf("<div class=\"box box-match-page\">"), // rawHtml.indexOf("<div id=\"comments\" class=\"box\">") // ); // } catch (StringIndexOutOfBoundsException e) { // LogUtils.LOGD(TAG, "Error fetching match data substring."); // e.printStackTrace(); // try { // trimmedHtml = rawHtml.substring( // rawHtml.indexOf("<div id=\"col1\" class=\"rows\">"), // rawHtml.indexOf("<div id=\"col2\" class=\"rows\">") // ); // } catch (StringIndexOutOfBoundsException e1) { // LogUtils.LOGD(TAG, "Error fetching match data, attempting slow method."); // e1.printStackTrace(); // // unknown how this will work... // trimmedHtml = rawHtml; // } // } // match basic data setupMatchData(rawHtml); // gosubet stats setupGosubetStats(rawHtml); // recent match perf setupRecentMatchPerf(rawHtml); // livestreams setupLivestreamUrls(rawHtml); // vods and players present setupGamebox(rawHtml); // now check steamapi for possible matches of teamnames/players return mMatch; } catch (IOException e) { LogUtils.LOGD(TAG, "Likely no internet reception, or timed out"); e.printStackTrace(); } catch (StringIndexOutOfBoundsException e2) { LogUtils.LOGD(TAG, "Error fetching match data."); e2.printStackTrace(); } return null; } private void setupGamebox(String trimmedHtml) { try { String gameBoxHtml = trimmedHtml.substring(trimmedHtml.indexOf("<div id=\"tab-content-wrapper\">")); Document d = Jsoup.parse(gameBoxHtml); ArrayList<Vod> vods = new ArrayList<Vod>(); ExecutorService executorService = Executors.newFixedThreadPool(10); // Videos Elements videoElements = d.getElementsByClass("video"); for (Element vE : videoElements) { String vodDesc = vE.getElementsByClass("vod-desc").first().text(); String vodUrl = "http://www.youtube.com/watch?v=" + vE.getElementsByTag("img").first().attr("src") .replace("https://i.ytimg.com/vi/", "").replace("/1.jpg", ""); vods.add(new Vod(vodUrl, vodDesc)); } HashSet<Player> teamOnePlayers = new HashSet<Player>(); HashSet<Player> teamTwoPlayers = new HashSet<Player>(); Elements gameTabElements = d.getElementsByClass("match-game-tab-content"); for (Element gTE : gameTabElements) { if (!gTE.getElementsByClass("novod-error").isEmpty() && gTE.getElementsByClass("novod-error") .first().text().equals("This game was not played.")) { LogUtils.LOGD(TAG, "entered here..."); continue; } Elements oL = gTE.getElementsByClass("opponent-left").first().getElementsByClass("player"); Elements oR = gTE.getElementsByClass("opponent-right").first().getElementsByClass("player"); for (Element p : oL) { Player tP = new Player(); tP.name = p.getElementsByTag("a").first().text(); if (tP.name.contains("Default Win") || tP.name.contains("Default Loss") || tP.name.contains("Winner Bracket") || tP.name.contains("Loser Bracket")) { continue; } if (!teamOnePlayers.contains(tP)) { tP.profilePageUrl = BASE_URL + p.getElementsByTag("a").first().attr("href").replaceAll("\\r\\n|\\r|\\n", ""); tP.isStandin = p.ownText().contains("*"); // futures.put(tP.name, executorService.submit( // new FetchPlayerImageUrl(tP.profilePageUrl))); teamOnePlayers.add(tP); } } for (Element p : oR) { Player tP = new Player(); tP.name = p.getElementsByTag("a").first().text(); if (tP.name.contains("Default Win") || tP.name.contains("Default Loss") || tP.name.contains("Winner Bracket") || tP.name.contains("Loser Bracket")) { continue; } if (!teamTwoPlayers.contains(tP)) { tP.profilePageUrl = BASE_URL + p.getElementsByTag("a").first().attr("href").replaceAll("\\r\\n|\\r|\\n", ""); tP.isStandin = (p.ownText().equals(" *") || p.ownText().equals("* ")); // futures.put(tP.name, executorService.submit( // new FetchPlayerImageUrl(tP.profilePageUrl))); teamTwoPlayers.add(tP); } } } executorService.shutdown(); executorService.awaitTermination(5000, TimeUnit.MILLISECONDS); mMatch.teamOne.players = new Player[teamOnePlayers.size()]; mMatch.teamTwo.players = new Player[teamTwoPlayers.size()]; int i = 0; for (Player player : teamOnePlayers) { //player.profileImageUrl = BASE_URL + futures.get(player.name).get(); mMatch.teamOne.players[i] = player; i++; } i = 0; for (Player player : teamTwoPlayers) { //player.profileImageUrl = BASE_URL + futures.get(player.name).get(); mMatch.teamTwo.players[i] = player; i++; } mMatch.vods = vods.toArray(new Vod[vods.size()]); } catch (StringIndexOutOfBoundsException e) { LogUtils.LOGD(TAG, "No Gamebox"); } catch (InterruptedException e2) { LogUtils.LOGD(TAG, "Error fetching vod data"); } catch (Exception e3) { LogUtils.LOGD(TAG, "Error dealing with futures"); e3.printStackTrace(); } } private void setupLivestreamUrls(String trimmedHtml) { try { String livestreamHtml = trimmedHtml.substring(trimmedHtml.indexOf("<div class=\"tab-wrapper\">"), trimmedHtml.indexOf("<div class=\"tab-wrapper tab-wrapper-bg\">")); Document d = Jsoup.parse(livestreamHtml); Elements streamTabs = d.getElementsByClass("stream-tab"); Elements streamTabContent = d.getElementsByClass("vod-wrap"); ArrayList<String> langs = new ArrayList<String>(); ArrayList<String> titles = new ArrayList<String>(); ArrayList<String> streamUrls = new ArrayList<String>(); for (int i = 0; i < streamTabs.size(); i++) { Element sT = streamTabs.get(i); Element sTC = streamTabContent.get(i); try { Element twitchElement = sTC.getElementsByTag("object").first(); String url = "http://www.twitch.tv/" + (Uri.parse(twitchElement.attr("data")).getQueryParameter("channel")); streamUrls.add(url); langs.add(sT.getElementsByClass("lang").first().text()); titles.add(sT.ownText().replaceAll(" \\- LIVE!", "")); continue; } catch (Exception e) { LogUtils.LOGD(TAG, "Stream isn't twitch"); } try { Element streamElement = d.getElementsByTag("iframe").first(); if (streamElement == null) { continue; } String url = streamElement.attr("src"); if (url.contains("hitbox") || url.contains("huomao")) { continue; } streamUrls.add(url); langs.add(sT.getElementsByClass("lang").first().text()); titles.add(sT.ownText().replaceAll(" \\- LIVE!", "")); continue; } catch (Exception e) { LogUtils.LOGD(TAG, "Stream isn't covered by iframe interpreter"); } } if (titles.size() > 0) { Livestream[] livestreams = new Livestream[titles.size()]; for (int i = 0; i < titles.size(); i++) { livestreams[i] = new Livestream(langs.get(i), titles.get(i), streamUrls.get(i)); } mMatch.livestreams = livestreams; } } catch (StringIndexOutOfBoundsException e) { LogUtils.LOGD(TAG, "No Livestreams"); } } // TODO: get h2h matchup data. private void setupRecentMatchPerf(String trimmedHtml) { try { String teamOneRecentPerfHtml = trimmedHtml.substring(trimmedHtml.indexOf("<div class=\"opp1-perf\">"), trimmedHtml.indexOf("<div class=\"opp2-perf\">")); String teamTwoRecentPerfHtml = trimmedHtml.substring(trimmedHtml.indexOf("<div class=\"opp2-perf\">"), trimmedHtml.indexOf("<div class=\"both-perf\">")); ArrayList<RecentMatch> recentMatchesTeamOne = new ArrayList<RecentMatch>(); ArrayList<RecentMatch> recentMatchesTeamTwo = new ArrayList<RecentMatch>(); Elements tOne = Jsoup.parse(teamOneRecentPerfHtml).getElementsByClass("match-list-row"); Elements tTwo = Jsoup.parse(teamTwoRecentPerfHtml).getElementsByClass("match-list-row"); for (Element eo : tOne) { recentMatchesTeamOne.add(new RecentMatch( eo.getElementsByTag("strong").first().text().replaceAll(" ?\\.?\\-?-?Dot[aA][\\s]?2", ""), eo.getElementsByTag("span").first().text(), BASE_URL + eo.getElementsByTag("img").first().attr("src"), BASE_URL + eo.getElementsByTag("a").first().attr("href"))); } for (Element et : tTwo) { recentMatchesTeamTwo.add(new RecentMatch( et.getElementsByTag("strong").first().text().replaceAll(" ?\\.?\\-?-?Dot[aA][\\s]?2", ""), et.getElementsByTag("span").first().text(), BASE_URL + et.getElementsByTag("img").first().attr("src"), BASE_URL + et.getElementsByTag("a").first().attr("href"))); } mMatch.teamOne.recPerf = recentMatchesTeamOne.toArray(new RecentMatch[recentMatchesTeamOne.size()]); mMatch.teamTwo.recPerf = recentMatchesTeamTwo.toArray(new RecentMatch[recentMatchesTeamTwo.size()]); } catch (Exception e) { LogUtils.LOGD(TAG, "No team recentperf"); } } private void setupGosubetStats(String trimmedHtml) { String gosuBetHtml = null; try { gosuBetHtml = trimmedHtml.substring(trimmedHtml.indexOf("<div id=\"tab-gb\">"), trimmedHtml.indexOf("<div id=\"tab-ib-rares\">")); Elements nodes = Jsoup.parse(gosuBetHtml).getElementsByClass("percentage"); if (nodes.size() == 3) { mMatch.teamOne.gosubetWin = nodes.get(0).text(); mMatch.teamOne.gosubetTie = nodes.get(1).text(); mMatch.teamTwo.gosubetTie = nodes.get(1).text(); mMatch.teamTwo.gosubetWin = nodes.get(2).text(); } else { mMatch.teamOne.gosubetWin = nodes.get(0).text(); mMatch.teamTwo.gosubetWin = nodes.get(1).text(); } //LOGD(TAG, "teamOneGosubet-teamTwoGosubet: " + teamOneGosubet + ":" + teamTwoGosubet); } catch (IndexOutOfBoundsException e) { LogUtils.LOGD(TAG, "Gosubet % unavailable via one method, trying other... "); try { gosuBetHtml = trimmedHtml.substring(trimmedHtml.indexOf("<div id=\"tab-gb\">"), trimmedHtml.indexOf("<div class=\"match-games-streams\">")); Elements nodes = Jsoup.parse(gosuBetHtml).getElementsByClass("percentage"); if (nodes.size() == 3) { mMatch.teamOne.gosubetWin = nodes.get(0).text(); mMatch.teamOne.gosubetTie = nodes.get(1).text(); mMatch.teamTwo.gosubetTie = nodes.get(1).text(); mMatch.teamTwo.gosubetWin = nodes.get(2).text(); } else { mMatch.teamOne.gosubetWin = nodes.get(0).text(); mMatch.teamTwo.gosubetWin = nodes.get(1).text(); } } catch (IndexOutOfBoundsException e1) { LogUtils.LOGD(TAG, "Gosubet % unavailable via one method, trying other... "); try { gosuBetHtml = trimmedHtml.substring(trimmedHtml.indexOf("<div id=\"tab-gb\">"), trimmedHtml.indexOf("<div class=\"match-performance\">")); Elements nodes = Jsoup.parse(gosuBetHtml).getElementsByClass("percentage"); if (nodes.size() == 3) { mMatch.teamOne.gosubetWin = nodes.get(0).text(); mMatch.teamOne.gosubetTie = nodes.get(1).text(); mMatch.teamTwo.gosubetTie = nodes.get(1).text(); mMatch.teamTwo.gosubetWin = nodes.get(2).text(); } else { mMatch.teamOne.gosubetWin = nodes.get(0).text(); mMatch.teamTwo.gosubetWin = nodes.get(1).text(); } } catch (IndexOutOfBoundsException e2) { LogUtils.LOGD(TAG, "No Gosubet % available"); } } } } private void setupMatchData(String trimmedHtml) { mMatch.teamOne = new Team(); mMatch.teamTwo = new Team(); String opponentHtml = null; try { opponentHtml = trimmedHtml.substring(trimmedHtml.indexOf("<div class=\"match-opponents\">"), trimmedHtml.indexOf("<div class=\"match-extras\">")); Element opponentOne = Jsoup.parse(opponentHtml).getElementsByClass("opponent1").first(); Element opponentTwo = Jsoup.parse(opponentHtml).getElementsByClass("opponent2").first(); mMatch.teamOne.teamUrl = BASE_URL + opponentOne.getElementsByTag("a").attr("href"); mMatch.teamTwo.teamUrl = BASE_URL + opponentTwo.getElementsByTag("a").attr("href"); } catch (IndexOutOfBoundsException e) { LogUtils.LOGD(TAG, "Couldn't get team links."); } String matchInfoBoxHtml = null; try { matchInfoBoxHtml = trimmedHtml.substring(trimmedHtml.indexOf("<p class=\"vs\">"), trimmedHtml.indexOf("<p class=\"datetime\">")); } catch (IndexOutOfBoundsException e) { LogUtils.LOGD(TAG, "Page does not have a score yet."); return; } Document d = Jsoup.parse(matchInfoBoxHtml); Elements scorebox = d.getElementsByClass("vs").first().getElementsByTag("span"); String teamOneScore = "0"; String teamTwoScore = "0"; try { teamOneScore = scorebox.get(2).text(); teamTwoScore = scorebox.get(3).text(); } catch (IndexOutOfBoundsException e) { LogUtils.LOGD(TAG, "No final scores, trying to get interim scores"); try { teamOneScore = Character.toString(scorebox.get(1).text().charAt(0)); teamTwoScore = Character.toString(scorebox.get(1).text().charAt(4)); } catch (Exception e2) { LogUtils.LOGD(TAG, "No interim scores, game must not have started yet."); } } mMatch.teamOne.score = teamOneScore; mMatch.teamTwo.score = teamTwoScore; } protected void onReleaseResources(Match match) { // For a simple List<> there is nothing to do. For something // like a Cursor, we would close it here. } private class FetchPlayerImageUrl implements Callable<String> { private String mUrl; public FetchPlayerImageUrl(String url) { mUrl = url; } @Override public String call() throws Exception { OkHttpClient okHttpClient = new OkHttpClient(); String rawHtml = okHttpClient.newCall(new Request.Builder().url(mUrl).build()).execute().body() .string(); String imageLink = rawHtml.substring(rawHtml.indexOf("<div class=\"playerImage\"") + 55, rawHtml.indexOf("<div class=\"playerNameHolder\">") - 11); //LOGD("FetchPlayerImageUrl", "ImageUrl: " + imageLink); return imageLink; } } }