package com.ringtone.music;
import java.io.IOException;
import android.os.Handler;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringEscapeUtils;
import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class RealmMusicSearcher implements IMusicSearcher {
private static final String URL_SEARCH = "http://mp3realm.org/search?q=";
private static final String URL_SEARCH_PROXY = "http://chaowebs.appspot.com/msearch/music.so?pf=mp3&query=";
private static final String REALM_MP3 = "http://mp3realm.org/";
private static final Pattern PATTERN_ROW = Pattern.compile("<li>(.*?)<li>", Pattern.DOTALL);
private static final Pattern PATTERN = Pattern.compile(
".*?href=\"(.*?)\">.*?<font.*?>(.+?)</font>.*?" + // 1 url 2 title
"<div.*?Artist.*?</h4>[<a.*Href=.*?>]?([^<]*)<.*?" + // 3 artist
"<div.*?Album.*?</h4>[<a.*Href=.*?>]?([^<]*)<.*?" + // 4 album
"<div.*?Year.*</h4>([^<]*)<.*?" + // 5 year
"<div.*?Genre.*</h4>([^<]*)<.*?" + // 6 Ignore
"<div.*?BitRate.*</h4>([^<]*)<.*?" + // 7 Ignore
"<div.*?Playtime.*</h4>([^<]*)<.*?" + // 8 Ignore
"<div.*?<i>.*?</i>[^0-9]*([^a-zA-Z]*M)B.*?" + // 9 size
""
, Pattern.DOTALL);
private static final Pattern PATTERN_ARTIST_ALBUM = Pattern.compile(".*?href=\".*?\">(.+)", Pattern.DOTALL);
private static final Pattern PATTERN_DOWNLOAD_URL = Pattern.compile(".*?href=\"([^\"]*)\">.*?\n.*?<font.*?>.*?\n.*?<b>Download</b>");
private static final String DOWNLOAD_MARKER = "Link Status";
private String mSearchUrl;
private int mPage; // Next page to fetch.
private volatile Handler mHandler = new Handler();
private static int sNumQueries = 0;
public RealmMusicSearcher() {
}
public void setQuery(String query) {
mPage = 1;
try {
mSearchUrl = URL_SEARCH + URLEncoder.encode(query, "gb2312");
} catch (UnsupportedEncodingException e) {
mSearchUrl = URL_SEARCH + URLEncoder.encode(query);
}
}
private String getNextUrl() {
return mPage == 1 ? mSearchUrl : mSearchUrl + "&page=" + mPage;
}
private ArrayList<MusicInfo> getMusicInfoListFromHtml(String html) throws UnsupportedEncodingException {
Utils.D("+++++++++++++++");
Utils.D(html);
Utils.D("+++++++++++++++");
ArrayList<MusicInfo> musicList = new ArrayList<MusicInfo>();
Matcher matcherRow = PATTERN_ROW.matcher(html);
while (matcherRow.find()) {
Matcher m = PATTERN.matcher(matcherRow.group(1));
while (m.find()) {
MusicInfo info = new MusicInfo();
info.addUrl(REALM_MP3+m.group(1).trim());
String title = m.group(2).trim();
title = title.replace("<b>", "");
title = title.replace("</b>", "");
info.setTitle(StringEscapeUtils.unescapeHtml(title));
String artist = m.group(3).trim();
Matcher matcherArtist = PATTERN_ARTIST_ALBUM.matcher(artist);
while (matcherArtist.find()) {
artist = matcherArtist.group(1);
}
info.setArtist(StringEscapeUtils.unescapeHtml(artist));
String album = m.group(4).trim();
Matcher matcherAlbum = PATTERN_ARTIST_ALBUM.matcher(album);
while (matcherAlbum.find()) {
album = matcherAlbum.group(1);
}
info.setAlbum(StringEscapeUtils.unescapeHtml(album));
String displayFileSize = m.group(9).trim();
if (displayFileSize.equals("unknown"))
displayFileSize = "Unknown size";
info.setDisplayFileSize(displayFileSize);
//info.setType(m.group(7).trim());
musicList.add(info);
}
}
Utils.D("Exit getMusicInfoListFromHtml");
return musicList;
}
// Used to signal between threads.
class Signal {
public boolean ready;
};
class HtmlData {
public String content;
};
class MyJavaScriptInterface {
Signal mSignal;
HtmlData mData;
public MyJavaScriptInterface(Signal s, HtmlData data) {
this.mSignal = s;
this.mData = data;
}
@SuppressWarnings("unused")
public void parseHtml(String html) {
mData.content = html;
mSignal.ready = true;
synchronized(mSignal) {
mSignal.notify();
}
}
}
private class FetchSearchPage extends WebViewClient {
@Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript:window.HTMLOUT.parseHtml(document.getElementsByTagName('html')[0].innerHTML);");
}
}
private boolean loadUrl(final Context context, final String url, final HtmlData data) {
final Signal s = new Signal();
s.ready = false;
mHandler.post(new Runnable() {
@Override
public void run() {
WebView web = new WebView(context);
web.getSettings().setJavaScriptEnabled(true);
web.getSettings().setLoadsImagesAutomatically(false);
web.getSettings().setBlockNetworkImage(true);
web.addJavascriptInterface(new MyJavaScriptInterface(s, data), "HTMLOUT");
web.setWebViewClient(new FetchSearchPage());
web.loadUrl(url);
}
});
synchronized(s) {
while (!s.ready) {
try {
s.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
return true;
}
}
// Returns null when something wrong happens.
@Override
public ArrayList<MusicInfo> getNextResultList(final Context context) {
sNumQueries++;
HtmlData data = new HtmlData();
if (!loadUrl(context, getNextUrl(), data))
return null;
if (TextUtils.isEmpty(data.content))
return null;
ArrayList<MusicInfo> musicList;
try {
musicList = getMusicInfoListFromHtml(data.content);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
if (musicList.size() > 0) {
mPage++;
}
return musicList;
}
@Override
public void setMusicDownloadUrl(Context context, MusicInfo info) {
try {
HtmlData data = new HtmlData();
loadUrl(context, info.getUrl(), data);
int start = data.content.indexOf(DOWNLOAD_MARKER) + DOWNLOAD_MARKER.length();
Matcher m = PATTERN_DOWNLOAD_URL.matcher(data.content.substring(start));
//Matcher m = PATTERN_DOWNLOAD_URL.matcher(data.content);
if (m.find()) {
info.addDownloadUrl(m.group(1));
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}