-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from mfurlando/master
Added support for the Italian Community Scambio Etico
- Loading branch information
Showing
2 changed files
with
255 additions
and
0 deletions.
There are no files selected for viewing
248 changes: 248 additions & 0 deletions
248
src/org/transdroid/search/ScambioEtico/ScambioEtico.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
/* | ||
* This file is part of Transdroid Torrent Search | ||
* <http://code.google.com/p/transdroid-search/> | ||
* | ||
* Transdroid Torrent Search is free software: you can redistribute | ||
* it and/or modify it under the terms of the GNU Lesser General | ||
* Public License as published by the Free Software Foundation, | ||
* either version 3 of the License, or (at your option) any later | ||
* version. | ||
* | ||
* Transdroid Torrent Search 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 Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with Transdroid. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package org.transdroid.search.ScambioEtico; | ||
|
||
import java.io.InputStream; | ||
import java.io.UnsupportedEncodingException; | ||
import java.net.URLEncoder; | ||
import java.security.InvalidParameterException; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
import javax.security.auth.login.LoginException; | ||
|
||
import org.apache.http.HttpResponse; | ||
import org.apache.http.client.entity.UrlEncodedFormEntity; | ||
import org.apache.http.client.methods.HttpGet; | ||
import org.apache.http.client.methods.HttpPost; | ||
import org.apache.http.impl.client.DefaultHttpClient; | ||
import org.apache.http.message.BasicNameValuePair; | ||
import org.apache.http.params.BasicHttpParams; | ||
import org.apache.http.params.HttpConnectionParams; | ||
import org.apache.http.params.HttpParams; | ||
import org.transdroid.search.ISearchAdapter; | ||
import org.transdroid.search.SearchResult; | ||
import org.transdroid.search.SortOrder; | ||
import org.transdroid.search.TorrentSite; | ||
import org.transdroid.search.gui.SettingsHelper; | ||
import org.transdroid.util.HttpHelper; | ||
|
||
import android.content.Context; | ||
import android.text.Html; | ||
import android.util.Log; | ||
|
||
/** | ||
* An adapter that provides access to Scambio Etico searches by parsing the raw HTML output. | ||
*/ | ||
public class ScambioEtico implements ISearchAdapter { | ||
|
||
private static final String LOGIN_USER = "UserName"; | ||
private static final String LOGIN_PASS = "PassWord"; | ||
private static final String LOGINURL = | ||
"http://forum.tntvillage.scambioetico.org/index.php?act=Login&CODE=01"; | ||
private static final String QUERYURL = | ||
"http://forum.tntvillage.scambioetico.org/index.php?act=allreleases&filter=%s%s"; | ||
private static final String TORRENT_URL = | ||
"http://forum.tntvillage.scambioetico.org/index.php?act=Attach&type=post&id=%s"; | ||
private static final String SORT_COMPOSITE = ""; | ||
private static final String SORT_SEEDS = "&sb=4"; | ||
private static final int CONNECTION_TIMEOUT = 8000; | ||
private static final String ENCODING = "ISO-8859-1"; | ||
|
||
private static final String WRONG_PASSWORD = "Password errata. Inserisci la password rispettando " | ||
+ "i caratteri MAIUSCOLI e minuscoli."; | ||
private static final String WRONG_LOGIN = "Non è possibile trovare un utente del Forum " | ||
+ "chiamato <b>"; | ||
|
||
// Texts to find subsequently (Used in parseHtml) | ||
private static final String START_RESULTS = "<!--TORRENT TABLE-->"; | ||
private static final String END_RESULTS = "<!--END TORRENT TABLE-->"; | ||
private static final String ITEM_PREFIX = "<tr class=\"row4\">"; | ||
|
||
// Regexps for extracting the informations that we care (Used in parseHtmlItem) | ||
private static final String MAIN_EXTRACTOR = | ||
"<a [^>]*href='(http://forum.tntvillage.scambioetico.org/" | ||
+ "index.php[?]showtopic=[0-9]+)'[^>]*>([^<]+)</a>"; | ||
private static final String TORRENT_ID_EXTRACTOR = | ||
"<a [^>]*href='http://forum.tntvillage.scambioetico.org/" | ||
+ "index.php[?]act=peers&pid=([0-9]+)'[^>]*>PeerLists</a>"; | ||
private static final String SIZE_EXTRACTOR = | ||
"\\[<span [^>]*style='color:blue'[^>]*>[^0-9\\.>]*([0-9\\.]+)[^0-9\\.>]*</span>\\]"; | ||
private static final String SEEDS_EXTRACTOR = | ||
"\\[<span [^>]*style='color:red'[^>]*>[^0-9\\.>]*([0-9]+)[^0-9\\.>]*</span>\\]"; | ||
private static final String LEECHERS_EXTRACTOR = | ||
"\\[<span [^>]*style='color:green'[^>]*>[^0-9\\.>]*([0-9]+)[^0-9\\.>]*</span>\\]"; | ||
|
||
private DefaultHttpClient prepareRequest(Context context) throws Exception { | ||
|
||
String username = SettingsHelper.getSiteUser(context, TorrentSite.ScambioEtico); | ||
String password = SettingsHelper.getSitePass(context, TorrentSite.ScambioEtico); | ||
if (username == null || password == null) { | ||
throw new InvalidParameterException("No username or password was provided, while " | ||
+ "this is required for Scambio Etico."); | ||
} | ||
|
||
// Setup request using GET | ||
HttpParams httpparams = new BasicHttpParams(); | ||
HttpConnectionParams.setConnectionTimeout(httpparams, CONNECTION_TIMEOUT); | ||
HttpConnectionParams.setSoTimeout(httpparams, CONNECTION_TIMEOUT); | ||
DefaultHttpClient httpclient = new DefaultHttpClient(httpparams); | ||
|
||
// First log in | ||
Log.d("ScambioEtico", "Starting Authentication"); | ||
HttpPost loginPost = new HttpPost(LOGINURL); | ||
loginPost.setEntity(new UrlEncodedFormEntity(Arrays.asList( | ||
new BasicNameValuePair[] { | ||
new BasicNameValuePair(LOGIN_USER, username), | ||
new BasicNameValuePair(LOGIN_PASS, password) | ||
}))); | ||
HttpResponse loginResult = httpclient.execute(loginPost); | ||
String loginHtml = HttpHelper.ConvertStreamToString(loginResult.getEntity().getContent()); | ||
if (loginHtml.indexOf(WRONG_LOGIN) >= 0) { | ||
throw new LoginException("Login failure for Scambio Etico wrong username " + username); | ||
} else if (loginHtml.indexOf(WRONG_PASSWORD) >= 0) { | ||
throw new LoginException("Login failure for Scambio Etico: bad password for user " + username); | ||
} | ||
Log.d("ScambioEtico", "Authentication successful"); | ||
|
||
return httpclient; | ||
} | ||
|
||
@Override | ||
public List<SearchResult> search(Context context, String query, SortOrder order, | ||
int maxResults) throws Exception { | ||
|
||
DefaultHttpClient httpclient = prepareRequest(context); | ||
|
||
// Build a search request parameters | ||
String encodedQuery = ""; | ||
try { | ||
encodedQuery = URLEncoder.encode(query, ENCODING); | ||
} catch (UnsupportedEncodingException e) { | ||
throw e; | ||
} | ||
|
||
String urlPostfix = (order == SortOrder.BySeeders) ? SORT_SEEDS : SORT_COMPOSITE; | ||
String url = String.format(QUERYURL, encodedQuery, urlPostfix); | ||
|
||
// Start synchronous search | ||
|
||
// Make request | ||
HttpGet httpget = new HttpGet(url); | ||
HttpResponse response = httpclient.execute(httpget); | ||
|
||
// Read HTML response | ||
InputStream instream = response.getEntity().getContent(); | ||
String html = HttpHelper.ConvertStreamToString(instream); | ||
instream.close(); | ||
return parseHtml(html, maxResults); | ||
|
||
} | ||
|
||
@Override | ||
public InputStream getTorrentFile(Context context, String url) throws Exception { | ||
// Provide an authenticated file handle to the requested url | ||
DefaultHttpClient httpclient = prepareRequest(context); | ||
HttpResponse response = httpclient.execute(new HttpGet(url)); | ||
return response.getEntity().getContent(); | ||
|
||
} | ||
|
||
// Parse the search results from HTML by looking for the identifying texts | ||
protected List<SearchResult> parseHtml(String html, int maxResults) throws Exception { | ||
int startResults = html.indexOf(START_RESULTS); | ||
int endResults = html.indexOf(END_RESULTS); | ||
|
||
List<SearchResult> results = new ArrayList<SearchResult>(); | ||
|
||
if (startResults < 0) { | ||
return results; // No results for this query | ||
} else if (endResults <= 0) { | ||
// This should not happen but, if the site administrator will change the END_RESULTS | ||
// string we may still try to keep in working (endResults is mainly for safety). | ||
// This is still adaptive programming that it chills me to the bone but let us keep a | ||
// pragmatic approach... and parsing html without a clear interface is fragile anyway. | ||
endResults = html.length(); | ||
} | ||
|
||
startResults += START_RESULTS.length(); | ||
String resultsTable = html.substring(startResults, endResults); | ||
|
||
int itemsPointer = 0; | ||
do { | ||
itemsPointer += ITEM_PREFIX.length(); | ||
int nextItem = resultsTable.indexOf(ITEM_PREFIX, itemsPointer); | ||
nextItem = (nextItem >= 0) ? nextItem : resultsTable.length(); | ||
|
||
results.add(parseHtmlItem(resultsTable.substring(itemsPointer, nextItem))); | ||
|
||
itemsPointer = nextItem; | ||
} while (itemsPointer < resultsTable.length() && results.size() < maxResults); | ||
return results; | ||
} | ||
|
||
private String extractData(String regexp, String htmlItem) { | ||
return extractData(regexp, htmlItem, 1); | ||
} | ||
|
||
private String extractData(String regexp, String htmlItem, int group) { | ||
Pattern pattern = Pattern.compile(regexp); | ||
Matcher matcher = pattern.matcher(htmlItem); | ||
if (matcher == null || !matcher.find()) { | ||
throw new IllegalStateException( | ||
"Impossible to parse results. Probably Scambio Etico refactored its html and this application must be updated."); | ||
} | ||
|
||
return matcher.group(group); | ||
} | ||
|
||
private SearchResult parseHtmlItem(String htmlItem) throws UnsupportedEncodingException { | ||
String title = Html.fromHtml(extractData(MAIN_EXTRACTOR, htmlItem, 2)).toString(); | ||
String detailsUrl = Html.fromHtml(extractData(MAIN_EXTRACTOR, htmlItem, 1)).toString(); | ||
String torrentId = extractData(TORRENT_ID_EXTRACTOR, htmlItem); | ||
String size = extractData(SIZE_EXTRACTOR, htmlItem) + " GiB"; | ||
int seeds = Integer.parseInt(extractData(SEEDS_EXTRACTOR, htmlItem)); | ||
int leechers = Integer.parseInt(extractData(LEECHERS_EXTRACTOR, htmlItem)); | ||
|
||
|
||
return new SearchResult(title, String.format(TORRENT_URL, torrentId), detailsUrl, size, null, seeds, leechers); | ||
|
||
} | ||
|
||
@Override | ||
public String buildRssFeedUrlFromSearch(String query, SortOrder order) { | ||
// Scambio Etico doesn't support RSS feed-based searches | ||
return null; | ||
} | ||
|
||
@Override | ||
public String getSiteName() { | ||
return "Scambio Etico"; | ||
} | ||
|
||
@Override | ||
public boolean isPrivateSite() { | ||
// Not really private, still it requires registration. | ||
return true; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters