1
0
mirror of https://github.com/Rogiel/httpchannel synced 2025-12-06 07:32:50 +00:00

Implements uptobox.com upload service

This commit is contained in:
2012-05-06 00:21:38 -03:00
parent d838636f2a
commit 4a9da1708e
10 changed files with 651 additions and 12 deletions

View File

@@ -31,8 +31,8 @@ package com.rogiel.httpchannel.service;
* quota</li> * quota</li>
* <li>{@link BandwidthQuotaAccountDetails} - for services that have limited * <li>{@link BandwidthQuotaAccountDetails} - for services that have limited
* bandwidth quota</li> * bandwidth quota</li>
* <li>{@link FilesizeLimitAccountDetails} - for services that have limited * <li>{@link FilesizeLimitAccountDetails} - for services that have limited file
* file sizes depending on the account</li> * sizes depending on the account</li>
* </ul> * </ul>
* You should not try to cast instances by yourself, instead they should be * You should not try to cast instances by yourself, instead they should be
* safely casted as such: * safely casted as such:
@@ -166,4 +166,34 @@ public interface AccountDetails {
*/ */
long getMaximumFilesize(); long getMaximumFilesize();
} }
/**
* Service accounts that has referring support
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface ReferralAccountDetails extends AccountDetails {
/**
* @return the number of members referred
*/
int getMembersReferred();
/**
* @return the account referral URL
*/
String getReferralURL();
}
/**
* Service account that has points attached to it (normally acquired through
* downloads of files from the account)
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface PointAccountDetails extends AccountDetails {
/**
* @return the number of point on the account
*/
int getPoints();
}
} }

View File

@@ -108,9 +108,7 @@ public class IFileService extends AbstractHttpService implements Service,
@Override @Override
public CapabilityMatrix<UploaderCapability> getUploadCapabilities() { public CapabilityMatrix<UploaderCapability> getUploadCapabilities() {
return new CapabilityMatrix<UploaderCapability>( return new CapabilityMatrix<UploaderCapability>(
UploaderCapability.UNAUTHENTICATED_UPLOAD, UploaderCapability.UNAUTHENTICATED_UPLOAD);
UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD,
UploaderCapability.PREMIUM_ACCOUNT_UPLOAD);
} }
protected class UploaderImpl extends protected class UploaderImpl extends

View File

@@ -0,0 +1 @@
com.rogiel.httpchannel.service.filesonic.FileSonicService

View File

@@ -0,0 +1,14 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>httpchannel-service</artifactId>
<groupId>com.rogiel.httpchannel</groupId>
<version>1.0.1-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>httpchannel-service-uptobox</artifactId>
<groupId>com.rogiel.httpchannel.services</groupId>
<name>HttpChannel/Service/UpToBox</name>
<description>Provides download and upload access to uptobox.com</description>
</project>

View File

@@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.rogiel.httpchannel.service.uptobox;
import com.rogiel.httpchannel.service.AbstractUploaderConfiguration;
import com.rogiel.httpchannel.service.Uploader.DescriptionableUploaderConfiguration;
import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration;
import com.rogiel.httpchannel.service.uptobox.UptoboxService.UploaderImpl;
/**
* Describes an configuration for an {@link UploaderImpl}
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class UptoboxConfiguration extends
AbstractUploaderConfiguration implements UploaderConfiguration,
DescriptionableUploaderConfiguration {
/**
* The upload description
*/
private String description = DescriptionableUploaderConfiguration.DEFAULT_DESCRIPTION;
@Override
public String description() {
return description;
}
@Override
public UptoboxConfiguration description(String description) {
this.description = description;
return this;
}
}

View File

@@ -0,0 +1,359 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.rogiel.httpchannel.service.uptobox;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.regex.Pattern;
import com.rogiel.httpchannel.service.AbstractAccountDetails;
import com.rogiel.httpchannel.service.AbstractAuthenticator;
import com.rogiel.httpchannel.service.AbstractHttpService;
import com.rogiel.httpchannel.service.AbstractUploader;
import com.rogiel.httpchannel.service.AccountDetails;
import com.rogiel.httpchannel.service.AccountDetails.DiskQuotaAccountDetails;
import com.rogiel.httpchannel.service.AccountDetails.FilesizeLimitAccountDetails;
import com.rogiel.httpchannel.service.AccountDetails.PointAccountDetails;
import com.rogiel.httpchannel.service.AccountDetails.PremiumAccountDetails;
import com.rogiel.httpchannel.service.AccountDetails.ReferralAccountDetails;
import com.rogiel.httpchannel.service.AuthenticationService;
import com.rogiel.httpchannel.service.Authenticator;
import com.rogiel.httpchannel.service.AuthenticatorCapability;
import com.rogiel.httpchannel.service.CapabilityMatrix;
import com.rogiel.httpchannel.service.Credential;
import com.rogiel.httpchannel.service.Service;
import com.rogiel.httpchannel.service.ServiceID;
import com.rogiel.httpchannel.service.ServiceMode;
import com.rogiel.httpchannel.service.UploadChannel;
import com.rogiel.httpchannel.service.UploadService;
import com.rogiel.httpchannel.service.Uploader;
import com.rogiel.httpchannel.service.UploaderCapability;
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadChannelCloseCallback;
import com.rogiel.httpchannel.service.config.NullAuthenticatorConfiguration;
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
import com.rogiel.httpchannel.util.Filesizes;
import com.rogiel.httpchannel.util.htmlparser.HTMLPage;
/**
* This service handles login, upload and download to uptobox.com.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
* @since 1.0
*/
public class UptoboxService extends AbstractHttpService implements Service,
UploadService<UptoboxConfiguration>,
AuthenticationService<NullAuthenticatorConfiguration> {
/**
* This service ID
*/
public static final ServiceID SERVICE_ID = ServiceID.create("uptobox");
private static final Pattern UPLOAD_URI_PATTERN = Pattern
.compile("http://www[0-9]+\\.uptobox\\.com/cgi-bin/upload.cgi\\?upload_id=");
private static final Pattern DOWNLOAD_URI_PATTERN = Pattern
.compile("http://(www\\.)?uptobox\\.com/[a-z0-9]+");
private static final Pattern DISK_USAGE_PATTERN = Pattern
.compile("Used space ([0-9]+(\\.[0-9]+)?) (Kb|Mb) of ([0-9]+) Mb");
@Override
public ServiceID getServiceID() {
return SERVICE_ID;
}
@Override
public int getMajorVersion() {
return 1;
}
@Override
public int getMinorVersion() {
return 0;
}
@Override
public CapabilityMatrix<ServiceMode> getPossibleServiceModes() {
return new CapabilityMatrix<ServiceMode>(ServiceMode.UNAUTHENTICATED,
ServiceMode.NON_PREMIUM, ServiceMode.PREMIUM);
}
@Override
public Uploader<UptoboxConfiguration> getUploader(String filename,
long filesize, UptoboxConfiguration configuration) {
return new UploaderImpl(filename, filesize, configuration);
}
@Override
public Uploader<UptoboxConfiguration> getUploader(String filename,
long filesize) {
return getUploader(filename, filesize, newUploaderConfiguration());
}
@Override
public UptoboxConfiguration newUploaderConfiguration() {
return new UptoboxConfiguration();
}
@Override
public long getMaximumFilesize() {
if (account == null) {
return 1 * 1024 * 1024 * 1024;
} else {
return account.as(FilesizeLimitAccountDetails.class)
.getMaximumFilesize();
}
}
@Override
public String[] getSupportedExtensions() {
return null;
}
@Override
public CapabilityMatrix<UploaderCapability> getUploadCapabilities() {
return new CapabilityMatrix<UploaderCapability>(
UploaderCapability.UNAUTHENTICATED_UPLOAD,
UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD,
UploaderCapability.PREMIUM_ACCOUNT_UPLOAD);
}
@Override
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
Credential credential, NullAuthenticatorConfiguration configuration) {
return new AuthenticatorImpl(credential, configuration);
}
@Override
public Authenticator<NullAuthenticatorConfiguration> getAuthenticator(
Credential credential) {
return getAuthenticator(credential, newAuthenticatorConfiguration());
}
@Override
public NullAuthenticatorConfiguration newAuthenticatorConfiguration() {
return NullAuthenticatorConfiguration.SHARED_INSTANCE;
}
@Override
public CapabilityMatrix<AuthenticatorCapability> getAuthenticationCapability() {
return new CapabilityMatrix<AuthenticatorCapability>(
AuthenticatorCapability.ACCOUNT_DETAILS);
}
@Override
public AccountDetails getAccountDetails() {
return account;
}
protected class UploaderImpl extends AbstractUploader<UptoboxConfiguration>
implements Uploader<UptoboxConfiguration>,
LinkedUploadChannelCloseCallback {
private Future<HTMLPage> uploadFuture;
public UploaderImpl(String filename, long filesize,
UptoboxConfiguration configuration) {
super(UptoboxService.this, filename, filesize, configuration);
}
@Override
public UploadChannel openChannel() throws IOException {
logger.debug("Starting upload to ifile.it");
final HTMLPage page = get("http://uptobox.com/").asPage();
String action = page.findFormAction(UPLOAD_URI_PATTERN);
final String srvTmpUrl = page.getInputValue("srv_tmp_url");
if (account != null) {
action += "&type=reg";
}
final String sessionID = page.getInputValue("sess_id");
logger.debug("Upload URI is {}", action);
final LinkedUploadChannel channel = createLinkedChannel(this);
uploadFuture = multipartPost(action).parameter("file_0", channel)
.parameter("file_0_descr", configuration.description())
.parameter("sess_id", sessionID)
.parameter("srv_tmp_url", srvTmpUrl).parameter("tos", true)
.asPageAsync();
return waitChannelLink(channel);
}
@Override
public String finish() throws IOException {
try {
return uploadFuture.get().findLink(DOWNLOAD_URI_PATTERN);
} catch (InterruptedException e) {
return null;
} catch (ExecutionException e) {
throw (IOException) e.getCause();
}
}
}
protected class AuthenticatorImpl extends
AbstractAuthenticator<NullAuthenticatorConfiguration> implements
Authenticator<NullAuthenticatorConfiguration> {
public AuthenticatorImpl(Credential credential,
NullAuthenticatorConfiguration configuration) {
super(credential, configuration);
}
@Override
public AccountDetails login() throws IOException {
final HTMLPage page = post("http://uptobox.com/")
.parameter("op", "login")
.parameter("redirect", "http://uptobox.com/?op=my_account")
.parameter("login", credential.getUsername())
.parameter("password", credential.getPassword()).asPage();
final String username = page.findPlain(
Pattern.compile("Username:(.+) Apply"), 1);
if (username == null)
throw new AuthenticationInvalidCredentialException();
final boolean premium = !page.containsPlain(Pattern.compile(
"Account type Free member", Pattern.MULTILINE));
final int points = page.findIntPlain(
Pattern.compile("You have collected:([0-9])+"), 1);
final int referrals = page.findIntPlain(
Pattern.compile("My referrals:([0-9])+"), 1);
final String referralURL = page.findLink(Pattern
.compile("http://uptobox\\.com/affiliate/[0-9]+"));
final HTMLPage index = get("http://uptobox.com/").asPage();
final int maximumFileSize = index.findIntPlain(
Pattern.compile("Up to ([0-9]*) Mb"), 1);
final HTMLPage disk = get("http://uptobox.com/?op=my_files")
.asPage();
final double usedDiskSpace = disk.findDoublePlain(
DISK_USAGE_PATTERN, 1);
final String usedDiskSpaceUnit = disk.findPlain(DISK_USAGE_PATTERN,
3);
final double maximumDiskSpace = disk.findDoublePlain(
DISK_USAGE_PATTERN, 4);
return (account = new AccountDetailsImpl(username, premium,
Filesizes.mb(maximumFileSize),
Filesizes.mb(maximumDiskSpace), Filesizes.auto(
usedDiskSpace, usedDiskSpaceUnit), points,
referrals, referralURL));
}
@Override
public void logout() throws IOException {
get("http://uptobox.com/?op=logout").request();
account = null;
}
}
private class AccountDetailsImpl extends AbstractAccountDetails implements
PremiumAccountDetails, ReferralAccountDetails, PointAccountDetails,
FilesizeLimitAccountDetails, DiskQuotaAccountDetails {
private final boolean premium;
private final long maximumFileSize;
private final long maximumDiskSpace;
private final long usedDiskSpace;
private final int points;
private final int referrals;
private final String referralURL;
/**
* @param username
* the username
* @param premium
* if the account is premium
* @param maximumFileSize
* the maximum file size
* @param maximumDiskSpace
* the maximum file size
* @param usedDiskSpace
* the maximum file size
* @param points
* the amount of points on the account
* @param referrals
* the number of referrals on the account
* @param referralURL
* the referral URL
*/
public AccountDetailsImpl(String username, boolean premium,
long maximumFileSize, long maximumDiskSpace,
long usedDiskSpace, int points, int referrals,
String referralURL) {
super(UptoboxService.this, username);
this.premium = premium;
this.maximumFileSize = maximumFileSize;
this.maximumDiskSpace = maximumDiskSpace;
this.usedDiskSpace = usedDiskSpace;
this.points = points;
this.referrals = referrals;
this.referralURL = referralURL;
}
@Override
public boolean isPremium() {
return premium;
}
@Override
public int getPoints() {
return points;
}
@Override
public int getMembersReferred() {
return referrals;
}
@Override
public String getReferralURL() {
return referralURL;
}
@Override
public long getMaximumFilesize() {
return maximumFileSize;
}
@Override
public long getUsedDiskSpace() {
return usedDiskSpace;
}
@Override
public long getMaximumDiskSpace() {
return maximumDiskSpace;
}
@Override
public long getFreeDiskSpace() {
return getMaximumDiskSpace() - getUsedDiskSpace();
}
}
@Override
public String toString() {
return this.getClass().getSimpleName() + " " + getMajorVersion() + "."
+ getMinorVersion();
}
}

View File

@@ -0,0 +1 @@
com.rogiel.httpchannel.service.filesonic.UptoboxService

View File

@@ -0,0 +1,130 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.rogiel.httpchannel.service.uptobox;
import static org.junit.Assert.assertEquals;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import com.rogiel.httpchannel.service.Credential;
import com.rogiel.httpchannel.service.ServiceID;
import com.rogiel.httpchannel.service.UploadChannel;
import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException;
import com.rogiel.httpchannel.service.helper.UploadServices;
import com.rogiel.httpchannel.util.ChannelUtils;
public class UptoboxServiceTest {
private UptoboxService service;
/**
* See <b>src/test/resources/config/megaupload.properties</b>
* <p>
* Key: username
*/
private String VALID_USERNAME;
/**
* See <b>src/test/resources/config/megaupload.properties</b>
* <p>
* Key: password
*/
private String VALID_PASSWORD;
private static final String INVALID_USERNAME = "invalid";
private static final String INVALID_PASSWORD = "abc";
@Before
public void setUp() throws Exception {
service = new UptoboxService();
final Properties properties = new Properties();
properties.load(new FileInputStream(
"../src/test/resources/login.properties"));
VALID_USERNAME = properties.getProperty("uptobox.username");
VALID_PASSWORD = properties.getProperty("uptobox.password");
}
@Test
public void testServiceId() {
assertEquals(ServiceID.create("uptobox"), service.getServiceID());
}
@Test
public void testValidAuthenticator() throws IOException {
service.getAuthenticator(new Credential(VALID_USERNAME, VALID_PASSWORD))
.login();
}
@Test(expected = AuthenticationInvalidCredentialException.class)
public void testInvalidAuthenticator() throws IOException {
service.getAuthenticator(
new Credential(INVALID_USERNAME, INVALID_PASSWORD)).login();
}
@Test
public void testNonLoguedInUploader() throws IOException {
final Path path = Paths
.get("../src/test/resources/upload-test-file.txt");
final UploadChannel channel = UploadServices.upload(service, path)
.openChannel();
final SeekableByteChannel inChannel = Files.newByteChannel(path);
try {
ChannelUtils.copy(inChannel, channel);
} finally {
inChannel.close();
channel.close();
}
System.out.println(channel.getDownloadLink());
Assert.assertNotNull(channel.getDownloadLink());
}
@Test
public void testLoggedInUploader() throws IOException {
service.getAuthenticator(new Credential(VALID_USERNAME, VALID_PASSWORD))
.login();
final Path path = Paths
.get("../src/test/resources/upload-test-file.txt");
final UploadChannel channel = UploadServices.upload(service, path)
.openChannel();
final SeekableByteChannel inChannel = Files.newByteChannel(path);
try {
ChannelUtils.copy(inChannel, channel);
} finally {
inChannel.close();
channel.close();
}
System.out.println(channel.getDownloadLink());
Assert.assertNotNull(channel.getDownloadLink());
}
}

