6
\$\begingroup\$

The idea is to batch download a list of movies (torrents) off a torrent site and add them to your server.

I have a little bit of Java experience (sophomore in college), so I'm looking for things that I could improve on.

Main.java

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;


public class Main {

    public static void main(String[] args) throws IOException, JSchException, InterruptedException, SftpException {
        //execution of program
        ConfigReader config = new ConfigReader();
        List < String > info = new ArrayList < String > ();
        info = config.grabUserInfo();
        Login login = new Login(info.get(0), info.get(1));
        Scanner File1 = new Scanner(new File("C:\\IPDownloader\\movies.txt"));
        String token = "";
        List < String > temps = new ArrayList < String > ();
        while (File1.hasNext()) {
            token = File1.nextLine();
            temps.add(token);
        }
        File1.close();
        RemoteConnect connect = new RemoteConnect(info.get(2), info.get(3), info.get(4));
        for (int i = 0; i <= temps.size() - 1; i++) {
            String movie = temps.get(i);
            Search search = new Search(login.grabLogin(), movie);
            TorrentStarter tor = new TorrentStarter(connect.getAuth(), search.searchMovie(), info.get(5), i);
            tor.downloadTorrent();
            if (i % 5 == 0 && i != 0) {
                System.out.println("Waiting 5 seconds");
                Thread.sleep(5000);
            }
        }
        System.exit(0);
    }
}

Login.java

import java.io.IOException;
import org.jsoup.Connection;
import org.jsoup.Connection.Method;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;
public class Login {
    private String username;
    private String password;
    public Login(String username, String password) {
        this.username = username;
        this.password = password;
    }
    public Connection.Response grabLogin() throws IOException {
        Response loginRes = Jsoup.connect("https://iptorrents.com/")
            .userAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0") //robots.txt
        .method(Method.GET)
            .execute();
        Connection.Response res = Jsoup.connect("https://iptorrents.com/")
            .userAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0")
            .followRedirects(true)
            .data("username", username, "password", password)
            .method(Method.POST)
            .cookies(loginRes.cookies())
            .execute();
        //posting with cookies using connection.response library
        return res;
    }
}

ConfigReader.java

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;


public class ConfigReader {
    /*
     * checking for config file or making a new one. can follow format to skip this
     */
    public List < String > grabUserInfo() throws IOException {
        File configDir = new File("C:\\IPDownloader\\");
        File checkFile = new File("C:\\IPDownloader\\config.txt");
        boolean exists = configDir.exists();
        if (exists && checkFile.length() != 0) {
            System.out.println("Reading Config");
            String token = "";
            Scanner File1 = new Scanner(new File("C:\\IPDownloader\\config.txt"));
            List < String > temps = new ArrayList < String > ();
            while (File1.hasNext()) {
                token = File1.next();
                temps.add(token);
            }
            File1.close();
            return temps;
        } else {
            Scanner s = new Scanner(System. in );
            System.out.println("Config not found or it is empty");
            System.out.println("Please input your username");
            String username = s.nextLine();
            System.out.println("Please input your password");
            String password = s.nextLine();
            System.out.println("Please input the server hostname");
            String ipCon = s.nextLine();
            System.out.println("Please input server username");
            String userCon = s.nextLine();
            System.out.println("Please input the server password");
            String passCon = s.nextLine();
            System.out.println("Please input the watch directory (excluding home directory");
            String watchDir = s.nextLine();
            System.out.println("Your information has been stored at C:\\IPDownloader\\");
            new File("C:\\IPDownloader\\").mkdir();
            File configFile = new File("C:\\IPDownloader\\config.txt");
            BufferedWriter writer = new BufferedWriter(new FileWriter(configFile));
            writer.write(username);
            writer.newLine();
            writer.write(password);
            writer.newLine();
            writer.write(ipCon);
            writer.newLine();
            writer.write(userCon);
            writer.newLine();
            writer.write(passCon);
            writer.newLine();
            writer.write(watchDir);
            writer.close();
            String token = "";
            Scanner File1 = new Scanner(new File("C:\\IPDownloader\\config.txt"));
            List < String > temps = new ArrayList < String > ();
            while (File1.hasNext()) {
                token = File1.next();
                temps.add(token);
            }
            File1.close();
            return temps;
        }
    }
}

How could I possibly shorten this?

RemoteConnect.java

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;

import java.io.*;


public class RemoteConnect {
    private String ipCon;
    private String userCon;
    private String passCon;
    public RemoteConnect(String ipCon, String userCon, String passCon) {
        this.ipCon = ipCon;
        this.userCon = userCon;
        this.passCon = passCon;
    }
    public Object[] getAuth() throws JSchException, InterruptedException, SftpException {
        int port = 22;
        //using JSch for this
        JSch jsch = new JSch();
        Session session = jsch.getSession(userCon, ipCon, port);
        session.setPassword(passCon);
        session.setConfig("StrictHostKeyChecking", "no"); //needed
        session.connect(10 * 8000); //timeout
        return new Object[] {
            jsch, session
        }; //need to keep
    }
}

Search.java

import java.io.IOException;

