package dareka.processor.impl; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.util.regex.Matcher; import java.util.regex.Pattern; import dareka.common.CloseUtil; import dareka.common.Logger; import dareka.processor.HttpHeader; import dareka.processor.HttpRequestHeader; import dareka.processor.Processor; import dareka.processor.Resource; import dareka.processor.impl.NicoIdInfoCache.Entry; public class YourfilehostCachingProcessor implements Processor { private static final String[] SUPPORTED_METHODS = new String[] { "GET" }; /** * YourFileHostの動画URLの正規表現 */ private static final Pattern UH_WMV_PATTERN = Pattern.compile("^http://cdn\\.yourfilehost\\.com/.+/(.+)(\\.(flv))$"); public YourfilehostCachingProcessor() { } public String[] getSupportedMethods() { return SUPPORTED_METHODS; } public Pattern getSupportedURLAsPattern() { return UH_WMV_PATTERN; } public String getSupportedURLAsString() { return null; } public Resource onRequest(HttpRequestHeader requestHeader) throws IOException { Matcher m = UH_WMV_PATTERN.matcher(requestHeader.getURI()); if (!m.find()) { // it must not happen... return Resource.get(Resource.Type.URL, requestHeader.getURI()); } MovieData data = new MovieData(m); if (data.getCache().exists()) { Logger.info("using cache: " + data.getCache().getCacheFileName()); if (Boolean.getBoolean("touchCache")) { data.getCache().touch(); } Resource r = Resource.get(Resource.Type.URL, data.getCache().getURLString()); r.setResponseHeader(HttpHeader.CONTENT_TYPE, "video/flv"); return r; } Logger.info("no cache found: " + data.getCache().getCacheFileName()); // [nl] ブラウザのレジューム無効と、NCでのレジューム対応 requestHeader.removeMessageHeader("Range"); requestHeader.removeMessageHeader("If-Range"); long tmpSize = data.getCache().tmpLength(); InputStream cacheInput = null; // [nl] 二重DLになる場合は、2つめのコネクションでは持っている分のキャッシュを利用する // また、2つめのコネクションは保存しない。かつ、強制的にレジュームする // TODO:排他処理がいるかもしれないが、まぁそこはそれ boolean dupconnect = Cache.getDLFlag(data.getCache().getId()); // [nl] レジュームするよー if (tmpSize != 0 && (dupconnect || Boolean.getBoolean("resumeDownload"))) { tmpSize = data.getCache().tmpLength(); requestHeader.setMessageHeader("Range", "bytes=" + tmpSize + "-"); cacheInput = new BufferedInputStream(data.getCache().getTmpInputStream()); } Resource r; try { // ensure cacheInput.close() in error cases. // [nl] DL中リストに入れる Cache.setDLFlag(data.getCache().getId(), Integer.MAX_VALUE); r = Resource.get(Resource.Type.URL, requestHeader.getURI()); r.addTransferListener(new NicoCachingListener(data.getCache(), null, cacheInput, dupconnect)); } catch (RuntimeException e) { Logger.error(e); CloseUtil.close(cacheInput); Cache.setDLFlag(data.getCache().getId(), -1); throw e; } return r; } /** * Class for manage various data for a movie. * */ static class MovieData { private String id; private String postfix; private Cache cache; private String type = "ufh"; private Entry idInfo; MovieData(Matcher m) { initializeId(m); initializeIdInfo(getId()); initializeTypeCache(idInfo); useAlternateCacheIfNecessary(); } private void initializeId(Matcher m) { id = m.group(1); postfix = m.group(2); } private void initializeTypeCache(Entry idInfo) { if (idInfo == null) { cache = new Cache(id, postfix); } else { cache = new Cache(id, postfix, idInfo.getTitle()); } } private void initializeIdInfo(String id) { if (Boolean.getBoolean("title")) { idInfo = NicoIdInfoCache.getInstance().get(id); } else { idInfo = null; } } private void useAlternateCacheIfNecessary() { if (!getCache().exists()) { if (idInfo == null) { cache = new Cache(id, postfix); } else { cache = new Cache(id, postfix, idInfo.getTitle()); } } } public Cache getCache() { return cache; } public Entry getIdInfo() { return idInfo; } public String getType() { return type; } public String getId() { return id; } } }