Add new workers
This commit is contained in:
parent
ee592def0c
commit
a4b61bf730
|
@ -1,216 +0,0 @@
|
|||
package org.schabi.newpipe.fragments.search;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||
import org.schabi.newpipe.extractor.search.SearchEngine;
|
||||
import org.schabi.newpipe.extractor.search.SearchResult;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 02.08.16.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||
* SearchWorker.java is part of NewPipe.
|
||||
*
|
||||
* NewPipe is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NewPipe 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
public class SearchWorker {
|
||||
private static final String TAG = SearchWorker.class.toString();
|
||||
|
||||
public interface SearchWorkerResultListener {
|
||||
void onResult(SearchResult result);
|
||||
void onNothingFound(final int stringResource);
|
||||
void onError(String message);
|
||||
void onReCaptchaChallenge();
|
||||
}
|
||||
|
||||
private class ResultRunnable implements Runnable {
|
||||
private final SearchResult result;
|
||||
private int requestId = 0;
|
||||
public ResultRunnable(SearchResult result, int requestId) {
|
||||
this.result = result;
|
||||
this.requestId = requestId;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
if(this.requestId == SearchWorker.this.requestId) {
|
||||
searchWorkerResultListener.onResult(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SearchRunnable implements Runnable {
|
||||
public static final String YOUTUBE = "Youtube";
|
||||
private final String query;
|
||||
private final int page;
|
||||
private final EnumSet<SearchEngine.Filter> filter;
|
||||
final Handler h = new Handler();
|
||||
private volatile boolean runs = true;
|
||||
private Activity a = null;
|
||||
private int serviceId = -1;
|
||||
public SearchRunnable(int serviceId,
|
||||
String query,
|
||||
int page,
|
||||
EnumSet<SearchEngine.Filter> filter,
|
||||
Activity activity,
|
||||
int requestId) {
|
||||
this.serviceId = serviceId;
|
||||
this.query = query;
|
||||
this.page = page;
|
||||
this.filter = filter;
|
||||
this.a = activity;
|
||||
}
|
||||
void terminate() {
|
||||
runs = false;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
final String serviceName = NewPipe.getNameOfService(serviceId);
|
||||
SearchResult result = null;
|
||||
SearchEngine engine = null;
|
||||
|
||||
try {
|
||||
engine = NewPipe.getService(serviceId)
|
||||
.getSearchEngineInstance();
|
||||
} catch(ExtractionException e) {
|
||||
ErrorActivity.reportError(h, a, e, null, null,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,
|
||||
Integer.toString(serviceId), query, R.string.general_error));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(a);
|
||||
String searchLanguageKey = a.getString(R.string.search_language_key);
|
||||
String searchLanguage = sp.getString(searchLanguageKey,
|
||||
a.getString(R.string.default_language_value));
|
||||
result = SearchResult
|
||||
.getSearchResult(engine, query, page, searchLanguage, filter);
|
||||
if(runs) {
|
||||
h.post(new ResultRunnable(result, requestId));
|
||||
}
|
||||
|
||||
// look for errors during extraction
|
||||
// soft errors:
|
||||
View rootView = a.findViewById(android.R.id.content);
|
||||
if(result != null &&
|
||||
!result.errors.isEmpty()) {
|
||||
Log.e(TAG, "OCCURRED ERRORS DURING SEARCH EXTRACTION:");
|
||||
for(Throwable e : result.errors) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "------");
|
||||
}
|
||||
|
||||
if(result.resultList.isEmpty()&& !result.errors.isEmpty()) {
|
||||
// if it compleatly failes dont show snackbar, instead show error directlry
|
||||
ErrorActivity.reportError(h, a, result.errors, null, null,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,
|
||||
serviceName, query, R.string.parsing_error));
|
||||
} else {
|
||||
// if it partly show snackbar
|
||||
ErrorActivity.reportError(h, a, result.errors, null, rootView,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,
|
||||
serviceName, query, R.string.light_parsing_error));
|
||||
}
|
||||
}
|
||||
// hard errors:
|
||||
} catch (ReCaptchaException e) {
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
searchWorkerResultListener.onReCaptchaChallenge();
|
||||
}
|
||||
});
|
||||
} catch(IOException e) {
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
searchWorkerResultListener.onNothingFound(R.string.network_error);
|
||||
}
|
||||
});
|
||||
e.printStackTrace();
|
||||
} catch(final SearchEngine.NothingFoundException e) {
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
searchWorkerResultListener.onError(e.getMessage());
|
||||
}
|
||||
});
|
||||
} catch(ExtractionException e) {
|
||||
ErrorActivity.reportError(h, a, e, null, null,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,
|
||||
serviceName, query, R.string.parsing_error));
|
||||
//postNewErrorToast(h, R.string.parsing_error);
|
||||
e.printStackTrace();
|
||||
|
||||
} catch(Exception e) {
|
||||
ErrorActivity.reportError(h, a, e, null, null,
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,
|
||||
/* todo: this shoudl not be assigned static */ YOUTUBE, query, R.string.general_error));
|
||||
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SearchWorker searchWorker = null;
|
||||
private SearchWorkerResultListener searchWorkerResultListener = null;
|
||||
private SearchRunnable runnable = null;
|
||||
private int requestId = 0; //prevents running requests that have already ben expired
|
||||
|
||||
public static SearchWorker getInstance() {
|
||||
return searchWorker == null ? (searchWorker = new SearchWorker()) : searchWorker;
|
||||
}
|
||||
|
||||
public void setSearchWorkerResultListener(SearchWorkerResultListener listener) {
|
||||
searchWorkerResultListener = listener;
|
||||
}
|
||||
|
||||
private SearchWorker() {
|
||||
|
||||
}
|
||||
|
||||
public void search(int serviceId,
|
||||
String query,
|
||||
int page,
|
||||
Activity a,
|
||||
EnumSet<SearchEngine.Filter> filter) {
|
||||
if(runnable != null) {
|
||||
terminate();
|
||||
}
|
||||
runnable = new SearchRunnable(serviceId, query, page, filter, a, requestId);
|
||||
Thread thread = new Thread(runnable);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
if (runnable == null) return;
|
||||
requestId++;
|
||||
runnable.terminate();
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
package org.schabi.newpipe.fragments.search;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.SuggestionExtractor;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 02.08.16.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||
* SuggestionSearchRunnable.java is part of NewPipe.
|
||||
*
|
||||
* NewPipe is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NewPipe 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class SuggestionSearchRunnable implements Runnable{
|
||||
|
||||
/**
|
||||
* Runnable to update a {@link SuggestionListAdapter}
|
||||
*/
|
||||
private class SuggestionResultRunnable implements Runnable{
|
||||
|
||||
private final List<String> suggestions;
|
||||
|
||||
private SuggestionResultRunnable(List<String> suggestions) {
|
||||
this.suggestions = suggestions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
adapter.updateAdapter(suggestions);
|
||||
}
|
||||
}
|
||||
|
||||
private final int serviceId;
|
||||
private final String query;
|
||||
private final Handler h = new Handler();
|
||||
private final Activity a;
|
||||
private final SuggestionListAdapter adapter;
|
||||
public SuggestionSearchRunnable(int serviceId, String query,
|
||||
Activity activity, SuggestionListAdapter adapter) {
|
||||
this.serviceId = serviceId;
|
||||
this.query = query;
|
||||
this.a = activity;
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
SuggestionExtractor se =
|
||||
NewPipe.getService(serviceId).getSuggestionExtractorInstance();
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(a);
|
||||
String searchLanguageKey = a.getString(R.string.search_language_key);
|
||||
String searchLanguage = sp.getString(searchLanguageKey,
|
||||
a.getString(R.string.default_language_value));
|
||||
List<String> suggestions = se.suggestionList(query, searchLanguage);
|
||||
h.post(new SuggestionResultRunnable(suggestions));
|
||||
} catch (ExtractionException e) {
|
||||
ErrorActivity.reportError(h, a, e, null, a.findViewById(android.R.id.content),
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,
|
||||
NewPipe.getNameOfService(serviceId), query, R.string.parsing_error));
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
postNewErrorToast(h, R.string.network_error);
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportError(h, a, e, null, a.findViewById(android.R.id.content),
|
||||
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,
|
||||
NewPipe.getNameOfService(serviceId), query, R.string.general_error));
|
||||
}
|
||||
}
|
||||
|
||||
private void postNewErrorToast(Handler h, final int stringResource) {
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(a, a.getString(stringResource),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
package org.schabi.newpipe.workers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfo;
|
||||
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Common properties of Workers
|
||||
*
|
||||
* @author mauriciocolli
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public abstract class AbstractWorker extends Thread {
|
||||
|
||||
private final AtomicBoolean isRunning = new AtomicBoolean(false);
|
||||
|
||||
private final int serviceId;
|
||||
private Context context;
|
||||
private Handler handler;
|
||||
private StreamingService service;
|
||||
|
||||
public AbstractWorker(Context context, int serviceId) {
|
||||
this.context = context;
|
||||
this.serviceId = serviceId;
|
||||
this.handler = new Handler(context.getMainLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
isRunning.set(true);
|
||||
service = NewPipe.getService(serviceId);
|
||||
doWork(serviceId);
|
||||
} catch (Exception e) {
|
||||
// Handle the exception only if thread is not interrupted
|
||||
e.printStackTrace();
|
||||
if (!isInterrupted() && !(e instanceof InterruptedIOException) && !(e.getCause() instanceof InterruptedIOException)) {
|
||||
handleException(e, serviceId);
|
||||
}
|
||||
} finally {
|
||||
isRunning.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Here is the place that the heavy work is realized
|
||||
*
|
||||
* @param serviceId serviceId that was passed when created this object
|
||||
*
|
||||
* @throws Exception these exceptions are handled by the {@link #handleException(Exception, int)}
|
||||
*/
|
||||
protected abstract void doWork(int serviceId) throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
* Method that handle the exception thrown by the {@link #doWork(int)}.
|
||||
*
|
||||
* @param exception {@link Exception} that was thrown by {@link #doWork(int)}
|
||||
*/
|
||||
protected abstract void handleException(Exception exception, int serviceId);
|
||||
|
||||
/**
|
||||
* Return true if the extraction is not completed yet
|
||||
*
|
||||
* @return the value of the AtomicBoolean {@link #isRunning}
|
||||
*/
|
||||
public boolean isRunning() {
|
||||
return isRunning.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel this ExtractorWorker, calling {@link #onDestroy()} and interrupting this thread.
|
||||
* <p>
|
||||
* <b>Note:</b> Any I/O that is active in the moment that this method is called will be canceled and a Exception will be thrown, because of the {@link #interrupt()}.<br>
|
||||
* This is useful when you don't want the resulting {@link StreamInfo} anymore, but don't want to waste bandwidth, otherwise it'd run till it receives the StreamInfo.
|
||||
*/
|
||||
public void cancel() {
|
||||
onDestroy();
|
||||
this.interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that discards everything that doesn't need anymore.<br>
|
||||
* Subclasses can override this method to destroy their garbage.
|
||||
*/
|
||||
protected void onDestroy() {
|
||||
this.isRunning.set(false);
|
||||
this.context = null;
|
||||
this.handler = null;
|
||||
this.service = null;
|
||||
}
|
||||
|
||||
public Handler getHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public StreamingService getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
public int getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return service == null ? "none" : service.getServiceInfo().name;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ public class ChannelExtractorWorker extends ExtractorWorker {
|
|||
* Interface which will be called for result and errors
|
||||
*/
|
||||
public interface OnChannelInfoReceive {
|
||||
void onReceive(ChannelInfo info);
|
||||
void onReceive(ChannelInfo info, boolean onlyVideos);
|
||||
void onError(int messageId);
|
||||
/**
|
||||
* Called when an unrecoverable error has occurred.
|
||||
|
@ -44,12 +44,15 @@ public class ChannelExtractorWorker extends ExtractorWorker {
|
|||
* @param context context for error reporting purposes
|
||||
* @param serviceId id of the request service
|
||||
* @param channelUrl channelUrl of the service (e.g. https://www.youtube.com/channel/UC_aEa8K-EOJ3D6gOs7HcyNg)
|
||||
* @param pageNumber which page to extract
|
||||
* @param onlyVideos flag that will be send by {@link OnChannelInfoReceive#onReceive(ChannelInfo, boolean)}
|
||||
* @param callback listener that will be called-back when events occur (check {@link ChannelExtractorWorker.OnChannelInfoReceive})
|
||||
*/
|
||||
public ChannelExtractorWorker(Context context, int serviceId, String channelUrl, int pageNumber, OnChannelInfoReceive callback) {
|
||||
public ChannelExtractorWorker(Context context, int serviceId, String channelUrl, int pageNumber, boolean onlyVideos, OnChannelInfoReceive callback) {
|
||||
super(context, channelUrl, serviceId);
|
||||
this.pageNumber = pageNumber;
|
||||
this.callback = callback;
|
||||
this.onlyVideos = onlyVideos;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,7 +74,7 @@ public class ChannelExtractorWorker extends ExtractorWorker {
|
|||
public void run() {
|
||||
if (isInterrupted() || callback == null) return;
|
||||
|
||||
callback.onReceive(channelInfo);
|
||||
callback.onReceive(channelInfo, onlyVideos);
|
||||
onDestroy();
|
||||
}
|
||||
});
|
||||
|
@ -107,13 +110,5 @@ public class ChannelExtractorWorker extends ExtractorWorker {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isOnlyVideos() {
|
||||
return onlyVideos;
|
||||
}
|
||||
|
||||
public void setOnlyVideos(boolean onlyVideos) {
|
||||
this.onlyVideos = onlyVideos;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,18 +2,12 @@ package org.schabi.newpipe.workers;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfo;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Common properties of ExtractorWorkers
|
||||
|
@ -21,38 +15,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
* @author mauriciocolli
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public abstract class ExtractorWorker extends Thread {
|
||||
|
||||
private final AtomicBoolean isRunning = new AtomicBoolean(false);
|
||||
|
||||
public abstract class ExtractorWorker extends AbstractWorker {
|
||||
private final String url;
|
||||
private final int serviceId;
|
||||
private Context context;
|
||||
private Handler handler;
|
||||
private StreamingService service;
|
||||
|
||||
public ExtractorWorker(Context context, String url, int serviceId) {
|
||||
this.context = context;
|
||||
super(context, serviceId);
|
||||
this.url = url;
|
||||
this.serviceId = serviceId;
|
||||
this.handler = new Handler(context.getMainLooper());
|
||||
if (url.length() >= 40) setName("Thread-" + url.substring(url.length() - 11, url.length()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
isRunning.set(true);
|
||||
service = NewPipe.getService(serviceId);
|
||||
doWork(serviceId, url);
|
||||
} catch (Exception e) {
|
||||
// Handle the exception only if thread is not interrupted
|
||||
if (!isInterrupted() && !(e instanceof InterruptedIOException) && !(e.getCause() instanceof InterruptedIOException)) {
|
||||
handleException(e, serviceId, url);
|
||||
}
|
||||
} finally {
|
||||
isRunning.set(false);
|
||||
}
|
||||
protected void doWork(int serviceId) throws Exception {
|
||||
doWork(serviceId, url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,6 +39,10 @@ public abstract class ExtractorWorker extends Thread {
|
|||
*/
|
||||
protected abstract void doWork(int serviceId, String url) throws Exception;
|
||||
|
||||
@Override
|
||||
protected void handleException(Exception exception, int serviceId) {
|
||||
handleException(exception, serviceId, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that handle the exception thrown by the {@link #doWork(int, String)}.
|
||||
|
@ -99,63 +77,12 @@ public abstract class ExtractorWorker extends Thread {
|
|||
}
|
||||
|
||||
if (getContext() instanceof Activity) {
|
||||
View rootView = getContext() != null ? ((Activity) getContext()).findViewById(android.R.id.content) : null;
|
||||
View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null;
|
||||
ErrorActivity.reportError(getHandler(), getContext(), errorsList, null, rootView, ErrorActivity.ErrorInfo.make(errorUserAction, getServiceName(), url, 0 /* no message for the user */));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the extraction is not completed yet
|
||||
*
|
||||
* @return the value of the AtomicBoolean {@link #isRunning}
|
||||
*/
|
||||
public boolean isRunning() {
|
||||
return isRunning.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel this ExtractorWorker, calling {@link #onDestroy()} and interrupting this thread.
|
||||
* <p>
|
||||
* <b>Note:</b> Any I/O that is active in the moment that this method is called will be canceled and a Exception will be thrown, because of the {@link #interrupt()}.<br>
|
||||
* This is useful when you don't want the resulting {@link StreamInfo} anymore, but don't want to waste bandwidth, otherwise it'd run till it receives the StreamInfo.
|
||||
*/
|
||||
public void cancel() {
|
||||
onDestroy();
|
||||
this.interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that discards everything that doesn't need anymore.<br>
|
||||
* Subclasses can override this method to destroy their garbage.
|
||||
*/
|
||||
protected void onDestroy() {
|
||||
this.isRunning.set(false);
|
||||
this.context = null;
|
||||
this.handler = null;
|
||||
this.service = null;
|
||||
}
|
||||
|
||||
public Handler getHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public StreamingService getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
public int getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return service == null ? "none" : service.getServiceInfo().name;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
package org.schabi.newpipe.workers;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||
import org.schabi.newpipe.extractor.search.SearchEngine;
|
||||
import org.schabi.newpipe.extractor.search.SearchResult;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Return list of results based on a query
|
||||
*
|
||||
* @author mauriciocolli
|
||||
*/
|
||||
public class SearchWorker extends AbstractWorker {
|
||||
|
||||
private EnumSet<SearchEngine.Filter> filter;
|
||||
private String query;
|
||||
private int page;
|
||||
private OnSearchResult callback;
|
||||
|
||||
/**
|
||||
* Interface which will be called for result and errors
|
||||
*/
|
||||
public interface OnSearchResult {
|
||||
void onSearchResult(SearchResult result);
|
||||
void onNothingFound(String message);
|
||||
void onSearchError(int messageId);
|
||||
void onReCaptchaChallenge();
|
||||
}
|
||||
|
||||
public SearchWorker(Context context, int serviceId, String query, int page, EnumSet<SearchEngine.Filter> filter, OnSearchResult callback) {
|
||||
super(context, serviceId);
|
||||
this.callback = callback;
|
||||
this.query = query;
|
||||
this.page = page;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public static SearchWorker startForQuery(Context context, int serviceId, @NonNull String query, int page, EnumSet<SearchEngine.Filter> filter, OnSearchResult callback) {
|
||||
SearchWorker worker = new SearchWorker(context, serviceId, query, page, filter, callback);
|
||||
worker.start();
|
||||
return worker;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
this.callback = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWork(int serviceId) throws Exception {
|
||||
SearchEngine searchEngine = getService().getSearchEngineInstance();
|
||||
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
String searchLanguageKey = getContext().getString(R.string.search_language_key);
|
||||
String searchLanguage = sharedPreferences.getString(searchLanguageKey, getContext().getString(R.string.default_language_value));
|
||||
|
||||
final SearchResult searchResult = SearchResult.getSearchResult(searchEngine, query, page, searchLanguage, filter);
|
||||
if (callback != null && searchResult != null && !isInterrupted()) getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isInterrupted() || callback == null) return;
|
||||
|
||||
callback.onSearchResult(searchResult);
|
||||
onDestroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleException(final Exception exception, int serviceId) {
|
||||
if (callback == null || getHandler() == null || isInterrupted()) return;
|
||||
|
||||
if (exception instanceof ReCaptchaException) {
|
||||
getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onReCaptchaChallenge();
|
||||
}
|
||||
});
|
||||
} else if (exception instanceof IOException) {
|
||||
getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onSearchError(R.string.network_error);
|
||||
}
|
||||
});
|
||||
} else if (exception instanceof SearchEngine.NothingFoundException) {
|
||||
getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onNothingFound(exception.getMessage());
|
||||
}
|
||||
});
|
||||
} else if (exception instanceof ExtractionException) {
|
||||
View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null;
|
||||
ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, getServiceName(), query, R.string.parsing_error));
|
||||
getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onSearchError(R.string.parsing_error);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null;
|
||||
ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, getServiceName(), query, R.string.general_error));
|
||||
getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onSearchError(R.string.general_error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package org.schabi.newpipe.workers;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.SuggestionExtractor;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Worker that get suggestions based on the query
|
||||
*
|
||||
* @author mauriciocolli
|
||||
*/
|
||||
public class SuggestionWorker extends AbstractWorker {
|
||||
|
||||
private String query;
|
||||
private OnSuggestionResult callback;
|
||||
|
||||
/**
|
||||
* Interface which will be called for result and errors
|
||||
*/
|
||||
public interface OnSuggestionResult {
|
||||
void onSuggestionResult(@NonNull List<String> suggestions);
|
||||
void onSuggestionError(int messageId);
|
||||
}
|
||||
|
||||
public SuggestionWorker(Context context, int serviceId, String query, OnSuggestionResult callback) {
|
||||
super(context, serviceId);
|
||||
this.callback = callback;
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public static SuggestionWorker startForQuery(Context context, int serviceId, @NonNull String query, OnSuggestionResult callback) {
|
||||
SuggestionWorker worker = new SuggestionWorker(context, serviceId, query, callback);
|
||||
worker.start();
|
||||
return worker;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
this.callback = null;
|
||||
this.query = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWork(int serviceId) throws Exception {
|
||||
SuggestionExtractor suggestionExtractor = getService().getSuggestionExtractorInstance();
|
||||
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
String searchLanguageKey = getContext().getString(R.string.search_language_key);
|
||||
String searchLanguage = sharedPreferences.getString(searchLanguageKey, getContext().getString(R.string.default_language_value));
|
||||
|
||||
final List<String> suggestions = suggestionExtractor.suggestionList(query, searchLanguage);
|
||||
|
||||
if (callback != null && suggestions != null && !isInterrupted()) getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isInterrupted() || callback == null) return;
|
||||
|
||||
callback.onSuggestionResult(suggestions);
|
||||
onDestroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleException(final Exception exception, int serviceId) {
|
||||
if (callback == null || getHandler() == null || isInterrupted()) return;
|
||||
|
||||
if (exception instanceof ExtractionException) {
|
||||
View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null;
|
||||
ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.GET_SUGGESTIONS, getServiceName(), query, R.string.parsing_error));
|
||||
getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onSuggestionError(R.string.parsing_error);
|
||||
}
|
||||
});
|
||||
} else if (exception instanceof IOException) {
|
||||
getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onSuggestionError(R.string.network_error);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null;
|
||||
ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.GET_SUGGESTIONS, getServiceName(), query, R.string.general_error));
|
||||
getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onSuggestionError(R.string.general_error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue