Rename project

This commit is contained in:
inorichi
2016-01-15 15:18:19 +01:00
parent 1508bf42fb
commit 70f4c7fcc3
167 changed files with 647 additions and 654 deletions

View File

@@ -0,0 +1,33 @@
package eu.kanade.tachiyomi.util;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import timber.log.Timber;
public class AndroidComponentUtil {
public static void toggleComponent(Context context, Class componentClass, boolean enable) {
Timber.i((enable ? "Enabling " : "Disabling ") + componentClass.getSimpleName());
ComponentName componentName = new ComponentName(context, componentClass);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(componentName,
enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
public static boolean isServiceRunning(Context context, Class serviceClass) {
ActivityManager manager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,127 @@
package eu.kanade.tachiyomi.util;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import eu.kanade.tachiyomi.data.database.models.Chapter;
import eu.kanade.tachiyomi.data.database.models.Manga;
public class ChapterRecognition {
private static final Pattern p1 = Pattern.compile("ch[^0-9]?\\s*(\\d+[\\.,]?\\d*)");
private static final Pattern p2 = Pattern.compile("(\\d+[\\.,]?\\d*)");
private static final Pattern p3 = Pattern.compile("(\\d+[\\.,]?\\d*\\s*:)");
private static final Pattern pUnwanted =
Pattern.compile("\\b(v|ver|vol|version|volume)\\.?\\s*\\d+\\b");
public static void parseChapterNumber(Chapter chapter, Manga manga) {
if (chapter.chapter_number != -1)
return;
String name = chapter.name.toLowerCase();
Matcher matcher;
// Safest option, the chapter has a token prepended
matcher = p1.matcher(name);
if (matcher.find()) {
chapter.chapter_number = Float.parseFloat(matcher.group(1));
return;
}
// Remove anything related to the volume or version
name = pUnwanted.matcher(name).replaceAll("");
List<Float> occurrences;
// If there's only one number, use it
matcher = p2.matcher(name);
occurrences = getAllOccurrences(matcher);
if (occurrences.size() == 1) {
chapter.chapter_number = occurrences.get(0);
return;
}
// If it has a colon, the chapter number should be that one
matcher = p3.matcher(name);
occurrences = getAllOccurrences(matcher);
if (occurrences.size() == 1) {
chapter.chapter_number = occurrences.get(0);
return;
}
// This can lead to issues if two numbers are separated by an space
name = name.replaceAll("\\s+", "");
// Try to remove the manga name from the chapter, and try again
String mangaName = replaceIrrelevantCharacters(manga.title);
String nameWithoutManga = difference(mangaName, name);
if (!nameWithoutManga.isEmpty()) {
matcher = p2.matcher(nameWithoutManga);
occurrences = getAllOccurrences(matcher);
if (occurrences.size() == 1) {
chapter.chapter_number = occurrences.get(0);
return;
}
}
// TODO more checks (maybe levenshtein?)
}
public static List<Float> getAllOccurrences(Matcher matcher) {
List<Float> occurences = new ArrayList<>();
while (matcher.find()) {
// Match again to get only numbers from the captured text
String text = matcher.group();
Matcher m = p2.matcher(text);
if (m.find()) {
try {
Float value = Float.parseFloat(m.group(1));
if (!occurences.contains(value)) {
occurences.add(value);
}
} catch (NumberFormatException e) { /* Do nothing */ }
}
}
return occurences;
}
public static String replaceIrrelevantCharacters(String str) {
return str.replaceAll("\\s+", "").toLowerCase();
}
public static String difference(String str1, String str2) {
if (str1 == null) {
return str2;
}
if (str2 == null) {
return str1;
}
int at = indexOfDifference(str1, str2);
if (at == -1) {
return "";
}
return str2.substring(at);
}
public static int indexOfDifference(String str1, String str2) {
if (str1 == str2) {
return -1;
}
if (str1 == null || str2 == null) {
return 0;
}
int i;
for (i = 0; i < str1.length() && i < str2.length(); ++i) {
if (str1.charAt(i) != str2.charAt(i)) {
break;
}
}
if (i < str2.length() || i < str1.length()) {
return i;
}
return -1;
}
}

View File

@@ -0,0 +1,100 @@
package eu.kanade.tachiyomi.util;
import java.io.File;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;
public final class DiskUtils {
private DiskUtils() {
throw new AssertionError();
}
public static String hashKeyForDisk(String key) {
String cacheKey;
try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(key.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(key.hashCode());
}
return cacheKey;
}
private static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
public static File saveBufferedSourceToDirectory(BufferedSource bufferedSource, File directory, String name) throws IOException {
createDirectory(directory);
File writeFile = new File(directory, name);
if (writeFile.exists()) {
if (writeFile.delete()) {
writeFile = new File(directory, name);
} else {
throw new IOException("Failed Deleting Existing File for Overwrite");
}
}
BufferedSink bufferedSink = null;
try {
bufferedSink = Okio.buffer(Okio.sink(writeFile));
bufferedSink.writeAll(bufferedSource);
} catch (Exception e) {
writeFile.delete();
throw new IOException("Unable to save image");
} finally {
if (bufferedSink != null) {
bufferedSink.close();
}
}
return writeFile;
}
public static void deleteFiles(File inputFile) {
if (inputFile.isDirectory()) {
for (File childFile : inputFile.listFiles()) {
deleteFiles(childFile);
}
}
inputFile.delete();
}
public static synchronized void createDirectory(File directory) throws IOException {
if (!directory.exists() && !directory.mkdirs()) {
throw new IOException("Failed creating directory");
}
}
public static long getDirectorySize(File f) {
long size = 0;
if (f.isDirectory()) {
for (File file : f.listFiles()) {
size += getDirectorySize(file);
}
} else {
size=f.length();
}
return size;
}
}

View File

@@ -0,0 +1,186 @@
package eu.kanade.tachiyomi.util;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import rx.Observable;
import rx.Observable.Operator;
import rx.Subscriber;
import rx.Subscription;
import rx.functions.Func1;
import rx.subscriptions.CompositeSubscription;
import rx.subscriptions.Subscriptions;
public class DynamicConcurrentMergeOperator<T, R> implements Operator<R, T> {
final Func1<? super T, ? extends Observable<? extends R>> mapper;
final Observable<Integer> workerCount;
public DynamicConcurrentMergeOperator(
Func1<? super T, ? extends Observable<? extends R>> mapper,
Observable<Integer> workerCount) {
this.mapper = mapper;
this.workerCount = workerCount;
}
@Override
public Subscriber<? super T> call(Subscriber<? super R> t) {
DynamicConcurrentMerge<T, R> parent = new DynamicConcurrentMerge<>(t, mapper);
t.add(parent);
parent.init(workerCount);
return parent;
}
static final class DynamicConcurrentMerge<T, R> extends Subscriber<T> {
final Subscriber<? super R> actual;
final Func1<? super T, ? extends Observable<? extends R>> mapper;
final Queue<T> queue;
final CopyOnWriteArrayList<DynamicWorker<T, R>> workers;
final CompositeSubscription composite;
final AtomicInteger wipActive;
final AtomicBoolean once;
long id;
public DynamicConcurrentMerge(Subscriber<? super R> actual,
Func1<? super T, ? extends Observable<? extends R>> mapper) {
this.actual = actual;
this.mapper = mapper;
this.queue = new ConcurrentLinkedQueue<>();
this.workers = new CopyOnWriteArrayList<>();
this.composite = new CompositeSubscription();
this.wipActive = new AtomicInteger(1);
this.once = new AtomicBoolean();
this.add(composite);
this.request(0);
}
public void init(Observable<Integer> workerCount) {
Subscription wc = workerCount.subscribe(n -> {
int n0 = workers.size();
if (n0 < n) {
for (int i = n0; i < n; i++) {
DynamicWorker<T, R> dw = new DynamicWorker<>(++id, this);
workers.add(dw);
request(1);
dw.tryNext();
}
} else if (n0 > n) {
for (int i = 0; i < n; i++) {
workers.get(i).start();
}
for (int i = n0 - 1; i >= n; i--) {
workers.get(i).stop();
}
}
if (!once.get() && once.compareAndSet(false, true)) {
request(n);
}
}, this::onError);
composite.add(wc);
}
void requestMore(long n) {
request(n);
}
@Override
public void onNext(T t) {
queue.offer(t);
wipActive.getAndIncrement();
for (DynamicWorker<T, R> w : workers) {
w.tryNext();
}
}
@Override
public void onError(Throwable e) {
composite.unsubscribe();
actual.onError(e);
}
@Override
public void onCompleted() {
if (wipActive.decrementAndGet() == 0) {
actual.onCompleted();
}
}
}
static final class DynamicWorker<T, R> {
final long id;
final AtomicBoolean running;
final DynamicConcurrentMerge<T, R> parent;
final AtomicBoolean stop;
public DynamicWorker(long id, DynamicConcurrentMerge<T, R> parent) {
this.id = id;
this.parent = parent;
this.stop = new AtomicBoolean();
this.running = new AtomicBoolean();
}
public void tryNext() {
if (!running.get() && running.compareAndSet(false, true)) {
T t;
if (stop.get()) {
parent.workers.remove(this);
return;
}
t = parent.queue.poll();
if (t == null) {
running.set(false);
return;
}
Observable out = parent.mapper.call(t);
Subscriber<R> s = new Subscriber<R>() {
@Override
public void onNext(R t) {
parent.actual.onNext(t);
}
@Override
public void onError(Throwable e) {
parent.onError(e);
}
@Override
public void onCompleted() {
parent.onCompleted();
if (parent.wipActive.get() != 0) {
running.set(false);
parent.requestMore(1);
tryNext();
}
}
};
parent.composite.add(s);
s.add(Subscriptions.create(() -> parent.composite.remove(s)));
// Unchecked assignment to avoid weird Android Studio errors
out.subscribe(s);
}
}
public void start() {
stop.set(false);
tryNext();
}
public void stop() {
stop.set(true);
if (running.compareAndSet(false, true)) {
parent.workers.remove(this);
}
}
}
}

View File

@@ -0,0 +1,7 @@
package eu.kanade.tachiyomi.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
public @interface EventBusHook {}

View File

@@ -0,0 +1,50 @@
package eu.kanade.tachiyomi.util;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
public class GLUtil {
public static int getMaxTextureSize() {
// Safe minimum default size
final int IMAGE_MAX_BITMAP_DIMENSION = 2048;
// Get EGL Display
EGL10 egl = (EGL10) EGLContext.getEGL();
EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
// Initialise
int[] version = new int[2];
egl.eglInitialize(display, version);
// Query total number of configurations
int[] totalConfigurations = new int[1];
egl.eglGetConfigs(display, null, 0, totalConfigurations);
// Query actual list configurations
EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]];
egl.eglGetConfigs(display, configurationsList, totalConfigurations[0], totalConfigurations);
int[] textureSize = new int[1];
int maximumTextureSize = 0;
// Iterate through all the configurations to located the maximum texture size
for (int i = 0; i < totalConfigurations[0]; i++) {
// Only need to check for width since opengl textures are always squared
egl.eglGetConfigAttrib(display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize);
// Keep track of the maximum texture size
if (maximumTextureSize < textureSize[0])
maximumTextureSize = textureSize[0];
}
// Release
egl.eglTerminate(display);
// Return largest texture size found, or default
return Math.max(maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION);
}
}

View File

@@ -0,0 +1,16 @@
package eu.kanade.tachiyomi.util;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
public class NetworkUtil {
public static boolean isNetworkConnected(Context context) {
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}
}

View File

@@ -0,0 +1,48 @@
package eu.kanade.tachiyomi.util;
import android.support.annotation.Nullable;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class Parser {
@Nullable
public static Element element(Element container, String pattern) {
return container.select(pattern).first();
}
@Nullable
public static String text(Element container, String pattern) {
return text(container, pattern, null);
}
@Nullable
public static String text(Element container, String pattern, String defValue) {
Element element = container.select(pattern).first();
return element != null ? element.text() : defValue;
}
@Nullable
public static String allText(Element container, String pattern) {
Elements elements = container.select(pattern);
return !elements.isEmpty() ? elements.text() : null;
}
@Nullable
public static String attr(Element container, String pattern, String attr) {
Element element = container.select(pattern).first();
return element != null ? element.attr(attr) : null;
}
@Nullable
public static String href(Element container, String pattern) {
return attr(container, pattern, "href");
}
@Nullable
public static String src(Element container, String pattern) {
return attr(container, pattern, "src");
}
}

View File

@@ -0,0 +1,32 @@
package eu.kanade.tachiyomi.util;
import rx.Observable;
import rx.subjects.PublishSubject;
public class RxPager {
private final int initialPageCount;
private final PublishSubject<Integer> requests = PublishSubject.create();
private int requestedCount;
public RxPager() {
this(1);
}
public RxPager(int initialPageCount) {
this.initialPageCount = initialPageCount;
}
public void requestNext(int page) {
requests.onNext(page);
}
public Observable<Integer> pages() {
return requests
.concatMap(targetPage -> targetPage <= requestedCount ?
Observable.<Integer>empty() :
Observable.range(requestedCount, targetPage - requestedCount))
.startWith(Observable.range(0, initialPageCount))
.doOnNext(it -> requestedCount = it + 1);
}
}

View File

@@ -0,0 +1,24 @@
package eu.kanade.tachiyomi.util;
import android.content.Context;
import android.widget.Toast;
public class ToastUtil {
public static void showShort(Context context, int resourceId) {
Toast.makeText(context, resourceId, Toast.LENGTH_SHORT).show();
}
public static void showLong(Context context, int resourceId) {
Toast.makeText(context, resourceId, Toast.LENGTH_LONG).show();
}
public static void showShort(Context context, String message) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
public static void showLong(Context context, String message) {
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
}
}

View File

@@ -0,0 +1,21 @@
package eu.kanade.tachiyomi.util;
import java.net.URI;
import java.net.URISyntaxException;
public class UrlUtil {
public static String getPath(String s) {
try {
URI uri = new URI(s);
String out = uri.getPath();
if (uri.getQuery() != null)
out += "?" + uri.getQuery();
if (uri.getFragment() != null)
out += "#" + uri.getFragment();
return out;
} catch (URISyntaxException e) {
return s;
}
}
}