/* * RSSFeed - Azureus2 Plugin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ package org.kmallan.azureus.rssfeed; //import org.eclipse.swt.graphics.Color; import org.w3c.dom.*; import org.xml.sax.*; import javax.xml.parsers.*; import javax.swing.text.html.parser.ParserDelegator; import java.io.*; import java.util.*; import java.net.*; public class Scheduler extends TimerTask { // private View view = null; // // public void setView(View view) { // this.view = view; // } private int getDelay() { int delay; delay = Plugin.getIntParameter("Delay"); if(delay < Plugin.MIN_REFRESH) { delay = Plugin.MIN_REFRESH; Plugin.setParameter("Delay", delay); } return delay; } private boolean isEnabled() { return Plugin.getBooleanParameter("Enabled"); } public void run() { // for (int iLoop = 0; iLoop < view.rssfeedConfig.getUrlCount(); iLoop++) { // final UrlBean urlBean = view.rssfeedConfig.getUrl(iLoop); // final ListGroup listGroup = urlBean.getGroup(view.treeViewManager, // getDelay()); // // final int delay = listGroup.getDelay(); // final int elapsed = urlBean.isHitting() ? 0 : listGroup.getElapsed(); // // if (elapsed >= delay && (isEnabled() && urlBean.isEnabled()) // || urlBean.getRefreshNow()) { // urlBean.resetGroup(getDelay()); // // Thread t = new Thread("Fetcher-" + urlBean.getName()) { // public void run() { // Plugin.debugOut("hitting " + urlBean.getName() + " - " // + urlBean.getLocation()); // urlBean.setHitting(true); // runFeed(urlBean); // addBacklogElements(urlBean); // urlBean.setHitting(false); // } // }; // // t.start(); // } // // if (view.isOpen() && view.display != null && !view.display.isDisposed()) // view.display.asyncExec(new Runnable() { // public void run() { // if (view.listTable == null || view.listTable.isDisposed()) // return; // // ListTreeItem listGroup = view.treeViewManager.getItem(urlBean); // if (urlBean.isHitting()) { // String s = urlBean.getStatus() + " "; // if (urlBean.getError().length() > 0 // && urlBean.getStatus().equals("Error")) { // s += "- " + urlBean.getError(); // } else if (urlBean.getStatus().equals("Downloading")) { // if (urlBean.getPercent() > 0) { // s += Integer.toString(urlBean.getPercent()) + "%"; // } else if (urlBean.getAmount() > 0) { // s += Double.toString(Math.floor(new Integer( // urlBean.getAmount()).doubleValue() // / (double) 1024 * (double) 100) // / (double) 100) // + "KB"; // } // } // listGroup.setText(1, s); // } else if (urlBean.isEnabled()) { // if (isEnabled()) { // int time = delay - elapsed; // int minutes = new Double( // Math.floor(new Integer(time).doubleValue() / (double) 60)).intValue(); // int seconds = time - (minutes * 60); // String newTime = Integer.toString(minutes) // + ":" // + (seconds < 10 ? "0" + Integer.toString(seconds) // : Integer.toString(seconds)); // listGroup.setText(1, newTime // + " until reload" // + (!urlBean.getError().equalsIgnoreCase("") ? " - " // + urlBean.getError() : "")); // } else { // listGroup.setText(1, "Automatic reload disabled" // + (!urlBean.getError().equalsIgnoreCase("") ? " - " // + urlBean.getError() : "")); // } // } else { // listGroup.setText(1, "Feed disabled" // + (!urlBean.getError().equalsIgnoreCase("") ? " - " // + urlBean.getError() : "")); // } // if (!urlBean.getError().equalsIgnoreCase("")) // listGroup.setForeground(new Color(view.display, 255, 0, 0)); // else // listGroup.resetForeground(); // } // }); // // } } public synchronized void runFeed(final UrlBean urlBean) { String url = urlBean.getLocation(); String title, link, description; ListGroup listBeans = urlBean.getGroup(); DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); docFactory.setIgnoringComments(true); docFactory.setIgnoringElementContentWhitespace(true); DocumentBuilder docBuild; Document feed; File xmlTmp = null; try { docBuild = docFactory.newDocumentBuilder(); Downloader downloader = new Downloader(); downloader.addListener(new DownloaderListener() { public boolean completed = false, error = false; public void downloaderUpdate(int state, int percent, int amount, String err) { if(completed || error) return; String status = new String("Pending"); switch(state) { case Downloader.DOWNLOADER_NON_INIT: status = "Pending"; break; case Downloader.DOWNLOADER_INIT: status = "Connecting"; break; case Downloader.DOWNLOADER_START: status = "Download Starting"; break; case Downloader.DOWNLOADER_DOWNLOADING: status = "Downloading"; break; case Downloader.DOWNLOADER_FINISHED: status = "Download Finished"; completed = true; break; case Downloader.DOWNLOADER_NOTMODIFIED: status = "Not modified"; completed = true; break; case Downloader.DOWNLOADER_ERROR: status = "Error"; error = true; break; } urlBean.setStatus(status); if(percent > 0) urlBean.setPercent(percent); if(amount > 0) urlBean.setAmount(amount); if(!err.equalsIgnoreCase("")) urlBean.setError(err); // if(view.isOpen() && view.display != null && !view.display.isDisposed()) // view.display.asyncExec(new Runnable() { // public void run() { // if(view.listTable == null || view.listTable.isDisposed()) return; // ListTreeItem listGroup = view.treeViewManager.getItem(urlBean); // listGroup.setText(1, urlBean.getStatus() + " " // + (!urlBean.getError().equalsIgnoreCase("") && urlBean.getStatus() == "Error"?"- " // + urlBean.getError():(urlBean.getStatus() == "Downloading"?(urlBean.getPercent() > 0?Integer.toString(urlBean.getPercent()) // + "%":(urlBean.getAmount() > 0?Double.toString(Math.floor(new Integer(urlBean.getAmount()).doubleValue() / (double) 1024 * (double) 100) / (double) 100) + "KB":"")):""))); // if(!urlBean.getError().equalsIgnoreCase("")) listGroup.setForeground(new Color(view.display, 255, 0, 0)); // else listGroup.resetForeground(); // } // }); } }); downloader.init(url, "text/xml, text/html, text/plain, application/x-httpd-php", null, (urlBean.getUseCookie()?urlBean.getCookie():null), urlBean.getLastModifed(), urlBean.getLastEtag()); if(downloader.getState() == Downloader.DOWNLOADER_ERROR) return; if(downloader.getState() == Downloader.DOWNLOADER_NOTMODIFIED) { // no change, add the old items again for(Iterator iter = listBeans.getPreviousItems().iterator(); iter.hasNext(); ) { addTableElement(urlBean, listBeans, (ListBean)iter.next()); } addBacklogElements(urlBean); downloader.notModified(); // use the last seen TTL value if available if(urlBean.getObeyTTL() && listBeans.getPreviousDelay() > 0) listBeans.setDelay(listBeans.getPreviousDelay()); return; } Plugin.debugOut(urlBean.getName() + " Last-Modified: " + downloader.lastModified + " ETag: " + downloader.etag); urlBean.setLastModifed(downloader.lastModified); urlBean.setLastEtag(downloader.etag); xmlTmp = new File(Plugin.getPluginDirectoryName(), "tmp-" + urlBean.getID() + ".xml"); xmlTmp.createNewFile(); FileOutputStream fileout = new FileOutputStream(xmlTmp, false); byte[] buf = new byte[2048]; int read = 0; do { if(downloader.getState() == Downloader.DOWNLOADER_CANCELED) break; read = downloader.read(buf); if(read > 0) { System.err.print("."); fileout.write(buf, 0, read); } else if(read == 0) { System.err.print("?"); try { long numMillisecondsToSleep = 100; Thread.sleep(numMillisecondsToSleep); } catch(InterruptedException e) { } } } while(read >= 0); fileout.flush(); fileout.close(); feed = docBuild.parse(xmlTmp); xmlTmp.delete(); downloader.done(); if(downloader.getState() == Downloader.DOWNLOADER_ERROR) return; } catch(ParserConfigurationException e) { if(xmlTmp != null) xmlTmp.delete(); urlBean.setError("Malformed RSS XML: " + e.getMessage()); return; } catch(SAXException e) { if(xmlTmp != null) xmlTmp.delete(); urlBean.setError("Malformed RSS XML: " + e.getMessage()); return; } catch(IOException e) { if(xmlTmp != null) xmlTmp.delete(); urlBean.setError("IO Exception: " + e.getMessage()); return; } if(urlBean.getObeyTTL()) { NodeList feedTTL = feed.getElementsByTagName("ttl"); if(feedTTL.getLength() == 1) { int newDelay = Integer.parseInt(getText(feedTTL.item(0))) * 60; if(newDelay > 0) urlBean.getGroup().setDelay(newDelay, true); } } // Parse the channel's "item"s NodeList feedItems = feed.getElementsByTagName("item"); int feedItemLen = feedItems.getLength(); for(int iLoop = 0; iLoop < feedItemLen; iLoop++) { Node item = feedItems.item(iLoop); NodeList params = item.getChildNodes(); int paramsLen = params.getLength(); title = link = description = ""; for(int i = 0; i < paramsLen; i++) { Node param = params.item(i); if(param.getNodeType() == Node.ELEMENT_NODE) { if(param.getNodeName().equalsIgnoreCase("title")) { title = getText(param); } else if(param.getNodeName().equalsIgnoreCase("enclosure") && param.hasAttributes()) { if((((param.getAttributes()).getNamedItem("type")).getNodeValue()).equalsIgnoreCase("application/x-bittorrent")) { link = ((param.getAttributes()).getNamedItem("url")).getNodeValue(); } } else if(param.getNodeName().equalsIgnoreCase("link") && link.length() == 0) { link = getText(param); } else if(param.getNodeName().equalsIgnoreCase("description")) { description = getText(param); if(description != null && description.trim().startsWith("<")) { // strip html tags and entity references from description HtmlAnalyzer parser = new HtmlAnalyzer(); try { new ParserDelegator().parse(new StringReader(description), parser, true); description = parser.getPlainText(); } catch(IOException e) { } } description += "\n"; } } } if (link.length() == 0) continue; if(link.indexOf("://") < 0) { try { link = HtmlAnalyzer.resolveRelativeURL(urlBean.getLocation(), link); } catch(MalformedURLException e) { Plugin.debugOut("Bad link URL: " + link + " -> " + e.getMessage()); continue; } } int state = ListBean.NO_DOWNLOAD; String titleTest = title.toLowerCase(); String linkTest = link.toLowerCase(); FilterBean curFilter = null; // for(int i = 0; i < view.rssfeedConfig.getFilterCount(); i++) { // curFilter = view.rssfeedConfig.getFilter(i); // if(curFilter == null) continue; // if(curFilter.matches(urlBean.getID(), titleTest, linkTest)) { // if(curFilter.getMode().equalsIgnoreCase("Pass")) { // state = ListBean.DOWNLOAD_INCL; // } else { // state = ListBean.DOWNLOAD_EXCL; // } // break; // } // } Episode e = null; final FilterBean filterBean = curFilter; if(filterBean != null && "TVShow".equalsIgnoreCase(filterBean.getType())) { try { e = FilterBean.getSeason(titleTest); } catch (Exception ee) {} try { if(e == null) e = FilterBean.getSeason(linkTest); } catch (Exception ee) {} } if(state == ListBean.DOWNLOAD_INCL) { Plugin.debugOut("testing for download: " + linkTest); if(filterBean.getUseSmartHistory()) { // for(int i = 0; i < view.rssfeedConfig.getHistoryCount(); i++) { // HistoryBean histBean = view.rssfeedConfig.getHistory(i); // if(linkTest.equalsIgnoreCase(histBean.getLocation())) { // Plugin.debugOut("found location match: " + histBean); // state = ListBean.DOWNLOAD_HIST; // break; // } // if(e != null && histBean.getFiltID() == filterBean.getID() && histBean.getSeasonStart() > 0 && filterBean.getUseSmartHistory()) { // int seasonStart = histBean.getSeasonStart(); // int episodeStart = histBean.getEpisodeStart(); // int seasonEnd = histBean.getSeasonEnd(); // int episodeEnd = histBean.getEpisodeEnd(); // Plugin.debugOut(e + " vs s" + seasonStart + "e" + episodeStart + " - s" + seasonEnd + "e" + episodeEnd); // if(e.inRange(seasonStart, episodeStart, seasonEnd, episodeEnd)) { // Plugin.debugOut("found filter and episode match: " + e); // state = ListBean.DOWNLOAD_HIST; // break; // } // } } } else Plugin.debugOut("Filter doesn't use smart history: " + filterBean); } // final ListBean listBean = addTableElement(urlBean, listBeans, title, link, description, state); // if(state == ListBean.DOWNLOAD_INCL) { // Add the feed // final String curLink = link; // boolean success = view.torrentDownloader.addTorrent(curLink, urlBean, filterBean, listBean); // if(success && filterBean.getType().equalsIgnoreCase("Other") && filterBean.getDisableAfter()) // filterBean.setEnabled(false); // // if(view.isOpen() && view.display != null && !view.display.isDisposed()) // view.display.asyncExec(new Runnable() { // public void run() { // ListTreeItem listItem = view.treeViewManager.getItem(listBean); // if(listItem != null) listItem.update(); // } // }); // } // } } private static String getText(Node node) { StringBuffer sb = new StringBuffer(); node.normalize(); NodeList children = node.getChildNodes(); int childrenLen = children.getLength(), type; for(int iLoop = 0; iLoop < childrenLen; iLoop++) { Node child = children.item(iLoop); type = child.getNodeType(); if(type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) { sb.append(child.getNodeValue()); sb.append(" "); } } return sb.toString().trim(); } private void addBacklogElements(UrlBean urlBean) { List backLog = urlBean.getBackLog(); // for(Iterator iter = backLog.iterator(); iter.hasNext(); ) // view.treeViewManager.addListBean((ListBean)iter.next(), urlBean, true); // if(backLog.size() != urlBean.getPrevBackLogSize()) view.rssfeedConfig.storeOptions(); } private ListBean addTableElement(UrlBean urlBean, ListGroup listBeans, String title, String link, String description, int state) { ListBean listBean = new ListBean(); listBean.setName(title); listBean.setLocation(link); listBean.setState(state); listBean.setDescription(description); return addTableElement(urlBean, listBeans, listBean); } private ListBean addTableElement(UrlBean urlBean, ListGroup listBeans, ListBean listBean) { listBean.setFeed(urlBean); // view.treeViewManager.addListBean(listBean, urlBean, false); listBeans.add(listBean); return listBean; } }