Search in sources :

Example 1 with DownloadErrorNotification

use of me.devsaki.hentoid.notification.download.DownloadErrorNotification in project Hentoid by avluis.

the class ContentDownloadWorker method moveToErrors.

private void moveToErrors(long contentId) {
    Content content = dao.selectContent(contentId);
    if (null == content)
        return;
    content.setStatus(StatusContent.ERROR);
    // Needs a download date to appear the right location when sorted by download date
    content.setDownloadDate(Instant.now().toEpochMilli());
    dao.insertContent(content);
    dao.deleteQueue(content);
    HentoidApp.trackDownloadEvent("Error");
    Context context = getApplicationContext();
    if (ContentHelper.updateQueueJson(context, dao))
        Timber.i(context.getString(R.string.queue_json_saved));
    else
        Timber.w(context.getString(R.string.queue_json_failed));
    notificationManager.notify(new DownloadErrorNotification(content));
}
Also used : Context(android.content.Context) Content(me.devsaki.hentoid.database.domains.Content) JsonContent(me.devsaki.hentoid.json.JsonContent) StatusContent(me.devsaki.hentoid.enums.StatusContent) DownloadErrorNotification(me.devsaki.hentoid.notification.download.DownloadErrorNotification)

Example 2 with DownloadErrorNotification

use of me.devsaki.hentoid.notification.download.DownloadErrorNotification in project Hentoid by avluis.

the class ContentDownloadWorker method completeDownload.

/**
 * Completes the download of a book when all images have been processed
 * Then launches a new IntentService
 *
 * @param contentId Id of the Content to mark as downloaded
 */
