Skip to content

Commit

Permalink
Azubu.tv streams support
Browse files Browse the repository at this point in the history
  • Loading branch information
hayksaakian committed Jan 25, 2015
1 parent f1827c8 commit 165ca35
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 34 deletions.
Binary file modified .gradle/2.2.1/taskArtifacts/cache.properties.lock
Binary file not shown.
Binary file modified .gradle/2.2.1/taskArtifacts/fileHashes.bin
Binary file not shown.
Binary file modified .gradle/2.2.1/taskArtifacts/fileSnapshots.bin
Binary file not shown.
Binary file modified .gradle/2.2.1/taskArtifacts/taskArtifacts.bin
Binary file not shown.
4 changes: 2 additions & 2 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="540"
android:versionName="5.40"
android:versionCode="550"
android:versionName="5.50"
package="gg.destiny.app">

<uses-sdk
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ public final class BuildConfig {
public static final String APPLICATION_ID = "gg.destiny.app";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 531;
public static final int VERSION_CODE = 540;
public static final String VERSION_NAME = "";
}
146 changes: 115 additions & 31 deletions src/gg/destiny/app/Business.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

import java.io.*;
import java.text.*;
import java.util.*;;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;;
import org.apache.http.*;

//import org.apache.http.*;
Expand Down Expand Up @@ -152,26 +154,31 @@ protected String checkStream(String url_or_channel_name) {
}

} else {
// 1) check twitch
jsno = getTwitchStatus(url_or_channel_name);
channelname = url_or_channel_name;
isLive = jsno != null && jsno.length() > 0;
if (isLive) {
status = jsno.getString("status");
} else {
status = channelname + " is offline. Type another channel\'s name below to watch something else.";
return jsno.getString("status");
}
// check hitbox unless twitch was good
if(isLive == false){
JSONObject hbStatus = getHitboxStatus(url_or_channel_name);
// because hitbox is bad and does not actually 404 from bad channel names
if(hbStatus.length() > 0) {
String liveStatus = hbStatus.getString("media_is_live");
isLive = "1".equals(liveStatus);
if (isLive) {
status = hbStatus.getString("media_status");
}
// 2) check hitbox unless twitch was good
jsno = getHitboxStatus(url_or_channel_name);
// because hitbox is bad and does not actually 404 from bad channel names
if(jsno.length() > 0) {
String liveStatus = jsno.getString("media_is_live");
isLive = "1".equals(liveStatus);
if (isLive) {
return jsno.getString("media_status");
}
}
// 3) check azubu
jsno = getAzubuStatus(url_or_channel_name);
isLive = false;
if (jsno.length() > 0){
isLive = true;
return jsno.getString("title");
}
return channelname + " is offline. Type another channel\'s name below to watch something else.";
}

} catch (JSONException e) {
Expand Down Expand Up @@ -225,26 +232,35 @@ protected HashMap doInBackground(String... channels) {
String auth = getTwitchAuth(channel);
newQualities = getTwitchQualities(channel, auth);

if(newQualities.size() > 0){
return newQualities;
}

// check hitbox if twitch doesn't have anything
if(newQualities.size() == 0){
try {
// unfortunately, getting the list of qualities
// does not truthfully tell us if the stream is live
// so we have to GET the status API too
// TODO: cache this maybe
JSONObject hbStatus = getHitboxStatus(channel);

if(hbStatus.length() > 0) {
String liveStatus = hbStatus.getString("media_is_live");
if ("1".equals(liveStatus)) {
String streams_url = String.format("http://api.hitbox.tv/player/hls/%s.m3u8", channel);
newQualities = parseQualitiesFromURL(streams_url);
}
try {
// unfortunately, getting the list of qualities
// does not truthfully tell us if the stream is live
// so we have to GET the status API too
// TODO: cache this maybe
JSONObject hbStatus = getHitboxStatus(channel);

if(hbStatus.length() > 0) {
String liveStatus = hbStatus.getString("media_is_live");
if ("1".equals(liveStatus)) {
String streams_url = String.format("http://api.hitbox.tv/player/hls/%s.m3u8", channel);
newQualities = parseQualitiesFromURL(streams_url);
}
} catch (JSONException e) {
e.printStackTrace();
}
} catch (JSONException e) {
e.printStackTrace();
}

if(newQualities.size() > 0){
return newQualities;
}

// check azubu if hitbox doesn't have anything
newQualities = getAzubuQualities(channel);
}

//String readURL = HttpGet(url);
Expand Down Expand Up @@ -348,6 +364,66 @@ public static HashMap getTwitchQualities(String channel, String auth) {
}
return mQualities;
}
public static HashMap getAzubuQualities(String channel) {
try {
JSONObject status = getAzubuStatus(channel);
if (status.length() > 0) {
return getAzubuQualities(channel, status);
}
} catch (JSONException e) {
e.printStackTrace();
}
return new HashMap<String, String>();
}

// this seems like a constant, but might not be
public static String AZUBU_PUB_ID = "3361910549001";

public static HashMap getAzubuQualities(String channel, JSONObject status) {
HashMap mQualities = new HashMap<String, String>();
try {

String keyContainingHtml = HttpGet("http://www.azubu.tv/"+channel);
// found here:
// https://github.com/chrippa/livestreamer/blob/da58e4a05405e0e23bbefb1f9d83a6dd88d1d454/src/livestreamer/plugins/azubutv.py#L135
Pattern pattern = Pattern.compile("name=\"playerKey\" value=\"(.+)\"");
Matcher matcher = pattern.matcher(keyContainingHtml);
matcher.find();

String playerKey = matcher.group(1);
String refId = "video" + status.getString("id") + "CH" + channel.replace("_", "");

String streamApiUrl = "http://c.brightcove.com/services/json/player/media/?command=find_media_by_reference_id" +
"&playerKey=" + playerKey +
"&refId=" + refId +
"&pubId=" + AZUBU_PUB_ID;

String sStreamApiData = HttpGet(streamApiUrl);
JSONObject json = new JSONObject(sStreamApiData);
String qualitiesURL = json.getString("FLVFullLengthURL");
if (!qualitiesURL.endsWith("m3u8")){
qualitiesURL = json.getJSONArray("IOSRenditions").getJSONObject(0).getString("defaultURL");
}

// their qualities are not prefixed by a proper url
mQualities = parseQualitiesFromURL(qualitiesURL, refId);

List<String> list = new ArrayList<String>();
list.addAll(mQualities.keySet());

String urlprefix = qualitiesURL.replace(refId+".m3u8", "");

for (int i = 0; i < list.size(); i++) {
String mq = list.get(i);
String mqpath = (String)mQualities.get(mq);
mQualities.put(mq, urlprefix + mqpath);
}
} catch (JSONException e) {
e.printStackTrace();
}

return mQualities;
}

public static JSONObject getAzubuStatus(String channel) throws JSONException{
String hburl = String.format("http://www.azubu.tv/api/video/active-stream/%s", channel);
Expand All @@ -359,6 +435,8 @@ public static JSONObject getAzubuStatus(String channel) throws JSONException{
return json.getJSONArray("data").getJSONObject(0);
}



public static JSONObject getHitboxStatus(String channel) throws JSONException{
JSONObject channelStatus = new JSONObject();

Expand Down Expand Up @@ -409,6 +487,9 @@ public static String getTwitchAuth(String channel) {
}

public static HashMap parseQualitiesFromURL(String url) {
return parseQualitiesFromURL(url, "http");
}
public static HashMap<String, String> parseQualitiesFromURL(String url, String urlPrefix) {
HashMap mQualities = new HashMap<String, String>();
String qualityOptions = HttpGet(url);
// Log.d("Quality Response", qualityOptions);
Expand Down Expand Up @@ -455,10 +536,13 @@ public static HashMap parseQualitiesFromURL(String url) {
if (mQualities.containsKey(lastquality) && info.containsKey("BANDWIDTH")) {
int bw = Integer.parseInt(info.get("BANDWIDTH"));
lastquality = lastquality + "@" + Integer.toString(bw / 1000) + "kbps";
}else if(lastquality.contains("BANDWIDTH=")){
int bw = Integer.parseInt(info.get("BANDWIDTH"));
lastquality = Integer.toString(bw / 1000) + "kbps";
}

Log.d("found quality", lastquality);
} else if (line.startsWith("http") && lastquality != null) {
} else if (line.startsWith(urlPrefix) && lastquality != null) {
// we need to pull the quality name out of the URL for hitbox m3u8 streams
if(line.contains("hitbox.tv/hls/") && line.contains("/index.m3u8")){
lastquality = line.substring(line.indexOf("hitbox.tv/hls/") + 1, line.indexOf("/index.m3u8"));
Expand Down
1 change: 1 addition & 0 deletions src/gg/destiny/app/EmoteDownloader.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public class EmoteDownloader extends AsyncTask<String, Void, String[]> {
protected String[] doInBackground(String... notes) {
String[] emotes = EMOTICON_LIST;
//if(false){

if (notes.length > 0) {
note = notes[0];

Expand Down

0 comments on commit 165ca35

Please sign in to comment.