*Plugins: Fixes/Changes/Maintenance*

- DeviantArtCom: added more precise errorhandling for account-only items RE forum 93906 refs #84455
- Bunkr: added generic detection for html based errors such as "The server hosting this file is currently overloaded. We've limited the download of this file* for now until the server is no longer overloaded. Apologies." RE ticket #XTAH9549-HIOZ-5861SOYK
- XFileSharingProBasic: updated errormessage for items that can only be downloaded via account refs #84455
- ResearchgateNet: minor changes
- KatholischDe: added missing htmldecode RE forum 94401
- rapideo.net and nopremium.pl: refactored plugins to use the same codebase, updated them to use the API only and added better errorhandling RE ticket #ZCUY2092-HWHC-6714QLEW

git-svn-id: svn://svn.jdownloader.org/jdownloader/trunk@49624 ebf7c1c2-ba36-0410-9fe8-c592906822b4

Former-commit-id: 752f648735d9c0863c2fbb185243b04bbc44ac15
This commit is contained in:
psp 2024-08-21 11:59:05 +00:00
parent bf1ffbbeda
commit 368550e845
9 changed files with 407 additions and 766 deletions

View File

@ -22,6 +22,7 @@ import org.appwork.utils.StringUtils;
import jd.PluginWrapper;
import jd.controlling.ProgressController;
import jd.http.Browser;
import jd.nutils.encoding.Encoding;
import jd.plugins.CryptedLink;
import jd.plugins.DecrypterPlugin;
import jd.plugins.DownloadLink;
@ -48,19 +49,20 @@ public class KatholischDe extends PluginForDecrypt {
/* Fallback */
title = br._getURL().getPath().replace("-", " ");
}
title = Encoding.htmlDecode(title).trim();
final String m3u8 = br.getRegex("file\\s*:\\s*'(https?://[^']*\\.m3u8)'").getMatch(0);
if (StringUtils.isEmpty(title) || StringUtils.isEmpty(m3u8)) {
return new ArrayList<DownloadLink>();
} else {
final Browser brc = br.cloneBrowser();
brc.getPage(m3u8);
final ArrayList<DownloadLink> ret = GenericM3u8Decrypter.parseM3U8(this, m3u8, brc, null, null, title);
if (ret.size() > 1) {
FilePackage fp = FilePackage.getInstance();
fp.setName(title);
fp.addLinks(ret);
}
return ret;
throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND);
}
final Browser brc = br.cloneBrowser();
brc.getPage(m3u8);
final ArrayList<DownloadLink> ret = GenericM3u8Decrypter.parseM3U8(this, m3u8, brc, null, null, title);
final FilePackage fp = FilePackage.getInstance();
fp.setName(title);
for (final DownloadLink result : ret) {
// result.setContainerUrl(br.getURL());
result._setFilePackage(fp);
}
return ret;
}
}

View File

