Compare commits

...
12 Commits
Author SHA1 Message Date
death-claw 67c605e640 v2.12.1 2020-05-22 15:55:05 +01:00
death-claw 8d4b878656 Fix alternative name bug 2020-05-22 15:54:11 +01:00
death-claw bf532dd1d0 v2.12.0 2020-05-21 16:43:03 +01:00
death-claw eb1a125e59 Use new user hash from the api 2020-05-21 16:41:16 +01:00
death-claw 256659a72d v2.11.7 2020-05-08 12:57:41 +01:00
death-claw dbf3aa7e7d Fix bug with paths creation
Move Open Link button
Rename rename all title
2020-05-08 12:56:11 +01:00
death-claw a75ce181ff v2.11.6 2020-05-04 21:07:16 +01:00
death-claw 37ae6b4ebf Merge branch 'master' of https://github.com/death-claw/vripper-project 2020-05-04 21:06:48 +01:00
death-claw 6631a6a95b PNG filenames are now correctly named
Fix issue with special characters in post titles
2020-05-04 21:04:51 +01:00
death-clawandGitHub 918f8578ad Update CHANGELOG.md 2020-05-03 16:40:26 +01:00
death-claw 10fa9f68ae v2.11.5 2020-05-03 15:18:28 +01:00
death-claw 6b5c9ccb0f Reduce rows buffer size 2020-05-03 15:16:31 +01:00
20 changed files with 95 additions and 86 deletions
+25 -2
View File
@@ -1,5 +1,28 @@
# Changelog
## [2.12.1] - 2020-05-22
### Changed
- Fix alternative name bug
## [2.12.0] - 2020-05-21
### Changed
- Use new user hash from the api
## [2.11.7] - 2020-05-08
### Changed
- Fix bug with paths creation
- Move Open Link button
- Rename rename all title
## [2.11.6] - 2020-05-04
### Changed
- PNG filenames are now correctly named
- Fix issue with special characters in post titles
## [2.11.5] - 2020-05-03
### Changed
- Reduce rows buffer size
## [2.11.4] - 2020-05-03
### Changed
- Code cleanup
@@ -11,7 +34,7 @@
- UI fixes and enhancements
### Added
- Add menu entry to rename a gallery to first alternative title
-Add menu on toolbar for massive rename to first alternative title
- Add menu on toolbar for massive rename to first alternative title
## [2.11.2] - 2020-04-26
### Changed
@@ -350,4 +373,4 @@
- Add real time communication for progress updates via websocket (SockJS)
- Add settings for download path, max concurrent download, enable/disable integration with vipergirls
- Add integration with vipergitls.to (possibility to auto leave thanks after grab post)
- Add support for acidimg.cc, imagezilla.net, imgbox.com, imx.to, pixhost.to, turboimagehost.com
- Add support for acidimg.cc, imagezilla.net, imgbox.com, imx.to, pixhost.to, turboimagehost.com
+2
View File
@@ -20,3 +20,5 @@ To build the desktop app:
mvn clean install -Pelectron -DskipTests
Maven will automatically handle front end compilation. However, for development, you will need to install a recent version of nodejs on your system.
[![Donate with PayPal](https://raw.githubusercontent.com/stefan-niedermann/paypal-donate-button/master/paypal-donate-button.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SC7M5LNWZ528Q)
+1 -1
View File
@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>tn.mnlr</groupId>
<artifactId>vripper</artifactId>
<version>2.11.4</version>
<version>2.12.1</version>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "vripper-electron",
"version": "2.11.4",
"version": "2.12.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "vripper-electron",
"version": "2.11.4",
"version": "2.12.1",
"description": "A ripper for vipergirls.to built using web technolgies",
"main": "main.js",
"author": "death-claw <53543762+death-claw@users.noreply.github.com>",
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>tn.mnlr</groupId>
<artifactId>vripper</artifactId>
<version>2.11.4</version>
<version>2.12.1</version>
</parent>
<artifactId>vripper-electron</artifactId>
<name>vripper-electron</name>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>tn.mnlr</groupId>
<artifactId>vripper</artifactId>
<version>2.11.4</version>
<version>2.12.1</version>
</parent>
<artifactId>vripper-server</artifactId>
<name>vripper-server</name>
@@ -43,7 +43,7 @@ public class Post {
private Map<String, Object> metadata;
private AtomicInteger done = new AtomicInteger(0);
private final AtomicInteger done = new AtomicInteger(0);
private int total;
@@ -53,6 +53,8 @@ public class Post {
private String forum;
private String securityToken;
@Setter
private String postFolderName;
@@ -60,7 +62,7 @@ public class Post {
this.appStateService = SpringContext.getBean(AppStateService.class);
}
public Post(String title, String url, List<Image> images, Map<String, Object> metadata, String postId, String threadId, String threadTitle, String forum) throws PostParseException {
public Post(String title, String url, List<Image> images, Map<String, Object> metadata, String postId, String threadId, String threadTitle, String forum, String securityToken) throws PostParseException {
this();
this.title = title;
this.url = url;
@@ -70,6 +72,7 @@ public class Post {
this.forum = forum;
this.threadId = threadId;
this.threadTitle = threadTitle;
this.securityToken = securityToken;
this.hosts = this.images.stream().map(Image::getHost).map(Host::getHost).collect(Collectors.toSet());
total = images.size();
status = Status.STOPPED;
@@ -178,6 +178,19 @@ abstract public class Host {
imageName = imageName.substring(0, imageName.length() - toReplace.length()) + ".jpg";
}
}
} else if (reader.getFormatName().toUpperCase().equals("PNG")) {
String imageNameLC = imageName.toLowerCase();
if (!imageNameLC.endsWith("_png")) {
imageName += ".png";
} else {
String toReplace = null;
if (imageNameLC.endsWith("_png")) {
toReplace = "_png";
}
if (toReplace != null) {
imageName = imageName.substring(0, imageName.length() - toReplace.length()) + ".png";
}
}
}
} catch (Exception e) {
throw new HostException("Failed to guess image format", e);
@@ -46,7 +46,7 @@ public class PathService {
}
public synchronized final void createDefaultPostFolder(Post post) {
File sourceFolder = _getDownloadDestinationFolder(post.getForum(), post.getThreadTitle(), post.getTitle());
File sourceFolder = _getDownloadDestinationFolder(post.getForum(), post.getThreadTitle(), sanitize(post.getTitle()));
File destFolder = makeDirs(sourceFolder);
post.setPostFolderName(destFolder.getName());
}
@@ -56,7 +56,7 @@ public class PathService {
if (post.getPostFolderName() == null) {
return;
}
File newDestFolder = makeDirs(_getDownloadDestinationFolder(post.getForum(), post.getThreadTitle(), altName));
File newDestFolder = makeDirs(_getDownloadDestinationFolder(post.getForum(), post.getThreadTitle(), sanitize(altName)));
File currentDesFolder = getDownloadDestinationFolder(post);
post.setPostFolderName(newDestFolder.getName());
@@ -23,6 +23,7 @@ import tn.mnlr.vripper.host.Host;
import javax.xml.parsers.SAXParserFactory;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import static tn.mnlr.vripper.services.PostParser.VR_API;
@@ -131,18 +132,25 @@ class VRPostParser {
private List<String> findTitleInContent(Node node) {
List<String> altTitle = new ArrayList<>();
findTitle(node, altTitle);
findTitle(node, altTitle, new AtomicBoolean(true));
return altTitle;
}
private boolean findTitle(Node node, List<String> altTitle) {
private void findTitle(Node node, List<String> altTitle, AtomicBoolean keepGoing) {
if (!keepGoing.get()) {
return;
}
if (node.getNodeName().equals("a") || node.getNodeName().equals("img")) {
return false;
keepGoing.set(false);
return;
}
if (node.getNodeType() == Node.ELEMENT_NODE) {
for (int i = 0; i < node.getChildNodes().getLength(); i++) {
Node item = node.getChildNodes().item(i);
findTitle(item, altTitle);
findTitle(item, altTitle, keepGoing);
if (!keepGoing.get()) {
return;
}
}
} else if (node.getNodeType() == Node.TEXT_NODE) {
@@ -151,7 +159,6 @@ class VRPostParser {
altTitle.add(text);
}
}
return true;
}
}
@@ -170,6 +177,7 @@ class VRApiPostHandler extends DefaultHandler {
private String threadTitle;
private String postTitle;
private String forum;
private String userHash;
private int previewCounter = 0;
private int index = 0;
private int imageCount;
@@ -200,6 +208,9 @@ class VRApiPostHandler extends DefaultHandler {
case "forum":
forum = attributes.getValue("title").trim();
break;
case "user":
userHash = attributes.getValue("hash").trim();
break;
case "thread":
threadTitle = attributes.getValue("title").trim();
break;
@@ -249,7 +260,8 @@ class VRApiPostHandler extends DefaultHandler {
postId,
threadId,
threadTitle,
forum);
forum,
userHash);
} catch (PostParseException e) {
logger.error(String.format("Error occurred while parsing postId %s", postId));
}
@@ -5,7 +5,6 @@ import lombok.Getter;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.cookie.Cookie;
@@ -17,13 +16,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import tn.mnlr.vripper.entities.Post;
import tn.mnlr.vripper.exception.VripperException;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Service
@@ -32,13 +29,11 @@ public class VipergirlsAuthService {
private static final Logger logger = LoggerFactory.getLogger(VipergirlsAuthService.class);
private final ConnectionManager cm;
private final HtmlProcessorService htmlProcessorService;
private final XpathService xpathService;
private final AppSettingsService appSettingsService;
private final CommonExecutor commonExecutor;
@Getter
private HttpClientContext context = HttpClientContext.create();
private final HttpClientContext context = HttpClientContext.create();
@Getter
private boolean authenticated = false;
@@ -47,13 +42,11 @@ public class VipergirlsAuthService {
private String loggedUser;
@Getter
private PublishProcessor<String> loggedInUser = PublishProcessor.create();
private final PublishProcessor<String> loggedInUser = PublishProcessor.create();
@Autowired
public VipergirlsAuthService(ConnectionManager cm, HtmlProcessorService htmlProcessorService, XpathService xpathService, AppSettingsService appSettingsService, CommonExecutor commonExecutor) {
public VipergirlsAuthService(ConnectionManager cm, AppSettingsService appSettingsService, CommonExecutor commonExecutor) {
this.cm = cm;
this.htmlProcessorService = htmlProcessorService;
this.xpathService = xpathService;
this.appSettingsService = appSettingsService;
this.commonExecutor = commonExecutor;
}
@@ -95,14 +88,10 @@ public class VipergirlsAuthService {
HttpPost postAuth = cm.buildHttpPost("https://vipergirls.to/login.php?do=login");
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("vb_login_username", username));
params.add(new BasicNameValuePair("vb_login_password", ""));
params.add(new BasicNameValuePair("vb_login_password_hint", "Password"));
params.add(new BasicNameValuePair("cookieuser", "1"));
params.add(new BasicNameValuePair("securitytoken", "guest"));
params.add(new BasicNameValuePair("do", "login"));
params.add(new BasicNameValuePair("vb_login_md5password", password));
params.add(new BasicNameValuePair("vb_login_md5password_utf", password));
try {
postAuth.setEntity(new UrlEncodedFormEntity(params));
} catch (Exception e) {
@@ -163,56 +152,21 @@ public class VipergirlsAuthService {
}
commonExecutor.getGeneralExecutor().submit(() -> {
try {
postThanks(post, getSecurityToken(post.getUrl()));
postThanks(post);
} catch (Exception e) {
logger.error(String.format("Failed to leave a thanks for url %s, post id %s", post.getUrl(), post.getPostId()), e);
}
});
}
private String getSecurityToken(String url) throws VripperException {
String securityToken;
HttpGet httpGet = cm.buildHttpGet(url);
httpGet.addHeader("Referer", "https://vipergirls.to/");
httpGet.addHeader("Host", "vipergirls.to");
CloseableHttpClient client = cm.getClient().build();
try (CloseableHttpResponse response = client.execute(httpGet, context)) {
String postPage = EntityUtils.toString(response.getEntity());
Document document = htmlProcessorService.clean(postPage);
String thanksUrl = xpathService
.getAsNode(document, "//li[contains(@id,'post_')][not(contains(@id,'post_thank'))]//a[@class='post_thanks_button']")
.getAttributes()
.getNamedItem("href")
.getTextContent()
.trim();
securityToken = Arrays.stream(thanksUrl.split("&amp;"))
.filter(v -> v.startsWith("securitytoken"))
.findAny()
.orElse("")
.replace("securitytoken=", "");
EntityUtils.consumeQuietly(response.getEntity());
} catch (Exception e) {
throw new VripperException(e);
}
return securityToken;
}
private void postThanks(Post post, String securityKey) throws VripperException {
private void postThanks(Post post) throws VripperException {
HttpPost postThanks = cm.buildHttpPost("https://vipergirls.to/post_thanks.php");
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("do", "post_thanks_add"));
params.add(new BasicNameValuePair("using_ajax", "1"));
params.add(new BasicNameValuePair("p", post.getPostId()));
params.add(new BasicNameValuePair("securitytoken", securityKey));
params.add(new BasicNameValuePair("securitytoken", post.getSecurityToken()));
try {
postThanks.setEntity(new UrlEncodedFormEntity(params));
} catch (Exception e) {
@@ -225,10 +179,16 @@ public class VipergirlsAuthService {
CloseableHttpClient client = cm.getClient().build();
try (CloseableHttpResponse response = client.execute(postThanks, context)) {
post.getMetadata().put(Post.METADATA.THANKED.name(), true);
if (response.getStatusLine().getStatusCode() / 100 == 2) {
post.getMetadata().put(Post.METADATA.THANKED.name(), true);
}
EntityUtils.consumeQuietly(response.getEntity());
} catch (Exception e) {
throw new VripperException(e);
}
if (!((Boolean) post.getMetadata().get(Post.METADATA.THANKED.name()))) {
throw new VripperException("Failed to leave");
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "vripper-ui",
"version": "2.11.4",
"version": "2.12.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "vripper-ui",
"version": "2.11.4",
"version": "2.12.1",
"scripts": {
"ng": "ng",
"start": "ng serve",
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>tn.mnlr</groupId>
<artifactId>vripper</artifactId>
<version>2.11.4</version>
<version>2.12.1</version>
</parent>
<artifactId>vripper-ui</artifactId>
<name>vripper-ui</name>
@@ -1,9 +1,5 @@
<mat-card class="mat-elevation-z4">
<mat-action-list>
<button (click)="goTo()" ngxClipboard [cbContent]="postState.url" mat-list-item>
<mat-icon>open_in_new</mat-icon>
<span>Open link</span>
</button>
<button
(click)="restart()"
*ngIf="
@@ -32,10 +28,6 @@
<mat-icon>list</mat-icon>
<span>Files</span>
</button>
<button *ngIf="isViewEnabled | async" (click)="openGallery()" mat-list-item>
<mat-icon>photo_library</mat-icon>
<span>View Photos</span>
</button>
<button (click)="useAltTitle()" mat-list-item>
<mat-icon>edit</mat-icon>
<span>Use alternative title</span>
@@ -44,6 +36,10 @@
<mat-icon>edit</mat-icon>
<span>Rename</span>
</button>
<button (click)="goTo()" ngxClipboard [cbContent]="postState.url" mat-list-item>
<mat-icon>open_in_new</mat-icon>
<span>Open link</span>
</button>
<button (click)="open()" *ngIf="electronService.isElectronApp" mat-list-item>
<mat-icon>folder</mat-icon>
<span>Download Location</span>
@@ -35,7 +35,6 @@ export class PostsComponent implements OnInit, OnDestroy, AfterViewInit {
headerCheckboxSelectionFilteredOnly: true
}
],
rowBuffer: 200,
rowHeight: 60,
animateRows: true,
rowSelection: 'multiple',
@@ -16,8 +16,9 @@
title="Stop selected">
<mat-icon>pause</mat-icon>
</button>
<button (click)="rename()" [disabled]="disableSelection | async" aria-label="Rename selected" mat-icon-button
title="Rename selected">
<button (click)="rename()" [disabled]="disableSelection | async" aria-label="Rename selected to alternative title"
mat-icon-button
title="Rename selected to alternative title">
<mat-icon>edit</mat-icon>
</button>
<div class="or-spacer-vertical left">
@@ -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: '2.11.4'
version: '2.12.1'
};
+1 -1
View File
@@ -6,7 +6,7 @@ export const environment = {
production: false,
localhost: 'http://localhost:8080',
ws: 'ws://localhost:8080',
version: '2.11.4'
version: '2.12.1'
};
/*