Skip to content

Commit

Permalink
Merge branch 'central-dev' into central-master
Browse files Browse the repository at this point in the history
  • Loading branch information
RobbWatershed committed Apr 9, 2019
2 parents d172b86 + d4ebcdb commit f9eab0f
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 88 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ android {
// or Perfect Viewer implements Content URI
//noinspection ExpiringTargetSdkVersion
targetSdkVersion 23
versionCode 88
versionName '1.6.8'
versionCode 89
versionName '1.6.9'

def fkToken = '\"' + (System.getenv("FK_TOKEN")?: "")+'\"'
def includeObjectBoxBrowser = System.getenv("INCLUDE_OBJECTBOX_BROWSER")?:"false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
String[] uriContents = treeUri.getPath().split(":");
String folderName = (uriContents.length > 1) ? uriContents[1] : "";
String folderPath = paths[0] + "/" + folderName;
if (!folderName.endsWith(Consts.DEFAULT_LOCAL_DIRECTORY)) // Don't create a .Hentoid subfolder inside the .Hentoid folder the user just selected...
if (!folderName.endsWith(Consts.DEFAULT_LOCAL_DIRECTORY.substring(1))) // Don't create a .Hentoid subfolder inside the .Hentoid (or Hentoid) folder the user just selected...
{
if (!folderPath.endsWith("/")) folderPath += "/";
folderPath += Consts.DEFAULT_LOCAL_DIRECTORY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ public abstract class BaseWebActivity extends BaseActivity implements ResultList
universalBlockedContent.add("adtng.com");
universalBlockedContent.add("popads.net");
universalBlockedContent.add("adsco.re");
universalBlockedContent.add("ads.exosrv.com");
universalBlockedContent.add("s24hc8xzag.com");
universalBlockedContent.add("/nutaku/");
}

protected abstract CustomWebViewClient getWebClient();
Expand Down Expand Up @@ -347,6 +348,8 @@ void processDownload() {

if (currentContent.getId() > 0) currentContent = db.selectContentById(currentContent.getId());

if (null == currentContent) return;

if (currentContent != null && StatusContent.DOWNLOADED == currentContent.getStatus()) {
ToastUtil.toast(this, R.string.already_downloaded);
changeFabActionMode(MODE_READ);
Expand Down
127 changes: 73 additions & 54 deletions app/src/main/java/me/devsaki/hentoid/adapters/ContentAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
Expand All @@ -29,6 +28,7 @@
import java.util.Date;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
Expand Down Expand Up @@ -163,7 +163,7 @@ public void onBindViewHolder(@NonNull ContentHolder holder, final int pos) {
attachSeries(holder, content);
attachArtist(holder, content);
attachTags(holder, content);
attachButtons(holder, content, pos);
attachButtons(holder, content);
attachOnClickListeners(holder, content, pos);
}

Expand Down Expand Up @@ -290,7 +290,7 @@ private void attachTags(ContentHolder holder, Content content) {
holder.tvTags.setText(Helper.fromHtml(tagsBuilder.toString()));
}

private void attachButtons(ContentHolder holder, final Content content, int pos) {
private void attachButtons(ContentHolder holder, final Content content) {
// Set source icon
if (content.getSite() != null) {
int img = content.getSite().getIco();
Expand Down Expand Up @@ -446,35 +446,38 @@ private void downloadAgain(final Content item) {
int images;
int imgErrors = 0;

images = item.getImageFiles().size();
if (item.getImageFiles() != null) {
images = item.getImageFiles().size();

for (ImageFile imgFile : item.getImageFiles()) {
if (imgFile.getStatus() == StatusContent.ERROR) {
imgErrors++;
for (ImageFile imgFile : item.getImageFiles()) {
if (imgFile.getStatus() == StatusContent.ERROR) {
imgErrors++;
}
}
}

String message = context.getString(R.string.redownload_dialog_message).replace("@clean", images - imgErrors + "").replace("@error", imgErrors + "").replace("@total", images + "");
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.redownload_dialog_title)
.setMessage(message)
.setPositiveButton(android.R.string.yes,
(dialog, which) -> {
downloadContent(item);
remove(item);
})
.setNegativeButton(android.R.string.no, null)
.setNeutralButton(R.string.redownload_view_log,
(dialog, which) -> showErrorLog(item))
.create().show();
String message = context.getString(R.string.redownload_dialog_message).replace("@clean", images - imgErrors + "").replace("@error", imgErrors + "").replace("@total", images + "");
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.redownload_dialog_title)
.setMessage(message)
.setPositiveButton(android.R.string.yes,
(dialog, which) -> {
downloadContent(item);
remove(item);
})
.setNegativeButton(android.R.string.no, null)
.setNeutralButton(R.string.redownload_view_log,
(dialog, which) -> showErrorLog(item))
.create().show();
}
}

private void downloadContent(Content item) {
ObjectBoxDB db = ObjectBoxDB.getInstance(context);

if (StatusContent.ONLINE == item.getStatus())
for (ImageFile im : item.getImageFiles())
db.updateImageFileStatusAndParams(im.setStatus(StatusContent.SAVED));
if (item.getImageFiles() != null)
for (ImageFile im : item.getImageFiles())
db.updateImageFileStatusAndParams(im.setStatus(StatusContent.SAVED));

item.setDownloadDate(new Date().getTime());
item.setStatus(StatusContent.DOWNLOADING);
Expand All @@ -501,8 +504,10 @@ private void showErrorLog(final Content content) {
errorLogInfo.fileName = "error_log" + content.getId();
errorLogInfo.noDataMessage = "No error detected.";

log.add("Error log for " + content.getTitle() + " : " + errorLog.size() + " errors");
for (ErrorRecord e : errorLog) log.add(e.toString());
if (errorLog != null) {
log.add("Error log for " + content.getTitle() + " : " + errorLog.size() + " errors");
for (ErrorRecord e : errorLog) log.add(e.toString());
}

File logFile = LogUtil.writeLog(context, log, errorLogInfo);
if (logFile != null) {
Expand Down Expand Up @@ -534,10 +539,7 @@ private void deleteContent(final Content item) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.ask_delete)
.setPositiveButton(android.R.string.yes,
(dialog, which) -> {
clearSelections();
deleteItem(item);
})
(dialog, which) -> deleteItem(item))
.setNegativeButton(android.R.string.no,
(dialog, which) -> {
clearSelections();
Expand Down Expand Up @@ -711,38 +713,55 @@ public void archiveSelectedItems() {
}

private void deleteItem(final Content item) {
remove(item);

clearSelections();
compositeDisposable.add(
Single.fromCallable(() -> deleteContent(item.getId()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
result -> {
remove(result);
ToastUtil.toast(context, context.getString(R.string.deleted).replace("@content", item.getTitle()));
},
Timber::e
)
);
}

private Content deleteContent(long contentId) {
ObjectBoxDB db = ObjectBoxDB.getInstance(context);
AsyncTask.execute(() -> {
FileHelper.removeContent(item);
db.deleteContent(item);
Timber.d("Removed item: %s from db and file system.", item.getTitle());
});
Content content = db.selectContentById(contentId);

ToastUtil.toast(context, context.getString(R.string.deleted).replace("@content", item.getTitle()));
}
if (content != null) {
FileHelper.removeContent(content);
db.deleteContent(content);
Timber.d("Removed item: %s from db and file system.", content.getTitle());

private void deleteItems(final List<Content> contents) {
mSortedList.beginBatchedUpdates();
for (Content content : contents) {
mSortedList.remove(content);
return content;
}
onContentRemovedListener.accept(contents.size());
mSortedList.endBatchedUpdates();
itemSelectListener.onItemClear(0);
throw new InvalidParameterException("ContentId " + contentId + " does not refer to a valid content");
}

ObjectBoxDB db = ObjectBoxDB.getInstance(context);
private void deleteItems(final List<Content> contents) {

AsyncTask.execute(() -> {
for (Content item : contents) {
FileHelper.removeContent(item);
db.deleteContent(item);
Timber.d("Removed item: %s from db and file system.", item.getTitle());
}
});
mSortedList.beginBatchedUpdates();

ToastUtil.toast(context, "Selected items have been deleted.");
compositeDisposable.add(
Observable.fromIterable(contents)
.subscribeOn(Schedulers.io())
.flatMap(s -> Observable.fromCallable(() -> deleteContent(s.getId())))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
mSortedList::remove,
Timber::e,
() -> {
onContentRemovedListener.accept(contents.size());
mSortedList.endBatchedUpdates();
itemSelectListener.onItemClear(0);
ToastUtil.toast(context, "Selected items have been deleted.");
}
)
);
}

private void remove(Content content) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ private void populateLayout(ViewHolder holder, Content content) {
attachSeries(holder, content);
attachArtist(holder, content);
attachTags(holder, content);

holder.ivSource.setImageResource(content.getSite().getIco());
attachSource(holder, content);
}

/**
Expand Down Expand Up @@ -224,6 +223,22 @@ private void attachTags(ViewHolder holder, Content content) {
holder.tvTags.setText(Helper.fromHtml(tags.toString()));
}

/**
* Build the source icon layout of the book viewholder using the designated Content properties
*
* @param holder Holder to populate
* @param content Content to display
*/
private void attachSource(ViewHolder holder, Content content) {
if (content.getSite() != null) {
int img = content.getSite().getIco();
holder.ivSource.setImageResource(img);
holder.ivSource.setOnClickListener(v -> Helper.viewContent(context, content));
} else {
holder.ivSource.setImageResource(R.drawable.ic_stat_hentoid);
}
}

/**
* Build the buttons of the book viewholder using the designated Content properties
*
Expand Down
45 changes: 23 additions & 22 deletions app/src/main/java/me/devsaki/hentoid/database/ObjectBoxDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,31 +169,32 @@ private void deleteContentById(long[] contentId) {

for (long id : contentId) {
Content c = contentBox.get(id);
store.runInTx(() -> {
if (c.getImageFiles() != null) {
for (ImageFile i : c.getImageFiles())
imageFileBox.remove(i); // Delete imageFiles
c.getImageFiles().clear(); // Clear links to all imageFiles
}

if (c.getErrorLog() != null) {
for (ErrorRecord e : c.getErrorLog())
errorBox.remove(e); // Delete error records
c.getErrorLog().clear(); // Clear links to all errorRecords
}
if (c != null)
store.runInTx(() -> {
if (c.getImageFiles() != null) {
for (ImageFile i : c.getImageFiles())
imageFileBox.remove(i); // Delete imageFiles
c.getImageFiles().clear(); // Clear links to all imageFiles
}

// Delete attribute when current content is the only content left on the attribute
for (Attribute a : c.getAttributes())
if (1 == a.contents.size()) {
for (AttributeLocation l : a.getLocations())
locationBox.remove(l); // Delete all locations
a.getLocations().clear(); // Clear location links
attributeBox.remove(a); // Delete the attribute itself
if (c.getErrorLog() != null) {
for (ErrorRecord e : c.getErrorLog())
errorBox.remove(e); // Delete error records
c.getErrorLog().clear(); // Clear links to all errorRecords
}
c.getAttributes().clear(); // Clear links to all attributes

contentBox.remove(c); // Remove the content itself
});
// Delete attribute when current content is the only content left on the attribute
for (Attribute a : c.getAttributes())
if (1 == a.contents.size()) {
for (AttributeLocation l : a.getLocations())
locationBox.remove(l); // Delete all locations
a.getLocations().clear(); // Clear location links
attributeBox.remove(a); // Delete the attribute itself
}
c.getAttributes().clear(); // Clear links to all attributes

contentBox.remove(c); // Remove the content itself
});
}
}

Expand Down
21 changes: 16 additions & 5 deletions app/src/main/java/me/devsaki/hentoid/parsers/HitomiParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
import org.jsoup.select.Elements;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import me.devsaki.hentoid.database.domains.Content;
import me.devsaki.hentoid.database.domains.ImageFile;
import me.devsaki.hentoid.util.JsonHelper;
import timber.log.Timber;

import static me.devsaki.hentoid.util.HttpHelper.getOnlineDocument;
Expand All @@ -16,16 +20,15 @@
* Created by neko on 08/07/2015.
* Handles parsing of content from hitomi.la
*/
public class HitomiParser extends BaseParser {
public class HitomiParser implements ContentParser {

// Reproduction of the Hitomi.la Javascript to find the hostname of the image server (see subdomain_from_url@reader.js)
private final static int NUMBER_OF_FRONTENDS = 2;
private final static String HOSTNAME_SUFFIX = "a";
private final static char HOSTNAME_PREFIX_BASE = 97;

@Override
protected List<String> parseImages(Content content) throws Exception {
List<String> result = new ArrayList<>();
public List<ImageFile> parseImageList(Content content) throws Exception {
List<ImageFile> result = new ArrayList<>();

Document doc = getOnlineDocument(content.getReaderUrl());
if (doc != null) {
Expand All @@ -44,8 +47,16 @@ protected List<String> parseImages(Content content) throws Exception {
referenceId = 0; // Yes, this is what Hitomi actually does (see common.js)
String imageSubdomain = Character.toString((char) (HOSTNAME_PREFIX_BASE + (referenceId % NUMBER_OF_FRONTENDS))) + HOSTNAME_SUFFIX;

Map<String, String> downloadParams = new HashMap<>();
// Add referer information to downloadParams for future image download
downloadParams.put("referer", content.getReaderUrl());
String downloadParamsStr = JsonHelper.serializeToJson(downloadParams);

int order = 1;
for (Element element : imgElements) {
result.add("https:" + replaceSubdomainWith(element.text(), imageSubdomain));
ImageFile img = ParseHelper.urlToImageFile("https:" + replaceSubdomainWith(element.text(), imageSubdomain), order++);
img.setDownloadParams(downloadParamsStr);
result.add(img);
}
} else {
Timber.w("Document null @ %s", content.getReaderUrl());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static OkHttpClient getInstance(int timeoutMs) {
private static okhttp3.Response onIntercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request()
.newBuilder()
.header("User-Agent", Consts.USER_AGENT)
.header("User-Agent", Consts.USER_AGENT_NEUTRAL)
.build();
return chain.proceed(request);
}
Expand Down

0 comments on commit f9eab0f

Please sign in to comment.