OSDN Git Service

2009/03/23リリース。
authoryuki <yuki@bdf3b611-c98c-6041-8292-703d9c9adbe7>
Sun, 22 Mar 2009 18:06:45 +0000 (18:06 +0000)
committeryuki <yuki@bdf3b611-c98c-6041-8292-703d9c9adbe7>
Sun, 22 Mar 2009 18:06:45 +0000 (18:06 +0000)
ダウンロード時にファイルが403となってダウンロードが正常に行えない問題を修正。

git-svn-id: http://192.168.11.7/svn/repository/NicoBrowserBranches/release_20090323/NicoBrowser@97 bdf3b611-c98c-6041-8292-703d9c9adbe7

19 files changed:
build.xml
createDDL.jdbc
default/nicobrowser.properties [new file with mode: 0644]
nbproject/build-impl.xml
nbproject/genfiles.properties
nbproject/groovy-build.xml [new file with mode: 0644]
nbproject/project.properties
nbproject/project.xml
src/META-INF/persistence.xml
src/nicobrowser/Config.java [new file with mode: 0644]
src/nicobrowser/NicoHttpClient.java
src/nicobrowser/entity/NicoContent.java
src/nicobrowser/main/Main.java [new file with mode: 0644]
src/nicobrowser/util/Result.java [new file with mode: 0644]
src/nicobrowser/util/ResultParse.groovy [new file with mode: 0644]
src/nicobrowser/util/Util.java [new file with mode: 0644]
test/nicobrowser/ConfigTest.java [new file with mode: 0644]
test/nicobrowser/NicoHttpClientTest.java
test/nicobrowser/util/UtilTest.java [new file with mode: 0644]

index 42b57c8..d4e3b6e 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -2,6 +2,11 @@
 <!-- You may freely edit this file. See commented blocks below for -->\r
 <!-- some examples of how to customize the build. -->\r
 <!-- (If you delete it and reopen the project it will be recreated.) -->\r
+<!-- By default, only the Clean and Build commands use this build script. -->\r
+<!-- Commands such as Run, Debug, and Test only use this build script if -->\r
+<!-- the Compile on Save feature is turned off for the project. -->\r
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->\r
+<!-- in the project's Project Properties dialog box.-->\r
 <project name="NicoBrowser" default="default" basedir=".">\r
     <description>Builds, tests, and runs the project NicoBrowser.</description>\r
     <import file="nbproject/build-impl.xml"/>\r
index 9936a82..50ff4cc 100644 (file)
@@ -1,3 +1,3 @@
-CREATE TABLE NICOCONTENT (ID NUMBER(19) NOT NULL, FILENAME VARCHAR(255), PAGELINK VARCHAR(255), TITLE VARCHAR(255), NICOID VARCHAR(255) NOT NULL, VERSION NUMBER(19), PRIMARY KEY (ID))
+CREATE TABLE NICOCONTENT (ID NUMBER(19) NOT NULL, CONVERTEDMP4 NUMBER(1) NOT NULL, PAGELINK VARCHAR(255), FILENAME VARCHAR(255), CONVERTEDMP3 NUMBER(1) NOT NULL, TITLE VARCHAR(255), FAILTIMES NUMBER(10), VERSION NUMBER(19), NICOID VARCHAR(255) NOT NULL, STATUS NUMBER(10) NOT NULL, PRIMARY KEY (ID))
 CREATE TABLE SEQUENCE (SEQ_NAME VARCHAR(50) NOT NULL, SEQ_COUNT NUMBER(19), PRIMARY KEY (SEQ_NAME))
 INSERT INTO SEQUENCE(SEQ_NAME, SEQ_COUNT) values ('SEQ_GEN', 1)
diff --git a/default/nicobrowser.properties b/default/nicobrowser.properties
new file mode 100644 (file)
index 0000000..792d50c
--- /dev/null
@@ -0,0 +1,10 @@
+nicovideo.mail=niconico.senyou@live.jp\r
+nicovideo.password=piyopiyo\r
+path.ffmpeg=C:\\Program Files\\Red Kawa\\Video Converter 3\\Tools\\FFmpeg\\ffmpeg.exe\r
+path.db=I:\\niconico\\flv\\browser\\db\\nicodb\r
+dir.save.src=I:\\niconico\\flv\\browser\r
+dir.save.mp4=\r
+dir.save.mp3=\r
+download.ext.mp4=true\r
+download.retry=3\r
+ffpmeg.option="-y -i %i -f %f -vcodec libx264 -level 30 -b 512k -bt 512k -bufsize 10000k -maxrate 10000k -g 300 -coder 0 -threads auto -acodec libfaac -ac 2 -ab 128k %o"\r
index 029ef38..e03bd4f 100644 (file)
@@ -19,7 +19,8 @@ is divided into following sections:
   - cleanup\r
 \r
         -->\r
-<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject2="http://www.netbeans.org/ns/j2se-project/2" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="NicoBrowser-impl">\r
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="NicoBrowser-impl">\r
+    <import file="groovy-build.xml"/>\r
     <import file="jnlp-impl.xml"/>\r
     <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>\r
     <!-- \r
@@ -153,7 +154,7 @@ is divided into following sections:
             <attribute default="${includes}" name="includes"/>\r
             <attribute default="${excludes}" name="excludes"/>\r
             <attribute default="${javac.debug}" name="debug"/>\r
-            <attribute default="" name="sourcepath"/>\r
+            <attribute default="/does/not/exist" name="sourcepath"/>\r
             <element name="customize" optional="true"/>\r
             <sequential>\r
                 <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">\r
@@ -219,13 +220,13 @@ is divided into following sections:
             </sequential>\r
         </macrodef>\r
     </target>\r
-    <target name="-init-macrodef-nbjpda">\r
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">\r
         <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">\r
             <attribute default="${main.class}" name="name"/>\r
             <attribute default="${debug.classpath}" name="classpath"/>\r
             <attribute default="" name="stopclassname"/>\r
             <sequential>\r
-                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="dt_socket">\r
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">\r
                     <classpath>\r
                         <path path="@{classpath}"/>\r
                     </classpath>\r
@@ -236,7 +237,9 @@ is divided into following sections:
             <attribute default="${build.classes.dir}" name="dir"/>\r
             <sequential>\r
                 <nbjpdareload>\r
-                    <fileset dir="@{dir}" includes="${fix.includes}*.class"/>\r
+                    <fileset dir="@{dir}" includes="${fix.classes}">\r
+                        <include name="${fix.includes}*.class"/>\r
+                    </fileset>\r
                 </nbjpdareload>\r
             </sequential>\r
         </macrodef>\r
@@ -254,6 +257,12 @@ is divided into following sections:
         <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">\r
             <istrue value="${have-jdk-older-than-1.4}"/>\r
         </condition>\r
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">\r
+            <os family="windows"/>\r
+        </condition>\r
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">\r
+            <isset property="debug.transport"/>\r
+        </condition>\r
     </target>\r
     <target depends="-init-debug-args" name="-init-macrodef-debug">\r
         <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">\r