View File

@@ -5,18 +5,31 @@ package com.rogiel.httpchannel.util;
/** /**
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
* *
*/ */
public class Filesizes { public class Filesizes {
public static long kb(long kb) { public static long kb(double kb) {
return kb * 1024; return (long) (kb * 1024);
} }
public static long mb(long mb) { public static long mb(double mb) {
return kb(mb) * 1024; return kb(mb) * 1024;
} }
public static long gb(long gb) { public static long gb(double gb) {
return mb(gb) * 1024; return mb(gb) * 1024;
} }
public static long auto(double value, String unit) {
unit = unit.toUpperCase().trim().substring(0, 1);
switch (unit) {
case "K":
return kb(value);
case "M":
return mb(value);
case "G":
return gb(value);
}
return 0;
}
} }

View File

@@ -75,6 +75,10 @@ public class HTMLPage {
return filtered; return filtered;
} }
public boolean containsPlain(Pattern pattern) {
return pattern.matcher(asString()).find();
}
public boolean contains(final Pattern pattern) { public boolean contains(final Pattern pattern) {
return !filter(Node.class, new ContainsFilter(pattern)).isEmpty(); return !filter(Node.class, new ContainsFilter(pattern)).isEmpty();
} }
@@ -90,6 +94,21 @@ public class HTMLPage {
.quote(text.toLowerCase())))).isEmpty(); .quote(text.toLowerCase())))).isEmpty();
} }
public String findPlain(final Pattern pattern, int n) {
final Matcher matcher = pattern.matcher(asString());
if (matcher.find())
return matcher.group(n);
return null;
}
public int findIntPlain(final Pattern pattern, int n) {
return Integer.parseInt(findPlain(pattern, n));
}
public double findDoublePlain(final Pattern pattern, int n) {
return Double.parseDouble(findPlain(pattern, n));
}
public String find(final Pattern pattern, int n) { public String find(final Pattern pattern, int n) {
for (final Node tag : filter(Tag.class, new ContainsFilter(pattern))) { for (final Node tag : filter(Tag.class, new ContainsFilter(pattern))) {
final Matcher matcher = pattern.matcher(tag.getText()); final Matcher matcher = pattern.matcher(tag.getText());
@@ -200,6 +219,10 @@ public class HTMLPage {
return ((TextareaTag) getTagByID(id)).getStringText(); return ((TextareaTag) getTagByID(id)).getStringText();
} }
public String getTextareaValueByName(String name) {
return ((TextareaTag) getTagByName(name)).getStringText();
}
public Tag getTagByID(final String id) { public Tag getTagByID(final String id) {
for (final Tag tag : filter(Tag.class, new IDFilter(id))) { for (final Tag tag : filter(Tag.class, new IDFilter(id))) {
return tag; return tag;
@@ -257,4 +280,25 @@ public class HTMLPage {
return null; return null;
} }
} }
public String asString() {
StringBuffer buff = new StringBuffer();
for (int i = 0; i < nodes.size(); i++) {
// final String content = nodes.elementAt(i).toPlainTextString()
// .replaceAll("\n", "").replaceAll("\\t", "").trim();
// if (content.length() > 0) {
// buff.append(" ").append(content);
// }
final String[] lines = nodes.elementAt(i).toPlainTextString()
.split("\n");
for (final String line : lines) {
final String processed = line.trim();
if (processed.length() > 0) {
buff.append(line.trim()).append(" ");
}
}
}
return buff.toString();
}
} }