mirror of
https://github.com/dev-claw/vripper-project.git
synced 2026-08-19 08:35:41 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b52ad7858 | ||
|
|
a0976bde02 |
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## [3.0.1] - 2020-08-03
|
||||
### Changed
|
||||
- Fix bugs with download queue
|
||||
|
||||
## [3.0.0] - 2020-08-03
|
||||
### Changed
|
||||
- Major rewrites
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>tn.mnlr</groupId>
|
||||
<artifactId>vripper</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<packaging>pom</packaging>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vripper-electron",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vripper-electron",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"description": "A ripper for vipergirls.to built using web technolgies",
|
||||
"main": "main.js",
|
||||
"author": "death-claw <53543762+death-claw@users.noreply.github.com>",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tn.mnlr</groupId>
|
||||
<artifactId>vripper</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
</parent>
|
||||
<artifactId>vripper-electron</artifactId>
|
||||
<name>vripper-electron</name>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tn.mnlr</groupId>
|
||||
<artifactId>vripper</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
</parent>
|
||||
<artifactId>vripper-server</artifactId>
|
||||
<name>vripper-server</name>
|
||||
|
||||
@@ -129,11 +129,12 @@ abstract public class Host {
|
||||
}
|
||||
File destinationFolder;
|
||||
synchronized (LOCK) {
|
||||
if (post.getPostFolderName() == null) {
|
||||
pathService.createDefaultPostFolder(post);
|
||||
Post updatedPost = dataService.findPostById(post.getId()).orElseThrow();
|
||||
if (updatedPost.getPostFolderName() == null) {
|
||||
pathService.createDefaultPostFolder(updatedPost);
|
||||
}
|
||||
destinationFolder = pathService.getDownloadDestinationFolder(post);
|
||||
authService.leaveThanks(post);
|
||||
destinationFolder = pathService.getDownloadDestinationFolder(updatedPost);
|
||||
authService.leaveThanks(updatedPost);
|
||||
}
|
||||
File outputFile = new File(destinationFolder.getPath() + File.separator + String.format("%03d_", image.getIndex()) + imageFileData.getImageName() + ".tmp");
|
||||
try (InputStream downloadStream = response.getEntity().getContent(); FileOutputStream fos = new FileOutputStream(outputFile)) {
|
||||
@@ -161,7 +162,7 @@ abstract public class Host {
|
||||
}
|
||||
dataService.updateImageStatus(image.getStatus(), image.getId());
|
||||
}
|
||||
File finalName = checkImageTypeAndRename(post, outputFile, imageFileData.getImageName(), image.getIndex());
|
||||
File finalName = checkImageTypeAndRename(dataService.findPostById(post.getId()).orElseThrow(), outputFile, imageFileData.getImageName(), image.getIndex());
|
||||
imageFileData.setFileName(finalName.getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -299,8 +300,8 @@ abstract public class Host {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
private Document document;
|
||||
private Header[] headers;
|
||||
private final Document document;
|
||||
private final Header[] headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,8 +14,6 @@ public interface IImageRepository extends IRepository {
|
||||
|
||||
List<Image> findByPostId(String postId);
|
||||
|
||||
Integer countRemaining();
|
||||
|
||||
Integer countError();
|
||||
|
||||
List<Image> findByPostIdAndIsNotCompleted(String postId);
|
||||
|
||||
-8
@@ -67,14 +67,6 @@ public class ImageRepository implements IImageRepository {
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer countRemaining() {
|
||||
return jdbcTemplate.queryForObject(
|
||||
"SELECT COUNT(*) FROM IMAGE AS image WHERE image.TOTAL = 0 OR image.TOTAL <> image.CURRENT",
|
||||
Integer.class
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer countError() {
|
||||
return jdbcTemplate.queryForObject(
|
||||
|
||||
@@ -3,23 +3,19 @@ package tn.mnlr.vripper.q;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.jodah.failsafe.function.CheckedRunnable;
|
||||
import tn.mnlr.vripper.SpringContext;
|
||||
import tn.mnlr.vripper.jpa.domain.Image;
|
||||
import tn.mnlr.vripper.jpa.domain.Post;
|
||||
import tn.mnlr.vripper.services.DataService;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
public class DownloadJob implements CheckedRunnable {
|
||||
|
||||
private final DataService dataService;
|
||||
@Getter
|
||||
private final Image image;
|
||||
|
||||
@Getter
|
||||
private Image image;
|
||||
|
||||
@Getter
|
||||
private Post post;
|
||||
private final Post post;
|
||||
|
||||
@Getter
|
||||
private final ImageFileData imageFileData = new ImageFileData();
|
||||
@@ -27,7 +23,6 @@ public class DownloadJob implements CheckedRunnable {
|
||||
DownloadJob(Post post, Image image) {
|
||||
this.image = image;
|
||||
this.post = post;
|
||||
dataService = SpringContext.getBean(DataService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,9 +45,4 @@ public class DownloadJob implements CheckedRunnable {
|
||||
public int hashCode() {
|
||||
return Objects.hash(image, post);
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
post = dataService.findPostById(post.getId()).orElseThrow();
|
||||
image = dataService.findImageById(image.getId()).orElseThrow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ public class ExecuteRunnable implements Runnable {
|
||||
mutexService.createPostLock(downloadJob.getPost().getPostId());
|
||||
ReentrantLock mutex = mutexService.getPostLock(downloadJob.getPost().getPostId());
|
||||
mutex.lock();
|
||||
downloadJob.refresh();
|
||||
executionService.beforeJobStart(downloadJob.getPost().getPostId());
|
||||
Failsafe.with(VripperApplication.retryPolicy)
|
||||
.onFailure(e -> {
|
||||
if (e.getFailure() instanceof InterruptedException || e.getFailure().getCause() instanceof InterruptedException) {
|
||||
|
||||
@@ -32,7 +32,7 @@ public class ExecutionService {
|
||||
private final ExecutorService executor = Executors.newFixedThreadPool(MAX_POOL_SIZE);
|
||||
private final BlockingQueue<DownloadJob> executionQueue = new LinkedBlockingQueue<>();
|
||||
private final Map<DownloadJob, Future<?>> futures = new ConcurrentHashMap<>();
|
||||
private final Map<String, AtomicInteger> downloadCount = new ConcurrentHashMap<>();
|
||||
// private final Map<String, AtomicInteger> downloadCount = new ConcurrentHashMap<>();
|
||||
|
||||
private final PendingQ pendingQ;
|
||||
private final AppSettingsService settings;
|
||||
@@ -106,7 +106,7 @@ public class ExecutionService {
|
||||
}
|
||||
|
||||
private void restart(@NonNull String postId) {
|
||||
if (isRunning(postId) || isPending(postId)) {
|
||||
if (isPending(postId)) {
|
||||
log.warn(String.format("Cannot restart, jobs are currently running for post id %s", postId));
|
||||
return;
|
||||
}
|
||||
@@ -132,11 +132,6 @@ public class ExecutionService {
|
||||
return pendingQ.isPending(postId);
|
||||
}
|
||||
|
||||
public boolean isRunning(@NonNull final String postId) {
|
||||
AtomicInteger runningCount = downloadCount.get(postId);
|
||||
return runningCount != null && runningCount.get() > 0;
|
||||
}
|
||||
|
||||
private void stop(String postId) {
|
||||
try {
|
||||
pauseQ = true;
|
||||
@@ -210,21 +205,9 @@ public class ExecutionService {
|
||||
futures.put(downloadJob, executor.submit(runnable));
|
||||
}
|
||||
|
||||
public void beforeJobStart(String postId) {
|
||||
checkKeyRunningPosts(postId);
|
||||
downloadCount.get(postId).incrementAndGet();
|
||||
}
|
||||
|
||||
private synchronized void checkKeyRunningPosts(@NonNull final String postId) {
|
||||
if (!downloadCount.containsKey(postId)) {
|
||||
downloadCount.put(postId, new AtomicInteger(0));
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void afterJobFinish(DownloadJob downloadJob) {
|
||||
int count = downloadCount.get(downloadJob.getPost().getPostId()).decrementAndGet();
|
||||
if (count == 0 && !pendingQ.isPending(downloadJob.getPost().getPostId())) {
|
||||
downloadCount.remove(downloadJob.getPost().getPostId());
|
||||
int count = pendingQ.afterJobFinish(downloadJob.getPost().getPostId());
|
||||
if (count == 0) {
|
||||
dataService.finishPost(downloadJob.getPost());
|
||||
mutexService.removePostLock(downloadJob.getPost().getPostId());
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.util.*;
|
||||
import java.util.concurrent.BlockingDeque;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@@ -24,6 +25,7 @@ public class PendingQ {
|
||||
private final List<Host> hosts;
|
||||
|
||||
private final ConcurrentHashMap<Host, BlockingDeque<DownloadJob>> pendingQ = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<String, AtomicInteger> toBeExecuted = new ConcurrentHashMap<>();
|
||||
|
||||
@Autowired
|
||||
public PendingQ(DataService dataService, AppSettingsService appSettingsService, List<Host> hosts) {
|
||||
@@ -44,6 +46,14 @@ public class PendingQ {
|
||||
dataService.updateImageCurrent(image.getCurrent(), image.getId());
|
||||
DownloadJob downloadJob = new DownloadJob(post, image);
|
||||
pendingQ.get(downloadJob.getImage().getHost()).putLast(downloadJob);
|
||||
checkKey(post.getPostId());
|
||||
toBeExecuted.get(post.getPostId()).incrementAndGet();
|
||||
}
|
||||
|
||||
private synchronized void checkKey(String postId) {
|
||||
if (!toBeExecuted.containsKey(postId)) {
|
||||
toBeExecuted.put(postId, new AtomicInteger(0));
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(final DownloadJob downloadJob) {
|
||||
@@ -74,7 +84,7 @@ public class PendingQ {
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return pendingQ.values().stream().mapToInt(BlockingDeque::size).sum();
|
||||
return toBeExecuted.values().stream().mapToInt(AtomicInteger::get).sum();
|
||||
}
|
||||
|
||||
public void remove(Post post) {
|
||||
@@ -85,6 +95,14 @@ public class PendingQ {
|
||||
}
|
||||
|
||||
public boolean isPending(String postId) {
|
||||
return pendingQ.values().stream().flatMap(Collection::stream).anyMatch(e -> e.getPost().getPostId().equals(postId));
|
||||
return toBeExecuted.containsKey(postId);
|
||||
}
|
||||
|
||||
public int afterJobFinish(String postId) {
|
||||
int count = toBeExecuted.get(postId).decrementAndGet();
|
||||
if (count == 0) {
|
||||
toBeExecuted.remove(postId);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,10 +169,6 @@ public class DataService {
|
||||
|
||||
}
|
||||
|
||||
public long countRemainingImages() {
|
||||
return imageRepository.countRemaining();
|
||||
}
|
||||
|
||||
public long countErrorImages() {
|
||||
return imageRepository.countError();
|
||||
}
|
||||
|
||||
@@ -8,13 +8,11 @@ import java.util.Objects;
|
||||
public class GlobalState {
|
||||
|
||||
private final long running;
|
||||
private final long queued;
|
||||
private final long remaining;
|
||||
private final long error;
|
||||
|
||||
GlobalState(long running, long queued, long remaining, long error) {
|
||||
GlobalState(long running, long remaining, long error) {
|
||||
this.running = running;
|
||||
this.queued = queued;
|
||||
this.remaining = remaining;
|
||||
this.error = error;
|
||||
}
|
||||
@@ -24,11 +22,11 @@ public class GlobalState {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
GlobalState that = (GlobalState) o;
|
||||
return running == that.running && queued == that.queued && remaining == that.remaining && error == that.error;
|
||||
return running == that.running && remaining == that.remaining && error == that.error;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(running, queued, remaining, error);
|
||||
return Objects.hash(running, remaining, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ public class GlobalStateService {
|
||||
GlobalState newGlobalState = new GlobalState(
|
||||
executionService.runningCount(),
|
||||
pendingQ.size(),
|
||||
dataService.countRemainingImages(),
|
||||
dataService.countErrorImages());
|
||||
if (!newGlobalState.equals(currentState)) {
|
||||
currentState = newGlobalState;
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vripper-ui",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vripper-ui",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tn.mnlr</groupId>
|
||||
<artifactId>vripper</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
</parent>
|
||||
<artifactId>vripper-ui</artifactId>
|
||||
<name>vripper-ui</name>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export class GlobalState {
|
||||
constructor(public running: number, public queued: number, public remaining: number, public error: number) {}
|
||||
constructor(public running: number, public remaining: number, public error: number) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
<span *ngIf="downloadSpeed$ | async as speed">{{ speed.speed + '/s' }}</span>
|
||||
<ng-container *ngIf="globalState$ | async as state">
|
||||
<span>Downloading: {{ state!.running }}</span>
|
||||
<span>Pending: {{ state!.queued }}</span>
|
||||
<span>Remaining: {{ state!.remaining }}</span>
|
||||
<span>Error: {{ state!.error }}</span>
|
||||
</ng-container>
|
||||
|
||||
@@ -16,7 +16,7 @@ export class StatusBarComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
downloadSpeed$: Subject<DownloadSpeed> = new BehaviorSubject(new DownloadSpeed('0 B'));
|
||||
globalState$: Subject<GlobalState> = new BehaviorSubject(new GlobalState(0, 0, 0, 0));
|
||||
globalState$: Subject<GlobalState> = new BehaviorSubject(new GlobalState(0, 0, 0));
|
||||
selected$: Subject<number> = new BehaviorSubject(0);
|
||||
subscriptions: Subscription[] = [];
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@ export const environment = {
|
||||
production: true,
|
||||
localhost: `${window.location.protocol}//${window.location.host}`,
|
||||
ws: `${window.location.protocol === 'http:' ? 'ws:' : 'wss:'}//${window.location.host}`,
|
||||
version: '3.0.0'
|
||||
version: '3.0.1'
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ export const environment = {
|
||||
production: false,
|
||||
localhost: 'http://localhost:8080',
|
||||
ws: 'ws://localhost:8080',
|
||||
version: '3.0.0'
|
||||
version: '3.0.1'
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user