private void completeDownload(final long contentId, @NonNull final String title, final int pagesOK, final int pagesKO, final long sizeDownloadedBytes) {
    ContentQueueManager contentQueueManager = ContentQueueManager.getInstance();
    // Get the latest value of Content
    Content content = dao.selectContent(contentId);
    if (null == content) {
        Timber.w("Content ID %s not found", contentId);
        return;
    }
    if (!downloadInterrupted.get()) {
        List<ImageFile> images = content.getImageFiles();
        if (null == images)
            images = Collections.emptyList();
        // Don't count the cover
        int nbImages = (int) Stream.of(images).filter(i -> !i.isCover()).count();
        boolean hasError = false;
        // Set error state if less pages than initially detected - More than 10% difference in number of pages
        if (content.getQtyPages() > 0 && nbImages < content.getQtyPages() && Math.abs(nbImages - content.getQtyPages()) > content.getQtyPages() * 0.1) {
            String errorMsg = String.format("The number of images found (%s) does not match the book's number of pages (%s)", nbImages, content.getQtyPages());
            logErrorRecord(contentId, ErrorType.PARSING, content.getGalleryUrl(), "pages", errorMsg);
            hasError = true;
        }
        // Set error state if there are non-downloaded pages
        // NB : this should not happen theoretically
        long nbDownloadedPages = content.getNbDownloadedPages();
        if (nbDownloadedPages < content.getQtyPages()) {
            Timber.i(">> downloaded vs. qty KO %s vs %s", nbDownloadedPages, content.getQtyPages());
            String errorMsg = String.format("The number of downloaded images (%s) does not match the book's number of pages (%s)", nbDownloadedPages, content.getQtyPages());
            logErrorRecord(contentId, ErrorType.PARSING, content.getGalleryUrl(), "pages", errorMsg);
            hasError = true;
        }
        // update the book's number of pages and download date
        if (nbImages > content.getQtyPages()) {
            content.setQtyPages(nbImages);
            content.setDownloadDate(Instant.now().toEpochMilli());
        }
        if (content.getStorageUri().isEmpty())
            return;
        DocumentFile dir = FileHelper.getFolderFromTreeUriString(getApplicationContext(), content.getStorageUri());
        if (dir != null) {
            // TODO - test to make sure the service's thread continues to run in such a scenario
            if (pagesKO > 0 && Preferences.isDlRetriesActive() && content.getNumberDownloadRetries() < Preferences.getDlRetriesNumber()) {
                double freeSpaceRatio = new FileHelper.MemoryUsageFigures(getApplicationContext(), dir).getFreeUsageRatio100();
                if (freeSpaceRatio < Preferences.getDlRetriesMemLimit()) {
                    Timber.i("Initiating auto-retry #%s for content %s (%s%% free space)", content.getNumberDownloadRetries() + 1, content.getTitle(), freeSpaceRatio);
                    logErrorRecord(content.getId(), ErrorType.UNDEFINED, "", content.getTitle(), "Auto-retry #" + content.getNumberDownloadRetries());
                    content.increaseNumberDownloadRetries();
                    // Re-queue all failed images
                    for (ImageFile img : images) if (img.getStatus().equals(StatusContent.ERROR)) {
                        Timber.i("Auto-retry #%s for content %s / image @ %s", content.getNumberDownloadRetries(), content.getTitle(), img.getUrl());
                        img.setStatus(StatusContent.SAVED);
                        dao.insertImageFile(img);
                        requestQueueManager.queueRequest(buildImageDownloadRequest(img, dir, content));
                    }
                    return;
                }
            }
            // Compute perceptual hash for the cover picture
            ContentHelper.computeAndSaveCoverHash(getApplicationContext(), content, dao);
            // Mark content as downloaded
            if (0 == content.getDownloadDate())
                content.setDownloadDate(Instant.now().toEpochMilli());
            content.setStatus((0 == pagesKO && !hasError) ? StatusContent.DOWNLOADED : StatusContent.ERROR);
            // Clear download params from content
            if (0 == pagesKO && !hasError)
                content.setDownloadParams("");
            content.computeSize();
            // Save JSON file
            try {
                DocumentFile jsonFile = JsonHelper.jsonToFile(getApplicationContext(), JsonContent.fromEntity(content), JsonContent.class, dir);
                // Cache its URI to the newly created content
                if (jsonFile != null) {
                    content.setJsonUri(jsonFile.getUri().toString());
                } else {
                    Timber.w("JSON file could not be cached for %s", title);
                }
            } catch (IOException e) {
                Timber.e(e, "I/O Error saving JSON: %s", title);
            }
            ContentHelper.addContent(getApplicationContext(), dao, content);
            Timber.i("Content download finished: %s [%s]", title, contentId);
            // Delete book from queue
            dao.deleteQueue(content);
            // Increase downloads count
            contentQueueManager.downloadComplete();
            if (0 == pagesKO) {
                int downloadCount = contentQueueManager.getDownloadCount();
                notificationManager.notify(new DownloadSuccessNotification(downloadCount));
                // Tracking Event (Download Success)
                HentoidApp.trackDownloadEvent("Success");
            } else {
                notificationManager.notify(new DownloadErrorNotification(content));
                // Tracking Event (Download Error)
                HentoidApp.trackDownloadEvent("Error");
            }
            // Signals current download as completed
            Timber.d("CompleteActivity : OK = %s; KO = %s", pagesOK, pagesKO);
            EventBus.getDefault().post(new DownloadEvent(content, DownloadEvent.Type.EV_COMPLETE, pagesOK, pagesKO, nbImages, sizeDownloadedBytes));
            Context context = getApplicationContext();
            if (ContentHelper.updateQueueJson(context, dao))
                Timber.i(context.getString(R.string.queue_json_saved));
            else
                Timber.w(context.getString(R.string.queue_json_failed));
            // Tracking Event (Download Completed)
            HentoidApp.trackDownloadEvent("Completed");
        } else {
            Timber.w("completeDownload : Directory %s does not exist - JSON not saved", content.getStorageUri());
        }
    } else if (downloadCanceled.get()) {
        Timber.d("Content download canceled: %s [%s]", title, contentId);
        notificationManager.cancel();
    } else {
        Timber.d("Content download skipped : %s [%s]", title, contentId);
    }
}
Also used : Context(android.content.Context) DocumentFile(androidx.documentfile.provider.DocumentFile) ImageFile(me.devsaki.hentoid.database.domains.ImageFile) DownloadEvent(me.devsaki.hentoid.events.DownloadEvent) DownloadSuccessNotification(me.devsaki.hentoid.notification.download.DownloadSuccessNotification) ContentQueueManager(me.devsaki.hentoid.util.download.ContentQueueManager) IOException(java.io.IOException) DownloadErrorNotification(me.devsaki.hentoid.notification.download.DownloadErrorNotification) SuppressLint(android.annotation.SuppressLint) FileHelper(me.devsaki.hentoid.util.FileHelper) Content(me.devsaki.hentoid.database.domains.Content) JsonContent(me.devsaki.hentoid.json.JsonContent) StatusContent(me.devsaki.hentoid.enums.StatusContent)