@@ -263,7 +272,7 @@ is divided into following sections:
             <sequential>\r
                 <java classname="@{classname}" dir="${work.dir}" fork="true">\r
                     <jvmarg line="${debug-args-line}"/>\r
-                    <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>\r
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>\r
                     <jvmarg line="${run.jvmargs}"/>\r
                     <classpath>\r
                         <path path="@{classpath}"/>\r
@@ -310,7 +319,14 @@ is divided into following sections:
                 ===================\r
             -->\r
     <target depends="init" name="deps-jar" unless="no.deps"/>\r
-    <target depends="init,deps-jar" name="-pre-pre-compile">\r
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>\r
+    <target depends="init" name="-check-automatic-build">\r
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>\r
+    </target>\r
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">\r
+        <antcall target="clean"/>\r
+    </target>\r
+    <target depends="init,deps-jar,-groovy-init-macrodef-javac" name="-pre-pre-compile">\r
         <mkdir dir="${build.classes.dir}"/>\r
     </target>\r
     <target name="-pre-compile">\r
@@ -330,7 +346,7 @@ is divided into following sections:
         <!-- Empty placeholder for easier customization. -->\r
         <!-- You can override this target in the ../build.xml file. -->\r
     </target>\r
-    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>\r
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>\r
     <target name="-pre-compile-single">\r
         <!-- Empty placeholder for easier customization. -->\r
         <!-- You can override this target in the ../build.xml file. -->\r
@@ -344,7 +360,7 @@ is divided into following sections:
         <!-- Empty placeholder for easier customization. -->\r
         <!-- You can override this target in the ../build.xml file. -->\r
     </target>\r
-    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>\r
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>\r
     <!--\r
                 ====================\r
                 JAR BUILDING SECTION\r
index 0260410..4048ca9 100644 (file)
@@ -1,8 +1,8 @@
-build.xml.data.CRC32=c5fd47ab\r
-build.xml.script.CRC32=c46c5d81\r
-build.xml.stylesheet.CRC32=be360661\r
+build.xml.data.CRC32=d1b53a37\r
+build.xml.script.CRC32=02aac843\r
+build.xml.stylesheet.CRC32=958a1d3e\r
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.\r
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.\r
-nbproject/build-impl.xml.data.CRC32=c5fd47ab\r
-nbproject/build-impl.xml.script.CRC32=9b6e51de\r
-nbproject/build-impl.xml.stylesheet.CRC32=f1d9da08\r
+nbproject/build-impl.xml.data.CRC32=d1b53a37\r
+nbproject/build-impl.xml.script.CRC32=099f93c3\r
+nbproject/build-impl.xml.stylesheet.CRC32=65b8de21\r
diff --git a/nbproject/groovy-build.xml b/nbproject/groovy-build.xml
new file mode 100644 (file)
index 0000000..fdd5454
--- /dev/null
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project>
+    <target name="-groovy-init-macrodef-javac">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="" name="sourcepath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <taskdef name="groovyc" classpath="${javac.classpath}" classname="org.codehaus.groovy.ant.Groovyc"/>
+                <groovyc destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includes="@{includes}" sourcepath="@{sourcepath}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
+                        <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
+                        <customize/>
+                    </javac>
+                </groovyc>
+            </sequential>
+        </macrodef>
+        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <sequential>
+                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </depend>
+            </sequential>
+        </macrodef>
+        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <sequential>
+                <fail unless="javac.includes">Must set javac.includes</fail>
+                <pathconvert pathsep="," property="javac.includes.binary">
+                    <path>
+                        <filelist dir="@{destdir}" files="${javac.includes}"/>
+                    </path>
+                    <globmapper from="*.java" to="*.class"/>
+                </pathconvert>
+                <delete>
+                    <files includes="${javac.includes.binary}"/>
+                </delete>
+            </sequential>
+        </macrodef>
+    </target>
+</project>
index 9e92ad6..515ce6a 100644 (file)
@@ -22,21 +22,24 @@ excludes=
 includes=**\r
 jar.compress=false\r
 javac.classpath=\\r
-    ${libs.HttpClient3.classpath}:\\r
-    ${libs.Log4J.classpath}:\\r
     ${libs.Codec.classpath}:\\r
     ${libs.Rome.classpath}:\\r
     ${libs.H2_DB.classpath}:\\r
-    ${libs.toplink.classpath}\r
+    ${libs.toplink.classpath}:\\r
+    ${libs.HttpClient4.classpath}:\\r
+    ${libs.Log4J.classpath}:\\r
+    ${libs.groovy-all.classpath}:\\r
+    ${libs.NekoHtml.classpath}\r
 # Space-separated list of extra javac options\r
 javac.compilerargs=\r
 javac.deprecation=false\r
 javac.source=1.5\r
-javac.target=1.6\r
+javac.target=1.5\r
 javac.test.classpath=\\r
     ${javac.classpath}:\\r
     ${build.classes.dir}:\\r
-    ${libs.junit_4.classpath}\r
+    ${libs.junit_4.classpath}:\\r
+    ${libs.groovy-all.classpath}\r
 javadoc.additionalparam=\r
 javadoc.author=false\r
 javadoc.encoding=${source.encoding}\r
@@ -59,16 +62,16 @@ libs.Codec.classpath=../../../java/commons/commons-codec-1.3/commons-codec-1.3.j
 # Property libs.H2_DB.classpath is set here just to make sharing of project simpler.\r
 # The library definition has always preference over this property.\r
 libs.H2_DB.classpath=../../../java/h2-2008-02-02/h2/bin/h2.jar\r
-# Property libs.HttpClient3.classpath is set here just to make sharing of project simpler.\r
+# Property libs.HttpClient4.classpath is set here just to make sharing of project simpler.\r
 # The library definition has always preference over this property.\r
-libs.HttpClient3.classpath=../../../java/commons/commons-httpclient-3.1/commons-httpclient-3.1.jar\r
+libs.HttpClient4.classpath=../../../java/commons/httpcomponents-client-4.0-alpha3-bin-with-dependencies/httpcomponents-client-4.0-alpha3/lib/commons-io-1.2.jar;../../../java/commons/httpcomponents-client-4.0-alpha3-bin-with-dependencies/httpcomponents-client-4.0-alpha3/lib/httpclient-4.0-alpha3.jar;../../../java/commons/httpcomponents-client-4.0-alpha3-bin-with-dependencies/httpcomponents-client-4.0-alpha3/lib/httpcore-4.0-beta1.jar;../../../java/commons/httpcomponents-client-4.0-alpha3-bin-with-dependencies/httpcomponents-client-4.0-alpha3/lib/httpmime-4.0-alpha3.jar\r
 # Property libs.Log4J.classpath is set here just to make sharing of project simpler.\r
 # The library definition has always preference over this property.\r
 libs.Log4J.classpath=../../../java/commons/commons-logging-1.1/commons-logging-adapters-1.1.jar;../../../java/commons/commons-logging-1.1/commons-logging-api-1.1.jar\r
 # Property libs.Rome.classpath is set here just to make sharing of project simpler.\r
 # The library definition has always preference over this property.\r
 libs.Rome.classpath=../../../java/commons/rome-0.9/rome-0.9.jar;../../../java/commons/jdom-1.1/build/jdom.jar\r