import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
public class Search {
    private Connection.Response res;
    private String search = "";
    public Search(Connection.Response res, String movie) {
        this.res = res;
        this.search = movie;
    }
    public Object[] searchMovie() throws IOException {
        String downloadLink = "https://iptorrents.com";
        String partLink = "";
        //1080p sorted by top seeded movies
        Document doc = Jsoup.connect("https://iptorrents.com/t?1080p;q=" + search + ";o=seeders#torrents") //uses jsoup to keep login
        .cookies(res.cookies())
        .get();
        //had to scrape the top DL link. works with dynamic tags. using the icon as a reference
        for (Element e: doc.select("td.ac").select("a")) {
            if (e.select("i[class=fa fa-download fa-2x]").size() > 0) {
                partLink = e.attr("href");
                System.out.println(partLink);
                downloadLink += partLink;
                break;
            }
        }
        if (partLink.isEmpty()) {
            System.out.println("going here");
            doc = Jsoup.connect("https://iptorrents.com/t?720p;q=" + search + ";o=seeders#torrents") //uses jsoup to keep login
            .cookies(res.cookies())
                .get();
            //had to scrape the top DL link. works with dynamic tags. using the icon as a reference
            for (Element a: doc.select("td.ac").select("a")) {
                if (a.select("i[class=fa fa-download fa-2x]").size() > 0) {
                    partLink = a.attr("href");
                    downloadLink += partLink;
                    break;
                }
            }
        }
        System.out.println("Added " + downloadLink);
        return new Object[] {
            downloadLink, res
        };
    }
}

TorrentStarter.java

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.Connection.Response;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;


public class TorrentStarter {
    private String homeDirectory = "";
    private String torrent = "";
    private Session session = null;
    private JSch jsch = null;
    private int count = 0;
    private Connection.Response res = null;
    private ChannelSftp channelSftp = null;
    public TorrentStarter(Object[] objectArray, Object[] objectArray2, String watchDir, int count) {
        this.torrent = (String) objectArray2[0];
        this.jsch = (JSch) objectArray[0];
        this.session = (Session) objectArray[1];
        this.res = (Response) objectArray2[1];
        this.homeDirectory = watchDir;
        this.count = count;
    }
    public void downloadTorrent() throws JSchException, InterruptedException, IOException, SftpException {
        //iptorrents requires passkey via cookies for each dl
        res = Jsoup.connect(torrent)
            .cookies(res.cookies())
            .ignoreContentType(true)
            .execute();
        FileOutputStream out = (new FileOutputStream(new java.io.File("C:\\IPDownloader\\" + "torrent1.torrent")));
        out.write(res.bodyAsBytes());
        out.close();
        Channel channel = session.openChannel("sftp"); //we open the channel here
        channel.connect();
        channelSftp = (ChannelSftp) channel;
        channelSftp.cd(channelSftp.getHome());
        File f = new File("C:\\IPDownloader\\torrent1.torrent"); //named torrent1.torrent
        FileInputStream fInput = new FileInputStream(f);
        channelSftp.put(fInput, f.getName());
        fInput.close();
        channelSftp.rename((channelSftp.getHome() + "/torrent1.torrent"), (channelSftp.getHome() + homeDirectory + "torrent" + count +".torrent"));
        //.rename allows to delete from first directory and then move to new directory. works well
        f.delete();
    }
}
\$\endgroup\$
  • \$\begingroup\$ This question is possibly uninteresting to reviewers. To help reviewers give you better answers, please add sufficient context to your question. The more you tell us about what your code does and what the purpose of doing that is, the easier it will be for reviewers to help you. See also this meta question. \$\endgroup\$ – Vogel612 Dec 19 '15 at 22:13
3
\$\begingroup\$

Some things I noticed while skimming over main:

Encapsulate your configuration

Instead of accessing your configuration through magic indices, you should introduce properly named getters for the properties.

    Login login = new Login(info.get(0), info.get(1));

becomes something much more manageable like:

Login login = new Login(config.getUsername(), config.getPassword());

This similarly applies for the construction of RemoteConnect.

Use of intermediary List and old File API

You're using an intermediary List (which uses memory) and the old File API (which is ... mediocre). Instead of

    Scanner File1 = new Scanner(new File("C:\\IPDownloader\\movies.txt"));
    String token = "";
    List < String > temps = new ArrayList < String > ();
    while (File1.hasNext()) {
        token = File1.nextLine();
        temps.add(token);
    }
    File1.close();

you should be able to process the whole "movies.txt" in a Stream:

try (Stream<String> movies = Files.lines(Paths.get(MOVIES_TXT))) {
    movies.flatMap(line -> Arrays.stream(line.split("[\\s]+")))
        .forEach(movie -> {
             //.. the body of your for-loop, best encapsuled in a method
         });
} catch (IOException e) {
     // handle properly :D
}

Nitpicks

  • The initial comment //execution of program is needlessness incarnate.
  • File1 should have a camelCased variable name and probably not one with a number in it :D
  • System.exit(0); is superfluous
\$\endgroup\$
  • \$\begingroup\$ Thank you so much for the advice! And yeah a lot of the Java I know is from old solutions and stuff in my textbooks / classes, which tends to use deprecated things. \$\endgroup\$ – Ben Dec 15 '15 at 10:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.