@ -9,6 +9,11 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import org.appwork.utils.StringUtils;
import org.appwork.utils.formatter.SizeFormatter;
import org.jdownloader.plugins.components.config.BunkrConfig;
import org.jdownloader.plugins.config.PluginJsonConfig;
import jd.PluginWrapper;
import jd.http.Browser;
import jd.http.URLConnectionAdapter;
@ -26,11 +31,6 @@ import jd.plugins.PluginException;
import jd.plugins.PluginForHost;
import jd.plugins.decrypter.BunkrAlbum;
import org.appwork.utils.StringUtils;
import org.appwork.utils.formatter.SizeFormatter;
import org.jdownloader.plugins.components.config.BunkrConfig;
import org.jdownloader.plugins.config.PluginJsonConfig;
@HostPlugin(revision = "$Revision$", interfaceVersion = 3, names = {}, urls = {})
@PluginDependencies(dependencies = { BunkrAlbum.class })
public class Bunkr extends PluginForHost {
@ -288,10 +288,10 @@ public class Bunkr extends PluginForHost {
}
String directurl;
if (new Regex(link.getPluginPatternMatcher(), BunkrAlbum.PATTERN_SINGLE_FILE).patternFind()) {
directurl = getDirecturlFromSingleFileAvailablecheck(link, contenturl, true);
directurl = getDirecturlFromSingleFileAvailablecheck(link, contenturl, true, isDownload);
if (!isDownload) {
return AvailableStatus.TRUE;
} else {
} else if (!StringUtils.isEmpty(directurl)) {
this.sleep(1000, link);
}
} else {
@ -304,6 +304,10 @@ public class Bunkr extends PluginForHost {
br.getHeaders().put("Referer", "https://" + Browser.getHost(directurl, false) + "/");
}
}
if (StringUtils.isEmpty(directurl)) {
handleHTMLErrors(link, br);
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
}
URLConnectionAdapter con = null;
try {
if (isDownload) {
@ -334,7 +338,7 @@ public class Bunkr extends PluginForHost {
/* E.g. resume of download which does not work at this stage -> Access URL to get HTML code. */
br.getPage(singleFileURL);
}
final String freshDirecturl = getDirecturlFromSingleFileAvailablecheck(link, br.getURL(), false);
final String freshDirecturl = getDirecturlFromSingleFileAvailablecheck(link, br.getURL(), false, isDownload);
/* Avoid trying again with the same directurl if we already know the result. */
if (StringUtils.equals(freshDirecturl, lastCachedDirecturl) && exceptionFromDirecturlCheck != null) {
throw exceptionFromDirecturlCheck;
@ -376,7 +380,7 @@ public class Bunkr extends PluginForHost {
return AvailableStatus.TRUE;
}
private String getDirecturlFromSingleFileAvailablecheck(final DownloadLink link, final String singleFileURL, final boolean accessURL) throws PluginException, IOException {
private String getDirecturlFromSingleFileAvailablecheck(final DownloadLink link, final String singleFileURL, final boolean accessURL, final boolean isDownload) throws PluginException, IOException {
link.setProperty(PROPERTY_LAST_GRABBED_DIRECTURL, null);
if (accessURL) {
br.getPage(singleFileURL);
@ -455,18 +459,16 @@ public class Bunkr extends PluginForHost {
}
}
}
if (directurl == null) {
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
if (directurl != null) {
directurl = Encoding.htmlOnlyDecode(directurl);
final String filename = getFilenameFromURL(directurl);
if (filename != null) {
setFilename(link, filename, true, true);
}
link.setProperty(PROPERTY_LAST_GRABBED_DIRECTURL, directurl);
} else {
logger.warning("Failed to find directurl");
}
directurl = Encoding.htmlOnlyDecode(directurl);
final String filename = getFilenameFromURL(directurl);
if (filename != null) {
setFilename(link, filename, true, true);
} else if (!link.isNameSet()) {
/* Unsafe name */
setFilename(link, filename, true, false);
}
link.setProperty(PROPERTY_LAST_GRABBED_DIRECTURL, directurl);
link.setProperty(PROPERTY_LAST_USED_SINGLE_FILE_URL, singleFileURL);
return directurl;
}
@ -549,6 +551,7 @@ public class Bunkr extends PluginForHost {
if (!this.looksLikeDownloadableContent(con)) {
br.followConnection(true);
handleResponsecodeErrors(con);
handleHTMLErrors(link, br);
throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, "File broken or temporarily unavailable", 2 * 60 * 60 * 1000l);
} else if (con.getURL().getPath().equalsIgnoreCase("/maintenance-vid.mp4") || con.getURL().getPath().equalsIgnoreCase("/v/maintenance-kek-bunkr.webm") || con.getURL().getPath().equalsIgnoreCase("/maintenance.mp4")) {
con.disconnect();
@ -559,6 +562,17 @@ public class Bunkr extends PluginForHost {
}
}
private void handleHTMLErrors(final DownloadLink link, final Browser br) throws PluginException {
final String downloadDisabledError = br.getRegex("class=\"down_disabled\"[^>]*>([^<]+)</div>").getMatch(0);
if (downloadDisabledError != null) {
/*
* E.g. <div class="down_disabled">The server hosting this file is currently overloaded. We've limited the download of this file
* for now until the server is no longer overloaded. Apologies.</div>
*/
throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, Encoding.htmlDecode(downloadDisabledError).trim(), 2 * 60 * 60 * 1000l);
}
}
private void handleResponsecodeErrors(final URLConnectionAdapter con) throws PluginException {
if (con.getResponseCode() == 403) {
throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, "Server error 403", 10 * 60 * 1000l);

View File

@ -22,6 +22,7 @@ import java.util.Map;
import org.appwork.storage.TypeRef;
import org.appwork.utils.Regex;
import org.appwork.utils.StringUtils;
import org.appwork.utils.formatter.SizeFormatter;
import org.appwork.utils.formatter.TimeFormatter;
import org.appwork.utils.parser.UrlQuery;
@ -366,6 +367,9 @@ public class CamvaultXyz extends PluginForHost {
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
}
final String fid = dlform.getInputFieldByName("videoToken").getValue();
if (StringUtils.isEmpty(fid)) {
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
}
link.setProperty(PROPERTY_INTERNAL_FILE_ID, fid);
/* 2023-11-28: They've added a captcha for premium downloads. */
String recaptchaV2Response = null;
@ -396,17 +400,11 @@ public class CamvaultXyz extends PluginForHost {
final String token = entries.get("token").toString();
dlform.setAction(br._getURL().getProtocol() + "://" + cdn + "/");
dlform.put("downloadToken", Encoding.urlEncode(token));
/* The following headers are not mandatory. */
br.getHeaders().put("Origin", "https://" + br2.getHost(true));
br.getHeaders().put("Referer", "https://" + br2.getHost(true) + "/");
dl = jd.plugins.BrowserAdapter.openDownload(br, link, dlform, false, 1);
if (!this.looksLikeDownloadableContent(dl.getConnection())) {
br.followConnection(true);
if (dl.getConnection().getResponseCode() == 403) {
throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, "Server error 403", 60 * 60 * 1000l);
} else if (dl.getConnection().getResponseCode() == 404) {
throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, "Server error 404", 60 * 60 * 1000l);
} else {
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
}
}
handleConnectionErrors(br, dl.getConnection());
dl.startDownload();
}
}

View File

@ -30,6 +30,18 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.appwork.storage.TypeRef;
import org.appwork.utils.StringUtils;
import org.appwork.utils.formatter.SizeFormatter;
import org.jdownloader.captcha.v2.challenge.recaptcha.v2.CaptchaHelperHostPluginRecaptchaV2;
import org.jdownloader.downloader.text.TextDownloader;
import org.jdownloader.gui.translate._GUI;
import org.jdownloader.plugins.components.config.DeviantArtComConfig;
import org.jdownloader.plugins.components.config.DeviantArtComConfig.ImageDownloadMode;
import org.jdownloader.plugins.config.PluginJsonConfig;
import org.jdownloader.plugins.controller.LazyPlugin;
import org.jdownloader.scripting.JavaScriptEngineFactory;
import jd.PluginWrapper;
import jd.controlling.AccountController;
import jd.http.Browser;
@ -53,18 +65,6 @@ import jd.plugins.PluginException;
import jd.plugins.PluginForHost;
import jd.plugins.components.PluginJSonUtils;
import org.appwork.storage.TypeRef;
import org.appwork.utils.StringUtils;
import org.appwork.utils.formatter.SizeFormatter;
import org.jdownloader.captcha.v2.challenge.recaptcha.v2.CaptchaHelperHostPluginRecaptchaV2;
import org.jdownloader.downloader.text.TextDownloader;
import org.jdownloader.gui.translate._GUI;
import org.jdownloader.plugins.components.config.DeviantArtComConfig;
import org.jdownloader.plugins.components.config.DeviantArtComConfig.ImageDownloadMode;
import org.jdownloader.plugins.config.PluginJsonConfig;
import org.jdownloader.plugins.controller.LazyPlugin;
import org.jdownloader.scripting.JavaScriptEngineFactory;
@HostPlugin(revision = "$Revision$", interfaceVersion = 3, names = { "deviantart.com" }, urls = { "https?://[\\w\\.\\-]*?deviantart\\.com/(([\\w\\-]+/)?(art|journal)/[\\w\\-]+-\\d+|([\\w\\-]+/)?status(?:-update)?/\\d+)" })
public class DeviantArtCom extends PluginForHost {
private final String TYPE_DOWNLOADALLOWED_HTML = "(?i)class=\"text\">HTML download</span>";
@ -219,7 +219,6 @@ public class DeviantArtCom extends PluginForHost {
displayedVideoSize = (Number) bestType.get("f");
}
}
}
} catch (Exception e) {
plugin.getLogger().log(e);
@ -278,6 +277,7 @@ public class DeviantArtCom extends PluginForHost {
Number originalFileSizeBytes = null;
String tierAccess = null;
List<String> blockReasons = new ArrayList<String>();
Map<String, Object> premiumFolderData = null;
String deviationHTML = null;
if (json != null) {
json = PluginJSonUtils.unescape(json);
@ -323,6 +323,7 @@ public class DeviantArtCom extends PluginForHost {
/* A status typically doesn't have a title so we goota create our own. */
title = fid + " by " + username;
}
premiumFolderData = (Map<String, Object>) thisArt.get("premiumFolderData");
if (StringUtils.isEmpty(officialDownloadurl)) {
final Map<String, Object> deviationExtended = (Map<String, Object>) entities.get("deviationExtended");
if (deviationExtended != null) {
@ -393,8 +394,8 @@ public class DeviantArtCom extends PluginForHost {
dllink = getDirecturl(br, link, account);
} catch (final PluginException e) {
/**
* This will happen if the item is not downloadable. </br> We're ignoring this during linkcheck as by now we know the file is
* online.
* This will happen if the item is not downloadable. </br>
* We're ignoring this during linkcheck as by now we know the file is online.
*/
}
String extByMimeType = null;
@ -468,6 +469,13 @@ public class DeviantArtCom extends PluginForHost {
link.setDownloadSize(originalFileSizeBytes.longValue());
}
throw new AccountRequiredException("Paid content");
} else if (premiumFolderData != null && Boolean.FALSE.equals(premiumFolderData.get("hasAccess"))) {
final String premiumType = (String) premiumFolderData.get("type");
if (StringUtils.equalsIgnoreCase(premiumType, "watchers")) {
throw new AccountRequiredException("Item is only accessible for followers of this artist");
} else {
throw new AccountRequiredException("Item blocked for reasons: " + blockReasons);
}
} else if (blockReasons != null && !blockReasons.isEmpty()) {
/* Mature content (account required) or blocked for other reasons. */
/* Examples for block reasons we can always circumvent: mature_filter */
@ -703,7 +711,8 @@ public class DeviantArtCom extends PluginForHost {
}
} else if (isBlurredImageLink(dllink)) {
/**
* Last resort errorhandling for "probably premium-only items". </br> This should usually be catched before.
* Last resort errorhandling for "probably premium-only items". </br>
* This should usually be catched before.
*/
throw new PluginException(LinkStatus.ERROR_FATAL, "Avoiding download of blurred image");
}

View File

@ -15,155 +15,50 @@
//along with this program. If not, see <http://www.gnu.org/licenses/>.
package jd.plugins.hoster;
import java.util.ArrayList;
import org.appwork.utils.formatter.SizeFormatter;
import org.jdownloader.plugins.controller.LazyPlugin;
import jd.PluginWrapper;
import jd.nutils.JDHash;
import jd.nutils.encoding.Encoding;
import jd.plugins.Account;
import jd.plugins.AccountInfo;
import jd.plugins.AccountInvalidException;
import jd.plugins.AccountUnavailableException;
import jd.plugins.DownloadLink;
import jd.plugins.DownloadLink.AvailableStatus;
import jd.plugins.HostPlugin;
import jd.plugins.LinkStatus;
import jd.plugins.PluginException;
import jd.plugins.PluginForHost;
import jd.plugins.components.MultiHosterManagement;
@HostPlugin(revision = "$Revision$", interfaceVersion = 3, names = { "nopremium.pl" }, urls = { "" })
public class NoPremiumPl extends PluginForHost {
protected static MultiHosterManagement mhm = new MultiHosterManagement("rapidtraffic.pl");
public class NoPremiumPl extends RapideoCore {
protected static MultiHosterManagement mhm = new MultiHosterManagement("nopremium.pl");
public NoPremiumPl(PluginWrapper wrapper) {
super(wrapper);
this.enablePremium("https://www.nopremium.pl/offer");
this.enablePremium("https://www." + getHost() + "/offer");
}
@Override
public String getAGBLink() {
return "https://www.nopremium.pl/tos";
return "https://www." + getHost() + "/tos";
}
@Override
public LazyPlugin.FEATURE[] getFeatures() {
return new LazyPlugin.FEATURE[] { LazyPlugin.FEATURE.MULTIHOST };
protected MultiHosterManagement getMultiHosterManagement() {
return mhm;
}
@Override
public AccountInfo fetchAccountInfo(Account account) throws Exception {
final AccountInfo ac = new AccountInfo();
// check if account is valid
br.postPage("http://crypt.nopremium.pl", "username=" + Encoding.urlEncode(account.getUser()) + "&password=" + JDHash.getSHA1(JDHash.getMD5(account.getPass())) + "&info=1&site=nopremium");
String adres = br.toString();
br.getPage(adres);
adres = br.getRedirectLocation();
br.getPage(adres);
// "Invalid login" / "Banned" / "Valid login"
if (br.containsHTML("Zbyt wiele prób logowania - dostęp został tymczasowo zablokowany")) {
throw new AccountInvalidException("Zbyt wiele prób logowania - dostęp został tymczasowo zablokowany");
} else if (br.containsHTML("balance")) {
ac.setStatus("Premium Account");
} else if (br.containsHTML("Nieprawidlowa nazwa uzytkownika/haslo")) {
throw new AccountInvalidException();
} else {
// unknown error
throw new AccountInvalidException("Unknown account status");
}
ac.setTrafficLeft(SizeFormatter.getSize(br.getRegex("balance=(\\d+)").getMatch(0) + "MB"));
account.setMaxSimultanDownloads(20);
account.setConcurrentUsePossible(true);
ac.setValidUntil(-1);
// now let's get a list of all supported hosts:
br.getPage("https://nopremium.pl/clipboard.php"); // different domain!
final String[] hosts = br.toString().split("<br />");
final ArrayList<String> supportedHosts = new ArrayList<String>();
for (String host : hosts) {
if (!host.isEmpty()) {
supportedHosts.add(host.trim());
}
}
/** 2023-08-14: Workaround because they sometimes don't update their API list of supported hosts... */
final boolean tryToFindMoreHostsViaWebsite = true;
if (tryToFindMoreHostsViaWebsite) {
try {
br.getPage("https://www." + this.getHost() + "/");
final String[] hostsWithoutTld = br.getRegex("class=\"ServerLogo\"[^>]*alt=\"([^\"]+)").getColumn(0);
if (hostsWithoutTld != null && hostsWithoutTld.length != 0) {
for (final String hostWithoutTld : hostsWithoutTld) {
supportedHosts.add(hostWithoutTld);
}
} else {
logger.warning("Website workaround for finding additional supported hosts failed");
}
} catch (final Throwable e) {
logger.log(e);
logger.warning("Website workaround for finding additional supported hosts failed with exception");
}
}
ac.setMultiHostSupport(this, supportedHosts);
return ac;
protected String getAPIBase() {
return "https://crypt." + getHost() + "/";
}
@Override
public int getMaxSimultanFreeDownloadNum() {
return 0;
protected String getAPISiteParam() {
return "nopremium";
}
@Override
public void handleFree(DownloadLink downloadLink) throws Exception, PluginException {
throw new PluginException(LinkStatus.ERROR_PREMIUM, PluginException.VALUE_ID_PREMIUM_ONLY);
}
/* no override to keep plugin compatible to old stable */
public void handleMultiHost(final DownloadLink link, final Account account) throws Exception {
mhm.runCheck(account, link);
String postData = "username=" + Encoding.urlEncode(account.getUser()) + "&password=" + JDHash.getSHA1(JDHash.getMD5(account.getPass())) + "&info=0&url=" + Encoding.urlEncode(link.getDownloadURL()) + "&site=nopremium";
String response = br.postPage("http://crypt.nopremium.pl", postData);
br.setFollowRedirects(true);
dl = jd.plugins.BrowserAdapter.openDownload(br, link, response, true, 0);
/*
* I really wanted to use Content Disposition below, but it just don't work for resume at hotfile -> Doesn't matter anymore, hotfile
* is offline
*/
if (!this.looksLikeDownloadableContent(dl.getConnection())) {
br.followConnection(true);
if (br.containsHTML("Brak")) {
/* No transfer left */
throw new AccountUnavailableException("No traffic left", 5 * 60 * 1000l);
} else if (br.containsHTML("Nieprawidlowa")) {
/* Wrong username/password */
throw new AccountInvalidException();
} else if (br.containsHTML("Konto")) {
/* Account Expired */
throw new AccountInvalidException("Account expired");
} else if (br.containsHTML("15=Hosting nie obslugiwany")) {
/* Host not supported */
mhm.putError(account, link, 5 * 60 * 1000l, "Host not supported");
} else {
mhm.handleErrorGeneric(account, link, "Final downloadurl did not lead to downloadable file", 50, 5 * 60 * 1000);
}
}
dl.startDownload();
protected String getPasswordAPI(Account account) {
return JDHash.getSHA1(JDHash.getMD5(account.getPass()));
}
@Override
public AvailableStatus requestFileInformation(DownloadLink link) throws Exception {
return AvailableStatus.UNCHECKABLE;
}
@Override
public boolean canHandle(final DownloadLink link, final Account account) throws Exception {
if (account == null) {
return false;
} else {
mhm.runCheck(account, link);
return true;
}
protected boolean useAPI() {
return true;
}
@Override

View File

@ -15,8 +15,9 @@
//along with this program. If not, see <http://www.gnu.org/licenses/>.
package jd.plugins.hoster;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashSet;
@ -25,6 +26,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Random;
import org.appwork.storage.JSonMapperException;
import org.appwork.storage.TypeRef;
import org.appwork.utils.StringUtils;
import org.appwork.utils.formatter.SizeFormatter;
@ -34,7 +36,6 @@ import org.jdownloader.plugins.controller.LazyPlugin;
import jd.PluginWrapper;
import jd.http.Browser;
import jd.http.Cookies;
import jd.nutils.JDHash;
import jd.nutils.encoding.Encoding;
import jd.parser.html.Form;
import jd.plugins.Account;
@ -53,8 +54,6 @@ import jd.plugins.components.MultiHosterManagement;
@HostPlugin(revision = "$Revision$", interfaceVersion = 3, names = {}, urls = {})
public abstract class RapideoCore extends PluginForHost {
private static final String PROPERTY_DIRECTURL = "rapideopldirectlink";
@Override
public Browser createNewBrowserInstance() {
final Browser br = super.createNewBrowserInstance();
@ -92,8 +91,11 @@ public abstract class RapideoCore extends PluginForHost {
protected abstract MultiHosterManagement getMultiHosterManagement();
/* Domain used for "enc.domain.tld" requests. */
protected abstract String getAPIDomain();
/**
* rapideo.net: enc.rapideo.pl </br>
* nopremium.pl: crypt.nopremium.pl
*/
protected abstract String getAPIBase();
/**
* rapideo.net: newrd </br>
@ -101,126 +103,259 @@ public abstract class RapideoCore extends PluginForHost {
*/
protected abstract String getAPISiteParam();
protected abstract boolean useAPIInDownloadMode();
/** If this returns true, only API will be used, otherwise only website. */
protected abstract boolean useAPI();
/** Returns value used as password for API requests. */
protected abstract String getPasswordAPI(final Account account);
@Override
public AccountInfo fetchAccountInfo(final Account account) throws Exception {
final AccountInfo ac = new AccountInfo();
login(account, true);
final boolean obtainTrafficViaOldAPI = true;
if (obtainTrafficViaOldAPI) {
/* API used in their browser addons */
final Browser brc = br.cloneBrowser();
final UrlQuery query = new UrlQuery();
query.add("site", getAPISiteParam());
query.add("output", "json");
query.add("loc", "1");
query.add("info", "1");
query.add("username", Encoding.urlEncode(account.getUser()));
query.add("password", md5HEX(account.getPass()));
brc.postPage("https://enc." + getAPIDomain() + "/", query);
final Map<String, Object> root = restoreFromString(brc.getRequest().getHtmlCode(), TypeRef.MAP);
final String trafficLeftStr = root.get("balance").toString();
if (trafficLeftStr != null && trafficLeftStr.matches("\\d+")) {
ac.setTrafficLeft(Long.parseLong(trafficLeftStr) * 1024);
}
if (this.useAPI()) {
return this.fetchAccountInfoAPI(account);
} else {
/* Obtain "Traffic left" value from website */
final String trafficLeftStr = br.getRegex("(?i)\">\\s*(?:Account balance|Stan Twojego konta)\\s*:\\s*(\\d+(\\.\\d{1,2})? [A-Za-z]{1,5})").getMatch(0);
if (trafficLeftStr != null) {
ac.setTrafficLeft(SizeFormatter.getSize(trafficLeftStr));
return this.fetchAccountInfoWebsite(account);
}
}
private AccountInfo fetchAccountInfoWebsite(final Account account) throws Exception {
loginWebsite(account, true);
final AccountInfo ac = new AccountInfo();
/* Obtain "Traffic left" value from website */
String trafficLeftStr = br.getRegex("\">\\s*(?:Account balance|Stan Twojego konta)\\s*:\\s*(\\d+(\\.\\d{1,2})? [A-Za-z]{1,5})").getMatch(0);
if (trafficLeftStr == null) {
/* nopremium.pl */
trafficLeftStr = br.getRegex("Pozostały transfer:\\s*<span[^>]*>([^<]+)</span>").getMatch(0);
}
if (trafficLeftStr != null) {
ac.setTrafficLeft(SizeFormatter.getSize(trafficLeftStr));
} else {
logger.warning("Failed to find trafficleft value");
}
/* Get a list of all supported hosts */
br.getPage("/twoje_pliki");
checkErrorsWebsite(br, null, account);
final HashSet<String> crippledhosts = new HashSet<String>();
/*
* This will not catch stuff like <li><strong>nitroflare (beta) </strong></li> ... but we are lazy and ignore this. Such hosts will
* be found too by the 2nd regex down below.
*/
final String[] crippledHosts = br.getRegex("<li>([A-Za-z0-9\\-\\.]+)</li>").getColumn(0);
if (crippledHosts != null && crippledHosts.length > 0) {
for (final String crippledhost : crippledHosts) {
crippledhosts.add(crippledhost);
}
}
final boolean obtainSupportedHostsListViaAPI = true;
final ArrayList<String> supportedHosts = new ArrayList<String>();
boolean accountEmailActivationNeeded = false;
if (obtainSupportedHostsListViaAPI) {
/* API */
br.getPage("https://www." + getHost() + "/clipboard.php?json=3");
final List<Map<String, Object>> hosterlist = (List<Map<String, Object>>) restoreFromString(br.getRequest().getHtmlCode(), TypeRef.OBJECT);
final boolean skipNonZeroSdownloadItems = false;
for (final Map<String, Object> hosterinfo : hosterlist) {
final List<String> domains = (List<String>) hosterinfo.get("domains");
final Object sdownload = hosterinfo.get("sdownload");
if (sdownload == null || domains == null) {
/* Skip invalid items (yes they exist, tested 2024-08-20) */
continue;
}
if (sdownload.toString().equals("0") || skipNonZeroSdownloadItems == false) {
supportedHosts.addAll(domains);
} else {
logger.info("Skipping serverside disabled domains: " + domains);
}
/* Alternative place to obtain supported hosts from */
final String[] crippledhosts2 = br.getRegex("class=\"active\"[^<]*>([^<]+)</a>").getColumn(0);
if (crippledhosts2 != null && crippledhosts2.length > 0) {
for (final String crippledhost : crippledhosts2) {
crippledhosts.add(crippledhost);
}
} else {
/* Website */
/* Get a list of all supported hosts */
br.getPage("/twoje_pliki");
final HashSet<String> crippledhosts = new HashSet<String>();
/*
* This will not catch stuff like <li><strong>nitroflare (beta) </strong></li> ... but we are lazy and ignore this. Such hosts
* will be found too by the 2nd regex down below.
*/
final String[] crippledHosts = br.getRegex("<li>([A-Za-z0-9\\-\\.]+)</li>").getColumn(0);
if (crippledHosts != null && crippledHosts.length > 0) {
for (final String crippledhost : crippledHosts) {
}
/* Alternative place to obtain supported hosts from */
String htmlMetadataStr = br.getRegex("name=\"keywords\" content=\"([\\w, ]+)").getMatch(0);
if (htmlMetadataStr != null) {
htmlMetadataStr = htmlMetadataStr.replace(" ", "");
final String[] crippledhosts3 = htmlMetadataStr.split(",");
if (crippledhosts3 != null && crippledhosts3.length > 0) {
for (final String crippledhost : crippledhosts3) {
crippledhosts.add(crippledhost);
}
}
/* Alternative place to obtain supported hosts from */
final String[] crippledhosts2 = br.getRegex("class=\"active\"[^<]*>([^<]+)</a>").getColumn(0);
if (crippledhosts2 != null && crippledhosts2.length > 0) {
for (final String crippledhost : crippledhosts2) {
crippledhosts.add(crippledhost);
}
}
final List<String> supportedHosts = new ArrayList<String>();
/* Sanitize data and add to final list */
for (String crippledhost : crippledhosts) {
crippledhost = crippledhost.toLowerCase(Locale.ENGLISH);
if (crippledhost.equalsIgnoreCase("mega")) {
supportedHosts.add("mega.nz");
} else {
supportedHosts.add(crippledhost);
}
/* Alternative place to obtain supported hosts from */
String htmlMetadataStr = br.getRegex("name=\"keywords\" content=\"([\\w, ]+)").getMatch(0);
if (htmlMetadataStr != null) {
htmlMetadataStr = htmlMetadataStr.replace(" ", "");
final String[] crippledhosts3 = htmlMetadataStr.split(",");
if (crippledhosts3 != null && crippledhosts3.length > 0) {
for (final String crippledhost : crippledhosts3) {
crippledhosts.add(crippledhost);
}
}
}
/* Sanitize data and add to final list */
for (String crippledhost : crippledhosts) {
crippledhost = crippledhost.toLowerCase(Locale.ENGLISH);
if (crippledhost.equalsIgnoreCase("mega")) {
supportedHosts.add("mega.nz");
} else {
supportedHosts.add(crippledhost);
}
}
accountEmailActivationNeeded = br.containsHTML("Check your email and");
}
/*
* They only have accounts with traffic, no free/premium difference (other than no traffic) - we treat no-traffic as FREE --> Cannot
* download anything
*/
if (ac.getTrafficLeft() > 0) {
if (trafficLeftStr != null && ac.getTrafficLeft() > 0) {
account.setType(AccountType.PREMIUM);
account.setMaxSimultanDownloads(-1);
ac.setStatus("Premium account");
} else {
account.setType(AccountType.FREE);
account.setMaxSimultanDownloads(-1);
ac.setStatus("Free account (no traffic left)");
}
account.setConcurrentUsePossible(true);
ac.setMultiHostSupport(this, supportedHosts);
if (ac.getTrafficLeft() == 0 && AccountType.FREE.equals(account.getType()) && accountEmailActivationNeeded) {
if ((ac.getTrafficLeft() == 0 || trafficLeftStr == null) && AccountType.FREE.equals(account.getType()) && br.containsHTML("Check your email and")) {
/* Un-activated free account without traffic -> Not usable at all. */
throw new AccountUnavailableException("Check your email and click the confirmation link to activate your account", 5 * 60 * 1000l);
}
return ac;
}
private AccountInfo fetchAccountInfoAPI(final Account account) throws Exception {
final Map<String, Object> root = loginAPI(br.cloneBrowser(), account);
final AccountInfo ac = new AccountInfo();
final Object trafficLeftO = root.get("balance");
if (trafficLeftO != null && trafficLeftO.toString().matches("\\d+")) {
ac.setTrafficLeft(Long.parseLong(trafficLeftO.toString()) * 1024 * 1024);
} else {
ac.setTrafficLeft(0);
}
/* API */
br.getPage("https://www." + getHost() + "/clipboard.php?json=3");
final ArrayList<String> supportedHosts = new ArrayList<String>();
final List<Map<String, Object>> hosterlist = (List<Map<String, Object>>) restoreFromString(br.getRequest().getHtmlCode(), TypeRef.OBJECT);
final boolean skipNonZeroSdownloadItems = false;
for (final Map<String, Object> hosterinfo : hosterlist) {
final List<String> domains = (List<String>) hosterinfo.get("domains");
final Object sdownload = hosterinfo.get("sdownload");
if (sdownload == null || domains == null) {
/* Skip invalid items (yes they exist, tested 2024-08-20) */
continue;
}
if (sdownload.toString().equals("0") || skipNonZeroSdownloadItems == false) {
supportedHosts.addAll(domains);
} else {
logger.info("Skipping serverside disabled domains: " + domains);
}
}
/*
* They only have accounts with traffic, no free/premium difference (other than no traffic) - we treat no-traffic as FREE --> Cannot
* download anything
*/
if (trafficLeftO != null && ac.getTrafficLeft() > 0) {
account.setType(AccountType.PREMIUM);
} else {
account.setType(AccountType.FREE);
}
account.setConcurrentUsePossible(true);
ac.setMultiHostSupport(this, supportedHosts);
return ac;
}
private void loginWebsite(final Account account, final boolean verifyCookies) throws Exception {
synchronized (account) {
br.setCookiesExclusive(true);
final Cookies cookies = account.loadCookies("");
if (cookies != null) {
br.setCookies(this.getHost(), cookies);
if (!verifyCookies) {
/* Don't verify */
return;
}
logger.info("Checking login cookies");
br.getPage("https://www." + getHost() + "/");
if (loggedINWebsite(this.br)) {
logger.info("Successfully loggedin via cookies");
account.saveCookies(br.getCookies(br.getHost()), "");
return;
} else {
logger.info("Failed to login via cookies");
}
}
logger.info("Attempting full login");
br.getPage("https://www." + getHost() + "/login");
checkErrorsWebsite(br, null, account);
/*
* 2020-11-02: There are two Forms matching this but the first one is the one we want - the 2nd one is the
* "register new account" Form.
*/
final Form loginform = br.getFormbyKey("remember");
if (loginform == null) {
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT, "Failed to find loginform");
}
loginform.put("login", Encoding.urlEncode(account.getUser()));
loginform.put("password", Encoding.urlEncode(account.getPass()));
loginform.put("remember", "on");
br.submitForm(loginform);
checkErrorsWebsite(br, null, account);
if (!loggedINWebsite(br)) {
throw new AccountInvalidException();
}
account.saveCookies(br.getCookies(br.getHost()), "");
return;
}
}
private boolean loggedINWebsite(final Browser br) {
if (br.containsHTML("Logged in as\\s*:|Zalogowany jako\\s*:")) {
return true;
} else {
return false;
}
}
private Map<String, Object> loginAPI(final Browser br, final Account account) throws IOException, PluginException {
final UrlQuery query = new UrlQuery();
query.add("site", getAPISiteParam());
query.add("output", "json");
query.add("loc", "1");
query.add("info", "1");
query.add("username", Encoding.urlEncode(account.getUser()));
query.add("password", getPasswordAPI(account));
br.postPage(getAPIBase(), query);
final Map<String, Object> root = this.checkErrorsAPI(br, null, account);
return root;
}
private void checkErrorsWebsite(final Browser br, final DownloadLink link, final Account account) throws PluginException {
final String geoLoginFailure = br.getRegex(">\\s*(You login from a different location than usual[^<]*)<").getMatch(0);
if (geoLoginFailure != null) {
/* 2020-11-02: Login from unusual location -> User has to confirm via URL send by mail and then try again in JD (?!). */
throw new AccountUnavailableException(geoLoginFailure + "\r\nOnce done, refresh your account in JDownloader.", 5 * 60 * 1000l);
} else if (br.containsHTML("<title>\\s*Dostęp zabroniony\\s*</title>")) {
errorBannedIP(account);
}
}
private Map<String, Object> checkErrorsAPI(final Browser br, final DownloadLink link, final Account account) throws PluginException {
Map<String, Object> entries = null;
try {
entries = (Map<String, Object>) restoreFromString(br.getRequest().getHtmlCode(), TypeRef.OBJECT);
} catch (final JSonMapperException e) {
/* Check for html based errors */
this.checkErrorsWebsite(br, link, account);
/* Check misc API responses */
if (br.getHttpConnection().getResponseCode() == 403) {
errorBannedIP(account);
}
/* Dead end */
final String errortext = "Invalid API response";
if (link == null) {
throw new AccountUnavailableException(errortext, 5 * 60 * 1000l);
} else {
throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, errortext);
}
}
return checkErrorsAPI(entries, link, account);
}
private final void errorBannedIP(final Account account) throws AccountUnavailableException {
throw new AccountUnavailableException("Your IP has been banned", 5 * 60 * 1000l);
}
private Map<String, Object> checkErrorsAPI(final Map<String, Object> entries, final DownloadLink link, final Account account) throws PluginException {
final Number errno = (Number) entries.get("errno");
final String error = (String) entries.get("errstring");
if (error == null || errno == null) {
/* No error */
return entries;
}
/* 2024-08-21: At this moment, we only handle account related error messages here. */
if (errno.intValue() == 80) {
/* Too many login attempts - access is temporarily blocked */
/* {"errno":80,"errstring":"Zbyt wiele pr\u00f3b logowania - dost\u0119p zosta\u0142 tymczasowo zablokowany"} */
throw new AccountUnavailableException(error, 5 * 60 * 1000l);
} else {
/* Permanent account error such as login/password invalid */
/* Example: {"errno":0,"errstring":"Nieprawid\u0142owa nazwa u\u017cytkownika\/has\u0142o"} */
throw new AccountInvalidException(error);
}
}
@Override
public int getMaxSimultanFreeDownloadNum() {
return 0;
return Integer.MAX_VALUE;
}
@Override
@ -228,30 +363,10 @@ public abstract class RapideoCore extends PluginForHost {
throw new AccountRequiredException();
}
public static String md5HEX(String s) {
String result = null;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] digest = md5.digest(s.getBytes());
result = toHex(digest);
} catch (NoSuchAlgorithmException e) {
// this won't happen, we know Java has MD5!
}
return result;
}
public static String toHex(byte[] a) {
final StringBuilder sb = new StringBuilder(a.length * 2);
for (int i = 0; i < a.length; i++) {
sb.append(Character.forDigit((a[i] & 0xf0) >> 4, 16));
sb.append(Character.forDigit(a[i] & 0x0f, 16));
}
return sb.toString();
}
@Override
public void handleMultiHost(final DownloadLink link, final Account account) throws Exception {
final String storedDirecturl = link.getStringProperty(PROPERTY_DIRECTURL);
final String directurlproperty = "directurl_" + this.getHost();
final String storedDirecturl = link.getStringProperty("directurl_" + this.getHost());
final MultiHosterManagement mhm = getMultiHosterManagement();
String dllink = null;
if (storedDirecturl != null) {
@ -259,24 +374,28 @@ public abstract class RapideoCore extends PluginForHost {
dllink = storedDirecturl;
} else {
mhm.runCheck(account, link);
login(account, false);
loginWebsite(account, false);
final String url_urlencoded = Encoding.urlEncode(link.getDefaultPlugin().buildExternalDownloadURL(link, this));
if (this.useAPIInDownloadMode()) {
// TODO: Test this and change it to work with json response and json parser
if (this.useAPI()) {
final Browser brc = br.cloneBrowser();
// final UrlQuery query = new UrlQuery();
// query.add("site", getAPISiteParam());
// query.add("output", "json");
// // query.add("loc", "1");
// query.add("info", "0");
// query.add("username", Encoding.urlEncode(account.getUser()));
// query.add("password", md5HEX(account.getPass()));
// query.add("url", url_urlencoded);
// brc.postPage("https://enc." + getAPIDomain() + "/", query);
// dllink = brc.getRequest().getHtmlCode();
final String postData = "username=" + Encoding.urlEncode(account.getUser()) + "&password=" + JDHash.getSHA1(JDHash.getMD5(account.getPass())) + "&info=0&url=" + Encoding.urlEncode(link.getDownloadURL()) + "&site=nopremium";
brc.postPage("http://crypt." + getAPIDomain(), postData);
final UrlQuery query = new UrlQuery();
query.add("site", getAPISiteParam());
query.add("output", "json");
// query.add("loc", "1");
query.add("info", "0");
query.add("username", Encoding.urlEncode(account.getUser()));
query.add("password", getPasswordAPI(account));
query.add("url", url_urlencoded);
brc.postPage(getAPIBase(), query);
/* We expect the whole response to be an URL. */
dllink = brc.getRequest().getHtmlCode();
try {
new URL(dllink);
} catch (final MalformedURLException e) {
/* This should never happen */
this.checkErrorsAPI(brc, link, account);
mhm.handleErrorGeneric(account, link, "API returned invalid downloadlink", 50);
}
} else {
/* Website */
final int random = new Random().nextInt(1000000);
@ -284,11 +403,12 @@ public abstract class RapideoCore extends PluginForHost {
final String random_session = df.format(random);
final String filename = link.getName();
br.getPage("https://www." + getHost() + "/twoje_pliki");
checkErrorsWebsite(br, link, account);
br.postPage("/twoje_pliki", "loadfiles=1");
br.postPage("/twoje_pliki", "loadfiles=2");
br.postPage("/twoje_pliki", "loadfiles=3");
br.postPage("/twoje_pliki", "session=" + random_session + "&links=" + url_urlencoded);
if (br.containsHTML("(?i)strong>Brak transferu</strong>")) {
if (br.containsHTML("strong>\\s*Brak transferu\\s*</strong>")) {
throw new AccountUnavailableException("Out of traffic", 1 * 60 * 1000l);
}
final String id = br.getRegex("data\\-id=\"([a-z0-9]+)\"").getMatch(0);
@ -304,6 +424,7 @@ public abstract class RapideoCore extends PluginForHost {
/* Sometimes it takes over 10 minutes until the file has been downloaded to the remote server. */
for (int i = 1; i <= 280; i++) {
br.postPage("/twoje_pliki", "downloadprogress=1");
checkErrorsWebsite(br, link, account);
final Map<String, Object> entries = restoreFromString(br.getRequest().getHtmlCode(), TypeRef.MAP);
final List<Map<String, Object>> standardFiles = (List<Map<String, Object>>) entries.get("StandardFiles");
Map<String, Object> activeDownloadingFileInfo = null;
@ -334,7 +455,7 @@ public abstract class RapideoCore extends PluginForHost {
}
}
if (StringUtils.isEmpty(dllink)) {
mhm.handleErrorGeneric(account, link, "dllink_null", 20);
mhm.handleErrorGeneric(account, link, "Failed to generate downloadurl", 20);
}
}
try {
@ -345,13 +466,13 @@ public abstract class RapideoCore extends PluginForHost {
}
} catch (final Exception e) {
if (storedDirecturl != null) {
link.removeProperty(PROPERTY_DIRECTURL);
link.removeProperty(directurlproperty);
throw new PluginException(LinkStatus.ERROR_RETRY, "Stored directurl expired?", e);
} else {
throw e;
}
}
link.setProperty(PROPERTY_DIRECTURL, dllink);
link.setProperty(directurlproperty, dllink);
dl.startDownload();
}
@ -360,60 +481,6 @@ public abstract class RapideoCore extends PluginForHost {
return AvailableStatus.UNCHECKABLE;
}
private void login(final Account account, final boolean verifyCookies) throws Exception {
synchronized (account) {
br.setCookiesExclusive(true);
final Cookies cookies = account.loadCookies("");
if (cookies != null) {
br.setCookies(this.getHost(), cookies);
if (!verifyCookies) {
/* Don't verify */
return;
}
logger.info("Checking login cookies");
br.getPage("https://www." + getHost() + "/");
if (loggedINWebsite(this.br)) {
logger.info("Successfully loggedin via cookies");
account.saveCookies(br.getCookies(br.getHost()), "");
return;
} else {
logger.info("Failed to login via cookies");
}
}
logger.info("Attempting full login");
br.getPage("https://www." + getHost() + "/");
/*
* 2020-11-02: There are two Forms matching this but the first one is the one we want - the 2nd one is the
* "register new account" Form.
*/
final Form loginform = br.getFormbyKey("remember");
if (loginform == null) {
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT, "Failed to find loginform");
}
loginform.put("login", Encoding.urlEncode(account.getUser()));
loginform.put("password", Encoding.urlEncode(account.getPass()));
loginform.put("remember", "on");
br.submitForm(loginform);
final String geoLoginFailure = br.getRegex(">\\s*(You login from a different location than usual[^<]*)<").getMatch(0);
if (geoLoginFailure != null) {
/* 2020-11-02: Login from unusual location -> User has to confirm via URL send by mail and then try again in JD (?!). */
throw new AccountUnavailableException(geoLoginFailure + "\r\nOnce done, refresh your account in JDownloader.", 5 * 60 * 1000l);
} else if (!loggedINWebsite(br)) {
throw new AccountInvalidException();
}
account.saveCookies(br.getCookies(br.getHost()), "");
return;
}
}
private boolean loggedINWebsite(final Browser br) {
if (br.containsHTML("(?i)Logged in as:|Zalogowany jako:")) {
return true;
} else {
return false;
}
}
@Override
public boolean canHandle(final DownloadLink link, final Account account) throws Exception {
if (account == null) {

View File

@ -17,83 +17,16 @@ package jd.plugins.hoster;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import org.appwork.storage.TypeRef;
import org.appwork.utils.StringUtils;
import org.appwork.utils.formatter.SizeFormatter;
import org.appwork.utils.parser.UrlQuery;
import org.jdownloader.plugins.controller.LazyPlugin;
import jd.PluginWrapper;
import jd.http.Browser;
import jd.http.Cookies;
import jd.nutils.encoding.Encoding;
import jd.parser.html.Form;
import jd.plugins.Account;
import jd.plugins.Account.AccountType;
import jd.plugins.AccountInfo;
import jd.plugins.AccountInvalidException;
import jd.plugins.AccountRequiredException;
import jd.plugins.AccountUnavailableException;
import jd.plugins.DownloadLink;
import jd.plugins.DownloadLink.AvailableStatus;
import jd.plugins.HostPlugin;
import jd.plugins.LinkStatus;
import jd.plugins.PluginException;
import jd.plugins.PluginForHost;
import jd.plugins.components.MultiHosterManagement;
@HostPlugin(revision = "$Revision$", interfaceVersion = 3, names = {}, urls = {})
public class RapideoPl extends PluginForHost {
private static final String PROPERTY_DIRECTURL = "rapideopldirectlink";
private static MultiHosterManagement mhm = new MultiHosterManagement("rapideo.net");
@Override
public Browser createNewBrowserInstance() {
final Browser br = super.createNewBrowserInstance();
br.setFollowRedirects(true);
br.setConnectTimeout(60 * 1000);
br.setReadTimeout(60 * 1000);
/* Prefer English language */
br.setCookie(br.getHost(), "lang2", "EN");
return br;
}
@Override
public boolean isResumeable(final DownloadLink link, final Account account) {
return true;
}
public int getMaxChunks(final DownloadLink link, final Account account) {
return 0;
}
public static List<String[]> getPluginDomains() {
final List<String[]> ret = new ArrayList<String[]>();
// each entry in List<String[]> will result in one PluginForHost, Plugin.getHost() will return String[0]->main domain
ret.add(new String[] { "rapideo.net", "rapideo.pl" });
return ret;
}
public static String[] getAnnotationNames() {
return buildAnnotationNames(getPluginDomains());
}
@Override
public String[] siteSupportedNames() {
return buildSupportedNames(getPluginDomains());
}
public static String[] getAnnotationUrls() {
return new String[] { "" };
}
@HostPlugin(revision = "$Revision$", interfaceVersion = 3, names = { "rapideo.net" }, urls = { "" })
public class RapideoPl extends RapideoCore {
protected static MultiHosterManagement mhm = new MultiHosterManagement("rapideo.net");
public RapideoPl(PluginWrapper wrapper) {
super(wrapper);
@ -102,153 +35,40 @@ public class RapideoPl extends PluginForHost {
@Override
public String getAGBLink() {
return "https://www." + getHost() + "/";
return "https://www." + getHost() + "/legal ";
}
@Override
public LazyPlugin.FEATURE[] getFeatures() {
return new LazyPlugin.FEATURE[] { LazyPlugin.FEATURE.MULTIHOST };
protected MultiHosterManagement getMultiHosterManagement() {
return mhm;
}
protected String getAPIDomain() {
// return getHost();
return "rapideo.pl";
@Override
protected String getAPIBase() {
/* Do NOT use rapideo.pl here! */
return "https://enc.rapideo.pl/";
}
@Override
protected String getAPISiteParam() {
return "newrd";
}
@Override
public AccountInfo fetchAccountInfo(final Account account) throws Exception {
final AccountInfo ac = new AccountInfo();
login(account, true);
final boolean obtainTrafficViaOldAPI = true;
if (obtainTrafficViaOldAPI) {
/* API used in their browser addons */
final Browser brc = br.cloneBrowser();
final UrlQuery query = new UrlQuery();
query.add("site", getAPISiteParam());
query.add("output", "json");
query.add("loc", "1");
query.add("info", "1");
query.add("username", Encoding.urlEncode(account.getUser()));
query.add("password", md5HEX(account.getPass()));
brc.postPage("https://enc." + getAPIDomain() + "/", query);
final Map<String, Object> root = restoreFromString(brc.getRequest().getHtmlCode(), TypeRef.MAP);
final String trafficLeftStr = root.get("balance").toString();
if (trafficLeftStr != null && trafficLeftStr.matches("\\d+")) {
ac.setTrafficLeft(Long.parseLong(trafficLeftStr) * 1024);
}
} else {
/* Obtain "Traffic left" value from website */
final String trafficLeftStr = br.getRegex("(?i)\">\\s*(?:Account balance|Stan Twojego konta)\\s*:\\s*(\\d+(\\.\\d{1,2})? [A-Za-z]{1,5})").getMatch(0);
if (trafficLeftStr != null) {
ac.setTrafficLeft(SizeFormatter.getSize(trafficLeftStr));
}
}
final boolean obtainSupportedHostsListViaAPI = true;
final ArrayList<String> supportedHosts = new ArrayList<String>();
boolean accountEmailActivationNeeded = false;
if (obtainSupportedHostsListViaAPI) {
/* API */
br.getPage("https://www." + getHost() + "/clipboard.php?json=3");
final List<Map<String, Object>> hosterlist = (List<Map<String, Object>>) restoreFromString(br.getRequest().getHtmlCode(), TypeRef.OBJECT);
final boolean skipNonZeroSdownloadItems = false;
for (final Map<String, Object> hosterinfo : hosterlist) {
final List<String> domains = (List<String>) hosterinfo.get("domains");
final Object sdownload = hosterinfo.get("sdownload");
if (sdownload == null || domains == null) {
/* Skip invalid items (yes they exist, tested 2024-08-20) */
continue;
}
if (sdownload.toString().equals("0") || skipNonZeroSdownloadItems == false) {
supportedHosts.addAll(domains);
} else {
logger.info("Skipping serverside disabled domains: " + domains);
}
}
} else {
/* Website */
/* Get a list of all supported hosts */
br.getPage("/twoje_pliki");
final HashSet<String> crippledhosts = new HashSet<String>();
/*
* This will not catch stuff like <li><strong>nitroflare (beta) </strong></li> ... but we are lazy and ignore this. Such hosts
* will be found too by the 2nd regex down below.
*/
final String[] crippledHosts = br.getRegex("<li>([A-Za-z0-9\\-\\.]+)</li>").getColumn(0);
if (crippledHosts != null && crippledHosts.length > 0) {
for (final String crippledhost : crippledHosts) {
crippledhosts.add(crippledhost);
}
}
/* Alternative place to obtain supported hosts from */
final String[] crippledhosts2 = br.getRegex("class=\"active\"[^<]*>([^<]+)</a>").getColumn(0);
if (crippledhosts2 != null && crippledhosts2.length > 0) {
for (final String crippledhost : crippledhosts2) {
crippledhosts.add(crippledhost);
}
}
/* Alternative place to obtain supported hosts from */
String htmlMetadataStr = br.getRegex("name=\"keywords\" content=\"([\\w, ]+)").getMatch(0);
if (htmlMetadataStr != null) {
htmlMetadataStr = htmlMetadataStr.replace(" ", "");
final String[] crippledhosts3 = htmlMetadataStr.split(",");
if (crippledhosts3 != null && crippledhosts3.length > 0) {
for (final String crippledhost : crippledhosts3) {
crippledhosts.add(crippledhost);
}
}
}
/* Sanitize data and add to final list */
for (String crippledhost : crippledhosts) {
crippledhost = crippledhost.toLowerCase(Locale.ENGLISH);
if (crippledhost.equalsIgnoreCase("mega")) {
supportedHosts.add("mega.nz");
} else {
supportedHosts.add(crippledhost);
}
}
accountEmailActivationNeeded = br.containsHTML("Check your email and");
}
/*
* They only have accounts with traffic, no free/premium difference (other than no traffic) - we treat no-traffic as FREE --> Cannot
* download anything
*/
if (ac.getTrafficLeft() > 0) {
account.setType(AccountType.PREMIUM);
account.setMaxSimultanDownloads(-1);
ac.setStatus("Premium account");
} else {
account.setType(AccountType.FREE);
account.setMaxSimultanDownloads(-1);
ac.setStatus("Free account (no traffic left)");
}
account.setConcurrentUsePossible(true);
ac.setMultiHostSupport(this, supportedHosts);
if (ac.getTrafficLeft() == 0 && AccountType.FREE.equals(account.getType()) && accountEmailActivationNeeded) {
/* Un-activated free account without traffic -> Not usable at all. */
throw new AccountUnavailableException("Check your email and click the confirmation link to activate your account", 5 * 60 * 1000l);
}
return ac;
protected String getPasswordAPI(Account account) {
return md5HEX(account.getPass());
}
@Override
public int getMaxSimultanFreeDownloadNum() {
return 0;
protected boolean useAPI() {
return true;
}
@Override
public void handleFree(final DownloadLink link) throws Exception, PluginException {
throw new AccountRequiredException();
}
public static String md5HEX(String s) {
private static String md5HEX(String s) {
String result = null;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] digest = md5.digest(s.getBytes());
final MessageDigest md5 = MessageDigest.getInstance("MD5");
final byte[] digest = md5.digest(s.getBytes());
result = toHex(digest);
} catch (NoSuchAlgorithmException e) {
// this won't happen, we know Java has MD5!
@ -256,7 +76,7 @@ public class RapideoPl extends PluginForHost {
return result;
}
public static String toHex(byte[] a) {
private static String toHex(byte[] a) {
final StringBuilder sb = new StringBuilder(a.length * 2);
for (int i = 0; i < a.length; i++) {
sb.append(Character.forDigit((a[i] & 0xf0) >> 4, 16));
@ -265,178 +85,6 @@ public class RapideoPl extends PluginForHost {
return sb.toString();
}
@Override
public void handleMultiHost(final DownloadLink link, final Account account) throws Exception {
final String storedDirecturl = link.getStringProperty(PROPERTY_DIRECTURL);
String dllink = null;
if (storedDirecturl != null) {
logger.info("Re-using stored directurl: " + storedDirecturl);
dllink = storedDirecturl;
} else {
mhm.runCheck(account, link);
login(account, false);
final String url_urlencoded = Encoding.urlEncode(link.getDefaultPlugin().buildExternalDownloadURL(link, this));
final boolean useAPI = false;
if (useAPI) {
// TODO: Test this
final Browser brc = br.cloneBrowser();
final UrlQuery query = new UrlQuery();
query.add("site", getAPISiteParam());
query.add("output", "json");
// query.add("loc", "1");
query.add("info", "0");
query.add("username", Encoding.urlEncode(account.getUser()));
query.add("password", md5HEX(account.getPass()));
query.add("url", url_urlencoded);
brc.postPage("https://enc." + getAPIDomain() + "/", query);
dllink = brc.getRequest().getHtmlCode();
} else {
/* Website */
final int random = new Random().nextInt(1000000);
final DecimalFormat df = new DecimalFormat("000000");
final String random_session = df.format(random);
final String filename = link.getName();
br.getPage("https://www." + getHost() + "/twoje_pliki");
br.postPage("/twoje_pliki", "loadfiles=1");
br.postPage("/twoje_pliki", "loadfiles=2");
br.postPage("/twoje_pliki", "loadfiles=3");
br.postPage("/twoje_pliki", "session=" + random_session + "&links=" + url_urlencoded);
if (br.containsHTML("(?i)strong>Brak transferu</strong>")) {
throw new AccountUnavailableException("Out of traffic", 1 * 60 * 1000l);
}
final String id = br.getRegex("data\\-id=\"([a-z0-9]+)\"").getMatch(0);
if (id == null) {
mhm.handleErrorGeneric(account, link, "Failed to find transferID", 20);
}
br.postPage("/twoje_pliki", "downloadprogress=1");
br.postPage("/progress", "session=" + random_session + "&total=1");
br.postPage("/twoje_pliki", "insert=1&ds=false&di=false&note=false&notepaths=" + url_urlencoded + "&sids=" + id + "&hids=&iids=&wids=");
br.postPage("/twoje_pliki", "loadfiles=1");
br.postPage("/twoje_pliki", "loadfiles=2");
br.postPage("/twoje_pliki", "loadfiles=3");
/* Sometimes it takes over 10 minutes until the file has been downloaded to the remote server. */
for (int i = 1; i <= 280; i++) {
br.postPage("/twoje_pliki", "downloadprogress=1");
final Map<String, Object> entries = restoreFromString(br.getRequest().getHtmlCode(), TypeRef.MAP);
final List<Map<String, Object>> standardFiles = (List<Map<String, Object>>) entries.get("StandardFiles");
Map<String, Object> activeDownloadingFileInfo = null;
for (final Map<String, Object> standardFile : standardFiles) {
final String thisFilename = (String) standardFile.get("filename");
final String thisFilenameFull = (String) standardFile.get("filename_full");
/* Find our file as multiple files could be downloading at the same time. */
if (thisFilename.equalsIgnoreCase(filename) || thisFilenameFull.equalsIgnoreCase(filename)) {
activeDownloadingFileInfo = standardFile;
break;
}
}
if (activeDownloadingFileInfo == null) {
mhm.handleErrorGeneric(account, link, "Failed to locate added info to actively downloading file", 20);
}
final String status = activeDownloadingFileInfo.get("status").toString();
if (status.equalsIgnoreCase("finish")) {
dllink = (String) activeDownloadingFileInfo.get("download_url");
break;
} else if (status.equalsIgnoreCase("initialization")) {
this.sleep(3 * 1000l, link);
continue;
} else {
/* Serverside download has never been started or stopped for unknown reasons. */
logger.warning("Serverside download failed?!");
break;
}
}
}
if (StringUtils.isEmpty(dllink)) {
mhm.handleErrorGeneric(account, link, "dllink_null", 20);
}
}
try {
dl = jd.plugins.BrowserAdapter.openDownload(br, link, dllink, this.isResumeable(link, account), this.getMaxChunks(link, account));
if (!looksLikeDownloadableContent(dl.getConnection())) {
br.followConnection(true);
mhm.handleErrorGeneric(account, link, "Final downloadlink did not lead to downloadable content", 50);
}
} catch (final Exception e) {
if (storedDirecturl != null) {
link.removeProperty(PROPERTY_DIRECTURL);
throw new PluginException(LinkStatus.ERROR_RETRY, "Stored directurl expired?", e);
} else {
throw e;
}
}
link.setProperty(PROPERTY_DIRECTURL, dllink);
dl.startDownload();
}
@Override
public AvailableStatus requestFileInformation(DownloadLink link) throws Exception {
return AvailableStatus.UNCHECKABLE;
}
private void login(final Account account, final boolean verifyCookies) throws Exception {
synchronized (account) {
br.setCookiesExclusive(true);
final Cookies cookies = account.loadCookies("");
if (cookies != null) {
br.setCookies(this.getHost(), cookies);
if (!verifyCookies) {
/* Don't verify */
return;
}
logger.info("Checking login cookies");
br.getPage("https://www." + getHost() + "/");
if (loggedINWebsite(this.br)) {
logger.info("Successfully loggedin via cookies");
account.saveCookies(br.getCookies(br.getHost()), "");
return;
} else {
logger.info("Failed to login via cookies");
}
}
logger.info("Attempting full login");
br.getPage("https://www." + getHost() + "/");
/*
* 2020-11-02: There are two Forms matching this but the first one is the one we want - the 2nd one is the
* "register new account" Form.
*/
final Form loginform = br.getFormbyKey("remember");
if (loginform == null) {
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT, "Failed to find loginform");
}
loginform.put("login", Encoding.urlEncode(account.getUser()));
loginform.put("password", Encoding.urlEncode(account.getPass()));
loginform.put("remember", "on");
br.submitForm(loginform);
final String geoLoginFailure = br.getRegex(">\\s*(You login from a different location than usual[^<]*)<").getMatch(0);
if (geoLoginFailure != null) {
/* 2020-11-02: Login from unusual location -> User has to confirm via URL send by mail and then try again in JD (?!). */
throw new AccountUnavailableException(geoLoginFailure + "\r\nOnce done, refresh your account in JDownloader.", 5 * 60 * 1000l);
} else if (!loggedINWebsite(br)) {
throw new AccountInvalidException();
}
account.saveCookies(br.getCookies(br.getHost()), "");
return;
}
}
private boolean loggedINWebsite(final Browser br) {
if (br.containsHTML("(?i)Logged in as:|Zalogowany jako:")) {
return true;
} else {
return false;
}
}
@Override
public boolean canHandle(final DownloadLink link, final Account account) throws Exception {
if (account == null) {
return false;
} else {
mhm.runCheck(account, link);
return true;
}
}
@Override
public void reset() {
}

View File

@ -41,6 +41,14 @@ public class ResearchgateNet extends PluginForHost {
super(wrapper);
}
@Override
public Browser createNewBrowserInstance() {
final Browser br = super.createNewBrowserInstance();
br.setFollowRedirects(true);
br.setAllowedResponseCodes(429);
return br;
}
@Override
public String getAGBLink() {
return "https://www.researchgate.net/application.TermsAndConditions.html";
@ -56,16 +64,22 @@ public class ResearchgateNet extends PluginForHost {
@Override
public AvailableStatus requestFileInformation(final DownloadLink link) throws IOException, PluginException {
final String urlTitle = new Regex(link.getPluginPatternMatcher(), "(?i)(?:publication|figure)/(.+)").getMatch(0);
dllink = null;
final String contenturl = link.getPluginPatternMatcher().replaceFirst("(?i)http://", "https://");
final boolean isTypeFigure = StringUtils.containsIgnoreCase(contenturl, "/figure/");
final String extDefault;
if (isTypeFigure) {
extDefault = ".jpg";
} else {
extDefault = ".zip";
}
if (!link.isNameSet()) {
/* Set fallback filename */
link.setName(urlTitle + ".zip");
final String urlTitle = new Regex(contenturl, "(?i)(?:publication|figure)/(.+)").getMatch(0);
link.setName(urlTitle.replace("-", " ").trim() + extDefault);
}
dllink = null;
this.setBrowserExclusive();
br.setFollowRedirects(true);
br.setAllowedResponseCodes(429);
br.getPage(link.getPluginPatternMatcher());
br.getPage(contenturl);
if (br.getHttpConnection().getResponseCode() == 429) {
throw new PluginException(LinkStatus.ERROR_IP_BLOCKED, "Server error 429", 10 * 60 * 1000l);
} else if (br.getHttpConnection().getResponseCode() == 404) {
@ -73,28 +87,26 @@ public class ResearchgateNet extends PluginForHost {
} else if (this.br.getURL().length() <= 60) {
throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND);
}
final String json_source = this.br.getRegex("createInitialWidget\\((.*?\\})\\s+").getMatch(0);
dllink = PluginJSonUtils.getJsonValue(json_source, "downloadLink");
final String json_source = br.getRegex("createInitialWidget\\((.*?\\})\\s+").getMatch(0);
String filename = PluginJSonUtils.getJsonValue(json_source, "fileName");
String filesize = PluginJSonUtils.getJsonValue(json_source, "fileSize");
if (filesize == null) {
/* 2021-12-01 */
filesize = br.getRegex("ile-list-item__meta-data-item\"><span class=\"\">(\\d+[^<]+)</span>").getMatch(0);
}
if (dllink == null) {
dllink = br.getRegex("full-text\" href=\"([^\"]+)\"").getMatch(0);
if (isTypeFigure) {
dllink = br.getRegex("property\\s*=\\s*\"og:image\"\\s*content\\s*=\\s*\"(https?://.*?\\.(png|jpe?g))\"").getMatch(0);
} else {
dllink = PluginJSonUtils.getJsonValue(json_source, "downloadLink");
if (dllink == null) {
dllink = br.getRegex("\"citation_pdf_url\"\\s*content\\s*=\\s*\"(https?://[^\"]*?\\.pdf)\"").getMatch(0);
}
if (dllink == null) {
/* 2021-12-01 */
dllink = br.getRegex("js-lite-click\" href=\"(https?://[^\"]+)\"").getMatch(0);
}
}
if (dllink == null) {
/* 2021-12-01 */
dllink = br.getRegex("js-lite-click\" href=\"(https?://[^\"]+)\"").getMatch(0);
}
if (dllink == null && StringUtils.containsIgnoreCase(link.getPluginPatternMatcher(), "/figure/")) {
dllink = br.getRegex("property\\s*=\\s*\"og:image\"\\s*content\\s*=\\s*\"(https?://.*?\\.(png|jpe?g))\"").getMatch(0);
}
if (filename == null || filename.equals("")) {
if (StringUtils.isEmpty(filename)) {
filename = br.getRegex("<title>\\s*([^<>\"].*?)\\s*((\\(PDF Download Available\\))|(\\|\\s*Download Scientific Diagram))?\\s*</title>").getMatch(0);
}
if (!StringUtils.isEmpty(filename)) {
@ -102,14 +114,12 @@ public class ResearchgateNet extends PluginForHost {
if (dllink != null) {
correctFileExtension = Plugin.getFileNameExtensionFromURL(dllink);
}
if (StringUtils.containsIgnoreCase(link.getPluginPatternMatcher(), "/figure/")) {
final String ext = getFileNameExtensionFromURL(dllink, ".jpg");
filename = this.applyFilenameExtension(filename, ext);
} else if (correctFileExtension != null) {
if (correctFileExtension != null) {
filename = Encoding.htmlDecode(filename.trim());
filename = this.applyFilenameExtension(filename, correctFileExtension);
} else {
filename = this.applyFilenameExtension(filename, ".zip");
final String ext = getFileNameExtensionFromURL(dllink, extDefault);
filename = this.applyFilenameExtension(filename, ext);
}
link.setName(filename);
}
@ -118,9 +128,8 @@ public class ResearchgateNet extends PluginForHost {
}
if (StringUtils.isEmpty(dllink) && br.containsHTML("=su_requestFulltext")) {
throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND, "Request full-text PDF");
} else {
return AvailableStatus.TRUE;
}
return AvailableStatus.TRUE;
}
@Override

View File

@ -4065,9 +4065,8 @@ public abstract class XFileSharingProBasic extends antiDDoSForHost implements Do
String filesizelimit = new Regex(html, "You can download files up to(.*?)only").getMatch(0);
if (filesizelimit != null) {
filesizelimit = filesizelimit.trim();
throw new AccountRequiredException("As free user you can download files up to " + filesizelimit + " only");
throw new AccountRequiredException("(Premium) account required to download files bigger than" + filesizelimit);
} else {
logger.info("Only downloadable via premium");
throw new AccountRequiredException();
}
} else if (new Regex(html, "(?i)>\\s*Expired download session").patternFind()) {