-main.class=nicobrowser.MainWindow\r
+main.class=nicobrowser.main.Main\r
 manifest.file=manifest.mf\r
 meta.inf.dir=${src.dir}/META-INF\r
 platform.active=default_platform\r
@@ -85,3 +88,4 @@ run.test.classpath=\
 source.encoding=UTF-8\r
 src.dir=src\r
 test.src.dir=test\r
+compile.on.save.unsupported.groovy=true\r
index ae68a6a..7fcdea1 100644 (file)
@@ -3,6 +3,9 @@
     <type>org.netbeans.modules.java.j2seproject</type>\r
     <configuration>\r
         <buildExtensions xmlns="http://www.netbeans.org/ns/ant-build-extender/1">\r
+            <extension file="groovy-build.xml" id="groovy">\r
+                <dependency dependsOn="-groovy-init-macrodef-javac" target="-pre-pre-compile"/>\r
+            </extension>\r
             <extension file="jnlp-impl.xml" id="jws">\r
                 <dependency dependsOn="jnlp" target="jar"/>\r
             </extension>\r
index edf3d0a..4f93d6c 100644 (file)
@@ -8,7 +8,7 @@
       <property name="toplink.jdbc.password" value=""/>
       <property name="toplink.jdbc.url" value="jdbc:h2:db/NicoDB"/>
       <property name="toplink.jdbc.driver" value="org.h2.Driver"/>
-      <property name="toplink.ddl-generation" value="drop-and-create-tables"/>
+      <property name="toplink.ddl-generation" value="create-tables"/>
     </properties>
   </persistence-unit>
 </persistence>