Example 3 with DownloadErrorNotification

use of me.devsaki.hentoid.notification.download.DownloadErrorNotification in project Hentoid by avluis.

the class ContentDownloadWorker method downloadFirstInQueue.

/**
 * Start the download of the 1st book of the download queue
 * <p>
 * NB : This method is not only called the 1st time the queue is awakened,
 * but also after every book has finished downloading
 *
 * @return 1st book of the download queue; null if no book is available to download
 */
@SuppressLint({ "TimberExceptionLogging", "TimberArgCount" })
@NonNull
private ImmutablePair<QueuingResult, Content> downloadFirstInQueue() {
    final String CONTENT_PART_IMAGE_LIST = "Image list";
    Context context = getApplicationContext();
    EventBus.getDefault().post(DownloadEvent.fromPreparationStep(DownloadEvent.Step.INIT));
    // Clear previously created requests
    compositeDisposable.clear();
    // Check if queue has been paused
    if (ContentQueueManager.getInstance().isQueuePaused()) {
        Timber.i("Queue is paused. Download aborted.");
        return new ImmutablePair<>(QueuingResult.QUEUE_END, null);
    }
    @NetworkHelper.Connectivity int connectivity = NetworkHelper.getConnectivity(context);
    // Check for network connectivity
    if (NetworkHelper.Connectivity.NO_INTERNET == connectivity) {
        Timber.i("No internet connection available. Queue paused.");
        EventBus.getDefault().post(DownloadEvent.fromPauseMotive(DownloadEvent.Motive.NO_INTERNET));
        return new ImmutablePair<>(QueuingResult.QUEUE_END, null);
    }
    // Check for wifi if wifi-only mode is on
    if (Preferences.isQueueWifiOnly() && NetworkHelper.Connectivity.WIFI != connectivity) {
        Timber.i("No wi-fi connection available. Queue paused.");
        EventBus.getDefault().post(DownloadEvent.fromPauseMotive(DownloadEvent.Motive.NO_WIFI));
        return new ImmutablePair<>(QueuingResult.QUEUE_END, null);
    }
    // Check for download folder existence, available free space and credentials
    if (Preferences.getStorageUri().trim().isEmpty()) {
        // May happen if user has skipped it during the intro
        Timber.i("No download folder set");
        EventBus.getDefault().post(DownloadEvent.fromPauseMotive(DownloadEvent.Motive.NO_DOWNLOAD_FOLDER));
        return new ImmutablePair<>(QueuingResult.QUEUE_END, null);
    }
    DocumentFile rootFolder = FileHelper.getFolderFromTreeUriString(context, Preferences.getStorageUri());
    if (null == rootFolder) {
        // May happen if the folder has been moved or deleted after it has been selected
        Timber.i("Download folder has not been found. Please select it again.");
        EventBus.getDefault().post(DownloadEvent.fromPauseMotive(DownloadEvent.Motive.DOWNLOAD_FOLDER_NOT_FOUND));
        return new ImmutablePair<>(QueuingResult.QUEUE_END, null);
    }
    if (!FileHelper.isUriPermissionPersisted(context.getContentResolver(), rootFolder.getUri())) {
        Timber.i("Insufficient credentials on download folder. Please select it again.");
        EventBus.getDefault().post(DownloadEvent.fromPauseMotive(DownloadEvent.Motive.DOWNLOAD_FOLDER_NO_CREDENTIALS));
        return new ImmutablePair<>(QueuingResult.QUEUE_END, null);
    }
    long spaceLeftBytes = new FileHelper.MemoryUsageFigures(context, rootFolder).getfreeUsageBytes();
    if (spaceLeftBytes < 2L * 1024 * 1024) {
        Timber.i("Device very low on storage space (<2 MB). Queue paused.");
        EventBus.getDefault().post(DownloadEvent.fromPauseMotive(DownloadEvent.Motive.NO_STORAGE, spaceLeftBytes));
        return new ImmutablePair<>(QueuingResult.QUEUE_END, null);
    }
    // Work on first item of queue
    // Check if there is a first item to process
    List<QueueRecord> queue = dao.selectQueue();
    if (queue.isEmpty()) {
        Timber.i("Queue is empty. Download aborted.");
        return new ImmutablePair<>(QueuingResult.QUEUE_END, null);
    }
    Content content = queue.get(0).getContent().getTarget();
    if (null == content) {
        Timber.i("Content is unavailable. Download aborted.");
        dao.deleteQueue(0);
        // Must supply content ID to the event for the UI to update properly
        content = new Content().setId(queue.get(0).getContent().getTargetId());
        EventBus.getDefault().post(new DownloadEvent(content, DownloadEvent.Type.EV_COMPLETE, 0, 0, 0, 0));
        notificationManager.notify(new DownloadErrorNotification());
        return new ImmutablePair<>(QueuingResult.CONTENT_SKIPPED, null);
    }
    if (StatusContent.DOWNLOADED == content.getStatus()) {
        Timber.i("Content is already downloaded. Download aborted.");
        dao.deleteQueue(0);
        EventBus.getDefault().post(new DownloadEvent(content, DownloadEvent.Type.EV_COMPLETE, 0, 0, 0, 0));
        notificationManager.notify(new DownloadErrorNotification(content));
        return new ImmutablePair<>(QueuingResult.CONTENT_SKIPPED, null);
    }
    downloadCanceled.set(false);
    downloadSkipped.set(false);
    downloadInterrupted.set(false);
    isCloudFlareBlocked = false;
    @Content.DownloadMode int downloadMode = content.getDownloadMode();
    dao.deleteErrorRecords(content.getId());
    // == PREPARATION PHASE ==
    // Parse images from the site (using image list parser)
    // - Case 1 : If no image is present => parse all images
    // - Case 2 : If all images are in ERROR state => re-parse all images
    // - Case 3 : If some images are in ERROR state and the site has backup URLs
    // => re-parse images with ERROR state using their order as reference
    boolean hasError = false;
    int nbErrors = 0;
    EventBus.getDefault().post(DownloadEvent.fromPreparationStep(DownloadEvent.Step.PROCESS_IMG));
    List<ImageFile> images = content.getImageFiles();
    if (null == images)
        images = new ArrayList<>();
    else
        // Safe copy of the original list
        images = new ArrayList<>(images);
    for (ImageFile img : images) if (img.getStatus().equals(StatusContent.ERROR))
        nbErrors++;
    StatusContent targetImageStatus = (downloadMode == Content.DownloadMode.DOWNLOAD) ? StatusContent.SAVED : StatusContent.ONLINE;
    if (images.isEmpty() || nbErrors == images.size() || (nbErrors > 0 && content.getSite().hasBackupURLs())) {
        EventBus.getDefault().post(DownloadEvent.fromPreparationStep(DownloadEvent.Step.FETCH_IMG));
        try {
            List<ImageFile> newImages = ContentHelper.fetchImageURLs(content, targetImageStatus);
            // Cases 1 and 2 : Replace existing images with the parsed images
            if (images.isEmpty() || nbErrors == images.size())
                images = newImages;
            // Case 3 : Replace images in ERROR state with the parsed images at the same position
            if (nbErrors > 0 && content.getSite().hasBackupURLs()) {
                for (int i = 0; i < images.size(); i++) {
                    ImageFile oldImage = images.get(i);
                    if (oldImage.getStatus().equals(StatusContent.ERROR)) {
                        for (ImageFile newImg : newImages) if (newImg.getOrder().equals(oldImage.getOrder()))
                            images.set(i, newImg);
                    }
                }
            }
            if (content.isUpdatedProperties())
                dao.insertContent(content);
            // Manually insert new images (without using insertContent)
            dao.replaceImageList(content.getId(), images);
        } catch (CaptchaException cpe) {
            Timber.i(cpe, "A captcha has been found while parsing %s. Download aborted.", content.getTitle());
            logErrorRecord(content.getId(), ErrorType.CAPTCHA, content.getUrl(), CONTENT_PART_IMAGE_LIST, "Captcha found. Please go back to the site, browse a book and solve the captcha.");
            hasError = true;
        } catch (AccountException ae) {
            String description = String.format("Your %s account does not allow to download the book %s. %s. Download aborted.", content.getSite().getDescription(), content.getTitle(), ae.getMessage());
            Timber.i(ae, description);
            logErrorRecord(content.getId(), ErrorType.ACCOUNT, content.getUrl(), CONTENT_PART_IMAGE_LIST, description);
            hasError = true;
        } catch (LimitReachedException lre) {
            String description = String.format("The bandwidth limit has been reached while parsing %s. %s. Download aborted.", content.getTitle(), lre.getMessage());
            Timber.i(lre, description);
            logErrorRecord(content.getId(), ErrorType.SITE_LIMIT, content.getUrl(), CONTENT_PART_IMAGE_LIST, description);
            hasError = true;
        } catch (PreparationInterruptedException ie) {
            Timber.i(ie, "Preparation of %s interrupted", content.getTitle());
        // not an error
        } catch (EmptyResultException ere) {
            Timber.i(ere, "No images have been found while parsing %s. Download aborted.", content.getTitle());
            logErrorRecord(content.getId(), ErrorType.PARSING, content.getUrl(), CONTENT_PART_IMAGE_LIST, "No images have been found. Error = " + ere.getMessage());
            hasError = true;
        } catch (Exception e) {
            Timber.w(e, "An exception has occurred while parsing %s. Download aborted.", content.getTitle());
            logErrorRecord(content.getId(), ErrorType.PARSING, content.getUrl(), CONTENT_PART_IMAGE_LIST, e.getMessage());
            hasError = true;
        }
    } else if (nbErrors > 0) {
        // Other cases : Reset ERROR status of images to mark them as "to be downloaded" (in DB and in memory)
        dao.updateImageContentStatus(content.getId(), StatusContent.ERROR, targetImageStatus);
    } else {
        if (downloadMode == Content.DownloadMode.STREAM)
            dao.updateImageContentStatus(content.getId(), null, StatusContent.ONLINE);
    }
    // Get updated Content with the udpated ID and status of new images
    content = dao.selectContent(content.getId());
    if (null == content)
        return new ImmutablePair<>(QueuingResult.CONTENT_SKIPPED, null);
    if (hasError) {
        moveToErrors(content.getId());
        EventBus.getDefault().post(new DownloadEvent(content, DownloadEvent.Type.EV_COMPLETE, 0, 0, 0, 0));
        return new ImmutablePair<>(QueuingResult.CONTENT_FAILED, content);
    }
    // NB : No log of any sort because this is normal behaviour
    if (downloadInterrupted.get())
        return new ImmutablePair<>(QueuingResult.CONTENT_SKIPPED, null);
    EventBus.getDefault().post(DownloadEvent.fromPreparationStep(DownloadEvent.Step.PREPARE_FOLDER));
    // Create destination folder for images to be downloaded
    DocumentFile dir = ContentHelper.getOrCreateContentDownloadDir(getApplicationContext(), content);
    // Folder creation failed
    if (null == dir || !dir.exists()) {
        String title = content.getTitle();
        String absolutePath = (null == dir) ? "" : dir.getUri().toString();
        String message = String.format("Directory could not be created: %s.", absolutePath);
        Timber.w(message);
        logErrorRecord(content.getId(), ErrorType.IO, content.getUrl(), "Destination folder", message);
        notificationManager.notify(new DownloadWarningNotification(title, absolutePath));
        // No sense in waiting for every image to be downloaded in error state (terrible waste of network resources)
        // => Create all images, flag them as failed as well as the book
        dao.updateImageContentStatus(content.getId(), targetImageStatus, StatusContent.ERROR);
        completeDownload(content.getId(), content.getTitle(), 0, images.size(), 0);
        return new ImmutablePair<>(QueuingResult.CONTENT_FAILED, content);
    }
    // Folder creation succeeds -> memorize its path
    content.setStorageUri(dir.getUri().toString());
    // Don't count the cover thumbnail in the number of pages
    if (0 == content.getQtyPages())
        content.setQtyPages(images.size() - 1);
    content.setStatus(StatusContent.DOWNLOADING);
    // Mark the cover for downloading when saving a streamed book
    if (downloadMode == Content.DownloadMode.STREAM)
        content.getCover().setStatus(StatusContent.SAVED);
    dao.insertContent(content);
    HentoidApp.trackDownloadEvent("Added");
    Timber.i("Downloading '%s' [%s]", content.getTitle(), content.getId());
    // Wait until the end of purge if the content is being purged (e.g. redownload from scratch)
    boolean isBeingDeleted = content.isBeingDeleted();
    if (isBeingDeleted)
        EventBus.getDefault().post(DownloadEvent.fromPreparationStep(DownloadEvent.Step.WAIT_PURGE));
    while (content.isBeingDeleted()) {
        Timber.d("Waiting for purge to complete");
        content = dao.selectContent(content.getId());
        if (null == content)
            return new ImmutablePair<>(QueuingResult.CONTENT_SKIPPED, null);
        Helper.pause(1000);
        if (downloadInterrupted.get())
            break;
    }
    if (isBeingDeleted && !downloadInterrupted.get())
        Timber.d("Purge completed; resuming download");
    // == DOWNLOAD PHASE ==
    EventBus.getDefault().post(DownloadEvent.fromPreparationStep(DownloadEvent.Step.PREPARE_DOWNLOAD));
    // Set up downloader constraints
    if (content.getSite().getParallelDownloadCap() > 0 && (requestQueueManager.getDownloadThreadCap() > content.getSite().getParallelDownloadCap() || -1 == requestQueueManager.getDownloadThreadCap())) {
        Timber.d("Setting parallel downloads count to %s", content.getSite().getParallelDownloadCap());
        requestQueueManager.initUsingDownloadThreadCount(getApplicationContext(), content.getSite().getParallelDownloadCap(), true);
    }
    if (0 == content.getSite().getParallelDownloadCap() && requestQueueManager.getDownloadThreadCap() > -1) {
        Timber.d("Resetting parallel downloads count to default");
        requestQueueManager.initUsingDownloadThreadCount(getApplicationContext(), -1, true);
    }
    requestQueueManager.setNbRequestsPerSecond(content.getSite().getRequestsCapPerSecond());
    // NB : No log of any sort because this is normal behaviour
    if (downloadInterrupted.get())
        return new ImmutablePair<>(QueuingResult.CONTENT_SKIPPED, null);
    List<ImageFile> pagesToParse = new ArrayList<>();
    List<ImageFile> ugoirasToDownload = new ArrayList<>();
    // Just get the cover if we're in a streamed download
    if (downloadMode == Content.DownloadMode.STREAM) {
        Optional<ImageFile> coverOptional = Stream.of(images).filter(ImageFile::isCover).findFirst();
        if (coverOptional.isPresent()) {
            ImageFile cover = coverOptional.get();
            enrichImageDownloadParams(cover, content);
            requestQueueManager.queueRequest(buildImageDownloadRequest(cover, dir, content));
        }
    } else {
        // Queue image download requests
        for (ImageFile img : images) {
            if (img.getStatus().equals(StatusContent.SAVED)) {
                enrichImageDownloadParams(img, content);
                // Set the 1st image of the list as a backup in case the cover URL is stale (might happen when restarting old downloads)
                if (img.isCover() && images.size() > 1)
                    img.setBackupUrl(images.get(1).getUrl());
                if (img.needsPageParsing())
                    pagesToParse.add(img);
                else if (img.getDownloadParams().contains(ContentHelper.KEY_DL_PARAMS_UGOIRA_FRAMES))
                    ugoirasToDownload.add(img);
                else
                    requestQueueManager.queueRequest(buildImageDownloadRequest(img, dir, content));
            }
        }
        // Parse pages for images
        if (!pagesToParse.isEmpty()) {
            final Content contentFinal = content;
            compositeDisposable.add(Observable.fromIterable(pagesToParse).observeOn(Schedulers.io()).subscribe(img -> parsePageforImage(img, dir, contentFinal), t -> {
            // Nothing; just exit the Rx chain
            }));
        }
        // Parse ugoiras for images
        if (!ugoirasToDownload.isEmpty()) {
            final Site siteFinal = content.getSite();
            compositeDisposable.add(Observable.fromIterable(ugoirasToDownload).observeOn(Schedulers.io()).subscribe(img -> downloadAndUnzipUgoira(img, dir, siteFinal), t -> {
            // Nothing; just exit the Rx chain
            }));
        }
    }
    EventBus.getDefault().post(DownloadEvent.fromPreparationStep(DownloadEvent.Step.SAVE_QUEUE));
    if (ContentHelper.updateQueueJson(getApplicationContext(), dao))
        Timber.i(context.getString(R.string.queue_json_saved));
    else
        Timber.w(context.getString(R.string.queue_json_failed));
    EventBus.getDefault().post(DownloadEvent.fromPreparationStep(DownloadEvent.Step.START_DOWNLOAD));
    return new ImmutablePair<>(QueuingResult.CONTENT_FOUND, content);
}
Also used : RequestQueueManager(me.devsaki.hentoid.util.download.RequestQueueManager) Content(me.devsaki.hentoid.database.domains.Content) NonNull(androidx.annotation.NonNull) DownloadHelper(me.devsaki.hentoid.util.download.DownloadHelper) NetworkHelper(me.devsaki.hentoid.util.network.NetworkHelper) Uri(android.net.Uri) Chapter(me.devsaki.hentoid.database.domains.Chapter) ContentHelper(me.devsaki.hentoid.util.ContentHelper) AccountException(me.devsaki.hentoid.util.exception.AccountException) Optional(com.annimon.stream.Optional) Consts(me.devsaki.hentoid.core.Consts) Site(me.devsaki.hentoid.enums.Site) InvalidParameterException(java.security.InvalidParameterException) DownloadWarningNotification(me.devsaki.hentoid.notification.download.DownloadWarningNotification) StringHelper(me.devsaki.hentoid.util.StringHelper) JsonContent(me.devsaki.hentoid.json.JsonContent) Map(java.util.Map) ImageFile(me.devsaki.hentoid.database.domains.ImageFile) JsonHelper(me.devsaki.hentoid.util.JsonHelper) UnsupportedContentException(me.devsaki.hentoid.util.exception.UnsupportedContentException) Schedulers(io.reactivex.schedulers.Schedulers) Data(androidx.work.Data) ServerError(com.android.volley.ServerError) DownloadEvent(me.devsaki.hentoid.events.DownloadEvent) PreparationInterruptedException(me.devsaki.hentoid.util.exception.PreparationInterruptedException) HttpHelper(me.devsaki.hentoid.util.network.HttpHelper) Timber(timber.log.Timber) List(java.util.List) CompositeDisposable(io.reactivex.disposables.CompositeDisposable) DocumentFile(androidx.documentfile.provider.DocumentFile) ParseError(com.android.volley.ParseError) CollectionDAO(me.devsaki.hentoid.database.CollectionDAO) ErrorType(me.devsaki.hentoid.enums.ErrorType) UserActionNotification(me.devsaki.hentoid.notification.action.UserActionNotification) Notification(me.devsaki.hentoid.util.notification.Notification) Context(android.content.Context) Preferences(me.devsaki.hentoid.util.Preferences) Stream(com.annimon.stream.Stream) DownloadReviveEvent(me.devsaki.hentoid.events.DownloadReviveEvent) EmptyResultException(me.devsaki.hentoid.util.exception.EmptyResultException) Pair(android.util.Pair) WorkerParameters(androidx.work.WorkerParameters) PixivIllustMetadata(me.devsaki.hentoid.json.sources.PixivIllustMetadata) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) Single(io.reactivex.Single) StatusContent(me.devsaki.hentoid.enums.StatusContent) NotificationManager(me.devsaki.hentoid.util.notification.NotificationManager) ArrayList(java.util.ArrayList) ImageHelper(me.devsaki.hentoid.util.ImageHelper) SuppressLint(android.annotation.SuppressLint) TimeoutError(com.android.volley.TimeoutError) Helper(me.devsaki.hentoid.util.Helper) EventBus(org.greenrobot.eventbus.EventBus) Instant(org.threeten.bp.Instant) LimitReachedException(me.devsaki.hentoid.util.exception.LimitReachedException) Observable(io.reactivex.Observable) AuthFailureError(com.android.volley.AuthFailureError) NoConnectionError(com.android.volley.NoConnectionError) Nullable(javax.annotation.Nullable) HentoidApp(me.devsaki.hentoid.core.HentoidApp) ContentParserFactory(me.devsaki.hentoid.parsers.ContentParserFactory) ErrorRecord(me.devsaki.hentoid.database.domains.ErrorRecord) RequestOrder(me.devsaki.hentoid.util.download.RequestOrder) ContentQueueManager(me.devsaki.hentoid.util.download.ContentQueueManager) CaptchaException(me.devsaki.hentoid.util.exception.CaptchaException) DownloadErrorNotification(me.devsaki.hentoid.notification.download.DownloadErrorNotification) IOException(java.io.IOException) VolleyError(com.android.volley.VolleyError) ImageListParser(me.devsaki.hentoid.parsers.images.ImageListParser) FileHelper(me.devsaki.hentoid.util.FileHelper) ImmutablePair(org.apache.commons.lang3.tuple.ImmutablePair) File(java.io.File) ObjectBoxDAO(me.devsaki.hentoid.database.ObjectBoxDAO) DownloadSuccessNotification(me.devsaki.hentoid.notification.download.DownloadSuccessNotification) R(me.devsaki.hentoid.R) Request(com.android.volley.Request) Subscribe(org.greenrobot.eventbus.Subscribe) DownloadProgressNotification(me.devsaki.hentoid.notification.download.DownloadProgressNotification) DownloadSpeedCalculator(me.devsaki.hentoid.util.network.DownloadSpeedCalculator) QueueRecord(me.devsaki.hentoid.database.domains.QueueRecord) Collections(java.util.Collections) ArchiveHelper(me.devsaki.hentoid.util.ArchiveHelper) MimeTypeMap(android.webkit.MimeTypeMap) NetworkError(com.android.volley.NetworkError) Site(me.devsaki.hentoid.enums.Site) StatusContent(me.devsaki.hentoid.enums.StatusContent) ImageFile(me.devsaki.hentoid.database.domains.ImageFile) EmptyResultException(me.devsaki.hentoid.util.exception.EmptyResultException) DownloadEvent(me.devsaki.hentoid.events.DownloadEvent) ArrayList(java.util.ArrayList) DownloadErrorNotification(me.devsaki.hentoid.notification.download.DownloadErrorNotification) DownloadWarningNotification(me.devsaki.hentoid.notification.download.DownloadWarningNotification) Context(android.content.Context) DocumentFile(androidx.documentfile.provider.DocumentFile) LimitReachedException(me.devsaki.hentoid.util.exception.LimitReachedException) PreparationInterruptedException(me.devsaki.hentoid.util.exception.PreparationInterruptedException) SuppressLint(android.annotation.SuppressLint) AccountException(me.devsaki.hentoid.util.exception.AccountException) InvalidParameterException(java.security.InvalidParameterException) UnsupportedContentException(me.devsaki.hentoid.util.exception.UnsupportedContentException) PreparationInterruptedException(me.devsaki.hentoid.util.exception.PreparationInterruptedException) EmptyResultException(me.devsaki.hentoid.util.exception.EmptyResultException) LimitReachedException(me.devsaki.hentoid.util.exception.LimitReachedException) CaptchaException(me.devsaki.hentoid.util.exception.CaptchaException) IOException(java.io.IOException) FileHelper(me.devsaki.hentoid.util.FileHelper) ImmutablePair(org.apache.commons.lang3.tuple.ImmutablePair) AccountException(me.devsaki.hentoid.util.exception.AccountException) QueueRecord(me.devsaki.hentoid.database.domains.QueueRecord) Content(me.devsaki.hentoid.database.domains.Content) JsonContent(me.devsaki.hentoid.json.JsonContent) StatusContent(me.devsaki.hentoid.enums.StatusContent) CaptchaException(me.devsaki.hentoid.util.exception.CaptchaException) NonNull(androidx.annotation.NonNull) SuppressLint(android.annotation.SuppressLint)

Aggregations

Context (android.content.Context)3 Content (me.devsaki.hentoid.database.domains.Content)3 StatusContent (me.devsaki.hentoid.enums.StatusContent)3 JsonContent (me.devsaki.hentoid.json.JsonContent)3 DownloadErrorNotification (me.devsaki.hentoid.notification.download.DownloadErrorNotification)3 SuppressLint (android.annotation.SuppressLint)2 DocumentFile (androidx.documentfile.provider.DocumentFile)2 IOException (java.io.IOException)2 ImageFile (me.devsaki.hentoid.database.domains.ImageFile)2 DownloadEvent (me.devsaki.hentoid.events.DownloadEvent)2 DownloadSuccessNotification (me.devsaki.hentoid.notification.download.DownloadSuccessNotification)2 FileHelper (me.devsaki.hentoid.util.FileHelper)2 ContentQueueManager (me.devsaki.hentoid.util.download.ContentQueueManager)2 Uri (android.net.Uri)1 Pair (android.util.Pair)1 MimeTypeMap (android.webkit.MimeTypeMap)1 NonNull (androidx.annotation.NonNull)1 Data (androidx.work.Data)1 WorkerParameters (androidx.work.WorkerParameters)1 AuthFailureError (com.android.volley.AuthFailureError)1