Add new workers
This commit is contained in:
parent
ee592def0c
commit
a4b61bf730
7 changed files with 368 additions and 414 deletions
|
@ -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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
118
app/src/main/java/org/schabi/newpipe/workers/AbstractWorker.java
Normal file
118
app/src/main/java/org/schabi/newpipe/workers/AbstractWorker.java
Normal file
|
@ -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
|
* Interface which will be called for result and errors
|
||||||
*/
|
*/
|
||||||
public interface OnChannelInfoReceive {
|
public interface OnChannelInfoReceive {
|
||||||
void onReceive(ChannelInfo info);
|
void onReceive(ChannelInfo info, boolean onlyVideos);
|
||||||
void onError(int messageId);
|
void onError(int messageId);
|
||||||
/**
|
/**
|
||||||
* Called when an unrecoverable error has occurred.
|
* Called when an unrecoverable error has occurred.
|
||||||
|
@ -44,12 +44,15 @@ public class ChannelExtractorWorker extends ExtractorWorker {
|
||||||
* @param context context for error reporting purposes
|
* @param context context for error reporting purposes
|
||||||
* @param serviceId id of the request service
|
* @param serviceId id of the request service
|
||||||
* @param channelUrl channelUrl of the service (e.g. https://www.youtube.com/channel/UC_aEa8K-EOJ3D6gOs7HcyNg)
|
* @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})
|
* @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);
|
super(context, channelUrl, serviceId);
|
||||||
this.pageNumber = pageNumber;
|
this.pageNumber = pageNumber;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
this.onlyVideos = onlyVideos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -71,7 +74,7 @@ public class ChannelExtractorWorker extends ExtractorWorker {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isInterrupted() || callback == null) return;
|
if (isInterrupted() || callback == null) return;
|
||||||
|
|
||||||
callback.onReceive(channelInfo);
|
callback.onReceive(channelInfo, onlyVideos);
|
||||||
onDestroy();
|
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.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
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 org.schabi.newpipe.report.ErrorActivity;
|
||||||
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common properties of ExtractorWorkers
|
* Common properties of ExtractorWorkers
|
||||||
|
@ -21,38 +15,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
* @author mauriciocolli
|
* @author mauriciocolli
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public abstract class ExtractorWorker extends Thread {
|
public abstract class ExtractorWorker extends AbstractWorker {
|
||||||
|
|
||||||
private final AtomicBoolean isRunning = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
private final String url;
|
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) {
|
public ExtractorWorker(Context context, String url, int serviceId) {
|
||||||
this.context = context;
|
super(context, serviceId);
|
||||||
this.url = url;
|
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()));
|
if (url.length() >= 40) setName("Thread-" + url.substring(url.length() - 11, url.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
protected void doWork(int serviceId) throws Exception {
|
||||||
try {
|
doWork(serviceId, url);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,6 +39,10 @@ public abstract class ExtractorWorker extends Thread {
|
||||||
*/
|
*/
|
||||||
protected abstract void doWork(int serviceId, String url) throws Exception;
|
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)}.
|
* 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) {
|
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 */));
|
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() {
|
public String getUrl() {
|
||||||
return url;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
127
app/src/main/java/org/schabi/newpipe/workers/SearchWorker.java
Normal file
127
app/src/main/java/org/schabi/newpipe/workers/SearchWorker.java
Normal file
|
@ -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 a new issue