diff --git a/src/nicobrowser/Config.java b/src/nicobrowser/Config.java
new file mode 100644 (file)
index 0000000..d8ea794
--- /dev/null
@@ -0,0 +1,144 @@
+/*$Id$*/
+package nicobrowser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+public final class Config {
+
+    private static Config instance;
+    private final Properties properties;
+    private final static String APPLICATION_NAME = "nicobrowser";
+    private final static String DEF_CONFIG_PATH = "default";
+    private final static String CONFIG_NAME = APPLICATION_NAME + ".properties";
+
+    private Config() throws IOException {
+        StringBuilder appHome = new StringBuilder(System.getProperty("user.home", "."));
+        if (appHome.charAt(appHome.length() - 1) != File.separatorChar) {
+            appHome.append(File.separator);
+        }
+        appHome.append("." + APPLICATION_NAME);
+
+        File appDir = new File(appHome.toString());
+        if (!appDir.isDirectory()) {
+            boolean result = appDir.mkdir();
+            if (!result) {
+                throw new IOException("アプリケーションディレクトリ作成失敗");
+            }
+            new File(appHome + File.separator + "flv").mkdir();
+        }
+
+        File config = new File(appHome + File.separator + CONFIG_NAME);
+        Properties currentProperties = new Properties();
+        if (config.isFile()) {
+            InputStream is = new FileInputStream(config);
+            currentProperties.load(is);
+            is.close();
+        }
+
+        properties = createNewProperties(currentProperties, appHome.toString());
+
+        FileOutputStream fos = new FileOutputStream(config);
+        properties.store(fos, APPLICATION_NAME + " (concept ver.) config file");
+        fos.close();
+    }
+
+    private Properties createNewProperties(Properties current, String home) {
+        Properties next = new Properties();
+        setNewProperty(next, current, "nicovideo.mail", "set.your@mail.address");
+        setNewProperty(next, current, "nicovideo.password", "set your password");
+        setNewProperty(next, current, "path.db", home + File.separator + "db" + File.separator + "nicodb");
+        setNewProperty(next, current, "dir.save.src", home + File.separator + "flv");
+        setNewProperty(next, current, "download.ext.mp4", "true");
+        setNewProperty(next, current, "download.retry", "3");
+        setNewProperty(next, current, "download.number", "20");
+        setNewProperty(next, current, "download.mylist", "");
+
+        return next;
+    }
+
+    private void setNewProperty(Properties next, Properties current, String key, String defaultValue) {
+        next.setProperty(key, current.getProperty(key, defaultValue));
+    }
+
+    public static Config getInstance() {
+        if (instance == null) {
+            try {
+                instance = new Config();
+            } catch (IOException e) {
+                throw new Error(e);
+            }
+        }
+        return instance;
+    }
+
+    /**
+     * @return ニコニコ動画ログインID.
+     */
+    public String getNicoMail() {
+        return properties.getProperty("nicovideo.mail");
+    }
+
+    /**
+     * @return ニコニコ動画ログインパスワード.
+     */
+    public String getNicoPassword() {
+        return properties.getProperty("nicovideo.password");
+    }
+
+    public String getFfmpegPath() {
+        return properties.getProperty("path.ffmpeg");
+    }
+
+    public String getFfmpegOption() {
+        return properties.getProperty("ffpmeg.option");
+    }
+
+    public String getDbPath() {
+        return properties.getProperty("path.db");
+    }
+
+    public String getSrcSaveDir() {
+        return properties.getProperty("dir.save.src");
+    }
+
+    /**
+     * video/mp4のストリーム保存時、ファイルの拡張子に
+     * .mp4を使用する(true)か、使用しない(.flv)か.
+     * @return mp4拡張子を使用する場合true.
+     */
+    public boolean isExtMp4Use() {
+        String res = properties.getProperty("download.ext.mp4");
+        if ("false".equalsIgnoreCase(res)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 失敗したダウンロードファイルの最大リトライ回数を取得する.
+     * @return リトライ回数.
+     */
+    public int getMaxRetry() {
+        String res = properties.getProperty("download.retry");
+        return Integer.parseInt(res);
+    }
+
+    /**
+     * 上位何位までの動画をダウンロードするか.
+     * @return ダウンロードするファイルの最下位.
+     */
+    public int getMaxDownloadNumber() {
+        String res = properties.getProperty("download.number");
+        return Integer.parseInt(res);
+    }
+    
+    public String[] getDownLoadMyList(){
+        String res = properties.getProperty("download.mylist");
+        return res.split(",");
+    }
+}
index 08ed29f..3019dfe 100644 (file)
@@ -1,6 +1,7 @@
 /*$Id$*/
 package nicobrowser;
 
+import java.net.URISyntaxException;
 import nicobrowser.entity.NicoContent;
 import com.sun.syndication.feed.synd.SyndContentImpl;
 import com.sun.syndication.feed.synd.SyndEntryImpl;
@@ -31,11 +32,22 @@ import javax.swing.text.html.parser.ParserDelegator;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.commons.httpclient.cookie.CookiePolicy;
-import org.apache.commons.httpclient.methods.GetMethod;
-import org.apache.commons.httpclient.methods.PostMethod;
+import nicobrowser.entity.NicoContent.Status;
+import nicobrowser.util.Result;
+import nicobrowser.util.Util;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.UrlEncodedFormEntity;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.client.params.CookiePolicy;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
@@ -45,7 +57,7 @@ import org.xml.sax.SAXException;
  *
  * @author yuki
  */
-public class NicoHttpClient extends HttpClient {
+public class NicoHttpClient extends DefaultHttpClient {
 
     static NicoHttpClient instance;
     private static final String LOGIN_PAGE =
@@ -57,9 +69,13 @@ public class NicoHttpClient extends HttpClient {
     private static final String MOVIE_THUMBNAIL_PAGE_HEADER =
             "http://www.nicovideo.jp/api/getthumbinfo/";
     private static final String GET_FLV_INFO = "http://www.nicovideo.jp/api/getflv?v=";
+    private static final String SEARCH_HEAD = "http://www.nicovideo.jp/search/";
+    private static final String SEARCH_TAIL = "?sort=v";
 
     private NicoHttpClient() {
         super();
+        getParams().setParameter(
+                ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
         instance = this;
     }
 
@@ -76,75 +92,133 @@ public class NicoHttpClient extends HttpClient {
      * @param password パスワード.
      * @return 認証がOKであればtrue.
      */
-    public boolean login(String mail, String password) {
+    public boolean login(String mail, String password) throws URISyntaxException, HttpException, InterruptedException {
         boolean auth = false;
-        PostMethod post = new PostMethod(LOGIN_PAGE);
+        HttpPost post = new HttpPost(LOGIN_PAGE);
 
         try {
-            post.addParameter("mail", mail);
-            post.addParameter("password", password);
-            post.addParameter("next_url", "");
-            post.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
-            int statusCode = executeMethod(post);
-            Logger.getLogger(NicoHttpClient.class.getName()).
-                    log(Level.INFO, "ログインステータスコード: " + statusCode);
+            NameValuePair[] nvps = new NameValuePair[]{
+                new BasicNameValuePair("mail", mail),
+                new BasicNameValuePair("password", password),
+                new BasicNameValuePair("next_url", "")
+            };
+            post.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
+
+            //post.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
+            HttpResponse response = execute(post);
+            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.INFO, "ログインステータスコード: " + response.getStatusLine().
+                    getStatusCode());
 
             // ログイン可否の判定.
-            // x-niconico-authflagで判定できそうだったが必ず0になる...
-            // Set-Cookieがあればログインできたとみなしているが,あまりよろしくないかも.
-            auth = (null != post.getResponseHeader("Set-Cookie")) ? true : false;
+            HttpEntity entity = response.getEntity();
+            entity.consumeContent();
+            List<Cookie> cookies = getCookieStore().getCookies();
+            if (!cookies.isEmpty()) {
+                auth = true;
+            }
         } catch (IOException ex) {
             Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
-        } finally {
-            post.releaseConnection();
         }
         return auth;
     }
 
-    public boolean logout() {
+    /**
+     * ニコニコ動画からログアウトする.
+     * @return ログアウトに成功すればtrue.
+     */
+    public boolean logout() throws URISyntaxException, HttpException, InterruptedException {
         boolean result = false;
-        GetMethod method = new GetMethod(LOGOUT_PAGE);
+        HttpGet method = new HttpGet(LOGOUT_PAGE);
         try {
-            int statusCode = executeMethod(method);
-            Logger.getLogger(NicoHttpClient.class.getName()).
-                    log(Level.INFO, "ログアウトステータスコード: " + statusCode);
+            HttpResponse response = execute(method);
+            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.INFO, "ログアウトステータスコード: " + response.getStatusLine().
+                    getStatusCode());
 
-            if (statusCode == HttpStatus.SC_OK) {
+            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                 result = true;
             }
+            response.getEntity().consumeContent();
         } catch (IOException ex) {
             Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
-        } finally {
-            method.releaseConnection();
         }
         return result;
     }
 
     /**
+     * キーワード検索を行う.
+     * @param word 検索キーワード
+     * @return 検索結果.
+     */
+    public List<NicoContent> search(String word) {
+        Logger.getLogger(NicoHttpClient.class.getName()).log(Level.INFO, "検索:" + word);
+
+        InputStream is = null;
+        List<NicoContent> conts = new ArrayList<NicoContent>();
+        String url = new String(SEARCH_HEAD + word + SEARCH_TAIL);
+
+        try {
+            while (url != null) {
+                HttpGet get = new HttpGet(url);
+                HttpResponse response;
+                response = execute(get);
+                is = new BufferedInputStream(response.getEntity().getContent());
+                assert is.markSupported();
+                is.mark(1024 * 1024);
+                List<Result> results = Util.parseSerchResult(is);
+                for (Result r : results) {
+                    NicoContent c = loadMyMovie(r.getId());
+                    if (c != null) {
+                        conts.add(c);
+                    }
+                }
+                is.reset();
+                url = Util.getNextPage(is);
+                is.close();
+            }
+        } catch (URISyntaxException ex) {
+            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
+        } catch (HttpException ex) {
+            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
+        } catch (IOException ex) {
+            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
+        } catch (InterruptedException ex) {
+            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        return conts;
+    }
+
+    /**
      * 「マイリスト登録数ランキング(本日)」の動画一覧を取得する。
      * @return 動画一覧.
      */
-    List<NicoContent> loadMyListDaily() {
+    public List<NicoContent> loadMyListDaily() throws URISyntaxException, HttpException, InterruptedException {
         List<NicoContent> list = new ArrayList<NicoContent>();
-        String url = new String("http://zio3.net/nicoRss/Handler.ashx");
+        String url = new String("http://www.nicovideo.jp/ranking/mylist/daily/all?rss=atom");
         Logger.getLogger(NicoHttpClient.class.getName()).log(Level.INFO, "全動画サイトのマイリスト登録数ランキング(本日)[全体] : " + url);
 
-        GetMethod get = new GetMethod(url);
+        HttpGet get = new HttpGet(url);
 
+        BufferedReader reader = null;
         try {
-            int statusCode = executeMethod(get);
-            BufferedReader reader = new BufferedReader(new InputStreamReader(get.getResponseBodyAsStream(), "UTF-8"));
+            HttpResponse response = execute(get);
+            reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
             // BOMを読み捨て
-            reader.skip(1);
+            // reader.skip(1);
             list = getNicoContents(reader);
+            response.getEntity().consumeContent();
         } catch (FeedException ex) {
             Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
         } catch (IOException ex) {
             Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
         } finally {
-            get.releaseConnection();
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException ex) {
+                    Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
+                }
+            }
         }
-
         return list;
     }
 
@@ -155,23 +229,30 @@ public class NicoHttpClient extends HttpClient {
      * @param listNo マイリストNo.
      * @return 動画一覧.
      */
-    public List<NicoContent> loadMyList(String listNo) {
+    public List<NicoContent> loadMyList(String listNo) throws URISyntaxException, HttpException, InterruptedException {
         List<NicoContent> contList = new ArrayList<NicoContent>();
         String url = new String(MY_LIST_PAGE_HEADER + listNo + "?rss=atom");
         Logger.getLogger(NicoHttpClient.class.getName()).log(Level.INFO, "マイリストURL: " + url);
 
-        GetMethod get = new GetMethod(url);
+        HttpGet get = new HttpGet(url);
 
+        Reader reader = null;
         try {
-            int statusCode = executeMethod(get);
-            Reader reader = new BufferedReader(new InputStreamReader(get.getResponseBodyAsStream(), "UTF-8"));
+            HttpResponse response = execute(get);
+            reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
             contList = getNicoContents(reader);
         } catch (FeedException ex) {
             Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, "FeedExceitpion" + listNo);
         } catch (IOException ex) {
             Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
         } finally {
-            get.releaseConnection();
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException ex) {
+                    Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
+                }
+            }
         }
         return contList;
     }
@@ -188,11 +269,12 @@ public class NicoHttpClient extends HttpClient {
         String url = new String(MOVIE_THUMBNAIL_PAGE_HEADER + movieNo);
         Logger.getLogger(NicoHttpClient.class.getName()).log(Level.INFO, "動画サムネイルURL: " + url);
 
-        GetMethod get = new GetMethod(url);
+        HttpGet get;
 
         try {
-            int statusCode = executeMethod(get);
-            re = get.getResponseBodyAsStream();
+            get = new HttpGet(url);
+            HttpResponse response = execute(get);
+            re = response.getEntity().getContent();
             // ドキュメントビルダーファクトリを生成
             DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
             // ドキュメントビルダーを生成
@@ -201,13 +283,18 @@ public class NicoHttpClient extends HttpClient {
             Document doc = builder.parse(re);
             // ルート要素を取得(タグ名:site)
             Element root = doc.getDocumentElement();
-            System.out.println("ルート要素のタグ名:" + root.getTagName());
+
+            if ("fail".equals(root.getAttribute("status"))) {
+                Logger.getLogger(NicoHttpClient.class.getName()).log(Level.INFO, "情報取得できません: " + movieNo);
+                return null;
+            }
 
             NodeList list2 = root.getElementsByTagName("thumb");
             cont = new NicoContent();
             Element element = (Element) list2.item(0);
 
-            String watch_url = ((Element) element.getElementsByTagName("watch_url").item(0)).getFirstChild().getNodeValue();
+            String watch_url = ((Element) element.getElementsByTagName("watch_url").item(0)).getFirstChild().
+                    getNodeValue();
             cont.setPageLink(watch_url);
 
             String title = ((Element) element.getElementsByTagName("title").item(0)).getFirstChild().getNodeValue();
@@ -219,6 +306,12 @@ public class NicoHttpClient extends HttpClient {
 //
 //        } catch (ParseException ex) {
 //            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
+        } catch (HttpException ex) {
+            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
+        } catch (InterruptedException ex) {
+            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
+        } catch (URISyntaxException ex) {
+            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
         } catch (SAXException ex) {
             Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
         } catch (IOException ex) {
@@ -227,13 +320,14 @@ public class NicoHttpClient extends HttpClient {
             Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
         } finally {
             try {
-                re.close();
+                if (re != null) {
+                    re.close();
+                }
             } catch (IOException ex) {
                 Logger.getLogger(NicoHttpClient.class.getName()).log(Level.SEVERE, null, ex);
             }
         }
         return cont;
-
     }
 
     private List<NicoContent> getNicoContents(Reader reader) throws FeedException {
@@ -320,7 +414,10 @@ public class NicoHttpClient extends HttpClient {
         for (SyndEntryImpl entry : list) {
             NicoContent content = new NicoContent();
 
-            content.setTitle(entry.getTitle());
+            String title = entry.getTitle();
+            // 本当のタイトルの前に「第XX位:」が付いてるので取り除く.
+            int offset = title.indexOf(":");
+            content.setTitle(title.substring(offset + 1));
             content.setPageLink(entry.getLink());
 
             // サムネイル画像リンクと説明文の取得
@@ -334,7 +431,7 @@ public class NicoHttpClient extends HttpClient {
                 }
             }
 
-            // リストへ追加.
+// リストへ追加.
             contList.add(content);
         }
         return contList;
@@ -348,15 +445,16 @@ public class NicoHttpClient extends HttpClient {
      * (参考: http://yusukebe.com/tech/archives/20070803/124356.html)
      * @param videoID ニコニコ動画のビデオID.
      * @return FLVファイル実体があるURL.
-     * @throws java.io.IOException
+     * @throws java.io.IOException ファイル取得失敗. 権限の無いファイルを取得しようとした場合も.
      */
-    public URL getFlvUrl(String videoID) throws IOException {
+    public URL getFlvUrl(String videoID) throws IOException, URISyntaxException, HttpException, InterruptedException {
         String accessUrl = GET_FLV_INFO + videoID;
-        GetMethod get = new GetMethod(accessUrl);
+        HttpGet get = new HttpGet(accessUrl);
         String resultString;
+        BufferedReader reader = null;
         try {
-            executeMethod(get);
-            BufferedReader reader = new BufferedReader(new InputStreamReader(get.getResponseBodyAsStream(), "UTF-8"));
+            HttpResponse response = execute(get);
+            reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
 
             String str;
             StringBuilder strBuilder = new StringBuilder();
@@ -364,8 +462,11 @@ public class NicoHttpClient extends HttpClient {
                 strBuilder.append(str);
             }
             resultString = strBuilder.toString();
+            response.getEntity().consumeContent();
         } finally {
-            get.releaseConnection();
+            if (reader != null) {
+                reader.close();
+            }
         }
 
         String[] urls = resultString.split("&");
@@ -378,33 +479,95 @@ public class NicoHttpClient extends HttpClient {
                 return new URL(result);
             }
         }
-        throw new IOException("フォーマット仕様変更?");
+        throw new IOException("フォーマット仕様変更? ID: " + videoID + ", パラメータ:" + resultString);
     }
 
-    void getFlvFile(String videoID) throws IOException {
+    /**
+     * ニコニコ動画から動画ファイルをダウンロードする.
+     * @param videoID smxxxx形式のビデオID.
+     * @param fileName ダウンロード後のファイル名. 拡張子は別途付与されるため不要.
+     * @param nowStatus ダウンロードしようとしている動画ファイルの, 現在のステータス.
+     * @param mp4ExtIsMp4 mp4ファイルの拡張子に.mp4を用いるか. falseの場合は.flvを付与する(過去のCraving Explorer互換用).
+     * @return この処理を行った後の, 対象ファイルのステータス.
+     * @throws java.io.IOException ファイル取得失敗. 権限の無いファイルを取得しようとした場合も.
+     */
+    public Status getFlvFile(String videoID, String fileName, Status nowStatus, boolean mp4ExtIsMp4) throws IOException,
+            URISyntaxException, HttpException, InterruptedException {
         byte[] buffer = new byte[1024 * 32];
         final String watchUrl = "http://www.nicovideo.jp/watch/" + videoID;
-        GetMethod get = new GetMethod(watchUrl);
-        executeMethod(get);
-        get.releaseConnection();
+        HttpGet get = new HttpGet(watchUrl);
+        HttpResponse response = execute(get);
+        response.getEntity().consumeContent();
 
         URL url = getFlvUrl(videoID);
+        if (nowStatus == Status.GET_LOW && url.toString().contains("low")) {
+            Logger.getLogger(NicoHttpClient.class.getName()).log(Level.INFO, "lowファイル取得済みのためスキップ" + videoID + ":" +
+                    fileName);
+            return nowStatus;
+        }
 
-        get = new GetMethod(url.toString());
-        executeMethod(get);
-        BufferedInputStream in = new BufferedInputStream(get.getResponseBodyAsStream());
+        get = new HttpGet(url.toURI());
+        response = execute(get);
+        String contentType = response.getEntity().getContentType().getValue();
+        System.out.println(contentType);
+        System.out.println(fileName);
+        if ("text/plain".equals(contentType) || "text/html".equals(contentType)) {
+            return Status.GET_INFO;
+        }
+        String ext = Util.getExtention(contentType);
+        if (!mp4ExtIsMp4) {
+            if (ext.equals("mp4")) {
+                ext = "flv";
+            }
+        }
 
-        //TODO ファイル保存場所を正しく.
-        FileOutputStream file = new FileOutputStream(new File("d:\\aaaccc.flv"));
-        BufferedOutputStream out = new BufferedOutputStream(file);
+        BufferedInputStream in = new BufferedInputStream(response.getEntity().getContent());
+
+        File file = new File(fileName + "." + ext);
+//        int postfix = 0;
+//        while (file.isFile()) {
+//            postfix++;
+//            file = new File(fileName + "(" + postfix + ")" + "." + ext);
+//        }
+        Logger.getLogger(NicoHttpClient.class.getName()).log(Level.INFO, "保存します:" + file.getPath());
+        FileOutputStream fos = new FileOutputStream(file);
+        BufferedOutputStream out = new BufferedOutputStream(fos);
 
         int i;
         while ((i = in.read(buffer)) != -1) {
             out.write(buffer, 0, i);
-            System.out.println(i);
         }
 
+        response.getEntity().consumeContent();
         out.close();
         in.close();
+        if (url.toString().contains("low")) {
+            return Status.GET_LOW;
+        }
+        return Status.GET_FILE;
+    }
+
+    /**
+     * ニコニコ動画から動画ファイルをダウンロードする.
+     * @param videoID smxxxx形式のビデオID.
+     * @param fileName ダウンロード後のファイル名. 拡張子は別途付与されるため不要.
+     * @return この処理を行った後の, 対象ファイルのステータス.
+     * @throws java.io.IOException ファイル取得失敗. 権限の無いファイルを取得しようとした場合も.
+     */
+    public Status getFlvFile(String videoID, String fileName) throws IOException, URISyntaxException, HttpException,
+            InterruptedException {
+        return getFlvFile(videoID, fileName, Status.GET_INFO, true);
+    }
+
+    /**
+     * ニコニコ動画から動画ファイルをダウンロードする.
+     * ファイル名はビデオID名となる.
+     * @param videoID smxxxx形式のビデオID.
+     * @return この処理を行った後の, 対象ファイルのステータス.
+     * @throws java.io.IOException ファイル取得失敗. 権限の無いファイルを取得しようとした場合も.
+     */
+    public Status getFlvFile(String videoID) throws IOException, URISyntaxException, HttpException,
+            InterruptedException {
+        return getFlvFile(videoID, videoID, Status.GET_INFO, true);
     }
 }
index 316dade..df84377 100644 (file)
@@ -14,6 +14,10 @@ import javax.persistence.Version;
 @Entity
 public class NicoContent implements java.io.Serializable {
 
+    public enum Status {
+
+        GET_INFO, GET_LOW, GET_FILE
+    }
     private static final long serialVersionUID = 1L;
     private Long id;
     private Long version;
@@ -21,6 +25,10 @@ public class NicoContent implements java.io.Serializable {
     private String pageLink;
     private String title;
     private String fileName;
+    private Status status = Status.GET_INFO;
+    private int failTimes;
+    private boolean convertedMp3;
+    private boolean convertedMp4;
 
     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
@@ -83,7 +91,8 @@ public class NicoContent implements java.io.Serializable {
         try {
             for (int i = 0; i < fileName.length(); i++) {
                 char c = fileName.charAt(i);
-                if (c == '\\' || c == '/' || c == ':' || c == '*' || c == '?' || c == '"' || c == '<' || c == '>' || c == '|') {
+                if (c == '\\' || c == '/' || c == ':' || c == '*' || c == '?' ||
+                        c == '"' || c == '<' || c == '>' || c == '|' || c == '.') {
                     c = '_';
                 }
                 str.append(c);
@@ -94,6 +103,41 @@ public class NicoContent implements java.io.Serializable {
         this.fileName = str.toString();
     }
 
+    @Column(nullable = false)
+    public Status getStatus() {
+        return status;
+    }
+
+    public void setStatus(Status status) {
+        this.status = status;
+    }
+
+    public int getFailTimes() {
+        return failTimes;
+    }
+
+    public void setFailTimes(int failTimes) {
+        this.failTimes = failTimes;
+    }
+
+    @Column(nullable = false)
+    public boolean isConvertedMp3() {
+        return convertedMp3;
+    }
+
+    public void setConvertedMp3(boolean convertedMp3) {
+        this.convertedMp3 = convertedMp3;
+    }
+
+    @Column(nullable = false)
+    public boolean isConvertedMp4() {
+        return convertedMp4;
+    }
+
+    public void setConvertedMp4(boolean convertedMp4) {
+        this.convertedMp4 = convertedMp4;
+    }
+
     @Override
     public int hashCode() {
         int hash = 0;
diff --git a/src/nicobrowser/main/Main.java b/src/nicobrowser/main/Main.java
new file mode 100644 (file)
index 0000000..c12a527
--- /dev/null
@@ -0,0 +1,140 @@
+/*$Id$*/
+package nicobrowser.main;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import nicobrowser.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Persistence;
+import javax.persistence.Query;
+import nicobrowser.entity.NicoContent;
+import nicobrowser.entity.NicoContent.Status;
+import org.apache.http.HttpException;
+
+public class Main {
+
+    public static void main(String[] args) {
+        System.out.println("Start");
+        new Main();
+    }
+
+    public Main() {
+        Config config = Config.getInstance();
+        List<NicoContent> dailyList = null;
+        ArrayList<List<NicoContent>> myLists = new ArrayList<List<NicoContent>>();
+        NicoHttpClient instance = null;
+        try {
+            System.out.println("リストの取得");
+            instance = NicoHttpClient.getInstance();
+            //list = instance.loadMyList("4315046");
+            dailyList = instance.loadMyListDaily();
+            String[] mylists = config.getDownLoadMyList();
+            for (String l : mylists) {
+                List<NicoContent> list = instance.loadMyList(l);
+                myLists.add(list);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return;
+        }
+
+        System.out.println("DBとの突合せ");
+        EntityManagerFactory factory;
+        EntityManager manager;
+
+        HashMap<String, String> map = new HashMap<String, String>();
+        map.put("toplink.jdbc.url", "jdbc:h2:" + config.getDbPath());
+        factory = Persistence.createEntityManagerFactory("NicoBrowserPU", map);
+        manager = factory.createEntityManager();
+
+        EntityTransaction transaction = manager.getTransaction();
+
+        transaction.begin();
+        try {
+            // ランキング上位のコンテンツ保存
+            int num = 0;
+            for (NicoContent c : dailyList) {
+                if (num >= config.getMaxDownloadNumber()) {
+                    break;
+                }
+                save(manager, c);
+                num++;
+            }
+
+            // マイリストに登録したコンテンツ保存
+            for (List<NicoContent> l : myLists) {
+                for (NicoContent c : l) {
+                    save(manager, c);
+                }
+            }
+
+            transaction.commit();
+
+            Query query = manager.createQuery("SELECT cont FROM NicoContent AS cont " + "WHERE ?1 <> cont.status").
+                    setParameter(1, NicoContent.Status.GET_FILE);
+            List<NicoContent> results = query.getResultList();
+            instance.login(config.getNicoMail(), config.getNicoPassword());
+            Date prevDate = null;
+            for (NicoContent c : results) {
+                if (c.getFailTimes() > config.getMaxRetry() + 1) {
+                    continue;
+                }
+                if (prevDate != null) {
+                    Date nowDate = Calendar.getInstance().getTime();
+                    long sleep = nowDate.getTime() - prevDate.getTime();
+                    sleep = 5000 - sleep;
+                    if (sleep > 0) {
+                        System.out.print("" + sleep + "ms sleep");
+                        Thread.sleep(sleep);
+                    }
+                }
+                prevDate = Calendar.getInstance().getTime();
+                System.out.print("FLVファイル取得: " + config.getSrcSaveDir() + File.separator + c.getFileName());
+                Status status;
+                try {
+                    status = instance.getFlvFile(c.getNicoId(),
+                            config.getSrcSaveDir() + File.separator + c.getFileName(), c.getStatus(),
+                            config.isExtMp4Use());
+                    c.setStatus(status);
+                    if (status == Status.GET_INFO) {
+                        c.setFailTimes(c.getFailTimes() + 1);
+                    }
+                } catch (Exception ex) {
+                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
+                    c.setFailTimes(c.getFailTimes() + 1);
+                }
+                transaction.begin();
+                manager.persist(c);
+                transaction.commit();
+                System.out.println("...完了");
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            transaction.rollback();
+        } finally {
+            manager.close();
+            factory.close();
+        }
+
+    }
+
+    private void save(EntityManager manager, NicoContent c) {
+        Query query = manager.createQuery("SELECT cont FROM NicoContent AS cont " + "WHERE ?1 = cont.nicoId").
+                setParameter(1, c.getNicoId());
+        List<NicoContent> resList = query.getResultList();
+        if (resList.isEmpty()) {
+            System.out.println("NEW! " + c.getNicoId() + " : " + c.getFileName());
+            manager.persist(c);
+        }
+    }
+}
diff --git a/src/nicobrowser/util/Result.java b/src/nicobrowser/util/Result.java
new file mode 100644 (file)
index 0000000..c94a0de
--- /dev/null
@@ -0,0 +1,26 @@
+/* $Id$ */
+package nicobrowser.util;
+
+public class Result {
+
+    private final String id;
+    private final String name;
+
+    public Result(String id, String name) {
+        this.id = id;
+        this.name = name;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return id + ", " + name;
+    }
+}
diff --git a/src/nicobrowser/util/ResultParse.groovy b/src/nicobrowser/util/ResultParse.groovy
new file mode 100644 (file)
index 0000000..5ec1365
--- /dev/null
@@ -0,0 +1,27 @@
+/* $Id$ */
+
+package nicobrowser.util
+import org.cyberneko.html.parsers.SAXParser
+
+
+class ResultParse {
+    List<nicobrowser.util.Result> parse(InputStream is){
+        def html = new XmlSlurper(new SAXParser()).parse(is)
+        def res = html.'**'.findAll{it.attributes()['class'] == 'video'}
+
+        List<nicobrowser.util.Result> list = []
+        res.each{list += new nicobrowser.util.Result(
+                it.attributes()['href'].replaceAll('watch/','').toString(),
+                it.toString())}
+
+        return list
+    }
+
+    String getNextPage(InputStream is){
+        def html = new XmlSlurper(new SAXParser()).parse(is)
+        def res = html.'**'.find{it.attributes()['class'] == 'nextpage'}
+        if(res==null) return null
+        return res.attributes()['href']
+    }
+}
+
diff --git a/src/nicobrowser/util/Util.java b/src/nicobrowser/util/Util.java
new file mode 100644 (file)
index 0000000..3881fc8
--- /dev/null
@@ -0,0 +1,29 @@
+/*$Id$*/
+package nicobrowser.util;
+
+import java.io.InputStream;
+import java.util.List;
+
+public class Util {
+
+    static ResultParse rp = new ResultParse();
+
+    public static String getExtention(String contentType) {
+        if ("video/flv".equals(contentType) || "video/x-flv".equals(contentType)) {
+            return "flv";
+        } else if ("video/mp4".equals(contentType)) {
+            return "mp4";
+        } else if ("application/x-shockwave-flash".equals(contentType)) {
+            return "swf";
+        }
+        return contentType.split("/")[1];
+    }
+
+    public static List<Result> parseSerchResult(InputStream is) {
+        return rp.parse(is);
+    }
+
+    public static String getNextPage(InputStream is) {
+        return rp.getNextPage(is);
+    }
+}
diff --git a/test/nicobrowser/ConfigTest.java b/test/nicobrowser/ConfigTest.java
new file mode 100644 (file)
index 0000000..22105cb
--- /dev/null
@@ -0,0 +1,47 @@
+/*$Id$*/
+package nicobrowser;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class ConfigTest {
+
+    public ConfigTest() {
+    }
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws Exception {
+    }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    /**
+     * Test of getInstance method, of class Config.
+     */
+    @Test
+    public void getInstance() {
+        System.out.println("getInstance");
+        
+        Config result = Config.getInstance();
+        assertNotNull(result);
+        
+        System.out.println(result.getDbPath());
+        System.out.println(result.getFfmpegPath());
+        System.out.println(result.getFfmpegOption());
+        
+    }
+}
index 710add0..ae8254a 100644 (file)
@@ -2,6 +2,8 @@
 package nicobrowser;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -11,6 +13,8 @@ import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.EntityTransaction;
 import javax.persistence.Persistence;
+import nicobrowser.entity.NicoContent.Status;
+import org.apache.http.HttpException;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
@@ -26,7 +30,7 @@ public class NicoHttpClientTest {
 
     static final String OK_MAIL = "niconico.senyou@live.jp";
     static final String OK_PASS = "piyopiyo";
-    static final String OK_LIST_NO = "4315046";
+    static final String OK_LIST_NO = "3693055";
 
     public NicoHttpClientTest() {
     }
@@ -65,7 +69,7 @@ public class NicoHttpClientTest {
      * Test of login method, of class NicoHttpClient.
      */
     @Test
-    public void login() {
+    public void login() throws HttpException, URISyntaxException, InterruptedException {
         System.out.println("login");
         NicoHttpClient instance = NicoHttpClient.getInstance();
 
@@ -83,7 +87,7 @@ public class NicoHttpClientTest {
     }
 
     @Test
-    public void logout() {
+    public void logout() throws URISyntaxException, HttpException, InterruptedException {
         System.out.println("logout");
 
         boolean result;
@@ -95,7 +99,7 @@ public class NicoHttpClientTest {
     }
 
     @Test
-    public void loadMyList() {
+    public void loadMyList() throws URISyntaxException, HttpException, InterruptedException {
         System.out.println("loadMyList");
 
         NicoHttpClient instance = NicoHttpClient.getInstance();
@@ -114,7 +118,7 @@ public class NicoHttpClientTest {
     }
 
     @Test
-    public void loadMyListDaily() {
+    public void loadMyListDaily() throws URISyntaxException, HttpException, InterruptedException {
         System.out.println("loadMyListDaily");
         NicoHttpClient instance = NicoHttpClient.getInstance();
         List<NicoContent> list = instance.loadMyListDaily();
@@ -151,13 +155,13 @@ public class NicoHttpClientTest {
     }
 
     @Test
-    public void getFlvUrl() {
+    public void getFlvUrl() throws URISyntaxException, HttpException, InterruptedException, IOException {
         System.out.println("getFlv");
 
         NicoHttpClient instance = NicoHttpClient.getInstance();
         instance.login(OK_MAIL, OK_PASS);
         try {
-            URL str = instance.getFlvUrl("sm9");
+            URL str = instance.getFlvUrl("sm1359820");
             System.out.println(str);
         } catch (IOException ex) {
             fail();
@@ -167,17 +171,88 @@ public class NicoHttpClientTest {
     }
 
     @Test
-    public void downLoad() {
+    public void downLoad() throws URISyntaxException, IOException, HttpException, InterruptedException {
         System.out.println("downLoad");
 
         NicoHttpClient instance = NicoHttpClient.getInstance();
         instance.login(OK_MAIL, OK_PASS);
 
         try {
-            instance.getFlvFile("sm9");
+            instance.getFlvFile("sm183036", "sm183036", NicoContent.Status.GET_INFO, false);
         } catch (IOException ex) {
             Logger.getLogger(NicoHttpClientTest.class.getName()).log(Level.SEVERE, null, ex);
             fail();
         }
     }
+
+    /**
+     * Test of getFlvFile method, of class NicoHttpClient.
+     */
+    @Test
+    public void getFlvFile_String() throws HttpException, InterruptedException, URISyntaxException {
+        System.out.println("getFlvFile");
+        String videoID = "sm1097445";
+        NicoHttpClient instance = NicoHttpClient.getInstance();
+        instance.login(OK_MAIL, OK_PASS);
+        Status result;
+        try {
+            result = instance.getFlvFile(videoID);
+            System.out.println(result);
+            assertNotSame(Status.GET_INFO, result);
+        } catch (Exception ex) {
+            Logger.getLogger(NicoHttpClientTest.class.getName()).log(Level.SEVERE, null, ex);
+            fail();
+        }
+
+        // 権限が無い動画?の取得
+        // http://www.nicovideo.jp/watch/1231042440
+        // 【亡き王女の為のセプテット・ツェペシュの幼き末裔】Priere -プリエール-
+        try {
+            result = instance.getFlvFile("1231042440");
+            fail("権限が無い動画を取得しようとした場合は例外が送出される");
+        } catch (IOException ex) {
+            Logger.getLogger(NicoHttpClientTest.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+
+    @Test
+    public void search() throws URISyntaxException, InterruptedException, HttpException, IOException {
+        System.out.println("search");
+        NicoHttpClient instance = NicoHttpClient.getInstance();
+        instance.login(OK_MAIL, OK_PASS);
+
+        List<NicoContent> conts = instance.search("初音ミク");
+        System.out.println("検索結果件数: " + conts.size());
+        assertTrue(conts.size() > 0);
+        assertTrue(conts.size() > 100);
+
+    }
+
+    @Test
+    public void loadMyMovie() throws URISyntaxException, InterruptedException, HttpException, IOException {
+        System.out.println("search");
+        NicoHttpClient instance = NicoHttpClient.getInstance();
+        instance.login(OK_MAIL, OK_PASS);
+
+        NicoContent cont;
+
+        // 通常の動画
+        cont = instance.loadMyMovie("sm9");
+        assertNotNull(cont);
+        assertEquals("sm9", cont.getNicoId());
+
+        // チャンネル動画はnull(statusがfailなので)
+        cont = instance.loadMyMovie("1228201771");
+        assertNull(cont);
+
+        // 削除済み
+        cont = instance.loadMyMovie("sm1");
+        assertNull(cont);
+
+        // 存在しない
+        cont = instance.loadMyMovie("xxx");
+        assertNull(cont);
+
+
+    }
 }
diff --git a/test/nicobrowser/util/UtilTest.java b/test/nicobrowser/util/UtilTest.java
new file mode 100644 (file)
index 0000000..e69f56e
--- /dev/null
@@ -0,0 +1,89 @@
+/* $Id$ */
+package nicobrowser.util;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.List;
+import nicobrowser.NicoHttpClient;
+import nicobrowser.entity.NicoContent;
+import nicobrowser.util.Result;
+import org.apache.http.HttpException;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class UtilTest {
+
+    static final String OK_MAIL = "niconico.senyou@live.jp";
+    static final String OK_PASS = "piyopiyo";
+
+    public UtilTest() {
+    }
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws Exception {
+    }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    /**
+     * Test of getExtention method, of class Util.
+     */
+    @Test
+    public void testGetExtention() {
+        System.out.println("getExtention");
+        String result;
+        result = Util.getExtention("video/x-flv");
+        assertEquals("flv", result);
+
+        result = Util.getExtention("video/flv");
+        assertEquals("flv", result);
+
+        result = Util.getExtention("video/mp4");
+        assertEquals("mp4", result);
+
+        result = Util.getExtention("application/x-shockwave-flash");
+        assertEquals("swf", result);
+
+        result = Util.getExtention("");
+        assertEquals("txt", result);
+    }
+
+    /**
+     * Test of getNextPage method, of class Util.
+     */
+    @Test
+    public void testGetNextPage() throws FileNotFoundException, MalformedURLException {
+        System.out.println("getNextPage");
+
+        InputStream is;
+        String result;
+
+        // 次のページがある場合
+        is = new FileInputStream("test_data/momiji.html");
+        result = Util.getNextPage(is);
+        assertEquals("http://www.nicovideo.jp/search/%E7%B4%85%E8%91%89?page=2", result);
+
+        // 最終ページ
+        is = new FileInputStream("test_data/momiji_lastpage.html");
+        result = Util.getNextPage(is);
+        assertNull(result);
+    }
+}
\ No newline at end of file