Revision: 26902
Author: pgardner
Date: 2012-03-14 15:50:25 +0000 (Wed, 14 Mar 2012)
Log Message:
-----------
Added Paths:
-----------
plugins/rssfeed/ChangeLog.txt
plugins/rssfeed/build.xml
plugins/rssfeed/license.txt
plugins/rssfeed/org/
plugins/rssfeed/org/kmallan/
plugins/rssfeed/org/kmallan/azureus/
plugins/rssfeed/org/kmallan/azureus/rssfeed/
plugins/rssfeed/org/kmallan/azureus/rssfeed/CBManager.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/Config.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/Downloader.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/DownloaderListener.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/Episode.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/FilterBean.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/FilterTableItem.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/Help.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/HistoryBean.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/HistoryTableItem.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/HtmlAnalyzer.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/KMAllanInputStream.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/ListBean.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/ListGroup.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/ListTreeItem.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/Plugin.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/Scheduler.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/SimpleDialog.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/TorrentDownloader.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/TreeViewManager.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/UrlBean.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/UrlTableItem.java
plugins/rssfeed/org/kmallan/azureus/rssfeed/View.java
plugins/rssfeed/org/kmallan/include/
plugins/rssfeed/org/kmallan/include/files.txt
plugins/rssfeed/org/kmallan/resource/
plugins/rssfeed/org/kmallan/resource/icons/
plugins/rssfeed/org/kmallan/resource/icons/Cancel.gif
plugins/rssfeed/org/kmallan/resource/icons/Copy.gif
plugins/rssfeed/org/kmallan/resource/icons/Download.gif
plugins/rssfeed/org/kmallan/resource/icons/DownloadTo.gif
plugins/rssfeed/org/kmallan/resource/icons/Filter.gif
plugins/rssfeed/org/kmallan/resource/icons/ItemAdd.gif
plugins/rssfeed/org/kmallan/resource/icons/ItemEdit.gif
plugins/rssfeed/org/kmallan/resource/icons/ItemMoveDown.gif
plugins/rssfeed/org/kmallan/resource/icons/ItemMoveUp.gif
plugins/rssfeed/org/kmallan/resource/icons/ItemRemove.gif
plugins/rssfeed/org/kmallan/resource/icons/Refresh.gif
plugins/rssfeed/org/kmallan/resource/icons/Remove.gif
plugins/rssfeed/org/kmallan/resource/icons/ShowInfo.gif
plugins/rssfeed/org/kmallan/resource/lang/
plugins/rssfeed/org/kmallan/resource/lang/Help.stf
plugins/rssfeed/org/kmallan/resource/lang/Help_fr_FR.stf
plugins/rssfeed/org/kmallan/resource/lang/Messages.properties
plugins/rssfeed/org/kmallan/resource/lang/Messages_fr_FR.properties
plugins/rssfeed/plugin.properties
Property Changed:
----------------
plugins/rssfeed/
Property changes on: plugins/rssfeed
___________________________________________________________________
Added: svn:ignore
+ .settings
.classpath
.cvsignore
.project
*.jar
*.vuze
*.zip
Added: plugins/rssfeed/ChangeLog.txt
===================================================================
--- plugins/rssfeed/ChangeLog.txt (rev 0)
+++ plugins/rssfeed/ChangeLog.txt 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,200 @@
+RSSFEED CHANGELOG - Changes by parg@...
+---------------------------------------------
+
+1.3.6 - magnet uri support
+
+1.3.4/5 - compatability fixes
+
+RSSFEED CHANGELOG - Changes by bowman@...
+---------------------------------------------
+
+RSSFEED 1.3.3 - 2006-11-06
+
+reduced # thread used
+prioritized torrent file guessing (when rss feed only contains url to html page)
+
+RSSFEED 1.3.2 - 2006-10-03
+
+BUGFIX: Fixed console UI problem
+
+RSSFEED 1.3.1 - 2006-09-21
+
+BUGFIX: Fixed timer and display problem
+
+RSSFEED 1.3.0 - 2006-09-16
+
+BUGFIX: Fixed scroll problem
+
+RSSFEED 1.2.9 - 2006-09-11
+
+BUGFIX: Use proper version number
+CHANGE: Updated Plugin API
+
+RSSFEED 1.2.8 - 2005-12-19
+
+BUGFIX: Stopped invalid regular expression from breaking feed loading
+FEATURE: Support self-signed SSL certificates
+
+RSSFEED 1.2.7 - 2005-07-05
+
+BUGFIX: Old non-tvshow-filters would not make use of smart history. For old tv-show filters you still need to use the "utilize smart history" checkbox.
+BUGFIX: Build is now compatible with older java versions again (1.2.6 was accidentally built with 1.5.0_03). Solves unsupported class version.
+BUGFIX: Improved error handling in case a torrent link isn't found even using the new mechanisms introduced in 1.2.6.
+BUGFIX: Fixed "create filter" menu item failing if the title was misidentified as tv show and contained certain special characters.
+FEATURE: Open/Copy link URL now works on feed items.
+
+
+RSSFEED 1.2.6 - 2005-06-29
+
+CHANGE: Added mechanisms to handle relative URLs in link elements.
+CHANGE: Improved support for indirect links: If the plugin encounters an html page without any obvious torrent file links, it will try HEAD requests for all hrefs until it finds the right content type.
+CHANGE: Old/Removed items are now only compared using the link urls, so items with changing titles (i.e including [seeders/peers] and similar dynamic indicators) will no longer cause multiple entries.
+BUGFIX: Made importing the old rssfeed.options format more robust.
+FEATURE: Indirect links to html with Refresh directives in the HTTP reply header are now handled.
+FEATURE: Added "Maximum items to keep" settings to limit number of old/removed items kept (default 1000).
+FEATURE: If a link element isn't pointing to torrent/html, the encountered content is now simply saved directly to the output dir (i.e non-torrent downloads).
+
+- I also received some post-1.2p3-code from Martyn Allan (one of the original authors) and managed to merge the following:
+CHANGE: Priority hidden for Azureus 2.2.0.0 and above.
+CHANGE: Threaded save & save as from the status table menu.
+UPDATE: Help has had an update.
+FEATURE: Smart History now optional per TVShow Filter item.
+
+
+RSSFEED 1.2.5 - 2005-05-14
+
+BUGFIX: Old/Removed items no longer deleted on restart.
+BUGFIX: History entries were saved as tvshow filter matches if their titles/locations looked like an episode mask.
+BUGFIX: File save location in history entries was incorrect for single file torrents.
+CHANGE: If an enclosure element with type "application/x-bittorrent" exists, it will now be used instead of the link element.
+CHANGE: Disabled feeds are no longer included in a manual "Refresh all feeds".
+CHANGE: Old/Removed items list reversed (recent items first).
+CHANGE: Error messages referring to required Azureus settings changed to match their current names.
+
+
+RSSFEED 1.2.4 - 2005-03-24
+
+BUGFIX: Import of the old rssfeed.options format would fail for certain files.
+BUGFIX: Fixed a bug that would sometimes identify torrent data as html when the link url didn't end with an explicit .torrent.
+BUGFIX: Fixed a few other situations that could cause failures on startup (empty tab).
+BUGFIX: Rss xml transfers that failed in mid-download would silently lock the thread forever ("Downloader" mechanisms really need to be rewritten).
+
+
+RSSFEED 1.2.3 - 2005-03-02
+
+BUGFIX: Filter test indicator would sometimes fail (not show anything at all).
+BUGFIX: Fixed table width issues on OSX.
+BUGFIX: Default refresh interval (global setting) was not used.
+BUGFIX: Corrupt/incomplete filters/feeds avoided (no longer saved). Broken items could cause NPE on startup.
+CHANGE: Improved "create filter" feature (status item menu), it should now identify tv shows better.
+CHANGE: Inverted history table, the top item is now the last downloaded.
+FEATURE: Added download time to history table.
+
+
+
+RSSFEED 1.2.2 - 2005-02-27
+
+BUGFIX: Added "support" for file:// urls to handle locally generated rss files.
+BUGFIX: More typos fixed and a few minor gui enhancements.
+BUGFIX: The setting for number of days to keep old items didn't work (was always 1 day).
+BUGFIX: Text can now be selected and copied in info dialog.
+CHANGE: Minimum refresh changed to 5 minutes (300 secs). For local files you can now use TTL to get any refresh rate.
+FEATURE: ETag and Last-Modified HTTP headers now used to avoid unecessary xml downloads (in case of unchanged feeds).
+FEATURE: Added new global setting for the initial state of manually saved torrents.
+FEATURE: New right click menu options for status tree: expand all, collapse all, open link url.
+FEATURE: Added age column to status tree.
+
+
+
+RSSFEED 1.2.1 - 2005-02-03
+
+FEATURE: Added automatic import of the previous rssfeed.options format (1.2p3 and earlier), if encountered on startup.
+
+
+RSSFEED 1.2 - 2005-01-31
+
+BUGFIX: It was not possible to add new feeds or filters unless at least one already existed in the list.
+BUGFIX: Certain characters (e.g [ ]) in xml elements would cause exceptions during parsing (no filters would be matched and refreshing would stop).
+BUGFIX: RSS feed downloads now synchronized to avoid filters matching the same item in multiple feeds when they are refreshed simultaneously.
+BUGFIX: Show info feature now works, regardless of what actually appears in the "description" element (broken html/xml stripped).
+BUGFIX: Fixed a few typos.
+CHANGE: Cleanup and refactoring of all source to make it easier to maintain (a lot of work remaining here).
+CHANGE: Reworked persistence, any old feed/filter/history data will NOT be compatible with this build (sorry).
+FEATURE: RSS feeds with links that point to an intermediary html page instead of the actual .torrent file are now handled (providing the html contains the real .torrent link).
+FEATURE: Test field added for filters. Can be used to test regexp/substring matches on an arbitrary pasted string (keep in mind all filter properties are used though, including "active" and tv show ep range).
+FEATURE. Items that are removed from feeds are now kept for a configurable time period (old items, but also removed/renamed/moved entries).
+
+
+
+
+RSSFEED CHANGELOG - Changes by the original authors
+---------------------------------------------------
+
+RSSFEED 1.2p3
+
+FEATURE: Smarter history added.
+BUGFIX: Fixed the problem that occurs if General_sDefaultTorrent_Directory is not set.
+FEATURE: Added A Dialog to show the description from the rss xml feed (if the item has one set).
+FEATURE: Added the ability to enter cookies (to be entered in the format of name=value[;name=value]).
+FEATURE: 'Disable After Success' Option Added for 'Other' Filters.
+FEATURE: Can now set the Priority, State (Queued, Forced & Stoped), Category, Download + Upload Rates (2.1.0.5 required for the later) and move items to the top of the list, Based on the filter.
+CHANGE: You may now enter a custom referrer (this is required for suprnova feeds).
+CHANGE: Updated buttons in Options Tab.
+CHANGE: Right click refresh and refresh all will now refresh disabled feeds.
+CHANGE: No longer recreates the status table when feeds are refreshed.
+BUGFIX: Fixed the problem of still not saving the torrents as '.torrent' files.
+
+
+
+RSSFEED 1.2p2
+
+FEATURE: Added Right Mouse Button Click for history listing.
+FEATURE: Ability to copy torrent location thru the torrent listing menu.
+FEATURE: Ability to copy torrent/file location thru the history listing.
+FEATURE: Ability to delete 1 or more history items thru the history listing.
+FEATURE: Displays errors & download status in the torrent listing (Both Feeds and Torrents).
+FEATURE: AutoLoad Added. See Configuration->Plugins->RSSFeed to turn it on.
+CHANGE: New Minimum Refresh of 900 seconds (15 min).
+CHANGE: Now Passes a 'User-Agent' (something other than the default: 'Java'+version)
+CHANGE: ObeyTTL enforced on Suprnova feeds.
+CHANGE: ObeyTTL default selected for new torrents.
+CHANGE: Downloading of Feeds and Torrents now runs smother.
+CHANGE: Double Click on Feed row in Status Tab now Expands & Contracts.
+CHANGE: You can now order the feeds, and the status table uses the order (requires restart)
+BUGFIX: Suprnova problem fixed with above changes.
+BUGFIX: Fails parsing the xml from some sites has been fixed.
+
+
+
+RSSFEED 1.2p1
+
+FEATURE: Added Right Mouse Button Click for torrent listing.
+FEATURE: Ability to Refresh & RefreshAll thru the torrent listing menu.
+FEATURE: Ability to Save & SaveAs for all of the torrents thru the torrent listing menu.
+FEATURE: Ability to Create a new Filter based on the selected torrent thru the torrent listing menu.
+CHANGE: Removed deprecated 'Load...' button under the torrent listing.
+FEATURE: Feeds now have a user settable default download dir.
+FEATURE: Ability to obey the TTL from the feed it self.
+FEATURE: Each feed has it's own download delay (and the one from version 1.0 is the default delay)
+CHANGE: The torrent listing is now in tree form (torrents branch out from the feed they originated).
+CHANGE: ETA/TimeRemaining now displayed in the torrent listing table, next to the respective feed.
+
+
+
+RSSFEED 1.1
+
+CHANGE: Do not hide options on accept.
+BUGFIX: NullPointerException fixed (Click on nothing on either Table under the Options Tab.)
+
+
+
+RSSFEED 1.0
+
+FEATURE: Parse Mutiple Feeds at once.
+FEATURE: Save your torrents in a specific directory, depending on the filter matched.
+FEATURE: Your choice of Regular Expression or Substring matches.
+FEATURE: "FAIL" rules.
+FEATURE: Generic, or feed specific filter rules.
+FEATURE: Episode notation parsing.
+FEATURE: Configurable download delay.
+FEATURE: Simple and easy to use GUI.
Added: plugins/rssfeed/build.xml
===================================================================
--- plugins/rssfeed/build.xml (rev 0)
+++ plugins/rssfeed/build.xml 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,121 @@
+<project name="RssFeed" default="jar">
+ <property name="src" value="src"/>
+ <property name="res" value="resource"/>
+ <property name="build" value="build"/>
+ <property name="include" value="include"/>
+ <property name="lib" value="lib"/>
+ <property name="dist" value="dist"/>
+ <loadproperties srcFile="${src}/plugin.properties"/>
+
+ <target name="init">
+ <mkdir dir="${build}"/>
+ <mkdir dir="${lib}"/>
+ <path id="classpath">
+ <fileset dir="lib">
+ <include name="**/*.jar"/>
+ </fileset>
+ </path>
+ <property name="classpath" refid="classpath" />
+ </target>
+
+ <target name="compile" depends="init">
+ <copy todir="${build}/">
+ <fileset dir="${src}" includes="**/*.java"/>
+ </copy>
+ <javac srcdir="${build}" destdir="${build}" debug="true" deprecation="false" debuglevel="lines,vars,source">
+ <classpath>
+ <pathelement path="${classpath}"/>
+ <fileset dir="${include}" includes="**/*.jar"/>
+ </classpath>
+ </javac>
+ </target>
+
+ <target name="jar" depends="compile">
+ <mkdir dir="${build}/org/kmallan/resource"/>
+ <copy todir="${build}/org/kmallan/resource">
+ <fileset dir="${res}">
+ <exclude name="**/.xvpics/*"/>
+ <include name="**/*.properties"/>
+ <include name="**/*.stf"/>
+ <include name="**/*.gif"/>
+ </fileset>
+ </copy>
+ <mkdir dir="${dist}"/>
+ <jar jarfile="${dist}/${plugin.id}_${plugin.version}.jar">
+ <fileset dir="${build}" excludes="**/*.java"/>
+ </jar>
+ <copy todir="${dist}">
+ <fileset dir="${src}" includes="plugin.properties"/>
+ <fileset dir=".">
+ <include name="ChangeLog.txt"/>
+ <include name="license.txt"/>
+ </fileset>
+ </copy>
+ </target>
+
+ <target name="dist-init">
+ <mkdir dir="${dist}"/>
+ </target>
+
+ <target name="dist" depends="jar,dist-init">
+ <zip destfile="${dist}/${plugin.id}_${plugin.version}.zip">
+ <zipfileset dir="${lib}/" prefix="plugins/${plugin.id}">
+ <include name="*_${plugin.version}*"/>
+ <include name="plugin.properties"/>
+ <include name="*.txt"/>
+ </zipfileset>
+ </zip>
+ </target>
+
+ <target name="dist-src" depends="init,dist-init">
+ <zip destfile="${dist}/${plugin.id}_${plugin.version}_src.zip">
+ <zipfileset dir="./" includes="build.xml" prefix="${plugin.id}"/>
+ <zipfileset dir="./" includes="*.txt" prefix="${plugin.id}"/>
+ <zipfileset dir="${src}/" excludes=".*" prefix="${plugin.id}/${src}"/>
+ <zipfileset dir="${include}/" includes="files.txt" prefix="${plugin.id}/${include}"/>
+ <zipfileset dir="${res}" prefix="${plugin.id}/${res}">
+ <exclude name="**/.xvpics/*"/>
+ <include name="**/*.properties"/>
+ <include name="**/*.stf"/>
+ <include name="**/*.gif"/>
+ </zipfileset>
+ </zip>
+ </target>
+
+ <target name="dist-src-full" depends="init,dist-init">
+ <zip destfile="${dist}/${plugin.id}_${plugin.version}_src.zip">
+ <zipfileset dir="./" includes="build.xml" prefix="${plugin.id}"/>
+ <zipfileset dir="./" includes="*.txt" prefix="${plugin.id}"/>
+ <zipfileset dir="${src}/" excludes=".*" prefix="${plugin.id}/${src}"/>
+ <zipfileset dir="${include}/" includes="*.jar" prefix="${plugin.id}/${include}"/>
+ <zipfileset dir="${res}" prefix="${plugin.id}/${res}">
+ <include name="**/*.properties"/>
+ <include name="**/*.stf"/>
+ <include name="**/*.gif"/>
+ <exclude name="**/.xvpics/*"/>
+ </zipfileset>
+ </zip>
+ </target>
+
+ <target name="distall" depends="dist,dist-src">
+ <zip destfile="${dist}/${plugin.id}_${plugin.version}_all.zip">
+ <zipfileset dir="${dist}">
+ <include name="${plugin.id}_${plugin.version}*"/>
+ <exclude name="${plugin.id}_${plugin.version}_all.zip"/>
+ </zipfileset>
+ </zip>
+ </target>
+
+ <target name="clean">
+ <delete dir="${build}"/>
+ <delete dir="${lib}"/>
+ </target>
+
+ <target name="dist-clean">
+ <delete dir="${dist}"/>
+ </target>
+
+ <target name="cleanall" depends="clean,dist-clean"/>
+
+</project>
+
Added: plugins/rssfeed/license.txt
===================================================================
--- plugins/rssfeed/license.txt (rev 0)
+++ plugins/rssfeed/license.txt 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,125 @@
+The GNU General Public License (GPL)
+Version 2, June 1991
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+
+b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+
+c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
+
+one line to give the program's name and a brief idea of what it does.
+Copyright (C)
+
+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
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
+
+Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
+
+Yoyodyne, Inc., hereby disclaims all copyright interest
+in the program `Gnomovision' (which makes passes at compilers)
+written by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/CBManager.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/CBManager.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/CBManager.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,55 @@
+/*
+ * 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 java.awt.*;
+import java.awt.datatransfer.*;
+import java.io.IOException;
+
+public class CBManager implements ClipboardOwner {
+
+ public void lostOwnership(Clipboard clipboard, Transferable contents) {
+ }
+
+ public void setClipboardContents(String str) {
+ StringSelection strSel = new StringSelection(str);
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ clipboard.setContents(strSel, this);
+ }
+
+ public String getClipboardContents() {
+ String result = "";
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ // odd: the Object param of getContents is not currently used
+ Transferable contents = clipboard.getContents(null);
+ boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor);
+ if(hasTransferableText) {
+ try {
+ result = (String) contents.getTransferData(DataFlavor.stringFlavor);
+ } catch(UnsupportedFlavorException e) {
+ // highly unlikely since we are using a standard DataFlavor
+ System.err.println("Unable to get clipboard contents: " + e);
+ } catch(IOException e) {
+ System.err.println("Unable to get clipboard contents: " + e);
+ }
+ }
+ return result;
+ }
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/Config.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/Config.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/Config.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,225 @@
+/*
+ * 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 java.io.*;
+import java.util.*;
+import java.net.*;
+
+public class Config implements Serializable {
+
+ private List urlBeans, filterBeans, histBeans;
+ public String path, separator;
+
+ public Config() {
+ this.urlBeans = new ArrayList();
+ this.filterBeans = new ArrayList();
+ this.histBeans = new ArrayList();
+
+ setPath(Plugin.getPluginDirectoryName());
+ try {
+ loadOptions();
+ } catch (Exception e) {
+ }
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ private void setPath(String newPath) {
+ this.path = newPath;
+ separator = System.getProperty("file.separator");
+ if(!path.endsWith(separator)) path = path + separator;
+ }
+
+ public synchronized void storeOptions() {
+ File optionsFile = new File(getPath() + "rssfeed.options");
+ Plugin.debugOut("storing options to file: " + optionsFile.getPath());
+ try {
+ if(!optionsFile.exists()) optionsFile.createNewFile();
+ storeObjectFile(optionsFile);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public synchronized void loadOptions() {
+ File optionsFile = new File(getPath() + "rssfeed.options");
+ Plugin.debugOut("loading options from file: " + optionsFile.getPath());
+ try {
+ if(optionsFile.exists()) {
+ loadObjectFile(optionsFile);
+ } else {
+ optionsFile.createNewFile();
+ storeObjectFile(optionsFile);
+ }
+ } catch(OptionalDataException e) {
+ Plugin.debugOut("found old file format, attempting import... (" + e + ")");
+ try {
+ loadLegacyFile(optionsFile);
+ optionsFile.renameTo(new File(getPath() + "rssfeed.options.bak"));
+ storeOptions();
+ } catch(Exception e1) {
+ e1.printStackTrace();
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void loadLegacyFile(File file) throws IOException, ClassNotFoundException {
+ KMAllanInputStream kis = new KMAllanInputStream(new FileInputStream(file));
+ urlBeans = new ArrayList(kis.readVector("UrlBean"));
+ filterBeans = new ArrayList(kis.readVector("FilterBean"));
+ histBeans = new ArrayList(kis.readVector("HistBean"));
+ kis.close();
+ }
+
+ private void storeObjectFile(File file) throws IOException {
+ ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
+ oos.writeObject(validateBeans(urlBeans));
+ oos.writeObject(validateBeans(filterBeans));
+ oos.writeObject(validateBeans(histBeans));
+ oos.close();
+ }
+
+ private void loadObjectFile(File file) throws IOException, ClassNotFoundException {
+ ObjectInputStream ois = null;
+ try {
+ ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)));
+ urlBeans = validateBeans((List)ois.readObject());
+ filterBeans = validateBeans((List)ois.readObject());
+ histBeans = validateBeans((List)ois.readObject());
+ Collections.sort(histBeans);
+ ois.close();
+ } catch(IOException e) {
+ throw e;
+ } finally {
+ if(ois != null) ois.close();
+ }
+ }
+
+ private List validateBeans(List beans) {
+ for(int i = (beans.size() - 1); i >= 0; i--) {
+ if(beans.get(i) == null) beans.remove(i);
+ else if(beans.get(i) instanceof UrlBean) ((UrlBean)beans.get(i)).cleanOldBackLog();
+ }
+ return beans;
+ }
+
+ public UrlBean getUrl(int index) {
+ if(index < 0 || index >= getUrlCount()) {
+ UrlBean urlBean = new UrlBean();
+ urlBeans.add(urlBean);
+ return urlBean;
+ }
+ return (UrlBean)urlBeans.get(index);
+ }
+
+ public void addUrl(UrlBean urlBean) {
+ urlBeans.add(urlBean);
+ }
+
+ public void setUrl(int index, UrlBean urlBean) {
+ if(index >= 0 && index < getUrlCount()) urlBeans.set(index, urlBean);
+ else urlBeans.add(urlBean);
+ }
+
+ public int getUrlCount() {
+ return urlBeans.size();
+ }
+
+ public int getUrlIndex(UrlBean urlBean) {
+ return urlBeans.indexOf(urlBean);
+ }
+
+ public void removeUrl(UrlBean urlBean) {
+ urlBeans.remove(urlBean);
+ }
+
+ public FilterBean getFilter(int index) {
+ if(index < 0 || index >= getFilterCount()) {
+ FilterBean filterBean = new FilterBean();
+ filterBeans.add(filterBean);
+ return filterBean;
+ }
+ return (FilterBean)filterBeans.get(index);
+ }
+
+ public void setFilter(FilterBean filterBean) {
+ filterBeans.add(filterBean);
+ }
+
+ public void setFilter(int index, FilterBean filterBean) {
+ if(index >= 0 && index < getFilterCount()) filterBeans.set(index, filterBean);
+ else filterBeans.add(filterBean);
+ }
+
+ public int getFilterCount() {
+ return filterBeans.size();
+ }
+
+ public int getFilterIndex(FilterBean filterBean) {
+ return filterBeans.indexOf(filterBean);
+ }
+
+ public void removeFilter(FilterBean filterBean) {
+ filterBeans.remove(filterBean);
+ }
+
+ public HistoryBean getHistory(int index) {
+ if(index < 0 || index >= getHistoryCount()) {
+ HistoryBean histBean = new HistoryBean();
+ histBeans.add(histBean);
+ return histBean;
+ }
+ return (HistoryBean)histBeans.get(index);
+ }
+
+ public void addHistory(HistoryBean histBean) {
+ histBeans.add(0, histBean);
+ }
+
+ public void setHistory(int index, HistoryBean histBean) {
+ if(index >= 0 && index < getHistoryCount()) histBeans.set(index, histBean);
+ else histBeans.add(histBean);
+ }
+
+ public int getHistoryCount() {
+ return histBeans.size();
+ }
+
+ public int getHistoryIndex(HistoryBean histBean) {
+ return histBeans.indexOf(histBean);
+ }
+
+ public void removeHistory(HistoryBean histBean) {
+ histBeans.remove(histBean);
+ }
+
+ public static void main(String[] args) throws Exception {
+ Socket s = new ServerSocket(5000).accept();
+ InputStream is = s.getInputStream();
+ while(true) is.read();
+ }
+
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/Downloader.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/Downloader.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/Downloader.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,385 @@
+/*
+ *
+ * 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.gudy.azureus2.core3.util.Constants;
+
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.regex.*;
+
+public class Downloader extends InputStream {
+
+ final static int DOWNLOADER_NON_INIT = 0, DOWNLOADER_INIT = 1, DOWNLOADER_START = 2;
+ final static int DOWNLOADER_DOWNLOADING = 3, DOWNLOADER_FINISHED = 4, DOWNLOADER_CANCELED = 5;
+ final static int DOWNLOADER_NOTMODIFIED = 6, DOWNLOADER_CHECKING = 7, DOWNLOADER_ERROR = -1;
+
+ private URL url;
+ private URLConnection con;
+
+ private int state = DOWNLOADER_NON_INIT;
+ private int percentDone = 0;
+ private int readTotal = 0;
+ private int size = 0;
+ private int refCount = 0;
+
+ protected String fileName, contentType, etag;
+ protected long lastModified;
+ protected InputStream in;
+ protected List listeners = new ArrayList();
+
+ public int getState() {
+ return state;
+ }
+
+ private synchronized void error(String err) {
+ synchronized(listeners) {
+ state = DOWNLOADER_ERROR;
+ fireDownloaderUpdate(state, 0, 0, err);
+ }
+ }
+
+/*
+ public static void testDownload(String url) throws Exception {
+ Downloader downloader = new Downloader();
+ downloader.addListener(new DownloaderListener() {
+ public void downloaderUpdate(int state, int percent, int amount, String err) {
+ System.out.println(state + " " + percent + " " + amount + " " + err);
+ }
+ });
+ downloader.init(url, "application/x-bittorrent, application/x-httpd-php", null, null, 0, null);
+
+ if(downloader.getState() == Downloader.DOWNLOADER_CANCELED || downloader.getState() == Downloader.DOWNLOADER_ERROR) {
+ System.out.println("null");
+ return;
+ }
+
+ String filename = downloader.fileName;
+ if(!downloader.fileName.toLowerCase().endsWith(".torrent"))
+ filename = "temp-" + Long.toString((new Date()).getTime()) + "-" + Long.toString((new Random()).nextLong()) + ".torrent";
+
+ File torrentLocation = new File(filename);
+ torrentLocation.createNewFile();
+ FileOutputStream fileout = new FileOutputStream(torrentLocation, false);
+
+ byte[] buf = new byte[4096];
+ int read;
+ while((read = downloader.read(buf)) != -1) {
+ fileout.write(buf, 0, read);
+ if(downloader.getState() == Downloader.DOWNLOADER_CANCELED) break;
+ }
+ fileout.flush();
+ fileout.close();
+
+ if(downloader.getState() == Downloader.DOWNLOADER_CANCELED || downloader.getState() == Downloader.DOWNLOADER_ERROR) {
+ downloader.done();
+ torrentLocation.delete();
+ return;
+ }
+
+ if(!downloader.fileName.toLowerCase().endsWith(".torrent")) {
+ Plugin.debugOut("contentType: " + downloader.contentType);
+
+ if(downloader.contentType != null && downloader.contentType.toLowerCase().startsWith("text/html")) {
+
+ // html file encountered, look for link to torrent
+ String href = TorrentDownloader.findTorrentHref(torrentLocation, url, null);
+ if(href != null) {
+ Plugin.debugOut("href: " + href);
+ torrentLocation.delete();
+ downloader.done();
+ testDownload(href);
+ } else throw new Exception("Html content returned, but no links to torrent files found.");
+
+ } else if(downloader.contentType != null && !downloader.contentType.toLowerCase().startsWith("application/x-bittorrent")) {
+
+ // something else encountered, just move it to outputdir
+ System.out.println("other " + downloader.fileName);
+
+ }
+ }
+ System.out.println("torrent?");
+ }
+
+ public static void main(String[] args) throws Exception {
+ String url = "";
+ testDownload(url);
+ }
+*/
+ public void init(String urlStr, String accept, String referer, String cookie, long lastModSince, String oldEtag) {
+
+ Pattern exprHost = Pattern.compile(".*(https?://.*?)", Pattern.CASE_INSENSITIVE);
+ Matcher m = exprHost.matcher(urlStr);
+ if(m.matches() && !m.group(1).equalsIgnoreCase(urlStr)) urlStr = m.group(1);
+ urlStr = urlStr.replaceAll(" ", "%20");
+
+ try {
+ synchronized(listeners) {
+ url = new URL(urlStr);
+
+ for (int i=0;i<2;i++){
+ try{
+
+ if(url.getProtocol().equalsIgnoreCase("https")) {
+ HttpsURLConnection sslCon = (HttpsURLConnection)url.openConnection();
+ // allow for certs that contain IP addresses rather than dns names
+ sslCon.setHostnameVerifier(new HostnameVerifier() {
+ public boolean verify(String host, SSLSession session) {return true;}
+ });
+ con = sslCon;
+ } else {
+ con = url.openConnection();
+ }
+
+ con.setDoInput(true);
+ con.setUseCaches(false);
+
+ if(con instanceof HttpURLConnection) {
+ exprHost = Pattern.compile("https?://([^/]+@)?([^/@:]+)(:[0-9]+)?/.*");
+ m = exprHost.matcher(urlStr.toLowerCase());
+ if(m.matches()) con.setRequestProperty("Host", m.group(2)); // isn't this handled automatically? /bow
+ con.setRequestProperty("User-Agent", Plugin.PLUGIN_VERSION);
+ if(referer != null && referer.length() > 0) con.setRequestProperty("Referer", referer);
+ if(accept != null && accept.length() > 0) con.setRequestProperty("Accept", accept);
+ if(cookie != null && cookie.length() > 0) con.setRequestProperty("Cookie", cookie);
+ if(lastModSince > 0) con.setIfModifiedSince(lastModSince);
+ if(oldEtag != null) con.setRequestProperty("If-None-Match", oldEtag);
+ }
+
+ state = DOWNLOADER_INIT;
+ fireDownloaderUpdate(state, 0, 0, "");
+
+ con.connect();
+
+ if(con instanceof HttpURLConnection) {
+ int response = ((HttpURLConnection)con).getResponseCode();
+ Plugin.debugOut("response code: " + response);
+
+ if(response == -1) { // HttpURLConnection in undefined state? weird stuff... occurs sporadically
+ Thread.sleep(10000); // waiting and trying again seems to do the trick
+ if(refCount++ < 5) {
+ init(urlStr, accept, referer, cookie, lastModSince, oldEtag);
+ return;
+ }
+ }
+
+ String refresh = con.getHeaderField("Refresh");
+ if(refresh != null) {
+ Plugin.debugOut("refresh: " + refresh);
+ int idx = refresh.indexOf("url=");
+ if(idx > -1) {
+ refresh = refresh.substring(idx + 4);
+ if(refresh.indexOf(' ') > -1) refresh = refresh.substring(0, refresh.lastIndexOf(' '));
+ ((HttpURLConnection)con).disconnect();
+ if(refresh.indexOf("://") == -1) refresh = HtmlAnalyzer.resolveRelativeURL(urlStr, refresh);
+ Plugin.debugOut("new url: " + refresh);
+ if(refCount++ < 3) init(refresh, accept, referer, cookie, lastModSince, oldEtag);
+ }
+ }
+
+ if(response == HttpURLConnection.HTTP_NOT_MODIFIED) {
+ state = DOWNLOADER_NOTMODIFIED;
+ return;
+ } else if((response != HttpURLConnection.HTTP_ACCEPTED) && (response != HttpURLConnection.HTTP_OK)) {
+ error("Bad response for '" + url.toString() + "': " + Integer.toString(response) + " " + ((HttpURLConnection)con).getResponseMessage());
+ return;
+ }
+ contentType = con.getContentType();
+ lastModified = con.getLastModified();
+ etag = con.getHeaderField("ETag");
+ url = con.getURL();
+
+ // some code to handle b0rked servers.
+ fileName = con.getHeaderField("Content-Disposition");
+ if((fileName != null) && fileName.toLowerCase().matches(".*attachment.*"))
+ while(fileName.toLowerCase().charAt(0) != 'a') fileName = fileName.substring(1);
+ if((fileName == null) || !fileName.toLowerCase().startsWith("attachment") || (fileName.indexOf('=') == -1)) {
+ String tmp = url.getFile();
+ if(tmp.lastIndexOf('/') != -1) tmp = tmp.substring(tmp.lastIndexOf('/') + 1);
+ // remove any params in the url
+ int paramPos = tmp.indexOf('?');
+ if(paramPos != -1) tmp = tmp.substring(0, paramPos);
+
+ fileName = URLDecoder.decode(tmp, Constants.DEFAULT_ENCODING);
+ } else {
+ fileName = fileName.substring(fileName.indexOf('=') + 1);
+ if(fileName.startsWith("\"") && fileName.endsWith("\"")) fileName = fileName.substring(1, fileName.lastIndexOf('\"'));
+ File temp = new File(fileName);
+ fileName = temp.getName();
+ }
+ }
+ }catch( SSLException e ){
+
+ if ( i == 0 ){
+
+ Plugin.getPluginInterface().getUtilities().getSecurityManager().installServerCertificate( url );
+
+ }else{
+
+ throw( e );
+ }
+ }
+ }
+
+ }
+ } catch(java.net.MalformedURLException e) {
+ e.printStackTrace();
+ error("Bad URL '" + url + "':" + e.getMessage());
+ } catch(java.net.UnknownHostException e) {
+ e.printStackTrace();
+ error("Unknown Host '" + e.getMessage() + "'");
+ } catch(IOException ioe) {
+ ioe.printStackTrace();
+ error("Failed: " + ioe.getMessage());
+ } catch(Throwable e) {
+ e.printStackTrace();
+ error("Failed: " + e.toString());
+ }
+
+ if(state != DOWNLOADER_ERROR) {
+ synchronized(listeners) {
+ state = DOWNLOADER_START;
+ fireDownloaderUpdate(state, 0, 0, "");
+ state = DOWNLOADER_DOWNLOADING;
+ fireDownloaderUpdate(state, 0, 0, "");
+ }
+ try {
+ in = con.getInputStream();
+ size = con.getContentLength();
+ percentDone = readTotal = 0;
+ } catch(Exception e) {
+ error("Exception while downloading '" + url.toString() + "':" + e.getMessage());
+ }
+ }
+ }
+
+ public InputStream getStream() {
+ return in;
+ }
+
+ public void cancel() {
+ if(state == DOWNLOADER_ERROR) return;
+ synchronized(listeners) {
+ state = DOWNLOADER_CANCELED;
+ fireDownloaderUpdate(state, 0, 0, "");
+ }
+ }
+
+ public void done() {
+ if(state == DOWNLOADER_ERROR || state == DOWNLOADER_CANCELED || state == DOWNLOADER_FINISHED) return;
+ synchronized(listeners) {
+ if(state != DOWNLOADER_NOTMODIFIED && readTotal == 0) {
+ error("No data contained in '" + url.toString() + "'");
+ return;
+ }
+ state = DOWNLOADER_FINISHED;
+ fireDownloaderUpdate(state, 0, 0, "");
+ }
+ }
+
+ public void notModified() {
+ if(state == DOWNLOADER_NOTMODIFIED) return;
+ synchronized(listeners) {
+ state = DOWNLOADER_NOTMODIFIED;
+ fireDownloaderUpdate(state, 0, 0, "");
+ }
+ }
+
+ protected void finalize() {
+ try {
+ in.close();
+ } catch(Exception e) {}
+ done();
+ }
+
+ // listeners
+ public void addListener(DownloaderListener l) {
+ synchronized(listeners) {
+ listeners.add(l);
+ }
+ }
+
+ public void removeListener(DownloaderListener l) {
+ synchronized(listeners) {
+ listeners.remove(l);
+ }
+ }
+
+ private void fireDownloaderUpdate(int state, int percentDone, int readTotal, String str) {
+ for(int i = 0; i < listeners.size(); i++) {
+ ((DownloaderListener)listeners.get(i)).downloaderUpdate(state, percentDone, readTotal, str);
+ }
+ }
+
+ // InputStream Filtered Stuff
+ public int read() {
+ try {
+ synchronized(listeners) {
+ int read = in.read();
+ readTotal += read;
+ if(this.size > 0) {
+ this.percentDone = (100 * this.readTotal) / this.size;
+ fireDownloaderUpdate(state, percentDone, 0, "");
+ } else fireDownloaderUpdate(state, 0, readTotal, "");
+ return read;
+ }
+ } catch(IOException e) {}
+ return -1;
+ }
+
+ public int read(byte b[]) {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte b[], int off, int len) {
+ try {
+ synchronized(listeners) {
+ int read = in.read(b, off, len);
+ this.readTotal += read;
+ if(this.size > 0) {
+ this.percentDone = (100 * this.readTotal) / this.size;
+ fireDownloaderUpdate(state, percentDone, 0, "");
+ } else fireDownloaderUpdate(state, 0, readTotal, "");
+ return read;
+ }
+ } catch(IOException e) {
+ }
+ return -1;
+ }
+
+ // InputStream PassThru Stuff
+ public long skip(long n) {
+ try { return in.skip(n); } catch(IOException e) { }
+ return 0;
+ }
+
+ public int available() {
+ try { return in.available(); } catch(IOException e) { }
+ return 0;
+ }
+
+ public void close() { try { in.close(); } catch(IOException e) { } }
+ public synchronized void mark(int readlimit) { in.mark(readlimit); }
+ public synchronized void reset() { try { in.reset(); } catch(IOException e) { } }
+ public boolean markSupported() { return in.markSupported(); }
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/DownloaderListener.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/DownloaderListener.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/DownloaderListener.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,26 @@
+/*
+ * File : DownloadManagerListener.java
+ * Created : 11-Jan-2004
+ * By : parg
+ *
+ * Azureus - a Java Bittorrent client
+ *
+ * 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.
+ *
+ * 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 ( see the LICENSE file ).
+ *
+ * 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;
+
+public interface DownloaderListener {
+ public void downloaderUpdate(int state, int percent, int amount, String err);
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/Episode.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/Episode.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/Episode.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+public class Episode {
+
+ public int seasonStart, seasonEnd, episodeStart, episodeEnd;
+ public String showTitle = "";
+
+ public Episode(int season, int episode) {
+ setEpisode(season, episode, season, episode);
+ }
+
+ public Episode(String title, int season, int episode) {
+ showTitle = title;
+ setEpisode(season, episode, season, episode);
+ }
+
+ public Episode(int sStart, int eStart, int sEnd, int eEnd) {
+ setEpisode(sStart, eStart, sEnd, eEnd);
+ }
+
+ public Episode(String title, int sStart, int eStart, int sEnd, int eEnd) {
+ showTitle = title;
+ setEpisode(sStart, eStart, sEnd, eEnd);
+ }
+
+ private void setEpisode(int sStart, int eStart, int sEnd, int eEnd) {
+ seasonStart = sStart;
+ episodeStart = eStart;
+ seasonEnd = sEnd;
+ episodeEnd = eEnd;
+ }
+
+ public boolean isFrom(int season, int episode) {
+ if(seasonStart > season) return true;
+ if((seasonStart == season) && (episodeStart >= episode)) return true;
+ return false;
+ }
+
+ public boolean isUpto(int season, int episode) {
+ if(seasonEnd < season) return true;
+ if((seasonEnd == season) && (episodeEnd <= episode)) return true;
+ return false;
+ }
+
+ public boolean inRange(int sStart, int eStart, int sEnd, int eEnd) {
+ if((isFrom(sStart, eStart)) && (isUpto(sEnd, eEnd))) return true;
+ return false;
+ }
+
+ public String toString() {
+ return showTitle + " s" + seasonStart + "e" + episodeStart + " - s" + seasonEnd + "e" + episodeEnd;
+ }
+}
+
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/FilterBean.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/FilterBean.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/FilterBean.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,391 @@
+/*
+ * 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.gudy.azureus2.plugins.download.Download;
+
+import java.io.Serializable;
+import java.util.regex.*;
+
+public class FilterBean implements Serializable {
+
+ static final long serialVersionUID = -979691945084080240L;
+
+ private String name, storeDir, expression, category, type, mode;
+ private int state, priority, rateUpload, rateDownload, startSeason, startEpisode, endSeason, endEpisode;
+ private long filtId, urlId = 0;
+ private boolean isRegex, matchTitle, matchLink, moveTop, customRate, renameFile, renameIncEpisode, disableAfter, cleanFile, enabled;
+ private boolean smartHistory = true;
+
+ private String exprLower;
+ private Pattern exprPat;
+
+ public static Pattern epsnnenn_snnenn = Pattern.compile("(.*?)" + "s([0-9]+)e([0-9]+)[\\-\\+]s([0-9]+)e([0-9]+)" + ".*?");
+ public static Pattern epsnnenn_enn = Pattern.compile("(.*?)" + "s([0-9]+)e([0-9]+)[\\-\\+]e([0-9]+)" + ".*?");
+ public static Pattern epsnnenn_nn = Pattern.compile("(.*?)" + "s([0-9]+)e([0-9]+)[\\-\\+]([0-9]+)" + ".*?");
+ public static Pattern epsnnenn = Pattern.compile("(.*?)" + "s([0-9]+)e([0-9]+)" + ".*?");
+ public static Pattern epnnxnn_nnxnn = Pattern.compile("(.*?)" + "([0-9]+)x([0-9]+)[\\-\\+]([0-9]+)x([0-9]+)" + ".*?");
+ public static Pattern epnnxnn_nn = Pattern.compile("(.*?)" + "([0-9]+)x([0-9]+)[\\-\\+]([0-9]+)" + ".*?");
+ public static Pattern epnnxnn = Pattern.compile("(.*?)" + "([0-9]+)x([0-9]+)" + ".*?");
+ public static Pattern epnnnn_nnnn = Pattern.compile("(.*?)" + "([0-9]+)([0-9]{2})[\\-\\+]([0-9]+)([0-9]{2})" + ".*?");
+ public static Pattern epnnnn_nn = Pattern.compile("(.*?)" + "([0-9]+)([0-9]{2})[\\-\\+]([0-9]{2})" + ".*?");
+ public static Pattern epnnnn = Pattern.compile("(.*?)" + "([0-9]+)([0-9]{2})" + ".*?");
+
+ public FilterBean() {
+ filtId = System.currentTimeMillis();
+
+ exprLower = "";
+ exprPat = Pattern.compile(".*" + exprLower + ".*");
+ }
+
+ public long getID() {
+ return filtId;
+ }
+
+ public void setID(long filtId) {
+ this.filtId = filtId;
+ }
+
+ public String getName() {
+ if(name == null) name = "";
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getStoreDir() {
+ if(storeDir == null) storeDir = "";
+ return storeDir;
+ }
+
+ public void setStoreDir(String storeDir) {
+ this.storeDir = storeDir;
+ }
+
+ public String getExpression() {
+ if(expression == null) expression = "";
+ return expression;
+ }
+
+ public void setExpression(String expression) {
+ this.expression = expression;
+ exprLower = expression.toLowerCase();
+ try {
+ exprPat = Pattern.compile(".*" + exprLower + ".*");
+ } catch (PatternSyntaxException e) {
+ exprPat = null;
+ }
+ }
+
+ public boolean getIsRegex() {
+ return isRegex;
+ }
+
+ public void setIsRegex(boolean isRegex) {
+ this.isRegex = isRegex;
+ }
+
+ public boolean getMatchTitle() {
+ return matchTitle;
+ }
+
+ public void setMatchTitle(boolean matchTitle) {
+ this.matchTitle = matchTitle;
+ }
+
+ public boolean getMatchLink() {
+ return matchLink;
+ }
+
+ public void setMatchLink(boolean matchLink) {
+ this.matchLink = matchLink;
+ }
+
+ public boolean getMoveTop() {
+ return moveTop;
+ }
+
+ public void setMoveTop(boolean moveTop) {
+ this.moveTop = moveTop;
+ }
+
+ public int getState() {
+ return state;
+ }
+
+ public void setState(int state) {
+ this.state = state;
+ }
+
+ public int getPriority() {
+ if(priority != Download.PR_HIGH_PRIORITY && priority != Download.PR_LOW_PRIORITY)
+ priority = Download.PR_HIGH_PRIORITY;
+ return priority;
+ }
+
+ public void setPriority(int priority) {
+ this.priority = priority;
+ }
+
+ public boolean getRateUseCustom() {
+ return customRate;
+ }
+
+ public void setRateUseCustom(boolean customRate) {
+ this.customRate = customRate;
+ }
+
+ public int getRateUpload() {
+ return rateUpload;
+ }
+
+ public void setRateUpload(int rateUpload) {
+ this.rateUpload = rateUpload;
+ }
+
+ public int getRateDownload() {
+ return rateDownload;
+ }
+
+ public void setRateDownload(int rateDownload) {
+ this.rateDownload = rateDownload;
+ }
+
+ public String getCategory() {
+ if(category == null) category = "";
+ return category;
+ }
+
+ public void setCategory(String category) {
+ this.category = category;
+ }
+
+ public long getFeed() {
+ return urlId;
+ }
+
+ public void setFeed(long urlId) {
+ this.urlId = urlId;
+ }
+
+ public String getType() {
+ if(type == null) type = "";
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public int getStartSeason() {
+ return startSeason;
+ }
+
+ public void setStartSeason(int startSeason) {
+ this.startSeason = startSeason;
+ }
+
+ public int getStartEpisode() {
+ return startEpisode;
+ }
+
+ public void setStartEpisode(int startEpisode) {
+ this.startEpisode = startEpisode;
+ }
+
+ public int getEndSeason() {
+ return endSeason;
+ }
+
+ public void setEndSeason(int endSeason) {
+ this.endSeason = endSeason;
+ }
+
+ public int getEndEpisode() {
+ return endEpisode;
+ }
+
+ public void setEndEpisode(int endEpisode) {
+ this.endEpisode = endEpisode;
+ }
+
+ public boolean getRenameFile() {
+ return renameFile;
+ }
+
+ public void setRenameFile(boolean renameFile) {
+ this.renameFile = renameFile;
+ }
+
+ public boolean getRenameIncEpisode() {
+ return renameIncEpisode;
+ }
+
+ public void setRenameIncEpisode(boolean renameIncEpisode) {
+ this.renameIncEpisode = renameIncEpisode;
+ }
+
+ public boolean getDisableAfter() {
+ return disableAfter;
+ }
+
+ public void setDisableAfter(boolean disableAfter) {
+ this.disableAfter = disableAfter;
+ }
+
+ public boolean getCleanFile() {
+ return cleanFile;
+ }
+
+ public void setCleanFile(boolean cleanFile) {
+ this.cleanFile = cleanFile;
+ }
+
+ public String getMode() {
+ if(mode == null) mode = "";
+ return mode;
+ }
+
+ public void setMode(String mode) {
+ this.mode = mode;
+ }
+
+ public boolean getEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public boolean matches(long urlId, String title, String link) {
+ if(!getEnabled()) return false;
+ if(getFeed() != 0 && urlId != getFeed()) return false;
+
+ boolean matched = false;
+ if((getMatchTitle()) && (match(title))) matched = true;
+ else if((getMatchLink()) && (match(link))) matched = true;
+ if(!matched) return false;
+
+ if(getType().equalsIgnoreCase("TVShow") && getStartSeason() + getEndSeason() >= 0) {
+ Episode e = getSeason(title);
+ if(e == null) e = getSeason(link);
+ if(e == null) return false;
+
+ if(getStartSeason() >= 0 && getEndSeason() > 0) {
+ if(!e.inRange(getStartSeason(), getStartEpisode(), getEndSeason(), getEndEpisode())) return false;
+ } else if(getStartSeason() >= 0) {
+ if(!e.isFrom(getStartSeason(), getStartEpisode())) return false;
+ } else {
+ if(!e.isUpto(getEndSeason(), getEndEpisode())) return false;
+ }
+ }
+ return true;
+ }
+
+ public static Episode getSeason(String str) {
+ str = str.toLowerCase();
+ Pattern lmp = Pattern.compile("(ht|f)tp:.*/(.*?)");
+ Matcher lmm = lmp.matcher(str);
+ if(lmm.matches()) str = lmm.group(2); // strip if url
+
+ String showTitle = "";
+ int seasonStart, seasonEnd, episodeStart, episodeEnd;
+ Episode e = null;
+
+ Matcher m = epsnnenn_snnenn.matcher(str);
+ if(!m.matches()) m = epsnnenn_enn.matcher(str);
+ if(!m.matches()) m = epsnnenn_nn.matcher(str);
+ if(!m.matches()) m = epsnnenn.matcher(str);
+ if(!m.matches()) m = epnnxnn_nnxnn.matcher(str);
+ if(!m.matches()) m = epnnxnn_nn.matcher(str);
+ if(!m.matches()) m = epnnxnn.matcher(str);
+ if(!m.matches()) m = epnnnn_nnnn.matcher(str);
+ if(!m.matches()) m = epnnnn_nn.matcher(str);
+ if(!m.matches()) m = epnnnn.matcher(str);
+ if(!m.matches()) return null;
+
+ showTitle = stringClean(m.group(1));
+
+ switch(m.groupCount()) {
+ case 3:
+ seasonStart = Integer.parseInt(m.group(2));
+ episodeStart = Integer.parseInt(m.group(3));
+ e = new Episode(showTitle, seasonStart, episodeStart);
+ break;
+ case 4:
+ seasonStart = Integer.parseInt(m.group(2));
+ episodeStart = Integer.parseInt(m.group(3));
+ seasonEnd = Integer.parseInt(m.group(2));
+ episodeEnd = Integer.parseInt(m.group(4));
+ e = new Episode(showTitle, seasonStart, episodeStart, seasonEnd, episodeEnd);
+ break;
+ case 5:
+ seasonStart = Integer.parseInt(m.group(2));
+ episodeStart = Integer.parseInt(m.group(3));
+ seasonEnd = Integer.parseInt(m.group(4));
+ episodeEnd = Integer.parseInt(m.group(5));
+ e = new Episode(showTitle, seasonStart, episodeStart, seasonEnd, episodeEnd);
+ break;
+ }
+
+ return e;
+ }
+
+ private static String stringClean(String str) {
+ str = str.replaceAll("[ \\._\\-]+", " ");
+ str = str.replaceAll("\\[.*\\]", "");
+ str = str.trim();
+ if(!str.equals(str.toLowerCase())) return str;
+
+ String[] strp = str.split("[^\\w\\d]+");
+ for(int iLoop = 0; iLoop < strp.length; iLoop++) {
+ if(strp[iLoop].length() == 0) continue;
+ String c = String.valueOf(strp[iLoop].charAt(0));
+ String nstrp = strp[iLoop].replaceFirst(c, c.toUpperCase());
+ str = str.replaceAll(strp[iLoop], nstrp);
+ }
+ return str;
+ }
+
+ private boolean match(String matchee) {
+ if(getIsRegex()){
+ if ( exprPat == null ){
+ return( false ); // invalid expression, always fail
+ }
+ Matcher m = exprPat.matcher(matchee.toLowerCase());
+ return m.matches();
+ } else {
+ if(matchee.toLowerCase().indexOf(exprLower) >= 0) return true;
+ }
+ return false;
+ }
+
+ public boolean getUseSmartHistory() {
+ if("TVShow".equalsIgnoreCase(type)) return smartHistory;
+ else return true;
+ }
+
+ public void setUseSmartHistory(boolean smartHistory) {
+ this.smartHistory = smartHistory;
+ }
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/FilterTableItem.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/FilterTableItem.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/FilterTableItem.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,192 @@
+/*
+ * 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.widgets.*;
+import org.eclipse.swt.SWT;
+import org.gudy.azureus2.plugins.download.Download;
+import org.gudy.azureus2.core3.util.Constants;
+
+public class FilterTableItem extends TableItem {
+
+ private Table parent;
+ private Config config;
+ private FilterBean data;
+
+ public FilterTableItem(Table parent, Config config) {
+ super(parent, SWT.NULL);
+ this.parent = parent;
+ this.config = config;
+ }
+
+ public void checkSubclass() {
+ return;
+ }
+
+ public FilterBean getBean() {
+ return data;
+ }
+
+ public void setBean(int index) {
+ this.data = config.getFilter(index);
+
+ update();
+ }
+
+ public void setBean(FilterBean data) {
+ if(this.data == null) config.setFilter(data);
+ else config.setFilter(config.getFilterIndex(this.data), data);
+ this.data = data;
+
+ update();
+ }
+
+ public void setup(View view) {
+ view.filtName.setText(data.getName());
+ view.filtStoreDir.setText(data.getStoreDir());
+ view.filtExpression.setText(data.getExpression());
+ view.filtIsRegex.setSelection(data.getIsRegex());
+ view.filtMatchTitle.setSelection(data.getMatchTitle());
+ view.filtMatchLink.setSelection(data.getMatchLink());
+ view.filtMoveTop.setSelection(data.getMoveTop());
+ view.filtState.select(data.getState());
+ if(Constants.compareVersions(Constants.getBaseVersion(),"2.2.0.0") < 0) {
+ switch(data.getPriority()) {
+ case Download.PR_HIGH_PRIORITY:
+ view.filtPriority.select(0);
+ break;
+ case Download.PR_LOW_PRIORITY:
+ view.filtPriority.select(1);
+ break;
+ }
+ }
+ view.filtRateUseCustom.setSelection(data.getRateUseCustom());
+ view.filtRateUpload.setText(Integer.toString(data.getRateUpload()));
+ view.filtRateDownload.setText(Integer.toString(data.getRateDownload()));
+ view.filtCategory.setText(data.getCategory());
+ view.filtFeed.removeAll();
+ long curFeed = data.getFeed();
+ view.filtFeed.add("All");
+ view.filtFeed.select(0);
+ for(int i = 0; i < config.getUrlCount(); i++) {
+ UrlBean urlBean = config.getUrl(i);
+ view.filtFeed.add(urlBean.getName());
+ if(curFeed == urlBean.getID()) {
+ view.filtFeed.select(i + 1);
+ }
+ }
+ if(data.getType().equalsIgnoreCase("")) {
+ view.filtType.select(0);
+ } else
+ for(int i = 0; i < view.filtType.getItemCount(); i++) {
+ if(data.getType().equalsIgnoreCase(view.filtType.getItem(i))) {
+ view.filtType.select(i);
+ }
+ }
+ switch(view.filtType.getSelectionIndex()) {
+ case 0:
+ view.filtStartSeason.setText(Integer.toString(data.getStartSeason()));
+ view.filtStartEpisode.setText(Integer.toString(data.getStartEpisode()));
+ view.filtEndSeason.setText(Integer.toString(data.getEndSeason()));
+ view.filtEndEpisode.setText(Integer.toString(data.getEndEpisode()));
+ view.filtSmartHist.setSelection(data.getUseSmartHistory());
+ case 1:
+ view.filtDisable.setSelection(data.getDisableAfter());
+ break;
+ }
+ view.filtEnabled.setSelection(data.getEnabled());
+ if(data.getMode().equalsIgnoreCase("")) {
+ view.filtMode.select(0);
+ } else
+ for(int i = 0; i < view.filtMode.getItemCount(); i++) {
+ if(data.getMode().equalsIgnoreCase(view.filtMode.getItem(i))) {
+ view.filtMode.select(i);
+ }
+ }
+
+ view.filtParamShow();
+ }
+
+ public void save(View view) {
+ save(this, view);
+
+ update();
+ }
+
+ public static FilterBean save(FilterTableItem item, View view) {
+ FilterBean data = item == null?new FilterBean():item.getBean();
+
+ data.setName(view.filtName.getText());
+ data.setStoreDir(view.filtStoreDir.getText());
+ data.setExpression(view.filtExpression.getText());
+ data.setIsRegex(view.filtIsRegex.getSelection());
+ data.setMatchTitle(view.filtMatchTitle.getSelection());
+ data.setMatchLink(view.filtMatchLink.getSelection());
+ data.setMoveTop(view.filtMoveTop.getSelection());
+ data.setState(view.filtState.getSelectionIndex());
+ if(Constants.compareVersions(Constants.getBaseVersion(),"2.2.0.0") < 0) {
+ switch(view.filtPriority.getSelectionIndex()) {
+ case 0:
+ data.setPriority(Download.PR_HIGH_PRIORITY);
+ break;
+ case 1:
+ data.setPriority(Download.PR_LOW_PRIORITY);
+ break;
+ }
+ }
+ data.setRateUseCustom(view.filtRateUseCustom.getSelection());
+ data.setRateUpload(Integer.parseInt(view.filtRateUpload.getText()));
+ data.setRateDownload(Integer.parseInt(view.filtRateDownload.getText()));
+ data.setCategory(view.filtCategory.getText());
+ if(view.filtFeed.getSelectionIndex() > 0 && item != null) {
+ UrlBean urlBean = item.config.getUrl(view.filtFeed.getSelectionIndex() - 1);
+ data.setFeed(urlBean.getID());
+ } else {
+ data.setFeed(0);
+ }
+ data.setType(view.filtType.getText());
+ switch(view.filtType.getSelectionIndex()) {
+ case 0:
+ data.setStartSeason(Integer.parseInt(view.filtStartSeason.getText()));
+ data.setStartEpisode(Integer.parseInt(view.filtStartEpisode.getText()));
+ data.setEndSeason(Integer.parseInt(view.filtEndSeason.getText()));
+ data.setEndEpisode(Integer.parseInt(view.filtEndEpisode.getText()));
+ data.setUseSmartHistory(view.filtSmartHist.getSelection());
+ case 1:
+ data.setDisableAfter(view.filtDisable.getSelection());
+ break;
+ }
+ data.setEnabled(view.filtEnabled.getSelection());
+ data.setMode(view.filtMode.getText());
+ return data;
+ }
+
+ public void update() {
+ setChecked(data.getEnabled());
+ setText(0, data.getName());
+ setText(1, data.getType());
+ setText(2, data.getMode());
+ }
+
+ public void remove() {
+ config.removeFilter(data);
+ parent.remove(parent.indexOf(this));
+ }
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/Help.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/Help.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/Help.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,150 @@
+/*
+ * 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.SWT;
+import org.eclipse.swt.custom.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+import org.gudy.azureus2.core3.internat.MessageText;
+
+import java.io.*;
+
+public class Help extends StyledText {
+ private Display display;
+
+ private static final String lineSeparator = System.getProperty("line.separator");
+
+ private String helpFile = "";
+
+ public Help(Composite parent, int style) {
+ super(parent, style);
+
+ display = parent.getDisplay();
+ }
+
+ public Help(Composite parent) {
+ this(parent, SWT.NULL);
+ }
+
+ public void load() throws Exception {
+ String curLocale = MessageText.getCurrentLocale().toString();
+ String newHelpFile = "/org/kmallan/resource/lang/Help" + (curLocale.equalsIgnoreCase("")?"":"_" + curLocale) + ".stf";
+ if(helpFile.equalsIgnoreCase(newHelpFile)) return;
+
+ InputStream stream = getClass().getResourceAsStream(newHelpFile);
+ if(stream == null) {
+ newHelpFile = "/org/kmallan/resource/lang/Help.stf";
+ if(helpFile.equalsIgnoreCase(newHelpFile)) return;
+
+ stream = getClass().getResourceAsStream(newHelpFile);
+ }
+
+ helpFile = newHelpFile;
+
+ this.setText("");
+ if(stream == null) {
+ System.err.println("RSSFeed: Error loading resource: /org/kmallan/resource/help.stf");
+ } else {
+ BufferedReader in = new BufferedReader(new InputStreamReader(stream));
+
+ this.setRedraw(false);
+ this.setWordWrap(true);
+
+ Color black = new Color((Device) display, 0, 0, 0);
+ Color white = new Color((Device) display, 255, 255, 255);
+ Color light = new Color((Device) display, 200, 200, 200);
+ Color grey = new Color((Device) display, 50, 50, 50);
+ Color green = new Color((Device) display, 30, 80, 30);
+ Color blue = new Color((Device) display, 20, 20, 80);
+ Color fg, bg;
+ int style;
+ boolean setStyle;
+
+ this.setForeground(grey);
+
+ String line;
+ while((line = in.readLine()) != null) {
+
+ setStyle = false;
+ fg = grey;
+ bg = white;
+ style = SWT.NORMAL;
+
+ char styleChar;
+ String text;
+
+ if(line.length() < 2) {
+ styleChar = ' ';
+ text = " " + lineSeparator;
+ } else {
+ styleChar = line.charAt(0);
+ text = line.substring(1) + lineSeparator;
+ }
+
+ switch(styleChar) {
+ case '*':
+ text = " * " + text;
+ fg = green;
+ setStyle = true;
+ break;
+ case '+':
+ text = " " + text;
+ fg = black;
+ bg = light;
+ style = SWT.BOLD;
+ setStyle = true;
+ break;
+ case '!':
+ style = SWT.BOLD;
+ setStyle = true;
+ break;
+ case '@':
+ fg = blue;
+ setStyle = true;
+ break;
+ case '$':
+ bg = blue;
+ fg = white;
+ style = SWT.BOLD;
+ setStyle = true;
+ break;
+ case ' ':
+ text = " " + text;
+ break;
+ }
+
+ this.append(text);
+
+ if(setStyle) {
+ int lineCount = this.getLineCount() - 1;
+ int charCount = this.getCharCount();
+
+ int lineOfs = this.getOffsetAtLine(lineCount - 1);
+ int lineLen = charCount - lineOfs;
+ this.setStyleRange(new StyleRange(lineOfs, lineLen, fg, bg, style));
+ this.setLineBackground(lineCount - 1, 1, bg);
+ }
+ }
+ }
+
+ this.setRedraw(true);
+ }
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/HistoryBean.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/HistoryBean.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/HistoryBean.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,170 @@
+/*
+ * 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 java.io.Serializable;
+import java.util.regex.*;
+
+public class HistoryBean implements Serializable, Comparable {
+
+ static final long serialVersionUID = -4112775156287555070L;
+
+ private String fileData, location, filtType, filtName;
+ private long histId, filtId;
+ private int seasonStart, seasonEnd, episodeStart, episodeEnd;
+
+ public HistoryBean() {
+ histId = System.currentTimeMillis();
+ }
+
+ public long getID() {
+ return histId;
+ }
+
+ public void setID(long histId) {
+ this.histId = histId;
+ }
+
+ public long getFiltID() {
+ return filtId;
+ }
+
+ public void setFiltID(long filtId) {
+ this.filtId = filtId;
+ }
+
+ public String getFileData() {
+ if(fileData == null) fileData = "";
+ return fileData;
+ }
+
+ public void setFileData(String fileData) {
+ this.fileData = fileData;
+ }
+
+ public String getLocation() {
+ if(location == null) location = "";
+ return location;
+ }
+
+ public void setLocation(String location) {
+ this.location = location;
+ }
+
+ public boolean setSeason(String str) {
+ Pattern lmp = Pattern.compile("(ht|f)tp:.*/(.*?)");
+ Matcher lmm = lmp.matcher(str);
+ if(lmm.matches()) {
+ str = lmm.group(2);
+ }
+
+ Matcher m = FilterBean.epsnnenn_snnenn.matcher(str);
+ if(!m.matches()) m = FilterBean.epsnnenn_enn.matcher(str);
+ if(!m.matches()) m = FilterBean.epsnnenn_nn.matcher(str);
+ if(!m.matches()) m = FilterBean.epsnnenn.matcher(str);
+ if(!m.matches()) m = FilterBean.epnnxnn_nnxnn.matcher(str);
+ if(!m.matches()) m = FilterBean.epnnxnn_nn.matcher(str);
+ if(!m.matches()) m = FilterBean.epnnxnn.matcher(str);
+ if(!m.matches()) m = FilterBean.epnnnn_nnnn.matcher(str);
+ if(!m.matches()) m = FilterBean.epnnnn_nn.matcher(str);
+ if(!m.matches()) m = FilterBean.epnnnn.matcher(str);
+ if(!m.matches()) return false;
+
+ switch(m.groupCount()) {
+ case 3:
+ setSeasonStart(Integer.parseInt(m.group(2)));
+ setEpisodeStart(Integer.parseInt(m.group(3)));
+ setSeasonEnd(Integer.parseInt(m.group(2)));
+ setEpisodeEnd(Integer.parseInt(m.group(3)));
+ break;
+ case 4:
+ setSeasonStart(Integer.parseInt(m.group(2)));
+ setEpisodeStart(Integer.parseInt(m.group(3)));
+ setSeasonEnd(Integer.parseInt(m.group(2)));
+ setEpisodeEnd(Integer.parseInt(m.group(4)));
+ break;
+ case 5:
+ setSeasonStart(Integer.parseInt(m.group(2)));
+ setEpisodeStart(Integer.parseInt(m.group(3)));
+ setSeasonEnd(Integer.parseInt(m.group(4)));
+ setEpisodeEnd(Integer.parseInt(m.group(5)));
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ public int getSeasonStart() {
+ return seasonStart;
+ }
+
+ public void setSeasonStart(int seasonStart) {
+ this.seasonStart = seasonStart;
+ }
+
+ public int getSeasonEnd() {
+ return seasonEnd;
+ }
+
+ public void setSeasonEnd(int seasonEnd) {
+ this.seasonEnd = seasonEnd;
+ }
+
+ public int getEpisodeStart() {
+ return episodeStart;
+ }
+
+ public void setEpisodeStart(int episodeStart) {
+ this.episodeStart = episodeStart;
+ }
+
+ public int getEpisodeEnd() {
+ return episodeEnd;
+ }
+
+ public void setEpisodeEnd(int episodeEnd) {
+ this.episodeEnd = episodeEnd;
+ }
+
+ public String toString() {
+ return location;
+ }
+
+ public int compareTo(Object o) {
+ return -(new Long(histId).compareTo(new Long(((HistoryBean)o).histId)));
+ }
+
+ public void setFilter(FilterBean filter) {
+ if(filter != null) {
+ this.filtId = filter.getID();
+ this.filtName = filter.getName();
+ this.filtType = filter.getType();
+ }
+ }
+
+ public String getFiltName() {
+ return filtName;
+ }
+
+ public String getFiltType() {
+ return filtType;
+ }
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/HistoryTableItem.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/HistoryTableItem.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/HistoryTableItem.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,92 @@
+/*
+ * 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.widgets.*;
+import org.eclipse.swt.SWT;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+public class HistoryTableItem extends TableItem {
+
+ private Table parent;
+ private Config config;
+ private HistoryBean data;
+
+ public HistoryTableItem(Table parent, Config config, int index) {
+ super(parent, SWT.NULL, index);
+ this.parent = parent;
+ this.config = config;
+ }
+
+ public void checkSubclass() {
+ return;
+ }
+
+ public HistoryBean getBean() {
+ return data;
+ }
+
+ public void setBean(int index) {
+ this.data = config.getHistory(index);
+
+ update();
+ }
+
+ /*
+ public void setBean(HistoryBean data) {
+ if(this.data == null) config.addHistory(data);
+ else config.setHistory(config.getHistoryIndex(this.data), data);
+ this.data = data;
+
+ update();
+ }
+ */
+
+ public void update() {
+ setText(0, DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(new Date(data.getID())));
+ setText(1, data.getFileData());
+ setText(2, data.getLocation());
+
+ String output = "";
+ if(data.getFiltID() != 0) {
+ output = "Filter Matched";
+ if(data.getFiltName() != null) output += ": '" + data.getFiltName() + "'";
+ if(data.getSeasonStart() >= 0) {
+ output += " Type: TVShow - Ep " + Integer.toString(data.getSeasonStart()) + "x" + Integer.toString(data.getEpisodeStart());
+ if(data.getSeasonEnd() > data.getSeasonStart())
+ output += "-" + Integer.toString(data.getSeasonEnd()) + "x" + Integer.toString(data.getEpisodeEnd());
+ else if(data.getEpisodeEnd() > data.getEpisodeStart())
+ output += "-" + Integer.toString(data.getEpisodeEnd());
+ }
+ } else {
+ output = "Manual Download";
+ }
+ setText(3, output);
+ }
+
+ public void remove() {
+ config.removeHistory(data);
+ parent.remove(parent.indexOf(this));
+ }
+
+
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/HtmlAnalyzer.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/HtmlAnalyzer.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/HtmlAnalyzer.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,199 @@
+/*
+ * 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 javax.swing.text.html.*;
+import javax.swing.text.MutableAttributeSet;
+import java.util.*;
+import java.net.*;
+import java.io.IOException;
+
+/**
+ * Used to parse the HTML on a URL recieved from the rss feed.
+ *
+ * First, it looks for a .torrent link. If one is not found, it checks
+ * each URL to see if it's HEAD is of torrent type
+ *
+ * Created by IntelliJ IDEA.
+ * User: Johan Frank
+ * Date: Jan 7, 2005
+ * Time: 12:48:57 AM
+ */
+public class HtmlAnalyzer extends HTMLEditorKit.ParserCallback implements Runnable {
+
+ private static final int HREF_CHECK_TIMEOUT = 60000;
+
+ private List hrefs = new ArrayList();
+ private String torrentUrl = null, baseUrl = null;
+ private StringBuffer text = new StringBuffer();
+ private ListBean listBean;
+
+ private String lastURL = null;
+ private boolean lastWasURL = false;
+ private String lastURLtext;
+
+ public HtmlAnalyzer() {
+ this("", null);
+ }
+
+ public HtmlAnalyzer(String baseUrl, ListBean listBean) {
+ this.baseUrl = baseUrl;
+ this.listBean = listBean;
+ }
+
+ public void handleStartTag(HTML.Tag tag, MutableAttributeSet mas, int pos) {
+ if(tag == HTML.Tag.A) {
+ lastURL = (String)mas.getAttribute(HTML.Attribute.HREF);
+ if(lastURL != null) {
+ if(lastURL.indexOf("://") < 0) {
+ try {
+ lastURL = resolveRelativeURL(baseUrl, lastURL);
+ } catch(MalformedURLException e) {}
+ }
+ if(lastURL.toLowerCase().endsWith(".torrent")) {
+ torrentUrl = lastURL;
+ } else {
+ lastWasURL = true;
+ }
+ }
+ } else {
+ lastWasURL = false;
+ }
+ }
+
+ public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet mutableAttributeSet, int i) {
+ if(tag == HTML.Tag.BR) text.append("\n");
+ }
+
+ public void handleEndTag(HTML.Tag tag, int i) {
+ if (tag == HTML.Tag.BODY || tag == HTML.Tag.HTML || tag == HTML.Tag.HEAD)
+ return;
+ else if (tag == HTML.Tag.A && lastWasURL && torrentUrl == null) {
+ // put links with .torrent name in them at the top of parsing list
+ if (lastURLtext != null && lastURLtext.contains(".torrent")) {
+ hrefs.add(0, lastURL);
+ }
+ hrefs.add(lastURL);
+ } else {
+ text.append("\n");
+ }
+ }
+
+ public void handleText(char[] chars, int i) {
+ String s = new String(chars);
+ if (lastWasURL) {
+ lastURLtext = s;
+ }
+ text.append(s.replace('<', ' ').replace('>', ' ').trim()); // remove remnants of broken tags :-P
+ }
+
+ public synchronized String getTorrentUrl() {
+ if(torrentUrl == null &! hrefs.isEmpty()) {
+ Plugin.debugOut("No url ending in .torrent, checking " + hrefs.size()
+ + " URL(s) to see if any are application/x-bittorrent");
+ Plugin.debugOut("After " + (HREF_CHECK_TIMEOUT / 1000)
+ + " seconds, check will abort.");
+
+ Thread hrefChecker = new Thread(this, "HrefContentCheckerThread");
+ hrefChecker.start();
+ try {
+ wait(HREF_CHECK_TIMEOUT);
+ } catch(InterruptedException e) {}
+ hrefChecker.interrupt();
+ }
+ Plugin.debugOut("returning torrentUrl: " + torrentUrl);
+ return torrentUrl;
+ }
+
+ public String getPlainText() {
+ return text.toString();
+ }
+
+ protected static String resolveRelativeURL(String url, String href) throws MalformedURLException {
+ URL u = new URL(url);
+ String newUrl = u.getProtocol() + "://" + u.getHost();
+ if(u.getPort() > 0) newUrl += ":" + u.getPort();
+ if(!href.startsWith("/")) { // path relative to current
+ String path = u.getPath(); // e.g /dir/file.php
+ if(path.indexOf("/") > -1) path = path.substring(0, path.lastIndexOf("/") + 1); // strip file part
+ newUrl += path; // append /dir
+ if(!newUrl.endsWith("/")) newUrl += "/";
+ }
+ return newUrl + href;
+ }
+
+ /**
+ * Check all the URLs that don't end in 'torrent' to see if they are actually
+ * torrents
+ */
+ public void run() {
+ synchronized(this) {
+ String href = null;
+ int count = 1;
+ for(Iterator iter = hrefs.iterator(); iter.hasNext(); ) {
+ href = (String)iter.next();
+ if(isHrefTorrent(href)) {
+ torrentUrl = href;
+ Plugin.debugOut("found torrent: " + href);
+ break;
+ }
+ updateView(count++);
+ }
+ notifyAll();
+ }
+ }
+
+ private void updateView(int count) {
+ if(listBean == null) return;
+ listBean.setState(Downloader.DOWNLOADER_CHECKING);
+ listBean.setAmount(count);
+ listBean.setPercent(hrefs.size());
+ Plugin.updateView(listBean);
+ }
+
+ /**
+ * Check one URL to see if it's a torrent by grabbing the HEAD and seeing
+ * if the connection type is of torrent type.
+ *
+ * @param href
+ * @return
+ */
+ private boolean isHrefTorrent(String href) {
+ try {
+ URLConnection conn = new URL(href).openConnection();
+ if(conn instanceof HttpURLConnection) {
+ ((HttpURLConnection)conn).setRequestMethod("HEAD");
+ String cookie = listBean.getFeed().getCookie();
+ if(cookie != null && cookie.length() > 0) conn.setRequestProperty("Cookie", cookie);
+ conn.connect();
+ String ct = conn.getContentType();
+ ((HttpURLConnection)conn).disconnect();
+ if(ct != null) {
+ Plugin.debugOut("href: " + href + " -> " + ct);
+ return ct.toLowerCase().startsWith("application/x-bittorrent");
+ }
+ }
+ } catch(IOException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/KMAllanInputStream.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/KMAllanInputStream.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/KMAllanInputStream.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,170 @@
+/*
+ * 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 java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+public class KMAllanInputStream extends ObjectInputStream {
+
+ private static final byte BC_VECTOR = (byte)0x80, BC_VECTOR_VRSN = (byte)0x80, BC_VECTOR_ITM = (byte)0x81;
+ private static final byte BC_URL_BEAN = (byte)0x82, BC_FILTER_BEAN = (byte)0x83, BC_HIST_BEAN = (byte)0x84;
+ private static final byte BC_TYPE_STRING = (byte)0x90, BC_TYPE_INT = (byte)0x91, BC_TYPE_LONG = (byte)0x92;
+ private static final byte BC_TYPE_BOOLEAN = (byte)0x93, BC_TYPE_UNKNOWN = (byte)0x9F;
+
+ private static final String[] strings = new String[] {"Name", "StoreDir", "Expression", "Type", "Category", "Mode",
+ "Location", "Referer", "Cookie", "FileData"};
+
+ private static final String[] bools = new String[] {"IsRegex", "MatchTitle", "MatchLink", "MoveTop", "RateUseCustom",
+ "RenameFile", "RenameIncEpisode", "DisableAfter", "CleanFile",
+ "Enabled", "ObeyTTL", "LocRef", "UseCookie"};
+
+ private static String[] ints = new String[] {"State", "Priority", "RateUpload", "RateDownload", "StartSeason",
+ "StartEpisode", "EndSeason", "EndEpisode", "Delay", "SeasonStart",
+ "SeasonEnd", "EpisodeStart", "EpisodeEnd"};
+
+ private static String[] longs = new String[] {"ID", "Feed", "FiltID"};
+
+ private static Map types;
+ static {
+ types = new HashMap();
+ for(int i = 0; i < strings.length; i++) types.put(strings[i], new Byte(BC_TYPE_STRING));
+ for(int i = 0; i < bools.length; i++) types.put(bools[i], new Byte(BC_TYPE_BOOLEAN));
+ for(int i = 0; i < ints.length; i++) types.put(ints[i], new Byte(BC_TYPE_INT));
+ for(int i = 0; i < longs.length; i++) types.put(longs[i], new Byte(BC_TYPE_LONG));
+ }
+
+ private static byte getType(String name) {
+ if(types.containsKey(name)) return ((Byte)types.get(name)).byteValue();
+ else return BC_TYPE_UNKNOWN;
+ }
+
+ public KMAllanInputStream(InputStream in) throws IOException {
+ super(in);
+ }
+
+ public Vector readVector(String mode) throws IOException, ClassNotFoundException {
+ if(readByte() != BC_VECTOR) throw new StreamCorruptedException();
+
+ Vector vect = new Vector();
+ if(mode.equalsIgnoreCase("UrlBean")) {
+ return readBean(UrlBean.class, BC_URL_BEAN, vect);
+ } else if(mode.equalsIgnoreCase("FilterBean")) {
+ return readBean(FilterBean.class, BC_FILTER_BEAN, vect);
+ } else if(mode.equalsIgnoreCase("HistBean")) {
+ return readBean(HistoryBean.class, BC_HIST_BEAN, vect);
+ } else {
+ throw new StreamCorruptedException("Bad Mode: " + mode);
+ }
+ }
+
+ private Vector readBean(Class beanClass, byte type, Vector vect) throws IOException, ClassNotFoundException {
+ int vectCount = readInt();
+ int vectVRSN = 0;
+ byte vb = readByte();
+ if(vb == BC_VECTOR_VRSN) {
+ vectVRSN = readInt();
+ vb = readByte();
+ }
+ if(vb != BC_VECTOR_ITM) throw new StreamCorruptedException();
+ if(vectVRSN <= 0) throw new StreamCorruptedException("Unsuported Options File Version: " + vectVRSN);
+
+ int itemCount = readInt();
+ String[] items = new String[itemCount];
+ for(int i = 0; i < itemCount; i++) items[i] = (String)readObject();
+
+ for(int n = 0; n < vectCount; n++) {
+ if(readByte() != type) throw new StreamCorruptedException();
+
+ Object bean = null;
+ try {
+ bean = beanClass.newInstance();
+ } catch(Exception e) {
+ throw new IOException("Unable to create bean instance for '" + beanClass.getName() + "' - " + e);
+ }
+
+ for(int i = 0; i < itemCount; i++) {
+ byte itemType = getType(items[i]);
+ byte itemStoreType;
+ if(vectVRSN == 1) itemStoreType = getStringType();
+ else itemStoreType = readByte();
+
+ if(itemStoreType == BC_TYPE_UNKNOWN) continue;
+
+ if(itemStoreType == itemType) {
+ switch(itemStoreType) {
+ case BC_TYPE_STRING:
+ setValue(bean, items[i], (String)readObject(), String.class);
+ break;
+ case BC_TYPE_INT:
+ setValue(bean, items[i], new Integer(readInt()), int.class);
+ break;
+ case BC_TYPE_LONG:
+ setValue(bean, items[i], new Long(readLong()), long.class);
+ break;
+ case BC_TYPE_BOOLEAN:
+ setValue(bean, items[i], new Boolean(readBoolean()), boolean.class);
+ break;
+ }
+ } else {
+ switch(itemStoreType) {
+ case BC_TYPE_STRING:
+ readObject();
+ break;
+ case BC_TYPE_INT:
+ readInt();
+ break;
+ case BC_TYPE_LONG:
+ readLong();
+ break;
+ case BC_TYPE_BOOLEAN:
+ readBoolean();
+ break;
+ default: throw new StreamCorruptedException();
+ }
+ }
+ }
+ vect.add(bean);
+ }
+ return vect;
+ }
+
+ private byte getStringType() throws IOException, ClassNotFoundException {
+ byte byteType = BC_TYPE_UNKNOWN;
+ String stringType = (String)readObject();
+ if(stringType.equalsIgnoreCase("String")) byteType = BC_TYPE_STRING;
+ else if(stringType.equalsIgnoreCase("Int")) byteType = BC_TYPE_INT;
+ else if(stringType.equalsIgnoreCase("Long")) byteType = BC_TYPE_LONG;
+ else if(stringType.equalsIgnoreCase("Boolean")) byteType = BC_TYPE_BOOLEAN;
+ else throw new StreamCorruptedException("Bad Item Type: " + stringType);
+ return byteType;
+ }
+
+ private void setValue(Object target, String name, Object value, Class type) throws StreamCorruptedException {
+ try {
+ Method m = target.getClass().getMethod("set" + name, new Class[] {type});
+ m.invoke(target, new Object[] {value});
+ } catch(Exception e) {
+ throw new StreamCorruptedException(e.toString());
+ }
+ }
+
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/ListBean.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/ListBean.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/ListBean.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,241 @@
+/*
+ * 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 java.io.Serializable;
+
+public class ListBean implements Serializable {
+
+ static final long serialVersionUID = -4786592909020746490L;
+
+ public static final int DOWNLOAD_INCL = 10, DOWNLOAD_EXCL = 11, DOWNLOAD_FAIL = 12, DOWNLOAD_HIST = 13;
+ public static final int NO_DOWNLOAD = 99;
+
+ private String name, location, description;
+ private long listId;
+ private UrlBean urlBean;
+
+ private String err;
+ private int state = NO_DOWNLOAD;
+ public boolean completed, canceled, error;
+
+ private transient int percent, amount;
+ public transient Downloader downloader = null;
+
+ public ListBean() {
+ listId = System.currentTimeMillis();
+ }
+
+ public long getID() {
+ return listId;
+ }
+
+ public String getName() {
+ if(name == null) name = "";
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLocation() {
+ if(location == null) location = "";
+ return location;
+ }
+
+ public void setLocation(String location) {
+ this.location = location;
+ }
+
+ public String getDescription() {
+ if(description == null) description = "";
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public UrlBean getFeed() {
+ return urlBean;
+ }
+
+ public void setFeed(UrlBean urlBean) {
+ this.urlBean = urlBean;
+ }
+
+ public void resetInfo() {
+ this.state = NO_DOWNLOAD;
+ this.percent = 0;
+ this.amount = 0;
+ this.err = "";
+ this.completed = this.canceled = this.error = false;
+ }
+
+ public String getInfo() {
+ String info = "";
+
+ switch(state) {
+ case Downloader.DOWNLOADER_NON_INIT:
+ info = "Incl";
+ break;
+ case Downloader.DOWNLOADER_INIT:
+ info = "Init";
+ break;
+ case Downloader.DOWNLOADER_START:
+ info = "Start";
+ break;
+ case Downloader.DOWNLOADER_DOWNLOADING:
+ info = "Get " + (this.percent > 0?Integer.toString(this.percent) + "%":(this.amount > 0?Double.toString(Math.floor(new Integer(this.amount).doubleValue() / (double) 1024 * (double) 100) / (double) 100) + "KB":""));
+ break;
+ case Downloader.DOWNLOADER_FINISHED:
+ this.completed = true;
+ info = "Done";
+ break;
+ case Downloader.DOWNLOADER_ERROR:
+ this.error = true;
+ info = "Error" + (!"".equals(err)?" - " + err:"");
+ break;
+ case Downloader.DOWNLOADER_CANCELED:
+ this.canceled = true;
+ info = "Canned";
+ break;
+ case Downloader.DOWNLOADER_CHECKING:
+ info = "Search " + this.amount + "/" + this.percent + " ...";
+ break;
+ case DOWNLOAD_INCL:
+ info = "Incl";
+ break;
+ case DOWNLOAD_EXCL:
+ this.completed = true;
+ info = "Excl";
+ break;
+ case DOWNLOAD_FAIL:
+ this.error = true;
+ info = "Fail" + (!"".equals(err)?" - " + err:"");
+ break;
+ case DOWNLOAD_HIST:
+ this.completed = true;
+ info = "Hist";
+ break;
+ }
+
+ return info;
+ }
+
+ public boolean checkDone() {
+ return (this.completed || this.canceled || this.error);
+ }
+
+ public int getState() {
+ return this.state;
+ }
+
+ public void setState(int state) {
+ if(checkDone()) return;
+ this.state = state;
+ }
+
+ public int getPercent() {
+ return this.percent;
+ }
+
+ public void setPercent(int percent) {
+ this.percent = percent;
+ }
+
+ public int getAmount() {
+ return this.amount;
+ }
+
+ public void setAmount(int amount) {
+ this.amount = amount;
+ }
+
+ public String getError() {
+ return this.err;
+ }
+
+ public void setError(String err) {
+ this.err = err;
+ }
+
+ public int getAge() {
+ long msAge = System.currentTimeMillis() - listId;
+ return (int)(msAge / (3600000 * 24));
+ }
+
+ public String getAgeStr() {
+ return makeDurationStr((System.currentTimeMillis() - listId) / 1000, false);
+ }
+
+ public boolean equals(Object o) {
+ if(this == o) return true;
+ if(!(o instanceof ListBean)) return false;
+ final ListBean listBean = (ListBean)o;
+ if(!location.equals(listBean.location)) return false;
+ // if(!name.equals(listBean.name)) return false;
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = name.hashCode();
+ result = 29 * result + location.hashCode();
+ return result;
+ }
+
+ public String toString() {
+ return name;
+ }
+
+ public static String makeDurationStr(long s, boolean detail) {
+ if(s < 60) return "";
+ int i = 0;
+ long tmp = -1;
+ String res = "";
+ while(s > 0) {
+ switch(i++) {
+ case 0:
+ tmp = s % 60;
+ res += tmp + (tmp!=1?" secs":" sec");
+ s = s / 60;
+ case 1:
+ tmp = s % 60;
+ if(tmp > 0) res = tmp + (tmp!=1?" mins ":" min ") + (detail?res:"");
+ s = s / 60;
+ case 2:
+ tmp = s % 24;
+ if(tmp > 0) res = tmp + (tmp!=1?" hours ":" hour ") + (detail?res:"");
+ s = s / 24;
+ case 3:
+ tmp = s % 7;
+ if(tmp > 0) res = tmp + (tmp!=1?" days ":" day ") + res;
+ s = s / 24;
+ case 4:
+ if(s > 0) res = s + (s!=1?" weeks ":" week ") + res;
+ s = 0;
+ }
+ }
+ return res.trim();
+ }
+
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/ListGroup.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/ListGroup.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/ListGroup.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,93 @@
+/*
+ * 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 java.util.*;
+
+public class ListGroup extends ArrayList {
+
+ private TreeViewManager treeViewManager;
+ private UrlBean urlBean = null;
+ private List previousItems;
+ private int previousDelay;
+
+ private int delay = 0;
+ private int elapsed = 0;
+
+ public ListGroup(TreeViewManager treeViewManager) {
+ this.treeViewManager = treeViewManager;
+ }
+
+ public void setUrl(UrlBean urlBean) {
+ this.urlBean = urlBean;
+ }
+
+ public UrlBean getUrl() {
+ return urlBean;
+ }
+
+ public int getDelay() {
+ return delay;
+ }
+
+ public void setDelay(int delay) {
+ this.delay = delay;
+ }
+
+ public void setDelay(int delay, boolean isTTL) {
+ this.delay = delay;
+ if(isTTL) this.previousDelay = delay;
+ }
+
+ public int getElapsed() {
+ if(elapsed == delay) return elapsed;
+ return elapsed++;
+ }
+
+ public void setElapsed(int elapsed) {
+ this.elapsed = elapsed;
+ }
+
+ public void resetElapsed() {
+ this.elapsed = 0;
+ }
+
+ public void cleanout() {
+ previousItems = new ArrayList(this);
+ clear();
+ treeViewManager.clearGroup(this);
+ }
+
+ public void remove() {
+ treeViewManager.remove(this);
+ }
+
+ public List getPreviousItems() {
+ return previousItems;
+ }
+
+ public int getPreviousDelay() {
+ return previousDelay;
+ }
+
+ public void setPreviousDelay(int previousDelay) {
+ this.previousDelay = previousDelay;
+ }
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/ListTreeItem.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/ListTreeItem.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/ListTreeItem.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,127 @@
+/*
+ * 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.custom.*;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.SWT;
+
+import java.util.Map;
+
+public class ListTreeItem extends TableTreeItem {
+
+ private View view = null;
+
+ private Object data;
+ private boolean isFeed, isBackLog;
+ private Color defaultForeground;
+ private ListTreeItem backLogItem;
+
+ public ListTreeItem(View view) {
+ super(view.listTable, SWT.NULL);
+ this.view = view;
+ this.isFeed = true;
+ this.defaultForeground = this.getForeground();
+ }
+
+ public ListTreeItem(ListTreeItem parent, View view) {
+ super(parent, SWT.NULL, parent.isBackLog()?0:parent.getItemCount()); // reverse order for backlog items
+ this.view = view;
+ this.isFeed = false;
+ this.defaultForeground = this.getForeground();
+ }
+
+ public ListTreeItem(ListTreeItem parent, View view, boolean isBackLog) {
+ super(parent, SWT.NULL);
+ this.view = view;
+ this.isFeed = true;
+ this.isBackLog = isBackLog;
+ if(isBackLog) parent.setBackLogItem(this);
+ this.defaultForeground = this.getForeground();
+ }
+
+ public boolean isFeed() {
+ return isFeed;
+ }
+
+ public boolean isBackLog() {
+ return isBackLog;
+ }
+
+ public void checkSubclass() {
+ return;
+ }
+
+ public Object getBean() {
+ return data;
+ }
+
+ public void setBean(Object data) {
+ this.data = data;
+
+ update();
+ }
+
+ public void update() {
+ if(isFeed) {
+ UrlBean urlBean = (UrlBean)data;
+ if(isBackLog) {
+ setText(0, "Old/Removed");
+ setText(1, this.getItemCount() + " items");
+ } else {
+ setText(0, urlBean.getName());
+ // todo set age? (time since last refresh)
+ }
+ } else {
+ ListBean listBean = (ListBean)data;
+ setText(0, listBean.getName());
+ setText(1, listBean.getLocation());
+ setText(2, listBean.getAgeStr());
+ setText(3, listBean.getInfo());
+
+ if(listBean.error) this.setForeground(new Color(view.display, 255, 0, 0));
+ else resetForeground();
+ }
+ }
+
+ public void resetForeground() {
+ this.setForeground(defaultForeground);
+ }
+
+ public void removeAll(Map allItems) {
+ TableTreeItem[] items = this.getItems();
+ for(int i = 0; i < items.length; i++) {
+ allItems.remove(items[i]);
+ items[i].dispose();
+ }
+ }
+
+ public void setBackLogItem(ListTreeItem item) {
+ if(isFeed) this.backLogItem = item;
+ }
+
+ public ListTreeItem getBackLogItem() {
+ return backLogItem;
+ }
+
+
+}
+
+
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/Plugin.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/Plugin.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/Plugin.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,206 @@
+/*
+ * 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 java.util.Date;
+
+import org.gudy.azureus2.plugins.PluginInterface;
+import org.gudy.azureus2.plugins.ui.UIInstance;
+import org.gudy.azureus2.plugins.ui.UIManagerListener;
+import org.gudy.azureus2.plugins.ui.config.*;
+import org.gudy.azureus2.ui.swt.plugins.UISWTInstance;
+import org.gudy.azureus2.ui.swt.plugins.UISWTViewEvent;
+import org.gudy.azureus2.ui.swt.plugins.UISWTViewEventListener;
+import org.eclipse.swt.program.Program;
+import org.eclipse.swt.widgets.Composite;
+
+public class Plugin implements org.gudy.azureus2.plugins.Plugin {
+
+ public static String PLUGIN_VERSION = "x.x.x";
+ public static final int MIN_REFRESH = 300;
+ public static final boolean DEBUG = false;
+
+ private static PluginInterface pluginInterface;
+ private final String VIEWID = "RSSFeed Scanner";
+ private ViewListener viewListener = null;
+ private UISWTInstance swtInstance = null;
+ private static Config rssfeedConfig;
+ private static View view = null;
+
+ public void initialize(PluginInterface pluginIf) {
+ pluginInterface = pluginIf;
+ rssfeedConfig = new Config();
+
+ pluginInterface.addConfigUIParameters(getParameters(), "RSSFeed.Config");
+ PLUGIN_VERSION = pluginInterface.getPluginVersion();
+
+ pluginInterface.getUIManager().addUIListener(
+ new UIManagerListener()
+ {
+ public void
+ UIAttached(
+ UIInstance instance )
+ {
+ if ( instance instanceof UISWTInstance ){
+ view = new View(pluginInterface, rssfeedConfig);
+
+ swtInstance = ((UISWTInstance) instance);
+
+ viewListener = new ViewListener();
+ if (viewListener != null) {
+ // Add it to the menu
+ swtInstance.addView(UISWTInstance.VIEW_MAIN, VIEWID, viewListener);
+ // Open it immediately
+ if( pluginInterface.getPluginconfig().getPluginBooleanParameter("AutoLoad", false) )
+ swtInstance.openMainView(VIEWID, viewListener, null);
+ }
+
+ }
+ }
+
+ public void
+ UIDetached(
+ UIInstance instance )
+ {
+ if (instance instanceof UISWTInstance)
+ instance = null;
+ }
+ });
+
+ }
+
+ private class ViewListener implements UISWTViewEventListener {
+
+ boolean bInitialized = false;
+
+ public boolean eventOccurred(UISWTViewEvent event) {
+ switch (event.getType()) {
+ case UISWTViewEvent.TYPE_CREATE:
+ /* We only want one view
+ *
+ * If we wanted multiple views, we would need a class to handle
+ * one view. Then, we could set up a Map, with the key
+ * being the UISWTView, and the value being a new instance of the
+ * class. When the other types of events are called, we would
+ * lookup our class using getView(), and then pass the work to
+ * the our class.
+ */
+ if (bInitialized)
+ return false;
+ break;
+
+ case UISWTViewEvent.TYPE_INITIALIZE:
+ if (bInitialized)
+ return false;
+
+ view.initialize((Composite) event.getData());
+ bInitialized = true;
+ break;
+
+ case UISWTViewEvent.TYPE_REFRESH:
+ //view.refresh();
+ break;
+
+ case UISWTViewEvent.TYPE_DESTROY:
+ view.delete();
+ bInitialized = false;
+ break;
+
+ case UISWTViewEvent.TYPE_DATASOURCE_CHANGED:
+ break;
+
+ case UISWTViewEvent.TYPE_FOCUSGAINED:
+ break;
+
+ case UISWTViewEvent.TYPE_FOCUSLOST:
+ break;
+
+ case UISWTViewEvent.TYPE_LANGUAGEUPDATE:
+ break;
+ }
+ return true;
+ }
+ }
+
+ private Parameter[] getParameters() {
+ PluginConfigUIFactory configUIFactory = pluginInterface.getPluginConfigUIFactory();
+ Parameter[] para = new Parameter[6];
+ para[0] = configUIFactory.createBooleanParameter("Enabled", "RSSFeed.Config.Enable", true);
+ para[1] = configUIFactory.createIntParameter("Delay", "RSSFeed.Config.Delay", 900);
+ para[2] = configUIFactory.createBooleanParameter("AutoLoad", "RSSFeed.Config.AutoLoad", false);
+ para[3] = configUIFactory.createBooleanParameter("AutoStartManual", "RSSFeed.Config.AutoStartManual", true);
+ para[4] = configUIFactory.createIntParameter("KeepOld", "RSSFeed.Config.KeepOld", 2);
+ para[5] = configUIFactory.createIntParameter("KeepMax", "RSSFeed.Config.KeepMax", 1000);
+ ((EnablerParameter) para[0]).addEnabledOnSelection(para[1]);
+
+ return para;
+ }
+
+ public static String getPluginDirectoryName() {
+ return pluginInterface.getPluginDirectoryName();
+ }
+
+ public static int getIntParameter(String name) {
+ return pluginInterface.getPluginconfig().getPluginIntParameter(name);
+ }
+
+ public static boolean getBooleanParameter(String name) {
+ return pluginInterface.getPluginconfig().getPluginBooleanParameter(name);
+ }
+
+ public static void setParameter(String name, int value) {
+ pluginInterface.getPluginconfig().setPluginParameter(name, value);
+ }
+
+ public static PluginInterface
+ getPluginInterface()
+ {
+ return( pluginInterface );
+ }
+
+ public static void updateView(final ListBean listBean) {
+ if (view != null && 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 listItem = view.treeViewManager.getItem(listBean);
+ listItem.update();
+ }
+ });
+ }
+ }
+
+ public static void debugOut(String s) {
+ if (DEBUG) {
+ System.out.println(new Date() + "] RSSFeed: " + s + " ["
+ + Thread.currentThread().getName() + "]");
+ }
+ }
+
+ public static void launchUrl(final String url) {
+ new Thread("URLLauncherThread") {
+ public void run() {
+ Program.launch(url);
+ }
+ }.start();
+ }
+}
\ No newline at end of file
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/Scheduler.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/Scheduler.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/Scheduler.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,445 @@
+/*
+ * 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 && !link.toLowerCase().startsWith( "magnet" )) {
+ 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;
+ }
+}
+
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/SimpleDialog.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/SimpleDialog.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/SimpleDialog.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,170 @@
+/*
+ * 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.SWT;
+import org.eclipse.swt.custom.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+import org.gudy.azureus2.ui.swt.*;
+
+public class SimpleDialog extends Dialog {
+ Object result;
+
+ private String title, info;
+
+ public SimpleDialog(Shell parent, int style) {
+ super(parent, style);
+ }
+
+ public SimpleDialog(Shell parent) {
+ this(parent, SWT.NULL);
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getTitle() {
+ if(title == null) title = "";
+ return title;
+ }
+
+ public void setInfo(String info) {
+ this.info = info;
+ }
+
+ public String getInfo() {
+ if(info == null) info = "";
+ return info;
+ }
+
+ public Object open() {
+ if(getInfo().equalsIgnoreCase("")) return null;
+
+ GridLayout layout;
+ GridData layoutData;
+
+ Shell parent = getParent();
+ final Shell myShell = new Shell(parent, SWT.MODELESS | SWT.DIALOG_TRIM | SWT.MAX | SWT.RESIZE);
+ myShell.setSize(640, 480);
+ myShell.setImage(ImageRepository.getImage("azureus"));
+ myShell.setText(getText());
+
+ layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ layoutData = new GridData(GridData.FILL_BOTH);
+ myShell.setLayout(layout);
+ myShell.setLayoutData(layoutData);
+
+ Display display = parent.getDisplay();
+
+ Composite myComp = new Composite(myShell, SWT.NULL);
+ layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ layoutData = new GridData(GridData.FILL_BOTH);
+ myComp.setLayout(layout);
+ myComp.setLayoutData(layoutData);
+
+ Composite tComp = new Composite(myComp, SWT.BORDER);
+ layout = new GridLayout();
+ layout.marginHeight = 3;
+ layout.marginWidth = 0;
+ layoutData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER);
+ tComp.setLayout(layout);
+ tComp.setLayoutData(layoutData);
+
+ tComp.setBackground(display.getSystemColor(SWT.COLOR_LIST_SELECTION));
+ tComp.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
+
+ Label tLabel = new Label(tComp, SWT.NULL);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER);
+ tLabel.setLayoutData(layoutData);
+ tLabel.setText(getTitle());
+
+ tLabel.setBackground(display.getSystemColor(SWT.COLOR_LIST_SELECTION));
+ tLabel.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
+ FontData[] curTLabel = tLabel.getFont().getFontData();
+ curTLabel[0].setStyle(SWT.BOLD);
+ curTLabel[0].setHeight((int) (curTLabel[0].getHeight() * 1.2));
+ tLabel.setFont(new Font((Device) display, curTLabel));
+
+ final ScrolledComposite lScrollComp = new ScrolledComposite(myComp, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
+ layout = new GridLayout();
+ layoutData = new GridData(GridData.FILL_BOTH);
+ lScrollComp.setLayout(layout);
+ lScrollComp.setLayoutData(layoutData);
+
+ lScrollComp.setExpandHorizontal(true);
+ lScrollComp.setExpandVertical(true);
+
+ final Composite lMainComp = new Composite(lScrollComp, SWT.NULL);
+ lScrollComp.setContent(lMainComp);
+ layout = new GridLayout();
+ layoutData = new GridData(GridData.FILL_BOTH);
+ lMainComp.setLayout(layout);
+ lMainComp.setLayoutData(layoutData);
+
+ Composite lComp = new Composite(lMainComp, SWT.NULL);
+ layout = new GridLayout();
+ layout.numColumns = 5;
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ lComp.setLayout(layout);
+ lComp.setLayoutData(layoutData);
+
+ StyledText st = new StyledText(lComp, SWT.NULL);
+ FontData[] curLbl = st.getFont().getFontData();
+ curLbl[0].setName("courier");
+ st.setFont(new Font((Device) display, curLbl));
+ st.setText(getInfo());
+ st.setEditable(false);
+
+ lMainComp.setBackground(st.getBackground());
+ lComp.setBackground(st.getBackground());
+
+ lScrollComp.setMinSize(lMainComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+
+ Composite bComp = new Composite(myComp, SWT.NULL);
+ layout = new GridLayout();
+ layout.marginHeight = 3;
+ layout.marginWidth = 3;
+ layoutData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER | GridData.VERTICAL_ALIGN_CENTER);
+ bComp.setLayout(layout);
+ bComp.setLayoutData(layoutData);
+
+ Button btnHide = new Button(bComp, SWT.PUSH);
+ Messages.setLanguageText(btnHide, "RSSFeed.InfoWin.Hide");
+
+ myShell.layout();
+ myShell.open();
+
+ btnHide.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event e) {
+ myShell.close();
+ }
+ });
+ return result;
+ }
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/TorrentDownloader.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/TorrentDownloader.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/TorrentDownloader.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,308 @@
+/*
+ * 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.widgets.Display;
+import org.gudy.azureus2.core3.config.COConfigurationManager;
+import org.gudy.azureus2.core3.util.Constants;
+import org.gudy.azureus2.plugins.download.*;
+import org.gudy.azureus2.plugins.torrent.*;
+
+import javax.swing.text.html.parser.ParserDelegator;
+import java.io.*;
+import java.util.*;
+import java.net.*;
+
+public class TorrentDownloader {
+
+ private View view;
+ private TorrentManager torrentManager;
+ private DownloadManager downloadManager;
+
+ public TorrentDownloader(View view, TorrentManager torrentManager, DownloadManager downloadManager) {
+ this.view = view;
+ this.torrentManager = torrentManager;
+ this.downloadManager = downloadManager;
+ }
+
+ public boolean addTorrent(ListBean listBean) {
+ return addTorrent(null, listBean);
+ }
+
+ public void addTorrentThreaded(final ListBean listBean) {
+ new Thread("TorrentDownloaderThread") {
+ public void run() {
+ addTorrent(listBean);
+ 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 listItem = view.treeViewManager.getItem(listBean);
+ listItem.update();
+ }
+ });
+ }
+ }.start();
+ }
+
+
+ public boolean addTorrent(FilterBean filterBean, ListBean listBean) {
+ return addTorrent(listBean.getLocation(), listBean.getFeed(), filterBean, listBean);
+ }
+
+ public boolean addTorrent(String link, final UrlBean urlBean, final FilterBean filterBean, final ListBean listBean) {
+ boolean ret = true;
+ String err = "";
+ File torrentLocation = null;
+
+ try {
+ boolean saveTorrents = false;
+ String torrentDirectory = "";
+ try {
+ saveTorrents = COConfigurationManager.getBooleanParameter("Save Torrent Files", true);
+ torrentDirectory = COConfigurationManager.getDirectoryParameter("General_sDefaultTorrent_Directory");
+ } catch(Exception egnore) {}
+
+ if(saveTorrents && torrentDirectory != null && torrentDirectory.length() > 0) {
+ torrentLocation = getTorrent(link, urlBean, listBean, torrentDirectory);
+ if(torrentLocation == null) return false;
+ Torrent curTorrent = torrentManager.createFromBEncodedFile(torrentLocation);
+
+ String storeFile = null;
+ if((curTorrent.getFiles()).length == 1) storeFile = curTorrent.getName();
+
+ String defaultPath = "";
+ if(filterBean != null && filterBean.getStoreDir().length() > 0) {
+ defaultPath = filterBean.getStoreDir();
+ } else if(urlBean != null && urlBean.getStoreDir().length() > 0) {
+ defaultPath = urlBean.getStoreDir();
+ } else if(COConfigurationManager.getBooleanParameter("Use default data dir", true)) {
+ defaultPath = COConfigurationManager.getStringParameter("Default save path", "");
+ }
+
+ if(defaultPath.length() > 0) {
+ File dataLocation = setFile(defaultPath, storeFile);
+
+ final Download download = addTorrent(curTorrent, torrentLocation, dataLocation);
+ ret = (download != null);
+ Plugin.debugOut("ret: " + ret + " download: " + download);
+
+ if(ret) {
+ if(filterBean != null) {
+ view.histAdd(listBean, download, dataLocation, filterBean);
+ try {
+ if (filterBean.getMoveTop()) {
+ for (int iLoop = 1; iLoop <= download.getIndex(); iLoop++) {
+ download.moveUp();
+ }
+ }
+
+ if (Constants.compareVersions(Constants.getBaseVersion(),
+ "2.2.0.0") >= 0) {
+ if (filterBean.getRateUseCustom()) {
+ download.setUploadRateLimitBytesPerSecond(filterBean.getRateUpload() * 1024);
+ }
+ } else {
+ download.setPriority(filterBean.getPriority());
+ }
+
+ switch (filterBean.getState()) {
+ case 1:
+ download.setForceStart(true);
+ break;
+ case 2:
+ download.stop();
+ break;
+ }
+ if (filterBean.getRateUseCustom())
+ download.setMaximumDownloadKBPerSecond(filterBean.getRateDownload());
+ if (filterBean.getCategory().length() > 0)
+ download.setCategory(filterBean.getCategory());
+ } catch (NoSuchMethodError e) {
+ /** < Azureus 2.1.0.5 **/
+ } catch (Exception e) {
+ }
+ } else {
+ if(!Plugin.getBooleanParameter("AutoStartManual")) download.stop();
+ view.histAdd(listBean, download, dataLocation);
+ }
+ }
+ } else {
+ ret = false;
+ err = "No Default Data Directory Set (Options > Files > Save to default data directory)";
+ }
+ } else {
+ ret = false;
+ err = "No Torrent Save Directory Set (Options > Files > Torrents > Save .torrent files)";
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+ System.err.println("Failed to add torrent: '" + link + "'");
+ err = e.getMessage();
+ ret = false;
+ }
+ if(!ret) {
+ listBean.setState(ListBean.DOWNLOAD_FAIL);
+ if(!"".equals(err)) listBean.setError(err);
+ }
+
+ if(!ret && torrentLocation != null) torrentLocation.delete();
+ return ret;
+ }
+
+ public boolean addTorrent(Torrent curTorrent, File torrentLocation, ListBean listBean, String storeLoc, String storeFile) throws Exception {
+ File dataLocation = null;
+ if(storeLoc != null && storeLoc.length() > 0) {
+ dataLocation = setFile(storeLoc, storeFile);
+ } else if(listBean != null && (listBean.getFeed()).getStoreDir().length() > 0) {
+ dataLocation = setFile((listBean.getFeed()).getStoreDir(), null);
+ }
+ Download download = addTorrent(curTorrent, torrentLocation, dataLocation);
+ if(download != null) view.histAdd(listBean, download, dataLocation);
+ return (download != null);
+ }
+
+ private Download addTorrent(Torrent curTorrent, File torrentLocation, File dataLocation) throws Exception {
+ Download download = null;
+ if(torrentLocation != null && dataLocation != null) {
+ download = downloadManager.addDownload(curTorrent, torrentLocation, dataLocation);
+ }
+ return download;
+ }
+
+ private File setFile(String storePath, String storeFile) {
+ File file = null;
+ if(!storePath.endsWith(view.rssfeedConfig.separator))
+ storePath = storePath + view.rssfeedConfig.separator;
+ try {
+ if(storeFile != null && storeFile.length() > 0) file = new File(storePath, storeFile);
+ else file = new File(storePath);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ return file;
+ }
+
+ public File getTorrent(String url, final UrlBean urlBean, final ListBean listBean, String directoryName) throws Exception {
+ listBean.resetInfo();
+ Downloader downloader = new Downloader();
+ downloader.addListener(new DownloaderListener() {
+ public void downloaderUpdate(int state, int percent, int amount, String err) {
+ listBean.setState(state);
+ if(percent > 0) listBean.setPercent(percent);
+ if(amount > 0) listBean.setAmount(amount);
+ if(!err.equalsIgnoreCase("")) listBean.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 listItem = view.treeViewManager.getItem(listBean);
+ if (listItem == null || listItem.isDisposed()) {
+ return;
+ }
+ listItem.update();
+ }
+ });
+ }
+ });
+
+ downloader.init(url, "application/x-bittorrent, application/x-httpd-php", (urlBean.getLocRef()?urlBean.getLocation():urlBean.getReferer()),
+ (urlBean.getUseCookie()?urlBean.getCookie():null), 0, null);
+ listBean.downloader = downloader;
+
+ if(downloader.getState() == Downloader.DOWNLOADER_CANCELED || downloader.getState() == Downloader.DOWNLOADER_ERROR) {
+ return null;
+ }
+
+ String filename = downloader.fileName;
+ if(!downloader.fileName.toLowerCase().endsWith(".torrent"))
+ filename = "temp-" + Long.toString((new Date()).getTime()) + "-" + Long.toString((new Random()).nextLong()) + ".torrent";
+
+ File torrentLocation = new File(directoryName, filename);
+ torrentLocation.createNewFile();
+ FileOutputStream fileout = new FileOutputStream(torrentLocation, false);
+
+ byte[] buf = new byte[4096];
+ int read;
+ while((read = downloader.read(buf)) != -1) {
+ fileout.write(buf, 0, read);
+ if(downloader.getState() == Downloader.DOWNLOADER_CANCELED) break;
+ }
+ fileout.flush();
+ fileout.close();
+
+ if(downloader.getState() == Downloader.DOWNLOADER_CANCELED || downloader.getState() == Downloader.DOWNLOADER_ERROR) {
+ listBean.downloader = null;
+ downloader.done();
+ torrentLocation.delete();
+ return null;
+ }
+
+ if(!downloader.fileName.toLowerCase().endsWith(".torrent")) {
+ Plugin.debugOut("contentType: " + downloader.contentType);
+
+ if(downloader.contentType != null && downloader.contentType.toLowerCase().startsWith("text/html")) {
+
+ // html file encountered, look for link to torrent
+ String href = findTorrentHref(torrentLocation, url, listBean);
+ Plugin.debugOut("href: " + href);
+ torrentLocation.delete();
+ if(href != null) {
+ listBean.downloader = null;
+ downloader.done();
+ return getTorrent(href, urlBean, listBean, directoryName);
+ } else throw new Exception("Html content returned, but no links to torrent files found.");
+
+ } else if(downloader.contentType != null && !downloader.contentType.toLowerCase().startsWith("application/x-bittorrent")) {
+
+ // something else encountered, just move it to outputdir
+ File newFile = new File(directoryName, downloader.fileName != null?downloader.fileName:torrentLocation.getName());
+ if(!torrentLocation.renameTo(newFile)) Plugin.debugOut("failed to move " + torrentLocation);
+ Plugin.debugOut("Non-torrent download encountered and moved: " + newFile + " (" + downloader.contentType + ")");
+ torrentLocation = null;
+
+ } else {
+
+ Torrent torrent = torrentManager.createFromBEncodedFile(torrentLocation);
+ String name = torrent.getName() + ".torrent";
+ File newFile = new File(directoryName, name);
+ if(torrentLocation.renameTo(newFile)) {
+ downloader.fileName = name;
+ torrentLocation = newFile;
+ }
+ torrent = null;
+
+ }
+ }
+
+ listBean.downloader = null;
+ downloader.done();
+ return torrentLocation;
+ }
+
+ protected static String findTorrentHref(File htmlDoc, String baseUrl, ListBean listBean) throws IOException {
+ BufferedReader bufReader = new BufferedReader(new InputStreamReader(new FileInputStream(htmlDoc)));
+ HtmlAnalyzer parser = new HtmlAnalyzer(baseUrl, listBean);
+ new ParserDelegator().parse(bufReader, parser, true);
+ return parser.getTorrentUrl();
+ }
+
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/TreeViewManager.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/TreeViewManager.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/TreeViewManager.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,183 @@
+/*
+ * 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.custom.*;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.*;
+
+import org.gudy.azureus2.ui.swt.mainwindow.Colors;
+
+import java.util.*;
+
+public class TreeViewManager {
+
+ public List allGroups;
+ private Map allItems;
+ private View view = null;
+
+ public TreeViewManager(View view) {
+ this.view = view;
+ this.allGroups = new ArrayList();
+ this.allItems = new HashMap();
+ }
+
+ public void addGroup(ListGroup listBeans) {
+ allGroups.add(listBeans);
+ }
+
+ public ListTreeItem getItem(UrlBean urlBean) {
+ ListTreeItem item = (ListTreeItem)allItems.get(urlBean);
+ if(item == null || item.isDisposed()) item = createFeedItem(urlBean);
+ return item;
+ }
+
+ public ListTreeItem getBackLogItem(UrlBean urlBean) {
+ ListTreeItem parent = getItem(urlBean);
+ ListTreeItem item = parent.getBackLogItem();
+ if(item == null || item.isDisposed()) item = createBackLogItem(urlBean);
+ return item;
+ }
+
+ public ListTreeItem getItem(ListBean listBean) {
+ ListTreeItem item = (ListTreeItem)allItems.get(listBean);
+ if(item == null) Plugin.debugOut("got request for nonexisting treeitem: " + listBean);
+ return item;
+ }
+
+ public void addListBean(final ListBean listBean, final UrlBean urlBean, final boolean addToBackLog) {
+ if(view.isOpen() && view.display != null && !view.display.isDisposed())
+ view.display.asyncExec(new Runnable() {
+ public void run() {
+ try {
+ if(view.listTable == null || view.listTable.isDisposed()) return;
+ ListTreeItem listMainItem = addToBackLog?getBackLogItem(urlBean):getItem(urlBean);
+ createItem(listMainItem, listBean);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ public void remove(final ListGroup listBeans) {
+ 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 item = (ListTreeItem)allItems.get(listBeans.getUrl());
+ if(item != null) {
+ allItems.remove(item.getBean());
+ item.dispose();
+ }
+ }
+ });
+ allGroups.remove(listBeans);
+ }
+
+ public void clearGroup(final ListGroup listBeans) {
+ 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;
+ getItem(listBeans.getUrl()).removeAll(allItems);
+ }
+ });
+ }
+
+ private ListTreeItem createFeedItem(UrlBean urlBean) {
+ ListTreeItem newItem = new ListTreeItem(view);
+ newItem.setBean(urlBean);
+ allItems.put(urlBean, newItem);
+ return newItem;
+ }
+
+ private ListTreeItem createBackLogItem(UrlBean urlBean) {
+ ListTreeItem parent = getItem(urlBean);
+ ListTreeItem newItem = new ListTreeItem(parent, view, true);
+ newItem.setBean(urlBean);
+ return newItem;
+ }
+
+ private ListTreeItem createItem(ListTreeItem parent, ListBean listBean) {
+ ListTreeItem newItem = new ListTreeItem(parent, view);
+ newItem.setBean(listBean);
+ allItems.put(listBean, newItem);
+ if(parent.isBackLog()) parent.update();
+ return newItem;
+ }
+
+ public void display() {
+ ListGroup listGroup;
+ ListBean listBean;
+ ListTreeItem listMainItem, listBackLogItem;
+ List backLog;
+
+ view.listTable.setRedraw(false);
+
+ for(Iterator ig = allGroups.iterator(); ig.hasNext(); ) {
+ listGroup = (ListGroup)ig.next();
+ if(listGroup == null || listGroup.getUrl() == null) { // todo getUrl().isDestroyed()?
+ remove(listGroup);
+ } else {
+ listMainItem = createFeedItem(listGroup.getUrl());
+
+ for(int i = 0; i < listGroup.size(); i++) {
+ listBean = (ListBean)listGroup.get(i);
+ if(listBean != null) createItem(listMainItem, listBean);
+ }
+
+ backLog = listGroup.getUrl().getBackLog();
+ if(!backLog.isEmpty()) {
+ listBackLogItem = createBackLogItem(listGroup.getUrl());
+ for(Iterator iter = backLog.iterator(); iter.hasNext(); ) {
+ listBean = (ListBean)iter.next();
+ if(listBean != null) createItem(listBackLogItem, listBean);
+ }
+ }
+ }
+ }
+
+ view.listTable.setRedraw(true);
+ }
+
+ private void setExpandAll(TableTreeItem[] items, boolean expanded) {
+ for(int i = 0; i < items.length; i++) {
+ items[i].setExpanded(expanded);
+ if(items[i].getItemCount() > 0) setExpandAll(items[i].getItems(), expanded);
+ }
+ }
+
+ public void expandAll() {
+ view.listTable.setRedraw(false);
+ setExpandAll(view.listTable.getItems(), true);
+ view.listTable.setRedraw(true);
+ }
+
+ public void collapseAll() {
+ view.listTable.setRedraw(false);
+ setExpandAll(view.listTable.getItems(), false);
+ view.listTable.setRedraw(true);
+ }
+
+
+}
+
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/UrlBean.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/UrlBean.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/UrlBean.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,330 @@
+/*
+ * 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 java.io.Serializable;
+import java.util.*;
+import java.util.regex.*;
+import java.net.*;
+
+public class UrlBean implements Serializable {
+
+ static final long serialVersionUID = -436386969314243288L;
+
+ private String name, location, storeDir, referer, cookie;
+ private long urlId;
+ private boolean obeyTTL = true, locReferer = true, useCookie = false, enabled;
+ private int delay = 0, prevBackLogSize;
+ private List backLog;
+
+ private transient String status = "", error = "";
+ private transient boolean hitting = false, refreshNow = false;
+ private transient int percent = 0, amount = 0;
+ private transient ListGroup currentItems;
+ private transient long lastModifed;
+ private transient String lastEtag;
+
+ public UrlBean() {
+ urlId = System.currentTimeMillis();
+ }
+
+ public long getID() {
+ return urlId;
+ }
+
+ public void setID(long urlId) {
+ this.urlId = urlId;
+ }
+
+ public String getName() {
+ if(name == null) name = "";
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLocation() {
+ if(location == null) location = "";
+ return location;
+ }
+
+ public String getBaseURL() {
+ if(location == null || "".equals(location)) return null;
+ try {
+ URL u = new URL(location);
+ if(!u.getProtocol().toLowerCase().startsWith("http")) return null;
+ u = new URL(u.getProtocol() + "://" + u.getHost() + (u.getPort() == -1?"":":"+u.getPort()) + "/");
+ Plugin.debugOut(u.toString());
+ return u.toString();
+ } catch(MalformedURLException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public void setLocation(String location) {
+ this.location = location;
+ }
+
+ public String getStoreDir() {
+ if(storeDir == null) storeDir = "";
+ return storeDir;
+ }
+
+ public void setStoreDir(String storeDir) {
+ this.storeDir = storeDir;
+ }
+
+ public int getDelay() {
+ if(this.delay <= 0) return 0;
+ if(this.delay < Plugin.MIN_REFRESH) this.delay = Plugin.MIN_REFRESH;
+ return this.delay;
+ }
+
+ public int getDelay(int delay) {
+ if(this.delay <= 0) return delay;
+ return getDelay();
+ }
+
+ public void setDelay(int delay) {
+ this.delay = delay;
+ }
+
+ public boolean getObeyTTL() {
+ Pattern snfeed = Pattern.compile(".*varchars.*");
+ Matcher m = snfeed.matcher(location);
+ if(m.matches()) obeyTTL = true;
+ return obeyTTL;
+ }
+
+ public void setObeyTTL(boolean obeyTTL) {
+ this.obeyTTL = obeyTTL;
+ }
+
+ public boolean getLocRef() {
+ return locReferer;
+ }
+
+ public void setLocRef(boolean locReferer) {
+ this.locReferer = locReferer;
+ }
+
+ public String getReferer() {
+ if(referer == null) referer = "";
+ return referer;
+ }
+
+ public void setReferer(String referer) {
+ this.referer = referer;
+ }
+
+ public boolean getUseCookie() {
+ return useCookie;
+ }
+
+ public void setUseCookie(boolean useCookie) {
+ this.useCookie = useCookie;
+ }
+
+ public String getCookie() {
+ if(cookie == null) cookie = "";
+ return cookie;
+ }
+
+ public void setCookie(String cookie) {
+ this.cookie = cookie;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public ListGroup getGroup() {
+ return currentItems;
+ }
+
+ public ListGroup getGroup(TreeViewManager treeViewManager, int delay) {
+ if(currentItems == null) newGroup(treeViewManager, delay);
+ return currentItems;
+ }
+
+ public void newGroup(TreeViewManager treeViewManager, int delay) {
+ if(this.currentItems != null) purgeGroup(treeViewManager);
+
+ currentItems = new ListGroup(treeViewManager);
+ currentItems.setUrl(this);
+ currentItems.setDelay(getDelay(delay));
+ currentItems.setElapsed(getDelay(delay) - 5);
+
+ treeViewManager.addGroup(currentItems);
+ }
+
+ public void purgeGroup(TreeViewManager treeViewManager) {
+ treeViewManager.remove(currentItems);
+ currentItems = null;
+ }
+
+ public void resetGroup(int delay) {
+ addToBackLog(currentItems);
+ currentItems.cleanout();
+ currentItems.setDelay(getDelay(delay));
+ currentItems.resetElapsed();
+ }
+
+ private void addToBackLog(ListGroup oldItems) {
+ if(backLog == null) backLog = new ArrayList();
+ prevBackLogSize = backLog.size();
+ ListBean lb;
+ for(Iterator iter = oldItems.iterator(); iter.hasNext(); ) {
+ lb = (ListBean)iter.next();
+ if(lb == null) continue;
+ if(!backLog.contains(lb)) backLog.add(lb);
+ }
+ cleanOldBackLog();
+ }
+
+ public void cleanOldBackLog() {
+ if(backLog == null) return;
+ ListBean lb;
+ int keepOld = Plugin.getIntParameter("KeepOld");
+ int keepMax = Plugin.getIntParameter("KeepMax");
+ if(keepOld <= 0) return;
+ if(keepMax < 0) keepMax = 0;
+ for(Iterator iter = new ArrayList(backLog).iterator(); iter.hasNext(); ) {
+ lb = (ListBean)iter.next();
+ if(lb.getAge() >= keepOld) {
+ backLog.remove(lb);
+ }
+ }
+ while(backLog.size() > keepMax) backLog.remove(0);
+ }
+
+ public void refreshGroup() {
+ currentItems.setElapsed(currentItems.getDelay());
+ this.refreshNow = true;
+ }
+
+ public boolean getRefreshNow() {
+ return this.refreshNow;
+ }
+
+ public void setHitting(boolean hitting) {
+ this.hitting = hitting;
+ if(hitting) {
+ this.status = "Pending";
+ this.percent = this.amount = 0;
+ this.error = "";
+ this.refreshNow = false;
+ }
+ }
+
+ public boolean isHitting() {
+ return hitting;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setAmount(int amount) {
+ this.amount = amount;
+ }
+
+ public int getAmount() {
+ return amount;
+ }
+
+ public void setPercent(int percent) {
+ this.percent = percent;
+ }
+
+ public int getPercent() {
+ return percent;
+ }
+
+ public void setError(String err) {
+ this.error = err;
+ }
+
+ public String getError() {
+ if(error == null) error = "";
+ return error;
+ }
+
+ public String toString() {
+ return location;
+ }
+
+ public List getBackLog() {
+ if(backLog == null || backLog.isEmpty()) {
+ backLog = new ArrayList();
+ } else {
+ for(Iterator iter = currentItems.iterator(); iter.hasNext(); ) backLog.remove(iter.next());
+ }
+ return backLog;
+ }
+
+ public int getPrevBackLogSize() {
+ return prevBackLogSize;
+ }
+
+ public void setPrevBackLogSize(int prevBackLogSize) {
+ this.prevBackLogSize = prevBackLogSize;
+ }
+
+ public long getLastModifed() {
+ return lastModifed;
+ }
+
+ public void setLastModifed(long lastModifed) {
+ this.lastModifed = lastModifed;
+ }
+
+ public String getLastEtag() {
+ return lastEtag;
+ }
+
+ public void setLastEtag(String lastEtag) {
+ this.lastEtag = lastEtag;
+ }
+
+ public boolean equals(Object o) {
+ if(this == o) return true;
+ if(!(o instanceof UrlBean)) return false;
+ final UrlBean urlBean = (UrlBean)o;
+ if(urlId != urlBean.urlId) return false;
+ return true;
+ }
+
+ public int hashCode() {
+ return (int)(urlId ^ (urlId >>> 32));
+ }
+
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/UrlTableItem.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/UrlTableItem.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/UrlTableItem.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,100 @@
+/*
+ * 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.widgets.*;
+import org.eclipse.swt.SWT;
+
+public class UrlTableItem extends TableItem {
+
+ private Table parent;
+ private Config config;
+ private UrlBean data;
+
+ public UrlTableItem(Table parent, Config config) {
+ super(parent, SWT.NULL);
+ this.parent = parent;
+ this.config = config;
+ }
+
+ public void checkSubclass() {
+ return;
+ }
+
+ public UrlBean getBean() {
+ return data;
+ }
+
+ public void setBean(int index) {
+ this.data = config.getUrl(index);
+
+ update();
+ }
+
+ public void setBean(UrlBean data) {
+ if(this.data == null) config.addUrl(data);
+ else config.setUrl(config.getUrlIndex(this.data), data);
+ this.data = data;
+
+ update();
+ }
+
+ public void setup(View view) {
+ view.urlName.setText(data.getName());
+ view.urlLocation.setText(data.getLocation());
+ view.urlStoreDir.setText(data.getStoreDir());
+ view.urlDelay.setText(Integer.toString(data.getDelay()));
+ view.urlObeyTTL.setSelection(data.getObeyTTL());
+ view.urlLocRef.setSelection(data.getLocRef());
+ view.urlReferer.setText(data.getReferer());
+ view.urlUseCookie.setSelection(data.getUseCookie());
+ view.urlCookie.setText(data.getCookie());
+ view.urlEnabled.setSelection(data.isEnabled());
+
+ view.urlParamShow();
+ }
+
+ public void save(View view) {
+ data.setName(view.urlName.getText());
+ data.setLocation(view.urlLocation.getText());
+ data.setStoreDir(view.urlStoreDir.getText());
+ data.setDelay(Integer.parseInt(view.urlDelay.getText()));
+ data.setObeyTTL(view.urlObeyTTL.getSelection());
+ data.setLocRef(view.urlLocRef.getSelection());
+ data.setReferer(view.urlReferer.getText());
+ data.setUseCookie(view.urlUseCookie.getSelection());
+ data.setCookie(view.urlCookie.getText());
+ data.setEnabled(view.urlEnabled.getSelection());
+
+ view.urlDelay.setText(String.valueOf(data.getDelay()));
+ update();
+ }
+
+ public void update() {
+ setChecked(data.isEnabled());
+ setText(0, data.getName());
+ }
+
+ public void remove() {
+ config.removeUrl(data);
+ parent.remove(parent.indexOf(this));
+ data.getGroup().remove();
+ }
+}
Added: plugins/rssfeed/org/kmallan/azureus/rssfeed/View.java
===================================================================
--- plugins/rssfeed/org/kmallan/azureus/rssfeed/View.java (rev 0)
+++ plugins/rssfeed/org/kmallan/azureus/rssfeed/View.java 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,1744 @@
+/*
+ * 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.SWT;
+import org.eclipse.swt.custom.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+import org.gudy.azureus2.core3.config.*;
+import org.gudy.azureus2.core3.internat.MessageText;
+import org.gudy.azureus2.core3.util.Constants;
+import org.gudy.azureus2.plugins.*;
+import org.gudy.azureus2.plugins.download.Download;
+import org.gudy.azureus2.plugins.torrent.Torrent;
+import org.gudy.azureus2.ui.swt.*;
+
+import java.io.*;
+import java.util.Timer;
+
+public class View implements MouseListener, SelectionListener, MenuListener, ModifyListener,
+ Listener, ParameterListener {
+
+ private PluginInterface pluginInterface;
+ public Config rssfeedConfig;
+ private Scheduler scheduler;
+ private Timer timer;
+ public Display display;
+ public Shell shell;
+
+ public TorrentDownloader torrentDownloader;
+
+ private CTabFolder tabFolder;
+ private CTabItem tabStatus, tabOptions, tabHist, tabHelp;
+ private Composite status, options, history, help;
+ public Label reloadLabel;
+ public TableTree listTable;
+ public Table histTable;
+
+ public Composite optParamComp;
+ private ScrolledComposite optParamScrollComp;
+
+ public Composite filtParamComp, filtSpecificTVShow, filtSpecificOther, filtSpecificNone;
+ public Table filtTable;
+ private ToolItem btnFiltUp, btnFiltAdd, btnFiltRemove, btnFiltDown;
+ private Button btnFiltStoreDir, btnFiltAccept, btnFiltReset, btnFiltCancel;
+
+ public Composite urlParamComp, urlOptCompCustReferer, urlOptCompCookie, urlOptCompNone;
+ public Table urlTable;
+ public Text urlStoreDir, urlDelay, urlReferer, urlCookie;
+ private ToolItem btnUrlUp, btnUrlAdd, btnUrlRemove, btnUrlDown;
+ private Button btnUrlAccept, btnUrlReset, btnUrlCancel;
+ public Button btnUrlStoreDir, urlObeyTTL, urlLocRef, urlUseCookie;
+
+ public Composite filtRatesCustom, filtRatesNone;
+ public Text filtName, filtStoreDir, filtExpression, filtRateUpload, filtRateDownload, filtCategory, filtStartSeason, filtStartEpisode, filtEndSeason, filtEndEpisode, filtTestMatch;
+ public Button filtIsRegex, filtMatchTitle, filtMatchLink, filtMoveTop, filtRateUseCustom, filtRename, filtRenameEppTitle, filtDisable, filtCleanup, filtEnabled, filtSmartHist;
+ public Combo filtState, filtPriority, filtType, filtMode, filtFeed;
+
+ public Text urlName, urlLocation;
+ public Button urlEnabled;
+
+ private UrlTableItem selUrlItem = null;
+ private FilterTableItem selFilterItem = null;
+ private ListTreeItem selListItem = null;
+
+ public Button btnFiltTest, btnConfigAccept, btnConfigReset, configRenEpisodeWCEnabled, configRenEpisodeFLEnabled, configRenTitleWCEnabled, configRenTitleFLEnabled, configRenKeepTitle, configRenKeepLink, configRenKeepFileName, configRenPrefsTitle, configRenPrefsLink, configRenPrefsFileName, configEnabled;
+ public Text configCleanup, configRenEpisodeWCIgnore, configRenTitleWCIgnore, configRenSeperator, configDelay;
+ public Combo configRenEppIndicator;
+
+ private Menu histTableMenu, listTableMenu;
+ private MenuItem itemCopyFile, itemCopyTorrent, itemDelete;
+ private MenuItem itemRefresh, itemRefreshAll, itemDownload, itemDownloadTo, itemCancel, itemCreateFilter, itemCopyLink, itemOpenLink, itemShowInfo;
+ private MenuItem itemExpandAll, itemCollapseAll;
+
+ public TreeViewManager treeViewManager;
+
+ private Help helpPanel;
+
+ private boolean isOpen = false;
+
+ public boolean isOpen() { return isOpen; }
+
+ private final View thisView;
+
+ public View(PluginInterface pluginInterface, Config rssfeedConfig) {
+ this.pluginInterface = pluginInterface;
+ this.rssfeedConfig = rssfeedConfig;
+ this.treeViewManager = new TreeViewManager(this);
+ this.torrentDownloader = new TorrentDownloader(this, pluginInterface.getTorrentManager(), pluginInterface.getDownloadManager());
+
+ scheduler = new Scheduler();
+ timer = new Timer(true);
+ scheduler.setView(this);
+ timer.schedule(scheduler, 100L, 1000L);
+
+ thisView = this;
+ }
+
+ public void finalize() {
+ Plugin.debugOut("Killing RSSFeed");
+ timer.cancel();
+ }
+
+ public String getPluginViewName() {
+ return MessageText.getString("RSSFeed.Name");
+ }
+
+ public String getFullTitle() {
+ if(helpPanel != null && !helpPanel.isDisposed())
+ try {
+ helpPanel.load();
+ } catch(Exception e) {
+ System.err.println("Unable to load help contents: " + e);
+ }
+ return MessageText.getString("RSSFeed.Title");
+ }
+
+ private GridLayout setupGridLayout(int nc, int hs, int vs, int mh, int mw) {
+ GridLayout layout = new GridLayout();
+ if(nc != -1) layout.numColumns = nc;
+ if(hs != -1) layout.horizontalSpacing = hs;
+ if(vs != -1) layout.verticalSpacing = vs;
+ if(mh != -1) layout.marginHeight = mh;
+ if(mw != -1) layout.marginWidth = mw;
+ return layout;
+ }
+
+ private Composite setupComposite(Composite parent, GridLayout layout, int gdsStyle) {
+ return setupComposite(parent, SWT.NULL, layout, gdsStyle);
+ }
+
+ private Composite setupComposite(Composite parent, int i, GridLayout layout, int gdsStyle) {
+ Composite cmp = new Composite(parent, i);
+ cmp.setLayout(layout);
+ cmp.setLayoutData(gdsStyle == -1?new GridData():new GridData(gdsStyle));
+ return cmp;
+ }
+
+ private ToolItem setupToolItem(ToolBar parent, String icon) {
+ ToolItem ti = new ToolItem(parent, SWT.PUSH);
+ ti.setImage(getImage("/org/kmallan/resource/icons/" + icon));
+ ti.addListener(SWT.Selection, this);
+ return ti;
+ }
+
+ private Button setupBtn(Composite parent, String text) {
+ Button btn = new Button(parent, SWT.PUSH);
+ Messages.setLanguageText(btn, text);
+ btn.addListener(SWT.Selection, this);
+ return btn;
+ }
+
+ private Label setupBoldLabel(Composite parent, String text, int gdsStyle) {
+ Label label = new Label(parent, SWT.NULL);
+ if(gdsStyle != -1) label.setLayoutData(new GridData(gdsStyle));
+ Messages.setLanguageText(label, text);
+ FontData[] curFontDataFilter = label.getFont().getFontData();
+ curFontDataFilter[0].setStyle(SWT.BOLD);
+ curFontDataFilter[0].setHeight((int)(curFontDataFilter[0].getHeight() * 1.2));
+ label.setFont(new Font((Device)display, curFontDataFilter));
+ return label;
+ }
+
+ private Label setupLabel(Composite parent, String text, int wh) {
+ Label lbl = new Label(parent, SWT.NULL);
+ GridData layoutData = new GridData();
+ layoutData.widthHint = wh;
+ lbl.setLayoutData(layoutData);
+ Messages.setLanguageText(lbl, text);
+ return lbl;
+ }
+
+ public void initialize(final Composite parent) {
+ GridLayout layout;
+ GridData layoutData;
+
+ this.display = parent.getDisplay();
+ this.shell = parent.getShell();
+
+ Composite tComp = setupComposite(parent, SWT.BORDER, setupGridLayout(-1, -1, -1, 3, 0), GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER);
+ tComp.setBackground(display.getSystemColor(SWT.COLOR_LIST_SELECTION));
+ tComp.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
+
+ Label tLabel = new Label(tComp, SWT.NULL);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER);
+ tLabel.setLayoutData(layoutData);
+ Messages.setLanguageText(tLabel, "RSSFeed.Title");
+
+ tLabel.setBackground(display.getSystemColor(SWT.COLOR_LIST_SELECTION));
+ tLabel.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
+ FontData[] curTLabel = tLabel.getFont().getFontData();
+ curTLabel[0].setStyle(SWT.BOLD);
+ curTLabel[0].setHeight((int)(curTLabel[0].getHeight() * 1.2));
+ tLabel.setFont(new Font((Device)display, curTLabel));
+
+ this.tabFolder = new CTabFolder(parent, SWT.FLAT);
+ tabFolder.setLayoutData(new GridData(GridData.FILL_BOTH));
+ try {
+ tabFolder.setMinimumCharacters(75);
+ } catch(NoSuchMethodError e) {/** < SWT 3.0M8 **/}
+ try {
+ tabFolder.setSelectionBackground(new Color[]{display.getSystemColor(SWT.COLOR_LIST_BACKGROUND),
+ display.getSystemColor(SWT.COLOR_LIST_BACKGROUND),
+ tabFolder.getBackground()},
+ new int[]{10, 90}, true);
+ } catch(NoSuchMethodError e) {/** < SWT 3.0M8 **/
+ tabFolder.setSelectionBackground(new Color[]{display.getSystemColor(SWT.COLOR_LIST_BACKGROUND)}, new int[0]);
+ }
+ tabFolder.setSelectionForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+ try {
+ tabFolder.setSimple(!COConfigurationManager.getBooleanParameter("GUI_SWT_bFancyTab"));
+ } catch(NoSuchMethodError e) {/** < SWT 3.0M8 **/}
+ COConfigurationManager.addParameterListener("GUI_SWT_bFancyTab", this);
+
+ this.tabStatus = new CTabItem(tabFolder, SWT.NULL);
+ Messages.setLanguageText(tabStatus, "RSSFeed.Tab.Status");
+ this.tabOptions = new CTabItem(tabFolder, SWT.NULL);
+ Messages.setLanguageText(tabOptions, "RSSFeed.Tab.Options");
+ this.tabHist = new CTabItem(tabFolder, SWT.NULL);
+ Messages.setLanguageText(tabHist, "RSSFeed.Tab.History");
+ this.tabHelp = new CTabItem(tabFolder, SWT.NULL);
+ Messages.setLanguageText(tabHelp, "RSSFeed.Tab.Help");
+ tabFolder.setSelection(tabStatus);
+
+ // Options Folder
+ this.options = setupComposite(tabFolder, setupGridLayout(2, -1, -1, -1, -1), GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
+ tabOptions.setControl(options);
+
+ // Options Folder - Tables
+ ScrolledComposite optValTblScrollComp = new ScrolledComposite(options, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
+ layout = new GridLayout();
+ layoutData = new GridData(GridData.FILL_VERTICAL);
+ layoutData.widthHint = 380;
+ optValTblScrollComp.setLayout(layout);
+ optValTblScrollComp.setLayoutData(layoutData);
+ optValTblScrollComp.setExpandHorizontal(true);
+ optValTblScrollComp.setExpandVertical(true);
+
+ Composite optValTblComp = setupComposite(optValTblScrollComp, setupGridLayout(1, 0, 0, 0, 0), GridData.FILL_BOTH);
+ optValTblScrollComp.setContent(optValTblComp);
+
+ // Options Folder - RSS Feed URLs Table
+ setupBoldLabel(optValTblComp, "RSSFeed.Options.Feed.Title", GridData.VERTICAL_ALIGN_BEGINNING | GridData.FILL_HORIZONTAL);
+ Composite urlComp = setupComposite(optValTblComp, setupGridLayout(2, 0, 0, 0, 0), GridData.FILL_HORIZONTAL);
+ urlTable = new Table(urlComp, SWT.CHECK | SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ layoutData.heightHint = 130;
+ urlTable.setLayoutData(layoutData);
+ urlTable.setHeaderVisible(true);
+
+ String urlColumnNames = "RSSFeed.Options.Feed.Table.Col";
+ int[] urlColumnWidths = {320};
+ for(int i = 0; i < urlColumnWidths.length; i++) {
+ TableColumn column = new TableColumn(urlTable, SWT.NULL);
+ Messages.setLanguageText(column, urlColumnNames + i);
+ column.setWidth(urlColumnWidths[i]);
+ }
+ urlTable.addMouseListener(this);
+
+ ToolBar urlCompBar = new ToolBar(urlComp, SWT.FLAT | SWT.VERTICAL);
+ btnUrlUp = setupToolItem(urlCompBar, "ItemMoveUp.gif");
+ btnUrlAdd = setupToolItem(urlCompBar, "ItemAdd.gif");
+ btnUrlRemove = setupToolItem(urlCompBar, "ItemRemove.gif");
+ btnUrlDown = setupToolItem(urlCompBar, "ItemMoveDown.gif");
+
+ // Options Folder - Filters Table
+ setupBoldLabel(optValTblComp, "RSSFeed.Options.Filter.Title", GridData.VERTICAL_ALIGN_BEGINNING | GridData.FILL_HORIZONTAL);
+
+ Composite filtComp = setupComposite(optValTblComp, setupGridLayout(2, 0, 0, 0, 0), GridData.FILL_VERTICAL | GridData.FILL_HORIZONTAL);
+ filtTable = new Table(filtComp, SWT.CHECK | SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
+ layoutData = new GridData(GridData.FILL_VERTICAL | GridData.FILL_HORIZONTAL);
+ filtTable.setLayoutData(layoutData);
+ filtTable.setHeaderVisible(true);
+
+ String filtColumnNames = "RSSFeed.Options.Filter.Table.Col";
+ int[] filtColumnWidths = {195, 65, 60};
+ for(int i = 0; i < filtColumnWidths.length; i++) {
+ TableColumn column = new TableColumn(filtTable, SWT.NULL);
+ Messages.setLanguageText(column, filtColumnNames + i);
+ column.setWidth(filtColumnWidths[i]);
+ }
+ filtTable.addMouseListener(this);
+
+ ToolBar filtCompBar = new ToolBar(filtComp, SWT.FLAT | SWT.VERTICAL);
+ btnFiltUp = setupToolItem(filtCompBar, "ItemMoveUp.gif");
+ btnFiltAdd = setupToolItem(filtCompBar, "ItemAdd.gif");
+ btnFiltRemove = setupToolItem(filtCompBar, "ItemRemove.gif");
+ btnFiltDown = setupToolItem(filtCompBar, "ItemMoveDown.gif");
+
+ optValTblScrollComp.setMinSize(optValTblComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+
+ // Options Folder - Params
+ optParamScrollComp = new ScrolledComposite(options, SWT.V_SCROLL | SWT.BORDER);
+ layout = new GridLayout();
+ layoutData = new GridData(GridData.FILL_BOTH);
+ optParamScrollComp.setLayout(layout);
+ optParamScrollComp.setLayoutData(layoutData);
+ optParamScrollComp.setExpandHorizontal(true);
+ optParamScrollComp.setExpandVertical(true);
+
+ optParamComp = setupComposite(optParamScrollComp, setupGridLayout(1, 0, 0, 0, 0), GridData.FILL_BOTH);
+ optParamScrollComp.setContent(optParamComp);
+
+ setupBoldLabel(optParamComp, "RSSFeed.Options.Title", -1);
+
+ // Options Folder - URL Params
+ urlParamComp = setupComposite(optParamComp, setupGridLayout(2, 5, 3, 5, 5), GridData.FILL_BOTH);
+ setupLabel(urlParamComp, "RSSFeed.Options.Feed.urlName", 75);
+ (urlName = new Text(urlParamComp, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ setupLabel(urlParamComp, "RSSFeed.Options.Feed.urlLocation", 75);
+ (urlLocation = new Text(urlParamComp, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ Messages.setLanguageText(new Label(urlParamComp, SWT.NULL), "RSSFeed.Options.Feed.urlStoreDir");
+ Composite urlStoreDirComp = setupComposite(urlParamComp, setupGridLayout(2, 0, 0, 0, 0), GridData.FILL_HORIZONTAL);
+ (urlStoreDir = new Text(urlStoreDirComp, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ btnUrlStoreDir = new Button(urlStoreDirComp, SWT.PUSH);
+ layoutData = new GridData();
+ layoutData.widthHint = 52;
+ layoutData.heightHint = 28;
+ btnUrlStoreDir.setLayoutData(layoutData);
+ btnUrlStoreDir.setText("...");
+ btnUrlStoreDir.addListener(SWT.Selection, this);
+
+ Messages.setLanguageText(new Label(urlParamComp, SWT.NULL), "RSSFeed.Options.Feed.urlDelay");
+ (urlDelay = new Text(urlParamComp, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ Messages.setLanguageText(new Label(urlParamComp, SWT.NULL), "RSSFeed.Options.Feed.Options");
+
+ Composite urlParamCompOpt = setupComposite(urlParamComp, setupGridLayout(4, 5, 0, 0, 0), -1);
+
+ urlObeyTTL = new Button(urlParamCompOpt, SWT.CHECK);
+ Messages.setLanguageText(urlObeyTTL, "RSSFeed.Options.Feed.urlObeyTTL");
+ urlLocRef = new Button(urlParamCompOpt, SWT.CHECK);
+ Messages.setLanguageText(urlLocRef, "RSSFeed.Options.Feed.urlLocRef");
+ urlLocRef.addListener(SWT.Selection, this);
+ urlUseCookie = new Button(urlParamCompOpt, SWT.CHECK);
+ Messages.setLanguageText(urlUseCookie, "RSSFeed.Options.Feed.urlUseCookie");
+ urlUseCookie.addListener(SWT.Selection, this);
+
+ Composite urlOptComp = new Composite(urlParamComp, SWT.NULL);
+ layout = setupGridLayout(1, 0, 0, 0, 0);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ layoutData.horizontalSpan = 2;
+ urlOptComp.setLayout(layout);
+ urlOptComp.setLayoutData(layoutData);
+
+ // Options Folder - URL Params - Options - Cust Referer
+ urlOptCompCustReferer = setupComposite(urlOptComp, setupGridLayout(3, 0, 0, 0, 0), GridData.FILL_HORIZONTAL);
+ (layoutData = new GridData()).widthHint = 35;
+ (new Label(urlOptCompCustReferer, SWT.NULL)).setLayoutData(layoutData);
+ setupLabel(urlOptCompCustReferer, "RSSFeed.Options.Feed.urlReferer", 100);
+ (urlReferer = new Text(urlOptCompCustReferer, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ // Options Folder - URL Params - Options - Cookies
+ urlOptCompCookie = setupComposite(urlOptComp, setupGridLayout(3, 0, 0, 0, 0), GridData.FILL_HORIZONTAL);
+ (layoutData = new GridData()).widthHint = 35;
+ (new Label(urlOptCompCookie, SWT.NULL)).setLayoutData(layoutData);
+ setupLabel(urlOptCompCookie, "RSSFeed.Options.Feed.urlCookie", 100);
+ (urlCookie = new Text(urlOptCompCookie, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ // Options Folder - URL Params - Options - None
+ urlOptCompNone = new Composite(urlOptComp, SWT.NULL);
+ layout = setupGridLayout(1, 0, 0, 0, 0);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ layoutData.heightHint = 1;
+ urlOptCompNone.setLayout(layout);
+ urlOptCompNone.setLayoutData(layoutData);
+ new Label(urlOptCompNone, SWT.NULL);
+
+ // Options Folder - URL Params - End Options
+ urlChooseOptions();
+
+ Messages.setLanguageText(new Label(urlParamComp, SWT.NULL), "RSSFeed.Options.Feed.urlActive");
+ urlEnabled = new Button(urlParamComp, SWT.CHECK);
+ Messages.setLanguageText(urlEnabled, "RSSFeed.Options.Feed.urlEnabled");
+
+ new Label(urlParamComp, SWT.NULL);
+ Composite urlParamCompButt = setupComposite(urlParamComp, setupGridLayout(3, 5, 0, 0, 0), -1);
+
+ btnUrlAccept = setupBtn(urlParamCompButt, "RSSFeed.Options.Feed.btnUrlAccept");
+ btnUrlReset = setupBtn(urlParamCompButt, "RSSFeed.Options.Feed.btnUrlReset");
+ btnUrlCancel = setupBtn(urlParamCompButt, "RSSFeed.Options.Feed.btnUrlCancel");
+
+ // Options Folder - Filter Params
+ filtParamComp = setupComposite(optParamComp, setupGridLayout(2, 5, 3, 5, 5), GridData.FILL_BOTH);
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.filtName", 75);
+ (filtName = new Text(filtParamComp, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.filtStoreDir", 75);
+ Composite filtStoreDirComp = setupComposite(filtParamComp, setupGridLayout(2, 0, 0, 0, 0), GridData.FILL_HORIZONTAL);
+ (filtStoreDir = new Text(filtStoreDirComp, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ btnFiltStoreDir = new Button(filtStoreDirComp, SWT.PUSH);
+ layoutData = new GridData();
+ layoutData.widthHint = 52;
+ layoutData.heightHint = 28;
+ btnFiltStoreDir.setLayoutData(layoutData);
+ btnFiltStoreDir.setText("...");
+ btnFiltStoreDir.addListener(SWT.Selection, this);
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.filtExpression", 75);
+ (filtExpression = new Text(filtParamComp, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.Options", 75);
+ Composite options = setupComposite(filtParamComp, setupGridLayout(2, 0, 0, 0, 0), -1);
+ filtIsRegex = new Button(options, SWT.CHECK);
+ Messages.setLanguageText(filtIsRegex, "RSSFeed.Options.Filter.Options.filtIsRegex");
+ layoutData = new GridData();
+ layoutData.horizontalSpan = 2;
+ filtIsRegex.setLayoutData(layoutData);
+ filtMatchTitle = new Button(options, SWT.CHECK);
+ Messages.setLanguageText(filtMatchTitle, "RSSFeed.Options.Filter.Options.filtMatch.Title");
+ filtMatchLink = new Button(options, SWT.CHECK);
+ Messages.setLanguageText(filtMatchLink, "RSSFeed.Options.Filter.Options.filtMatch.Link");
+ filtMoveTop = new Button(options, SWT.CHECK);
+ Messages.setLanguageText(filtMoveTop, "RSSFeed.Options.Filter.Options.MoveTop");
+ layoutData = new GridData();
+ layoutData.horizontalSpan = 2;
+ filtMoveTop.setLayoutData(layoutData);
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.State", 75);
+ filtState = new Combo(filtParamComp, SWT.DROP_DOWN | SWT.READ_ONLY);
+ layoutData = new GridData();
+ layoutData.widthHint = 200;
+ filtState.setLayoutData(layoutData);
+ filtState.add(MessageText.getString("RSSFeed.Options.Filter.State.Queued"));
+ filtState.add(MessageText.getString("RSSFeed.Options.Filter.State.Forced"));
+ filtState.add(MessageText.getString("RSSFeed.Options.Filter.State.Stopped"));
+ filtState.select(0);
+
+ if(Constants.compareVersions(Constants.getBaseVersion(), "2.2.0.0") < 0) {
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.Priority", 75);
+ filtPriority = new Combo(filtParamComp, SWT.DROP_DOWN | SWT.READ_ONLY);
+ layoutData = new GridData();
+ layoutData.widthHint = 200;
+ filtPriority.setLayoutData(layoutData);
+ filtPriority.add(MessageText.getString("RSSFeed.Options.Filter.Priority.High"));
+ filtPriority.add(MessageText.getString("RSSFeed.Options.Filter.Priority.Low"));
+ filtPriority.select(0);
+ }
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.Rates", 75);
+ filtRateUseCustom = new Button(filtParamComp, SWT.CHECK);
+ Messages.setLanguageText(filtRateUseCustom, "RSSFeed.Options.Filter.Rates.UseCustom");
+ filtRateUseCustom.addListener(SWT.Selection, this);
+
+ Composite filtRatesComp = new Composite(filtParamComp, SWT.NULL);
+ layout = setupGridLayout(1, 0, 0, 0, 0);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ layoutData.horizontalSpan = 2;
+ filtRatesComp.setLayout(layout);
+ filtRatesComp.setLayoutData(layoutData);
+
+ // Options Folder - Filter Params - Rates - Custom
+ filtRatesCustom = setupComposite(filtRatesComp, setupGridLayout(3, 0, 0, 0, 0), GridData.FILL_HORIZONTAL);
+
+ (layoutData = new GridData()).widthHint = 35;
+ (new Label(filtRatesCustom, SWT.NULL)).setLayoutData(layoutData);
+ setupLabel(filtRatesCustom, "RSSFeed.Options.Filter.Rates.Upload", 135);
+ (filtRateUpload = new Text(filtRatesCustom, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ (layoutData = new GridData()).widthHint = 35;
+ (new Label(filtRatesCustom, SWT.NULL)).setLayoutData(layoutData);
+ setupLabel(filtRatesCustom, "RSSFeed.Options.Filter.Rates.Download", 135);
+ (filtRateDownload = new Text(filtRatesCustom, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ // Options Folder - Filter Params - Rates - None
+ filtRatesNone = new Composite(filtRatesComp, SWT.NULL);
+ layout = setupGridLayout(1, 0, 0, 0, 0);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ layoutData.heightHint = 1;
+ filtRatesNone.setLayout(layout);
+ filtRatesNone.setLayoutData(layoutData);
+ new Label(urlOptCompNone, SWT.NULL);
+
+ // Options Folder - Filter Params - End Rates
+ urlSetRates();
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.filtCategory", 75);
+ (filtCategory = new Text(filtParamComp, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.filtFeed", 75);
+ filtFeed = new Combo(filtParamComp, SWT.DROP_DOWN | SWT.READ_ONLY);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ filtFeed.setLayoutData(layoutData);
+ filtFeed.add(MessageText.getString("RSSFeed.Options.Filter.filtFeed.All"));
+ filtFeed.select(0);
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.filtType", 75);
+ filtType = new Combo(filtParamComp, SWT.DROP_DOWN | SWT.READ_ONLY);
+ layoutData = new GridData();
+ layoutData.widthHint = 200;
+ filtType.setLayoutData(layoutData);
+ filtType.add(MessageText.getString("RSSFeed.Options.Filter.filtType.TVShow"));
+ filtType.add(MessageText.getString("RSSFeed.Options.Filter.filtType.Other"));
+ filtType.add(MessageText.getString("RSSFeed.Options.Filter.filtType.None"));
+ filtType.select(0);
+ filtType.addModifyListener(this);
+
+ Composite filtSpecific = new Composite(filtParamComp, SWT.NULL);
+ layout = setupGridLayout(1, 0, 0, 0, 0);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ layoutData.horizontalSpan = 2;
+ filtSpecific.setLayout(layout);
+ filtSpecific.setLayoutData(layoutData);
+
+ // Options Folder - Filter Params - TVShow Specific
+ filtSpecificTVShow = setupComposite(filtSpecific, setupGridLayout(3, 0, 0, 0, 0), GridData.FILL_HORIZONTAL);
+
+ (layoutData = new GridData()).widthHint = 35;
+ (new Label(filtSpecificTVShow, SWT.NULL)).setLayoutData(layoutData);
+ setupLabel(filtSpecificTVShow, "RSSFeed.Options.Filter.TVShow.filtStart", 75);
+ Composite season = setupComposite(filtSpecificTVShow, setupGridLayout(4, 5, 0, 0, 0), -1);
+
+ Messages.setLanguageText(new Label(season, SWT.NULL), "RSSFeed.Options.Filter.TVShow.filtStart.Season");
+ layoutData = new GridData();
+ layoutData.widthHint = 24;
+ (filtStartSeason = new Text(season, SWT.BORDER)).setLayoutData(layoutData);
+ Messages.setLanguageText(new Label(season, SWT.NULL), "RSSFeed.Options.Filter.TVShow.filtStart.Episode");
+ layoutData = new GridData();
+ layoutData.widthHint = 24;
+ (filtStartEpisode = new Text(season, SWT.BORDER)).setLayoutData(layoutData);
+
+ (layoutData = new GridData()).widthHint = 35;
+ (new Label(filtSpecificTVShow, SWT.NULL)).setLayoutData(layoutData);
+ setupLabel(filtSpecificTVShow, "RSSFeed.Options.Filter.TVShow.filtEnd", 75);
+ season = setupComposite(filtSpecificTVShow, setupGridLayout(4, 5, 0, 0, 0), -1);
+
+ Messages.setLanguageText(new Label(season, SWT.NULL), "RSSFeed.Options.Filter.TVShow.filtEnd.Season");
+ layoutData = new GridData();
+ layoutData.widthHint = 24;
+ (filtEndSeason = new Text(season, SWT.BORDER)).setLayoutData(layoutData);
+ Messages.setLanguageText(new Label(season, SWT.NULL), "RSSFeed.Options.Filter.TVShow.filtEnd.Episode");
+ layoutData = new GridData();
+ layoutData.widthHint = 24;
+ (filtEndEpisode = new Text(season, SWT.BORDER)).setLayoutData(layoutData);
+
+ (layoutData = new GridData()).widthHint = 35;
+ (new Label(filtSpecificTVShow, SWT.NULL)).setLayoutData(layoutData);
+ setupLabel(filtSpecificTVShow, "RSSFeed.Options.Filter.TVShow.Options", 75);
+ filtSmartHist = new Button(filtSpecificTVShow, SWT.CHECK);
+ Messages.setLanguageText(filtSmartHist, "RSSFeed.Options.Filter.TVShow.Options.SmartHist");
+
+ // Options Folder - Filter Params - Other Specific
+ filtSpecificOther = setupComposite(filtSpecific, setupGridLayout(3, 0, 0, 0, 0), GridData.FILL_HORIZONTAL);
+ (layoutData = new GridData()).widthHint = 35;
+ (new Label(filtSpecificOther, SWT.NULL)).setLayoutData(layoutData);
+ setupLabel(filtSpecificOther, "RSSFeed.Options.Filter.Other.Options", 75);
+ filtDisable = new Button(filtSpecificOther, SWT.CHECK);
+ Messages.setLanguageText(filtDisable, "RSSFeed.Options.Filter.Other.Options.Disable");
+
+ // Options Folder - Filter Params - None Specific
+ filtSpecificNone = new Composite(filtSpecific, SWT.NULL);
+ layout = setupGridLayout(1, 0, 0, 0, 0);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ layoutData.heightHint = 1;
+ filtSpecificNone.setLayout(layout);
+ filtSpecificNone.setLayoutData(layoutData);
+ new Label(filtSpecificNone, SWT.NULL);
+
+ // Options Folder - Filter Params - End Specific
+ filtChooseSpecific(filtType.getSelectionIndex());
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.filtActive", 75);
+ filtEnabled = new Button(filtParamComp, SWT.CHECK);
+ Messages.setLanguageText(filtEnabled, "RSSFeed.Options.Filter.filtEnabled");
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.filtMode", 75);
+ filtMode = new Combo(filtParamComp, SWT.DROP_DOWN | SWT.READ_ONLY);
+ layoutData = new GridData();
+ layoutData.widthHint = 200;
+ filtMode.setLayoutData(layoutData);
+ filtMode.add(MessageText.getString("RSSFeed.Options.Filter.filtMode.Pass"));
+ filtMode.add(MessageText.getString("RSSFeed.Options.Filter.filtMode.Fail"));
+ filtMode.select(0);
+
+ setupLabel(filtParamComp, "RSSFeed.Options.Filter.filtTestMatch", 75);
+ (filtTestMatch = new Text(filtParamComp, SWT.BORDER)).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ new Label(filtParamComp, SWT.NULL);
+ Composite filtParamCompButt = setupComposite(filtParamComp, setupGridLayout(4, 5, 0, 0, 0), -1);
+
+ btnFiltAccept = setupBtn(filtParamCompButt, "RSSFeed.Options.Filter.btnFiltAccept");
+ btnFiltReset = setupBtn(filtParamCompButt, "RSSFeed.Options.Filter.btnFiltReset");
+ btnFiltCancel = setupBtn(filtParamCompButt, "RSSFeed.Options.Filter.btnFiltCancel");
+ btnFiltTest = setupBtn(filtParamCompButt, "RSSFeed.Options.Filter.btnFiltTest");
+
+ optParamScrollComp.setMinSize(optParamComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+
+ // History
+ this.history = setupComposite(tabFolder, setupGridLayout(1, -1, -1, -1, -1), GridData.FILL_BOTH);
+ tabHist.setControl(history);
+
+ histTable = new Table(history, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);
+ layoutData = new GridData(GridData.FILL_BOTH);
+ histTable.setLayoutData(layoutData);
+ histTable.setHeaderVisible(true);
+ histTableMenu = setupHistMenu(shell);
+ histTable.setMenu(histTableMenu);
+
+ String histColumnNames = "RSSFeed.Hist.HistTable.Col";
+ int[] histColumnWidths = {120, 300, 300, 160};
+ for(int i = 0; i < histColumnWidths.length; i++) {
+ TableColumn column = new TableColumn(histTable, SWT.NULL);
+ Messages.setLanguageText(column, histColumnNames + i);
+ column.setWidth(histColumnWidths[i]);
+ }
+
+ histTable.addMouseListener(this);
+
+ // Help
+ this.help = setupComposite(tabFolder, setupGridLayout(1, -1, -1, -1, -1), GridData.FILL_BOTH);
+ tabHelp.setControl(help);
+ helpPanel = new Help(help, SWT.VERTICAL);
+ layoutData = new GridData(GridData.FILL_BOTH);
+ helpPanel.setLayoutData(layoutData);
+
+ helpPanel.setEditable(false);
+ try {
+ helpPanel.load();
+ } catch(Exception e) {
+ System.err.println("Unable to load help contents:" + e);
+ }
+ getConfig();
+
+ // Status
+ this.status = setupComposite(tabFolder, setupGridLayout(1, -1, -1, -1, -1), GridData.FILL_BOTH);
+ tabStatus.setControl(status);
+
+
+ listTable = new TableTree(status, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
+ Table listTableTree = listTable.getTable();
+ listTableTree.setHeaderVisible(true);
+ listTableMenu = listMenu(shell);
+ listTableTree.setMenu(listTableMenu);
+
+ String columnNames = "RSSFeed.Status.ListTable.Col";
+ int[] columnWidths = {350, 450, 80, 100};
+ for(int i = 0; i < columnWidths.length; i++) {
+ TableColumn column = new TableColumn(listTableTree, SWT.NULL);
+ Messages.setLanguageText(column, columnNames + i);
+ column.setWidth(columnWidths[i]);
+ }
+
+ GridData gdTable = new GridData(GridData.FILL_BOTH);
+ listTable.setLayoutData(gdTable);
+
+ listTableTree.addMouseListener(this);
+ listTableTree.addSelectionListener(this);
+
+ treeViewManager.display();
+ tabFolder.pack();
+
+ selUrlItem = null;
+ selFilterItem = null;
+ paramHideAll();
+
+ urlTable.addSelectionListener(this);
+ filtTable.addSelectionListener(this);
+
+ isOpen = true;
+ }
+
+ public void delete() {
+ isOpen = false;
+ getComposite().dispose();
+ }
+
+ public void getConfig() {
+ UrlTableItem urlItem;
+ FilterTableItem filterItem;
+ HistoryTableItem histItem;
+
+ for(int i = 0; i < rssfeedConfig.getUrlCount(); i++) {
+ urlItem = new UrlTableItem(urlTable, rssfeedConfig);
+ urlItem.setBean(i);
+ }
+ Utils.alternateTableBackground(urlTable);
+
+ for(int i = 0; i < rssfeedConfig.getFilterCount(); i++) {
+ filterItem = new FilterTableItem(filtTable, rssfeedConfig);
+ filterItem.setBean(i);
+ }
+ Utils.alternateTableBackground(filtTable);
+
+ for(int i = 0; i < rssfeedConfig.getHistoryCount(); i++) {
+ histItem = new HistoryTableItem(histTable, rssfeedConfig, i);
+ histItem.setBean(i);
+ }
+ Utils.alternateTableBackground(histTable);
+ }
+
+ private void urlOrder(int move) {
+ urlOrder(move, true);
+ }
+
+ private void urlOrder(int move, boolean storeIt) {
+ if(urlTable == null || urlTable.isDisposed()) return;
+ if(urlTable.getSelectionCount() == 1) {
+ int curPos = urlTable.getSelectionIndex();
+ int newPos = curPos + move;
+ if((newPos >= 0) && (newPos < urlTable.getItemCount())) {
+ urlTable.setRedraw(false);
+ TableItem[] items = urlTable.getItems();
+ UrlTableItem curItem = (UrlTableItem)items[curPos];
+ UrlTableItem newItem = (UrlTableItem)items[newPos];
+ UrlBean tmpBean = curItem.getBean();
+ curItem.setBean(newItem.getBean());
+ newItem.setBean(tmpBean);
+ urlTable.setSelection(newPos);
+ selUrlItem = newItem;
+ urlTable.setRedraw(true);
+ }
+ }
+ if(storeIt) rssfeedConfig.storeOptions();
+ Utils.alternateTableBackground(urlTable);
+ }
+
+ private void urlAdd() {
+ urlTable.setRedraw(false);
+ UrlTableItem newItem = new UrlTableItem(urlTable, rssfeedConfig);
+ UrlBean tmpBean = new UrlBean();
+ tmpBean.setName("New Item");
+ newItem.setBean(tmpBean);
+ newItem.setup(thisView);
+ int newPos = urlTable.indexOf(newItem);
+ urlTable.setSelection(newPos);
+ urlTable.setRedraw(true);
+ selUrlItem = newItem;
+ rssfeedConfig.storeOptions();
+ Utils.alternateTableBackground(urlTable);
+ }
+
+ private void urlRemove() {
+ int curPos = urlTable.getSelectionIndex();
+ if(curPos >= 0) {
+ ((UrlTableItem)(urlTable.getItem(curPos))).remove();
+ }
+ urlParamHide();
+ rssfeedConfig.storeOptions();
+ Utils.alternateTableBackground(urlTable);
+ }
+
+ private void urlAccept() {
+ int curPos = urlTable.getSelectionIndex();
+ if(curPos >= 0) {
+ UrlTableItem urlItem = (UrlTableItem)urlTable.getItem(curPos);
+ urlItem.save(thisView);
+ treeViewManager.getItem(urlItem.getBean()).update();
+ }
+ rssfeedConfig.storeOptions();
+ }
+
+ private void urlReset() {
+ int curPos = urlTable.getSelectionIndex();
+ if(curPos >= 0) {
+ ((UrlTableItem)(urlTable.getItem(curPos))).setup(thisView);
+ }
+ }
+
+ private void urlCancel() {
+ urlParamHide();
+ }
+
+ private void filtOrder(int move) {
+ filtOrder(move, true);
+ }
+
+ private void filtOrder(int move, boolean storeIt) {
+ if(filtTable == null || filtTable.isDisposed()) return;
+ if(filtTable.getSelectionCount() == 1) {
+ int curPos = filtTable.getSelectionIndex();
+ int newPos = curPos + move;
+ if((newPos >= 0) && (newPos < filtTable.getItemCount())) {
+ filtTable.setRedraw(false);
+ TableItem[] items = filtTable.getItems();
+ FilterTableItem curItem = (FilterTableItem)items[curPos];
+ FilterTableItem newItem = (FilterTableItem)items[newPos];
+ FilterBean tmpBean = curItem.getBean();
+ curItem.setBean(newItem.getBean());
+ newItem.setBean(tmpBean);
+ filtTable.setSelection(newPos);
+ selFilterItem = newItem;
+ filtTable.setRedraw(true);
+ }
+ }
+ if(storeIt) rssfeedConfig.storeOptions();
+ Utils.alternateTableBackground(filtTable);
+ }
+
+ private void filtAdd() {
+ filtTable.setRedraw(false);
+ FilterTableItem newItem = new FilterTableItem(filtTable, rssfeedConfig);
+ FilterBean tmpBean = new FilterBean();
+ tmpBean.setName("New Item");
+ tmpBean.setType("TVShow");
+ tmpBean.setMode("Pass");
+ tmpBean.setMatchLink(true);
+ tmpBean.setMatchTitle(true);
+ newItem.setBean(tmpBean);
+ newItem.setup(thisView);
+ int curPos = filtTable.getSelectionIndex();
+ if(curPos >= 0) {
+ int topPos = filtTable.getTopIndex();
+ int newPos = filtTable.indexOf(newItem);
+ filtTable.setSelection(newPos);
+ for(int iLoop = 1; iLoop <= newPos - curPos; ++iLoop) filtOrder(-1, false);
+ filtTable.setTopIndex(topPos);
+ } else {
+ int newPos = filtTable.indexOf(newItem);
+ filtTable.setSelection(newPos);
+ }
+ filtTable.setRedraw(true);
+ selFilterItem = newItem;
+ rssfeedConfig.storeOptions();
+ Utils.alternateTableBackground(filtTable);
+ }
+
+ private void filtRemove() {
+ int curPos = filtTable.getSelectionIndex();
+ if(curPos >= 0) {
+ ((FilterTableItem)(filtTable.getItem(curPos))).remove();
+ }
+ filtParamHide();
+ rssfeedConfig.storeOptions();
+ Utils.alternateTableBackground(filtTable);
+ }
+
+ private void filtAccept() {
+ int curPos = filtTable.getSelectionIndex();
+ if(curPos >= 0) {
+ ((FilterTableItem)(filtTable.getItem(curPos))).save(thisView);
+ }
+ rssfeedConfig.storeOptions();
+ }
+
+ private void filtReset() {
+ int curPos = filtTable.getSelectionIndex();
+ if(curPos >= 0) {
+ ((FilterTableItem)(filtTable.getItem(curPos))).setup(thisView);
+ }
+ }
+
+ private void filtCancel() {
+ filtParamHide();
+ }
+
+ private void filtTest() {
+ String testStr = filtTestMatch.getText();
+ if(testStr != null) {
+ testStr = testStr.toLowerCase();
+ boolean match = FilterTableItem.save(null, thisView).matches(0, testStr, testStr);
+ Color green = display.getSystemColor(SWT.COLOR_GREEN);
+ Color red = display.getSystemColor(SWT.COLOR_RED);
+ filtTestMatch.setBackground(match?green:red);
+ }
+ }
+
+ public void histAdd(ListBean listBean, Download download, File file) {
+ histAdd(listBean, download, file, null);
+ }
+
+ public void histAdd(ListBean listBean, Download download, File file, FilterBean filter) {
+ String path = file.getPath();
+ if(file.isDirectory()) {
+ if(path.length() > 0 && !path.endsWith(rssfeedConfig.separator)) path = path + rssfeedConfig.separator;
+ path += download.getName();
+ }
+
+ HistoryBean tmpBean = new HistoryBean();
+ tmpBean.setFileData(path);
+ tmpBean.setLocation(listBean.getLocation());
+
+ if(filter != null) {
+ tmpBean.setFilter(filter);
+ if("TVShow".equalsIgnoreCase(filter.getType())) {
+ if(!tmpBean.setSeason(listBean.getName().toLowerCase())) tmpBean.setSeason(listBean.getName().toLowerCase());
+ }
+ } // else manual download
+
+ rssfeedConfig.addHistory(tmpBean);
+ rssfeedConfig.storeOptions();
+
+ final int histIndex = rssfeedConfig.getHistoryIndex(tmpBean);
+ if(display == null || display.isDisposed() || !isOpen) return;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ HistoryTableItem newItem = new HistoryTableItem(histTable, rssfeedConfig, histIndex);
+ newItem.setBean(histIndex);
+ Utils.alternateTableBackground(histTable);
+ }
+ });
+ }
+
+ private void histRemove() {
+ TableItem[] items = histTable.getSelection();
+ for(int iLoop = 0; iLoop < items.length; iLoop++) {
+ ((HistoryTableItem)items[iLoop]).remove();
+ }
+ histTable.deselectAll();
+ rssfeedConfig.storeOptions();
+ Utils.alternateTableBackground(histTable);
+ }
+
+ private void updateStoreDirLoc(final Shell myShell, Text itemStoreDir) {
+ DirectoryDialog dDialog = new DirectoryDialog(myShell, SWT.SYSTEM_MODAL);
+ String default_path = "";
+ if(itemStoreDir.getText().length() > 0) {
+ default_path = itemStoreDir.getText();
+ } else if(COConfigurationManager.getBooleanParameter("Use default data dir", true)) {
+ default_path = COConfigurationManager.getStringParameter("Default save path", "");
+ }
+ if(default_path.length() > 0) {
+ dDialog.setFilterPath(default_path);
+ }
+ dDialog.setText(filtName.getText() + " - Save Location");
+ String savePath = dDialog.open();
+ if(savePath == null) return;
+ itemStoreDir.setText(savePath);
+ }
+
+ public void urlParamShow() {
+ filtParamHide();
+ urlChooseOptions();
+
+ if(urlParamComp.isVisible() == true) return;
+
+ GridData layoutData = new GridData(GridData.FILL_BOTH);
+ urlParamComp.setLayoutData(layoutData);
+ optParamScrollComp.setMinSize(optParamComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ optParamComp.layout(true);
+ urlParamComp.setVisible(true);
+ }
+
+ public void urlParamHide() {
+ if(urlParamComp.isVisible() == false) return;
+
+ urlParamComp.setVisible(false);
+ GridData layoutData = new GridData();
+ layoutData.heightHint = 0;
+ urlParamComp.setLayoutData(layoutData);
+ optParamScrollComp.setMinSize(optParamComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ optParamComp.layout(true);
+
+ selUrlItem = null;
+ urlTable.deselectAll();
+ }
+
+ public void filtParamShow() {
+ urlParamHide();
+ filtChooseSpecific(filtType.getSelectionIndex());
+ urlSetRates();
+
+ if(filtParamComp.isVisible() == true) return;
+
+ GridData layoutData = new GridData(GridData.FILL_BOTH);
+ filtParamComp.setLayoutData(layoutData);
+ optParamScrollComp.setMinSize(optParamComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ optParamComp.layout(true);
+ filtParamComp.setVisible(true);
+ }
+
+ public void filtParamHide() {
+ if(filtParamComp.isVisible() == false) return;
+
+ filtParamComp.setVisible(false);
+ GridData layoutData = new GridData();
+ layoutData.heightHint = 0;
+ filtParamComp.setLayoutData(layoutData);
+ optParamScrollComp.setMinSize(optParamComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ optParamComp.layout(true);
+
+ selFilterItem = null;
+ filtTable.deselectAll();
+ }
+
+ public void paramHideAll() {
+ if(optParamComp.isVisible() == true) return;
+
+ GridData layoutData;
+ urlParamComp.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ urlParamComp.setLayoutData(layoutData);
+ filtParamComp.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ filtParamComp.setLayoutData(layoutData);
+ optParamScrollComp.setMinSize(optParamComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ optParamComp.layout(true);
+
+ selUrlItem = null;
+ selFilterItem = null;
+ urlTable.deselectAll();
+ filtTable.deselectAll();
+ }
+
+ private void urlChooseOptions() {
+ GridData layoutData;
+ boolean displayNone = true;
+
+ if(urlLocRef.getSelection()) {
+ urlOptCompCustReferer.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ urlOptCompCustReferer.setLayoutData(layoutData);
+ } else {
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ urlOptCompCustReferer.setLayoutData(layoutData);
+ urlOptCompCustReferer.setVisible(true);
+ displayNone = false;
+ }
+ if(urlUseCookie.getSelection()) {
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ urlOptCompCookie.setLayoutData(layoutData);
+ urlOptCompCookie.setVisible(true);
+ displayNone = false;
+ } else {
+ urlOptCompCookie.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ urlOptCompCookie.setLayoutData(layoutData);
+ }
+ if(displayNone) {
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ layoutData.heightHint = 1;
+ urlOptCompNone.setLayoutData(layoutData);
+ urlOptCompNone.setVisible(true);
+ } else {
+ urlOptCompNone.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ urlOptCompNone.setLayoutData(layoutData);
+ }
+
+ optParamScrollComp.setMinSize(optParamComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ urlParamComp.layout(true);
+ }
+
+ private void urlSetRates() {
+ GridData layoutData;
+
+ if(filtRateUseCustom.getSelection()) {
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ filtRatesCustom.setLayoutData(layoutData);
+ filtRatesCustom.setVisible(true);
+ filtRatesNone.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ filtRatesNone.setLayoutData(layoutData);
+ } else {
+ filtRatesCustom.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ filtRatesCustom.setLayoutData(layoutData);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ layoutData.heightHint = 1;
+ filtRatesNone.setLayoutData(layoutData);
+ filtRatesNone.setVisible(true);
+ }
+
+ optParamScrollComp.setMinSize(optParamComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ filtParamComp.layout(true);
+ }
+
+ private void filtChooseSpecific(int curType) {
+ GridData layoutData;
+
+ switch(curType) {
+ case 0:
+ filtSpecificOther.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ filtSpecificOther.setLayoutData(layoutData);
+ filtSpecificNone.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ filtSpecificNone.setLayoutData(layoutData);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ filtSpecificTVShow.setLayoutData(layoutData);
+ filtSpecificTVShow.setVisible(true);
+ break;
+ case 1:
+ filtSpecificTVShow.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ filtSpecificTVShow.setLayoutData(layoutData);
+ filtSpecificNone.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ filtSpecificNone.setLayoutData(layoutData);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ filtSpecificOther.setLayoutData(layoutData);
+ filtSpecificOther.setVisible(true);
+ break;
+ case 2:
+ filtSpecificTVShow.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ filtSpecificTVShow.setLayoutData(layoutData);
+ filtSpecificOther.setVisible(false);
+ layoutData = new GridData();
+ layoutData.heightHint = 0;
+ filtSpecificOther.setLayoutData(layoutData);
+ layoutData = new GridData(GridData.FILL_HORIZONTAL);
+ layoutData.heightHint = 1;
+ filtSpecificNone.setLayoutData(layoutData);
+ filtSpecificNone.setVisible(true);
+ }
+
+ optParamScrollComp.setMinSize(optParamComp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ filtParamComp.layout(true);
+ }
+
+ private Image getImage(String res) {
+ return getImage(res, 255);
+ }
+
+ private Image getImage(String res, int alpha) {
+ Image image;
+ InputStream stream = getClass().getResourceAsStream(res);
+ if(stream != null) {
+ if(alpha == 255) {
+ image = new Image(display, stream);
+ } else {
+ ImageData imageData = new ImageData(stream);
+ imageData.alpha = alpha;
+ image = new Image(display, imageData);
+ }
+ return image;
+ } else {
+ System.err.println("RSSFeed: Error loading resource: " + res);
+ }
+ return null;
+ }
+
+ private Menu listMenu(final Shell shell) {
+ listTableMenu = new Menu(shell, SWT.POP_UP);
+
+ itemRefresh = setupListMenuItem("Refresh", "Refresh.gif");
+ listTableMenu.setDefaultItem(itemRefresh);
+ itemRefreshAll = setupListMenuItem("RefreshAll", "Refresh.gif");
+ new MenuItem(listTableMenu, SWT.SEPARATOR);
+ itemExpandAll = setupListMenuItem("Expand", "ItemAdd.gif");
+ itemCollapseAll = setupListMenuItem("Collapse", "ItemRemove.gif");
+ new MenuItem(listTableMenu, SWT.SEPARATOR);
+ itemDownload = setupListMenuItem("Download", "Download.gif");
+ itemDownloadTo = setupListMenuItem("DownloadTo", "DownloadTo.gif");
+ itemCancel = setupListMenuItem("Cancel", "Cancel.gif");
+ new MenuItem(listTableMenu, SWT.SEPARATOR);
+ itemCreateFilter = setupListMenuItem("FilterFrom", "Filter.gif");
+ itemCopyLink = setupListMenuItem("CopyLink", "Copy.gif");
+ itemOpenLink = setupListMenuItem("OpenLink", "Copy.gif");
+ new MenuItem(listTableMenu, SWT.SEPARATOR);
+ itemShowInfo = setupListMenuItem("ShowInfo", "ShowInfo.gif");
+ listTableMenu.addMenuListener(this);
+
+ return listTableMenu;
+ }
+
+ private MenuItem setupListMenuItem(String strName, String iconName) {
+ MenuItem item = new MenuItem(listTableMenu, SWT.PUSH);
+ Messages.setLanguageText(item, "RSSFeed.Status.ListTable.Menu." + strName);
+ item.setImage(getImage("/org/kmallan/resource/icons/" + iconName));
+ item.addSelectionListener(this);
+ return item;
+ }
+
+ private Menu setupHistMenu(final Shell shell) {
+ histTableMenu = new Menu(shell, SWT.POP_UP);
+ itemCopyFile = setupHistMenuItem("CopyFile", "Copy.gif");
+ histTableMenu.setDefaultItem(itemCopyFile);
+ itemCopyTorrent = setupHistMenuItem("CopyTorrent", "Copy.gif");
+ new MenuItem(histTableMenu, SWT.SEPARATOR);
+ itemDelete = setupHistMenuItem("Delete", "Remove.gif");
+ histTableMenu.addMenuListener(this);
+ return histTableMenu;
+ }
+
+ private MenuItem setupHistMenuItem(String strName, String iconName) {
+ MenuItem item = new MenuItem(histTableMenu, SWT.PUSH);
+ Messages.setLanguageText(item, "RSSFeed.Hist.HistTable.Menu." + strName);
+ item.setImage(getImage("/org/kmallan/resource/icons/" + iconName));
+ item.addSelectionListener(this);
+ return item;
+ }
+
+ public Composite getComposite() {
+ return this.tabFolder;
+ }
+
+ public void mouseDoubleClick(MouseEvent event) {
+ Object src = event.getSource();
+ Point pMousePosition = new Point(event.x, event.y);
+
+ if(src == listTable.getTable()) {
+ Rectangle rTableArea = listTable.getClientArea();
+ if(rTableArea.contains(pMousePosition)) {
+ if(listTable == null || listTable.isDisposed()) return;
+ TableTreeItem[] items = listTable.getSelection();
+ if(items.length == 1) {
+ final ListTreeItem listItem = (ListTreeItem)items[0];
+ if(listItem.isFeed()) {
+ listItem.setExpanded(!listItem.getExpanded());
+ } else {
+ new Thread("ManualFetcher") {
+ public void run() {
+ ListBean listBean = (ListBean)listItem.getBean();
+ torrentDownloader.addTorrent(listBean);
+ if(isOpen() && display != null && !display.isDisposed())
+ display.asyncExec(new Runnable() {
+ public void run() {listItem.update();}
+ });
+ }
+ }.start();
+ }
+ }
+ }
+ }
+
+ }
+
+ public void mouseDown(MouseEvent event) {
+ Object src = event.getSource();
+ Point pMousePosition = new Point(event.x, event.y);
+
+ if(src == urlTable) {
+ Rectangle rTableArea = urlTable.getClientArea();
+ if(rTableArea.contains(pMousePosition)) {
+ UrlTableItem urlItem = (UrlTableItem)urlTable.getItem(pMousePosition);
+ if(urlItem == null) urlParamHide();
+ }
+
+ } else if(src == filtTable) {
+ Rectangle rTableArea = filtTable.getClientArea();
+ if(rTableArea.contains(pMousePosition)) {
+ FilterTableItem filterItem = (FilterTableItem)filtTable.getItem(pMousePosition);
+ if(filterItem == null) filtParamHide();
+ }
+
+ } else if(src == listTable.getTable()) {
+ Rectangle rTableArea = listTable.getClientArea();
+ if(rTableArea.contains(pMousePosition)) {
+ // Use 2 because of inconsistent behaviour of getItem
+ // when table is scrolled right.
+ pMousePosition.x = 2;
+ TableTreeItem listItem = listTable.getItem(pMousePosition);
+ if(listItem == null) {
+ listTable.deselectAll();
+ selListItem = null;
+ }
+ }
+ }
+
+ }
+
+ public void mouseUp(MouseEvent event) {
+ Object src = event.getSource();
+ Point pMousePosition = new Point(event.x, event.y);
+
+ if(src == urlTable) {
+ Rectangle rTableArea = urlTable.getClientArea();
+ if(rTableArea.contains(pMousePosition)) {
+ UrlTableItem urlItem = (UrlTableItem)urlTable.getItem(pMousePosition);
+ if(urlItem == null) return;
+
+ UrlBean urlBean = urlItem.getBean();
+ if(urlBean.isEnabled() != urlItem.getChecked()) {
+ urlBean.setEnabled(urlItem.getChecked());
+ rssfeedConfig.storeOptions();
+ if(urlItem.equals(selUrlItem)) urlItem.setup(thisView);
+ }
+ }
+
+ } else if(src == filtTable) {
+
+ Rectangle rTableArea = filtTable.getClientArea();
+ if(rTableArea.contains(pMousePosition)) {
+ FilterTableItem filterItem = (FilterTableItem)filtTable.getItem(pMousePosition);
+ if(filterItem == null) return;
+
+ FilterBean filterBean = filterItem.getBean();
+ if(filterBean.getEnabled() != filterItem.getChecked()) {
+ filterBean.setEnabled(filterItem.getChecked());
+ rssfeedConfig.storeOptions();
+ if(selFilterItem.equals(filterItem)) filterItem.setup(thisView);
+ }
+ }
+
+ } else if(src == histTable) {
+
+ Rectangle rTableArea = histTable.getClientArea();
+ if(rTableArea.contains(pMousePosition)) {
+ // Use 2 because of inconsistent behaviour of getItem when table is scrolled right.
+ pMousePosition.x = 2;
+ HistoryTableItem histItem = (HistoryTableItem)histTable.getItem(pMousePosition);
+ if(histItem == null) histTable.deselectAll();
+ }
+ }
+ }
+
+ public void widgetSelected(SelectionEvent event) {
+ Object src = event.getSource();
+
+ // history table
+ TableItem[] histItems = histTable.getSelection();
+ if(src == itemDelete) {
+ histRemove();
+ } else if(src == itemCopyTorrent) {
+ if(histItems.length == 1) {
+ CBManager clipboard = new CBManager();
+ clipboard.setClipboardContents(((HistoryTableItem)histItems[0]).getBean().getLocation());
+ }
+ } else if(src == itemCopyFile) {
+ if(histItems.length == 1) {
+ CBManager clipboard = new CBManager();
+ clipboard.setClipboardContents(((HistoryTableItem)histItems[0]).getBean().getFileData());
+ }
+ }
+
+ // list table
+ if(src == itemRefresh) {
+ UrlBean urlBean;
+ if(selListItem.isFeed()) {
+ urlBean = (UrlBean)selListItem.getBean();
+ } else {
+ urlBean = ((ListBean)selListItem.getBean()).getFeed();
+ }
+ urlBean.refreshGroup();
+
+ } else if(src == itemRefreshAll) {
+ for(int iLoop = 0; iLoop < rssfeedConfig.getUrlCount(); iLoop++) {
+ UrlBean urlBean = rssfeedConfig.getUrl(iLoop);
+ if(urlBean.isEnabled()) urlBean.refreshGroup();
+ }
+
+ } else if(src == itemDownload) {
+ if(!selListItem.isFeed()) {
+ torrentDownloader.addTorrentThreaded((ListBean)selListItem.getBean());
+ }
+
+ } else if(src == itemCancel) {
+ if(!selListItem.isFeed()) {
+ ListBean listBean = (ListBean)selListItem.getBean();
+ if(listBean.downloader == null) return;
+ listBean.downloader.cancel();
+ }
+
+ } else if(src == itemCopyLink) {
+ CBManager clipboard = new CBManager();
+ if(!selListItem.isFeed()) {
+ ListBean listBean = (ListBean)selListItem.getBean();
+ clipboard.setClipboardContents(listBean.getLocation());
+ } else {
+ UrlBean urlBean = (UrlBean)selListItem.getBean();
+ clipboard.setClipboardContents(urlBean.getLocation());
+ }
+
+ } else if(src == itemOpenLink) {
+ if(!selListItem.isFeed()) {
+ ListBean listBean = (ListBean)selListItem.getBean();
+ Plugin.launchUrl(listBean.getLocation());
+ } else {
+ UrlBean urlBean = (UrlBean)selListItem.getBean();
+ Plugin.launchUrl(urlBean.getBaseURL());
+ }
+
+ } else if(src == itemExpandAll) {
+ treeViewManager.expandAll();
+
+ } else if(src == itemCollapseAll) {
+ treeViewManager.collapseAll();
+
+ } else if(src == itemShowInfo) {
+ //
+ ListBean lb = (ListBean)selListItem.getBean();
+ Plugin.debugOut("showInfo for " + lb.getName() + " - " + lb.getDescription() + " - " + lb.getInfo());
+ //
+ SimpleDialog dialog = new SimpleDialog(shell);
+ dialog.setText(((ListBean)selListItem.getBean()).getName());
+ dialog.setTitle(MessageText.getString("RSSFeed.Status.ListTable.Menu.ShowInfo.Dialog.Title"));
+ dialog.setInfo(((ListBean)selListItem.getBean()).getDescription());
+ dialog.open();
+
+ } else if(src == itemCreateFilter) {
+ if(!selListItem.isFeed()) {
+ ListBean listBean = (ListBean)selListItem.getBean();
+ UrlBean urlBean = listBean.getFeed();
+
+ filtTable.setRedraw(false);
+ FilterTableItem newItem = new FilterTableItem(filtTable, rssfeedConfig);
+ FilterBean newBean = new FilterBean();
+ Episode e = FilterBean.getSeason(listBean.getName());
+ if(e == null && listBean.getLocation().toLowerCase().endsWith(".torrent"))
+ e = FilterBean.getSeason(listBean.getLocation());
+
+ newBean.setName(listBean.getName());
+ newBean.setType("Other");
+ newBean.setMode("Pass");
+ newBean.setFeed(urlBean.getID());
+ if(e != null) {
+ newBean.setName(e.showTitle);
+ newBean.setExpression((e.showTitle.toLowerCase()).replaceAll(" ", ".").replaceAll("\\(", ".").replaceAll("\\)", "."));
+ newBean.setIsRegex(true);
+ newBean.setMatchTitle(true);
+ newBean.setMatchLink(true);
+ newBean.setType("TVShow");
+ newBean.setStartSeason(e.seasonStart);
+ newBean.setStartEpisode(e.episodeStart);
+ }
+ newItem.setBean(newBean);
+ newItem.setup(thisView);
+
+ int newPos = filtTable.indexOf(newItem);
+ filtTable.setSelection(newPos);
+ filtTable.setRedraw(true);
+ selFilterItem = newItem;
+ rssfeedConfig.storeOptions();
+
+ tabFolder.setSelection(tabOptions);
+ filtParamShow();
+ filtTestMatch.setText(listBean.getName());
+ }
+
+ } else if(src == itemDownloadTo) {
+ if(!selListItem.isFeed()) {
+ downloadToThreaded(); // todo
+ }
+
+ } else if(src == listTable.getTable()) {
+ if(listTable == null || listTable.isDisposed()) return;
+ TableTreeItem[] items = listTable.getSelection();
+ if(items.length == 1) {
+ ListTreeItem listItem = (ListTreeItem)items[0];
+ if(selListItem == null || listItem != selListItem) selListItem = listItem;
+ }
+
+ } else if(src == urlTable) {
+ if(urlTable == null || urlTable.isDisposed()) return;
+ TableItem[] items = urlTable.getSelection();
+ if(items.length == 1) {
+ UrlTableItem urlItem = (UrlTableItem)items[0];
+ if(selUrlItem == null || urlItem != selUrlItem) {
+ selUrlItem = urlItem;
+ selUrlItem.setup(thisView);
+ }
+
+ UrlBean urlBean = selUrlItem.getBean();
+ if(urlBean.isEnabled() != selUrlItem.getChecked()) {
+ urlBean.setEnabled(selUrlItem.getChecked());
+ rssfeedConfig.storeOptions();
+ selUrlItem.setup(thisView);
+ }
+ } else {
+ urlParamHide();
+ }
+
+ } else if(src == filtTable) {
+ if(filtTable == null || filtTable.isDisposed()) return;
+ TableItem[] items = filtTable.getSelection();
+ if(items.length == 1) {
+ FilterTableItem filtItem = (FilterTableItem)items[0];
+ if(selFilterItem == null || filtItem != selFilterItem) {
+ selFilterItem = filtItem;
+ selFilterItem.setup(thisView);
+ }
+
+ FilterBean filtBean = selFilterItem.getBean();
+ if(filtBean.getEnabled() != selFilterItem.getChecked()) {
+ filtBean.setEnabled(selFilterItem.getChecked());
+ rssfeedConfig.storeOptions();
+ selFilterItem.setup(thisView);
+ }
+ } else {
+ filtParamHide();
+ }
+ }
+
+ }
+
+ private void downloadToThreaded() {
+ Thread t = new Thread() {
+ public void run() {
+ boolean success = false;
+ File torrentLocation = null;
+
+ final ListBean listBean = (ListBean)selListItem.getBean();
+ UrlBean urlBean = listBean.getFeed();
+
+ String default_path = new String("");
+ if(urlBean.getStoreDir().length() > 0) {
+ default_path = urlBean.getStoreDir();
+ } else if(COConfigurationManager.getBooleanParameter("Use default data dir", true)) {
+ default_path = COConfigurationManager.getStringParameter("Default save path", "");
+ }
+
+ String link = listBean.getLocation();
+
+ boolean saveTorrents = false;
+ String torrentDirectory = new String("");
+ try {
+ saveTorrents = COConfigurationManager.getBooleanParameter("Save Torrent Files", true);
+ torrentDirectory = COConfigurationManager.getDirectoryParameter("General_sDefaultTorrent_Directory");
+ } catch(Exception egnore) {}
+ if(!saveTorrents || torrentDirectory == null || torrentDirectory.length() == 0) return;
+
+ try {
+ torrentLocation = torrentDownloader.getTorrent(link, urlBean, listBean, torrentDirectory);
+ if(torrentLocation == null) return;
+ Torrent curTorrent = pluginInterface.getTorrentManager().createFromBEncodedFile(torrentLocation);
+
+ final boolean singleFile = (curTorrent.getFiles()).length == 1;
+ final String singleFileName = curTorrent.getName();
+ final String defaultPath = default_path;
+
+ String storeLoc = null, storeFile = null;
+ if(isOpen() && display != null && !display.isDisposed()) {
+ Thread t = new Thread() {
+ public void run() {
+ String loc = null;
+ try {
+ if(singleFile) {
+ FileDialog fDialog = new FileDialog(shell, SWT.SYSTEM_MODAL | SWT.SAVE);
+ if(defaultPath.length() > 0) {
+ fDialog.setFilterPath(defaultPath);
+ }
+ fDialog.setFileName(singleFileName);
+ fDialog.setText(MessageText.getString("MainWindow.dialog.choose.savepath") + " (" + singleFileName + ")");
+ loc = fDialog.open();
+ } else {
+ DirectoryDialog dDialog = new DirectoryDialog(shell, SWT.SYSTEM_MODAL);
+ if(defaultPath.length() > 0) {
+ dDialog.setFilterPath(defaultPath);
+ }
+ dDialog.setText(MessageText.getString("MainWindow.dialog.choose.savepath") + " (" + singleFileName + ")");
+ loc = dDialog.open();
+ }
+ } catch(Exception e) {
+ listBean.setState(ListBean.DOWNLOAD_FAIL);
+ listBean.setError(e.getMessage());
+ }
+ if(loc == null) loc = new String("");
+ setName(loc);
+ }
+ };
+ display.asyncExec(t);
+ int counter = 0;
+ do {
+ try {
+ long numMillisecondsToSleep = 1000;
+ sleep(numMillisecondsToSleep);
+ } catch(InterruptedException e) {
+ }
+ } while(t.getName().matches("Thread-[0-9]+") && counter++ < 30);
+ if(counter >= 30) throw new Exception("Save Timeout (30s)");
+ storeLoc = t.getName();
+ }
+ if(storeLoc != null && storeLoc.length() != 0) {
+ if(singleFile) {
+ String[] slp = storeLoc.split(rssfeedConfig.separator);
+ storeFile = slp[slp.length - 1];
+ storeLoc = storeLoc.substring(0, storeLoc.lastIndexOf(rssfeedConfig.separator));
+ }
+ success = torrentDownloader.addTorrent(curTorrent, torrentLocation, listBean, storeLoc, storeFile);
+ if(!success) listBean.setState(ListBean.DOWNLOAD_FAIL);
+ }
+ } catch(Exception e) {
+ listBean.setState(ListBean.DOWNLOAD_FAIL);
+ listBean.setError(e.getMessage());
+ }
+ if(isOpen() && display != null && !display.isDisposed())
+ display.asyncExec(new Runnable() {
+ public void run() {
+ selListItem.update();
+ }
+ });
+
+ if(!success && torrentLocation != null) torrentLocation.delete();
+ }
+ };
+ t.start();
+ }
+
+ public void widgetDefaultSelected(SelectionEvent event) {
+
+ }
+
+ public void menuHidden(MenuEvent event) {}
+
+ public void menuShown(MenuEvent event) {
+ Object src = event.getSource();
+
+ if(src == histTableMenu) {
+ TableItem[] items = histTable.getSelection();
+ if(items.length == 1) {
+ itemCopyFile.setEnabled(true);
+ itemCopyTorrent.setEnabled(true);
+ itemDelete.setEnabled(true);
+ } else if(items.length > 1) {
+ itemCopyFile.setEnabled(false);
+ itemCopyTorrent.setEnabled(false);
+ itemDelete.setEnabled(true);
+ } else {
+ itemCopyFile.setEnabled(false);
+ itemCopyTorrent.setEnabled(false);
+ itemDelete.setEnabled(false);
+ }
+ } else if(src == listTableMenu) {
+ itemRefreshAll.setEnabled(true);
+ if(selListItem == null) {
+ itemRefresh.setEnabled(false);
+ itemDownload.setEnabled(false);
+ itemDownloadTo.setEnabled(false);
+ itemCancel.setEnabled(false);
+ itemCreateFilter.setEnabled(false);
+ itemCopyLink.setEnabled(false);
+ itemOpenLink.setEnabled(false);
+ itemShowInfo.setEnabled(false);
+ } else {
+ itemRefresh.setEnabled(true);
+ if(selListItem.isFeed()) {
+ itemDownload.setEnabled(false);
+ itemDownloadTo.setEnabled(false);
+ itemCancel.setEnabled(false);
+ itemCreateFilter.setEnabled(false);
+ itemCopyLink.setEnabled(true);
+ itemOpenLink.setEnabled(true);
+ itemShowInfo.setEnabled(false);
+ } else {
+ itemDownload.setEnabled(true);
+ itemDownloadTo.setEnabled(true);
+ ListBean listBean = (ListBean)selListItem.getBean();
+ if(listBean.getState() != ListBean.NO_DOWNLOAD && !listBean.checkDone()) {
+ itemCancel.setEnabled(true);
+ } else {
+ itemCancel.setEnabled(false);
+ }
+ itemCreateFilter.setEnabled(true);
+ itemCopyLink.setEnabled(true);
+ itemOpenLink.setEnabled(true);
+ if(((ListBean)selListItem.getBean()).getDescription().equalsIgnoreCase("")) {
+ itemShowInfo.setEnabled(false);
+ } else {
+ itemShowInfo.setEnabled(true);
+ }
+ }
+ }
+
+ }
+
+ }
+
+ public void handleEvent(Event event) {
+ Widget src = event.widget;
+
+ if(src == btnUrlUp) {
+ if(selUrlItem == null) return;
+ urlOrder(-1);
+ } else if(src == btnUrlAdd) {
+ urlAdd();
+ } else if(src == btnUrlRemove) {
+ if(selUrlItem == null) return;
+ urlRemove();
+ } else if(src == btnUrlDown) {
+ if(selUrlItem == null) return;
+ urlOrder(1);
+ } else if(src == btnFiltUp) {
+ if(selFilterItem == null) return;
+ filtOrder(-1);
+ } else if(src == btnFiltAdd) {
+ filtAdd();
+ } else if(src == btnFiltRemove) {
+ if(selFilterItem == null) return;
+ filtRemove();
+ } else if(src == btnFiltDown) {
+ if(selFilterItem == null) return;
+ filtOrder(1);
+ } else if(src == btnUrlStoreDir) {
+ updateStoreDirLoc(shell, urlStoreDir);
+ } else if(src == urlLocRef || src == urlUseCookie) {
+ urlChooseOptions();
+ } else if(src == btnUrlAccept) {
+ urlAccept();
+ } else if(src == btnUrlReset) {
+ urlReset();
+ } else if(src == btnUrlCancel) {
+ urlCancel();
+ } else if(src == btnFiltStoreDir) {
+ updateStoreDirLoc(shell, filtStoreDir);
+ } else if(src == filtRateUseCustom) {
+ urlSetRates();
+ } else if(src == btnFiltAccept) {
+ filtAccept();
+ } else if(src == btnFiltReset) {
+ filtReset();
+ } else if(src == btnFiltCancel) {
+ filtCancel();
+ } else if(src == btnFiltTest) {
+ filtTest();
+ }
+
+ }
+
+ public void modifyText(ModifyEvent event) {
+ Object src = event.getSource();
+
+ if(src == filtType) {
+ filtChooseSpecific(filtType.getSelectionIndex());
+ }
+ }
+
+ public void parameterChanged(String parameterName) {
+ if(parameterName.equalsIgnoreCase("GUI_SWT_bFancyTab")
+ && tabFolder instanceof CTabFolder && tabFolder != null
+ && !tabFolder.isDisposed()) {
+ try {
+ tabFolder.setSimple(!COConfigurationManager.getBooleanParameter("GUI_SWT_bFancyTab"));
+ } catch(NoSuchMethodError e) {/** < SWT 3.0M8 **/}
+ }
+
+ }
+}
+
Added: plugins/rssfeed/org/kmallan/include/files.txt
===================================================================
--- plugins/rssfeed/org/kmallan/include/files.txt (rev 0)
+++ plugins/rssfeed/org/kmallan/include/files.txt 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1 @@
+Copy the Azureus2.jar & swt*.jar from your azureus dir into this dir.
Added: plugins/rssfeed/org/kmallan/resource/icons/Cancel.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/Cancel.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/Copy.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/Copy.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/Download.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/Download.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/DownloadTo.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/DownloadTo.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/Filter.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/Filter.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/ItemAdd.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/ItemAdd.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/ItemEdit.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/ItemEdit.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/ItemMoveDown.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/ItemMoveDown.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/ItemMoveUp.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/ItemMoveUp.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/ItemRemove.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/ItemRemove.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/Refresh.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/Refresh.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/Remove.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/Remove.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/icons/ShowInfo.gif
===================================================================
(Binary files differ)
Property changes on: plugins/rssfeed/org/kmallan/resource/icons/ShowInfo.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: plugins/rssfeed/org/kmallan/resource/lang/Help.stf
===================================================================
--- plugins/rssfeed/org/kmallan/resource/lang/Help.stf (rev 0)
+++ plugins/rssfeed/org/kmallan/resource/lang/Help.stf 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,211 @@
+$
+$ RSS Feed Scanner Help
+$
+
++
++About the RSS Feed Scanner
+
+!What is RSS?
+ Many torrent providers make lists of their most recent torrents available to the users in an XML (eXtensible Markup Language) format known as RSS (Really Simple Syndication) so that the users can use parsers to automatically process this information for a number of purposes.
+
+ Some such programs can display the most recent torrents on your screen, generate torrent lists for websites, or automatically launch torrent clients to fetch specific torrents when they appear.
+
+ This plugin is of the latter variety.
+
+!What does this plugin do?
+ It will periodically check the RSS feed URLs that you specify, and fetch the torrents that you are interested in, automatically starting them downloading in Azureus.
+
+ Because of it's integration into the Azureus BitTorrent client, this plugin can be extended in its range of functionality to do things that the currently available RSS feed scanners cannot, such as:
+
+!What else can this plugin do?
+*Save your torrents in a specific directory, depending on the filter matched.
+*Only run when your BitTorrent client is running.
+
+ In addition to these benefits of running in the Azureus BitTorrent client, this scanner has more advanced functionality, unavailable in other RSS clients currently.
+
+ This RSS Feed Scanner plugin allows you to build more flexible rules, to target your exact needs...
+
+!What are some of the more advanced features?
+
+*Your choice of Regular Expression or Substring matches
+ If you don't understand regular expression syntax, you can simply use the less powerful, but more easily understood substring format.
+ Using the substring format, the title and/or torrent is searched for the existence of the particular text that you specify.
+ Both of these are case-insensitive.
+
+*"FAIL" rules
+ You can use any the same critera that you would normally use to match torrents that you want to download to also match torrents that you don't want to download.
+ For example, you could stop the plugin from downloading any torrents with the text "svcd", "tvrip" or any other text that you design, simply by creating a rule that matches "(svcd|tvrip)", setting it to FAIL and placing it above all the other PASS filters.
+ If the parser matches a FAIL rule before it gets to a matching PASS rule, then the download will never occur.
+
+*Multiple Sources
+ Some rss readers only allow you to monitor one RSS feed.
+ This plugin allows you to specify multiple, and have feed specific rules. (see next point)
+
+*Generic, or feed specific rules
+ These will allow your filters to target specific matches to either one specific feed, or all of the source feeds.
+ This is helpful if you only want to download a specific torrent from a specific source.
+
+*Episode notation parsing
+ With the episode notation parsing, you can specify that you only want to match a particular range of episodes in a series of torrents.
+ When the torrents use any of the common episode labeling formats this plugin will read the episode id, and decide whether you want to download based upon your preferences.
+
+*Configurable download delay
+ You may specify your own RSS feed download interval on all of the feeds, as well as globally.
+
+*Send a referer
+ You can get it to send the referer when retrieving the torrent.
+ By default it will send what is set in the URL as the referer, but you can also set a custom one (leaving it blank will stop a referer from being sent.
+
+*Send cookies
+ If you use a source like TorrentBits, which requires cookies to be set, you can do this.
+ The format is as follows: '<name>=<value>'
+ You need to replace the '<name>' and '<value>' with the name and the value of the cookie.
+ If you need to, you can enter multiple, simply by separating them by a semi-column ';'.
+ For TorrentBits you would have something that looks like 'uid=123456;pass=0123456789abcdef0123456789abcdef'.
+
+*Post Fetch Processing
+ After successfully fetching a torrent, you can have it do the following automatically:
+ Move the download to the top.
+ Set the state of the download (States: Do Nothing, Queued, Forced Download, Stopped).
+ Set the download speed in KB/s.
+ Set the upload speed in KB/s (requires Azureus 2.2.0.0).
+ Set the priority (not available with Azureus 2.2.0.0).
+ Set a category for the download.
+
+*Only download an item once
+ When downloading a TVShow, it will utilize smart history as to not download an item more than once.
+ When downloading all Other items, you can make it disable itself after the first successfully downloaded match.
+
+*Simple and easy to use GUI
+ Editing your rules hase never been easier, since now you can edit your configuration within the GUI.
+ Theres no need to resort to hand editing text files; you can do it all from within the Azureus interface.
+
+
++
++All about RSS Feeds
+
+!Where do I get RSS feed URLs from?
+ There are a variety of places to get feeds from.
+
+ Mostly you just need to have a quick look on the sites that you visit to see if you can spot the link.
+
+ Another way to find lots of torrent feeds is to go to google.com and search for "torrent rss"
+
+!Ok, I have a RSS feed URL, what now?
+ Simply:
+*Click on the options tab
+*Find the RSS Feed URLs table
+*Click on the "+" beside the table
+*Type a meaningful name for this feed into the name field (Just make one up)
+*Paste the URL into the URL field
+*Click the "Active" checkbox
+*Click the "Accept" button
+
+ You may also do the the following optional steps (before clicking the "Accept" button):
+*Set a default directory to download items from that feed to
+*Set a delay for the feed (if left blank, it will use the global delay set in the Azureus Config under Plugins->RSSFeed Configuration)
+*Set a custom referer, to do this, uncheck 'Use URL as Referer for Torrents', and populate the box provided (to send no referer, leave it blank)
+*Set some cookies to be passed
+
+ You may follow the same procedure to add more feeds.
+
++
++All about Torrent Filters
+
+!How do filters work?
+ Filters are quite easy to build, but it is helpful to understand how the matching process works.
+
+ First, when a RSS feed is fetched, the filters are matched against each item in the feed, starting at the top of the filter list until it finds a filter that matches.
+
+!Ok, I want to add a filter, guide me through?
+ This process is much like the process of adding a feed url.
+ What follows is a basic filter, and there are more advanced ways and options to be explored which will be covered later:
+*Click on the options tab
+*Find the Filters table
+*Click on the "+" beside the table
+*Type a meaningful name for this filter into the name field (Just make one up)
+*Type the text that you want to match into the "Filter" field.
+ EG: To match the TV Show Tru Calling, you would type "tru calling"
+*Click the "Filter searches title" and "Filter searches link" boxes.
+*Click the "Active" checkbox
+*Click the "Accept" button
+
+!What do Pass/Fail mean?
+ If the filter that matches is of the "FAIL" type, then that particular item is discarded, and not checked any further.
+
+ If the filter that matches is of the "PASS" type, then the torrent is added to Azureus' download list, and is started.
+
+ If the item gets all the way through the filter list without matching then is it discarded.
+
+!What can I match on?
+ Filters may match either the title, the filename, or either.
+
+ Filters may also be either the Regular Expression type, or the Substring type.
+
+!What are Regular Expressions?
+ Regular Expression types utilize a specially written code that defines a set of matching criteria that may be used by power users to write more flexible rules.
+ This is not the place to discuss the intricacies of Regular Expressions, but suffice to say a Google search on "regular expressions" provides ample documentation for those wishing to learn.
+ Others may use the less powerful substring match below.
+
+!That sounds too complex!
+ The Substring match is more suitable for novice users and only matches if the supplied text is found inside the text of the title or file.
+
+!I have a torrent that is on multiple feeds, but I only want to download it from one.
+ The feed selection allows you to specify if the expression applies to all the feeds, or only a specific one.
+
+!About filter types
+ The type allows you to specify the type of the download that will be downloading, and for specific types will supply you with various options that are available for that type.
+
+@The TVShow type:
+ The TVShow type provides the episode notation parsing options.
+
+ The From and To sections allow you to specify a range of episodes in the series that you are interested in, eg:
+
+! From: Series "2" episode "10"
+! To: Series "0" episode "0"
+ Says that the torrent filename must have some kind of episode number or range in it and the episode(s) must be from series 2, episode 10 onwards.
+ This plugin can recognize most of the common formats like:
+ s1e01, 1x01, s01e01-02, 01x01-02, 01x01-01x02, 01x01+02
+
+ If the episode(s) that are in the torrent are within the range that you are interested in, then it will be scheduled for download.
+ If either the from or to series is 0, then there is no start or end to the range, respectively.
+ If both are 0 then there is no range, and any match to the filter matches.
+
+@The Other type:
+ The Other type is for every thing else.
+
+ It has the folowing options:
+*Disable after success
+
+!How can I temporarily disable a specific filter?
+ The Active setting allows you to temporarily enable/disable the current filter, without having to delete/re-add it.
+
+!What is the Mode used for?
+ The Mode can be set to either PASS or FAIL.
+
+ The PASS mode triggers the download to occur if all the criteria are met.
+ The FAIL mode causes no download, even if following filters would have matched.
+
+!What do the other settings do?
+*Move to top
+ This setting will move the download to the top of the list, when it is first added.
+*Set State To
+@ Do Nothing
+ This as it name suggests, does nothing.
+@ Queued
+ When the download is added, it's state will be set to queued.
+@ Forced Download
+ When the download is added, it's state will be set to forced download.
+@ Stopped
+ When the download is added, it's state will be set to stopped.
+*Download Speed (KB/s)
+ When the download is added, it's download speed will be automatically be set to this.
+*Upload Speed (KB/s)
+ When the download is added, it's upload speed will be automatically be set to this.
+ This setting becomes available in Azuerus 2.2.0.0
+*Priority
+ When the download is added, it's priority will be automatically be set to this.
+ This setting is no longer available in Azuerus 2.2.0.0
+*Set Category
+ When the download is added, it will automatically be assigned to this category.
+
Added: plugins/rssfeed/org/kmallan/resource/lang/Help_fr_FR.stf
===================================================================
--- plugins/rssfeed/org/kmallan/resource/lang/Help_fr_FR.stf (rev 0)
+++ plugins/rssfeed/org/kmallan/resource/lang/Help_fr_FR.stf 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,210 @@
+$
+$ Aide De Module de balayage D'Alimentation de RSS
+$
+
++
++Au sujet du module de balayage d'alimentation de RSS
+
+!Quel est RSS?
+ Beaucoup de fournisseurs de torrent font des listes de leurs torrents plus r\xE9cents disponibles aux utilisateurs dans un XML (Extensible Markup Language) composer connu comme RSS (syndication vraiment simple) de sorte que les utilisateurs puissent employer des analyseurs pour traiter automatiquement cette information pour un certain nombre de buts.
+
+ Quelques tels programmes peuvent montrer les torrents les plus r\xE9cents sur votre \xE9cran, produisent des listes de torrent pour des sites Web, ou lancent automatiquement des clients de torrent pour chercher les torrents sp\xE9cifiques quand ils apparaissent.
+
+ Ce plugin est de la derni\xE8re vari\xE9t\xE9.
+
+!Que ce plugin fait?
+ Il v\xE9rifiera p\xE9riodiquement l'alimentation URLs de RSS que vous indiquez, et cherche les torrents que vous \xEAtes int\xE9ress\xE9 dedans, automatiquement les commen\xE7ant t\xE9l\xE9charger par Azureus.
+
+ En raison de l'int\xE9gration d'it's dans le client d'Azureus BitTorrent, ce plugin peut \xEAtre prolong\xE9 dans sa gamme de la fonctionnalit\xE9 pour faire les choses que les modules de balayage actuellement disponibles d'alimentation de RSS ne peuvent pas, comme:
+
+!Queest-ce que peut ce plugin faire?
+*\xC9conomiser vos torrents dans un annuaire sp\xE9cifique, selon le filtre assorti.
+*Courez seulement quand votre client de BitTorrent court.
+
+ En plus de ces avantages de courir dans le client d'Azureus BitTorrent, ce module de balayage a plus avanc\xE9 la fonctionnalit\xE9, indisponible dans d'autres clients de RSS actuellement.
+
+ Ce module de balayage d'alimentation de RSS plugin vous permet d'\xE9tablir des r\xE8gles plus flexibles, pour viser vos besoins exacts...
+
+!Quels sont certains des dispositifs plus avan\xE7\xE9s ?
+
+*Votre choix des allumettes r\xE9guli\xE8res d'expression ou de sous-cha\xEEne
+ Si vous don't comprenez la syntaxe r\xE9guli\xE8re d'expression, vous pouvez simplement employer le format moins puissant, mais plus facilement compris de sous-cha\xEEne.
+ En utilisant le format de sous-cha\xEEne, le titre et/ou le torrent est recherch\xE9 l'existence du texte particulier que vous indiquez.
+
+*"\xC9CHOUER"; r\xE8gles
+ Vous pouvez employer tout le m\xEAme critera que vous aviez l'habitude normalement d'assortir les torrents que vous voulez t\xE9l\xE9charger pour assortir \xE9galement les torrents que vous don't voulez t\xE9l\xE9charger.
+ Par exemple, vous pourriez arr\xEAter le plugin de t\xE9l\xE9charger tous les torrents avec le "svcd" des textes;, "tvrip"; ou tout autre texte que vous concevez, simplement en cr\xE9ant une r\xE8gle qui assortit le "(svcd|tvrip)";, la pla\xE7ant POUR \xC9CHOUER et la pla\xE7ant surtout l'autre PASSAGE filtre.
+ Si l'analyseur assortit une r\xE8gle d'\xC9CHOUER avant qu'il obtienne \xE0 une r\xE8gle assortie de PASSAGE, alors le envoy ne se produira jamais.
+
+*Sources Multiples
+ Les lecteurs de quelques rss vous permettent seulement de surveiller une alimentation de RSS.
+ Ce plugin vous permet d'indiquer le multiple, et a des r\xE8gles sp\xE9cifiques d'alimentation (voir le prochain point)
+
+*R\xE8gles g\xE9n\xE9riques, ou d'alimentation de d\xE9tail
+ Ceux-ci permettront \xE0 vos filtres de viser les allumettes sp\xE9cifiques \xE0 une alimentation sp\xE9cifique, ou \xE0 toutes les alimentations de source.
+ C'est utile si vous voulez seulement t\xE9l\xE9charger un torrent sp\xE9cifique d'une source sp\xE9cifique.
+
+*Analyse de notation d'\xE9pisode
+ Avec la notation d'\xE9pisode analysant, vous pouvez indiquer que vous voulez seulement assortir une gamme particuli\xE8re des \xE9pisodes dans une s\xE9rie de torrents.
+ Quand les torrents emploient n'importe lequel des formats marquants d'\xE9pisode commun cette volont\xE9 plugin a lu l'identification d'\xE9pisode, et d\xE9cide si vous voulez au envoy bas\xE9 sur vos pr\xE9f\xE9rences.
+
+*Le envoy configurable retarde
+ Vous pouvez indiquer votre propre intervalle de envoy d'alimentation de RSS sur toutes les alimentations, aussi bien que globalement.
+
+*Envoyez un referer
+ Vous pouvez l'obtenir pour envoyer le referer en recherchant le torrent.
+ Par d\xE9faut il enverra ce qui est plac\xE9 dans le URL comme referer, mais vous pouvez \xE9galement placer fait sur commande (en lui laissant la volont\xE9 blanche arr\xEAtez un referer de l'envoi).
+
+*Envoyez les biscuits
+ Si vous employez une source comme TorrentBits, qui exige des biscuits d'\xEAtre plac\xE9s, vous pouvez faire ceci.
+ Le format est comme suit: '<nom>=<valeur>'
+ Vous devez remplacer le '<nom>' et '<valeur>' avec le nom et la valeur du biscuit.
+ Si vous avez besoin, vous pouvez \xE9crire le multiple, simplement en les s\xE9parant par une semi-colonne ';'.
+ Pour TorrentBits vous prendriez quelque chose qui ressemble \xE0 'uid=123456;pass=0123456789abcdef0123456789abcdef'.
+
+*Le Poteau Cherchent Le Traitement
+ Apr\xE8s avoir avec succ\xE8s cherch\xE9 un torrent, vous pouvez l'avoir faites le suivant automatiquement:
+ D\xE9placez le envoy au dessus.
+ Placez l'\xE9tat du envoy (\xC9tats: Ne faites Rien, Align\xE9, envoy Obligatoire, Arr\xEAt\xE9).
+ Placez la vitesse de envoy dans KB/s.
+ Placez la vitesse de t\xE9l\xE9chargement dans KB/s (exige Azureus 2.2.0.0).
+ \xC9tablissez la priorit\xE9 (non disponible avec Azureus 2.2.0.0).
+ Placez une cat\xE9gorie pour le envoy.
+
+*T\xE9l\xE9chargez seulement un article une fois
+ Quand t\xE9l\xE9chargeant un TVShow, il utilisera l'histoire fut\xE9e quant pas au envoy un article plus d'une fois.
+ En t\xE9l\xE9chargeant tous autres articles, vous pouvez le faire se neutraliser apr\xE8s la premi\xE8re allumette avec succ\xE8s t\xE9l\xE9charg\xE9e.
+
+*Simple et facile pour utiliser le GUI
+ L'\xE9dition de votre hase de r\xE8gles non jamais \xE9t\xE9 plus facile, depuis maintenant vous peut \xE9diter votre configuration dans le GUI.
+ Theres aucun besoin de recourir pour remettre \xE9diter des dossiers des textes; vous pouvez les faire tous de dans l'interface d'Azureus.
+
+
++
++Tout au sujet des alimentations de RSS
+
+!D'o\xF9 obtiens-je l'alimentation URLs de RSS?
+ Il y a une vari\xE9t\xE9 d'endroits pour obtenir des alimentations de.
+
+ La plupart du temps vous le besoin juste d'avoir un examen rapide sur les emplacements que vous visitez pour voir si vous pouvez rep\xE8rer le lien.
+
+ Une autre mani\xE8re de trouver un bon nombre d'alimentations de torrent est aller \xE0 google.com et de rechercher le "torrent rss"
+
+!Ok, j'ai un URL d'alimentation de RSS, ce qui maintenant?
+ Simplement:
+*Clic sur l'\xE9tiquette d'options
+*Trouvez la table d'URLs d'alimentation de RSS
+*Clic sur le "+" pr\xE8s de la table
+*Type a meaningful name for this feed into the name field (Just make one up)
+*Collez le URL dans le champ de URL
+*Cliquez le "Actif" checkbox
+*Cliquez le "Acceptez" bouton
+
+ Vous pouvez \xE9galement faire les les \xE9tapes facultatives suivantes (avant de cliquer "Acceptez" bouton):
+*Placez un annuaire de d\xE9faut pour t\xE9l\xE9charger des articles de cette alimentation \xE0
+*Placez retarde pour l'alimentation (si le blanc laiss\xE9, il emploiera le global retarde l'ensemble dans les config d'Azureus sous la Plugins->Configuration De RSSFeed)
+*Placez un referer fait sur commande, pour faire ceci, l'uncheck 'Employez le URL comme Referer pour des torrents', et peuplez la bo\xEEte fournie (pour n'envoyer aucun referer, laissez-le blanc)
+*Placez quelques biscuits \xE0 passer
+
+ Vous pouvez suivre le m\xEAme proc\xE9d\xE9 pour ajouter plus d'alimentations.
+
++
++Tout au sujet des filtres de torrent
+
+!Comment effectuez le travail de filtres?
+ Il est tout \xE0 fait facile construire des filtres, mais il est utile de comprendre comment le processus assorti fonctionne.
+
+ D'abord, quand une alimentation de RSS est cherch\xE9e, les filtres sont assortis contre chaque article dans l'alimentation, d\xE9marrant au dessus de la liste de filtre jusqu'\xE0 ce qu'elle trouve un filtre qui assortit.
+
+!Ok, je veux ajouter un filtre, me guide \xE0 travers?
+ Ce processus est tout comme le processus d'ajouter un URL d'alimentation.
+ Ce qui suit est un filtre de base, et il y a davantage des mani\xE8res et des options avanc\xE9es d'\xEAtre explor\xE9es qui seront couvertes plus tard:
+*Clic sur l'\xE9tiquette d'options
+*Trouvez la table de filtres
+*Clic sur le "+" pr\xE8s de la table
+*Dactylographiez un nom signicatif pour ce filtre dans la zone d'identification (composez juste un)
+*Dactylographiez le texte que vous voulez assortir dans le "Filtre" champ.
+ PAR EXEMPLE: Pour assortir le Tru Calling d'exposition de TV, vous dactylographieriez le "tru calling"
+*Cliquez le "Le filtre recherche le titre" et "Le filtre recherche le lien" bo\xEEtes.
+*Cliquez le "Actif" checkbox
+*Cliquez le "Acceptez" bouton
+
+!Que Passage/\xC9chouer signifient-ils?
+ Si le filtre qui s'assortit est du "\xC9CHOUER" dactylographiez, alors cet article particulier est jet\xE9, et pas plus pas v\xE9rifi\xE9.
+
+ Si le filtre qui s'assortit est du "PASSAGE" dactylographiez, alors le torrent est ajout\xE9 \xE0 Azureus' ; t\xE9l\xE9chargez la liste, et \xEAtes commenc\xE9.
+
+ Si l'article obtient compl\xE8tement la liste de filtre sans assortir alors est lui a jet\xE9.
+
+!Ce qui peut allumette de I dessus?
+ Les filtres peuvent assortir l'un ou l'autre le titre, le nom de fichier, ou l'un ou l'autre.
+
+ Les filtres peuvent \xE9galement \xEAtre le type r\xE9gulier d'expression, ou le type de sous-cha\xEEne.
+
+!Ce qui sont des expressions r\xE9guli\xE8res?
+ Les types r\xE9guliers d'expression utilisent un code particuli\xE8rement \xE9crit qui d\xE9finit un ensemble de crit\xE8res assortis qui peuvent \xEAtre employ\xE9s par des utilisateurs de puissance pour \xE9crire des r\xE8gles plus flexibles.
+ Ce n'est pas l'endroit pour discuter les complexit\xE9s des expressions r\xE9guli\xE8res, mais suffit pour dire une recherche de Google sur le "expressions r\xE9guli\xE8res" ; fournit la documentation suffisante pour ceux qui souhaitent apprendre.
+ D'autres peuvent employer l'allumette moins puissante de sous-cha\xEEne ci-dessous.
+
+!Cela semble trop complexe!
+ L'allumette de sous-cha\xEEne est plus appropri\xE9e aux utilisateurs et seulement aux allumettes de d\xE9butant si le texte assur\xE9 est trouv\xE9 \xE0 l'int\xE9rieur du texte du titre ou du dossier.
+
+!J'ai un torrent qui est sur les alimentations multiples, mais je veux seulement le t\xE9l\xE9charger d'une.
+ Le choix d'alimentation permet \xE0 vous d'indiquer si l'expression s'applique \xE0 toutes les alimentations, ou seulement sp\xE9cifique.
+
+!Au sujet des types de filtre
+ Le type vous permet d'iPASSAGEndiquer le type du envoy qui t\xE9l\xE9chargera, et pour les types sp\xE9cifiques vous fournira les diverses options qui sont disponibles pour ce type.
+
+@Le type de TVShow:
+ Le type de TVShow fournit les options d'analyse de notation d'\xE9pisode.
+
+ Et derri\xE8re des sections permettez-vous d'indiquer une gamme des \xE9pisodes dans la s\xE9rie que vous \xEAtes int\xE9ress\xE9 dedans, par exemple:
+
+! De: S\xE9rie "2", \xC9pisode "10"
+! \xC0: S\xE9rie "0", \xC9pisode "0"
+ Dit que le nom de fichier de torrent doit avoir un certain genre de nombre d'\xE9pisode ou la gamme dans elle et l'episode(s) doit \xEAtre de la s\xE9rie 2, l'\xE9pisode 10 en avant.
+ Ce bidon plugin identifient la plupart des formats communs comme:
+ s1e01, 1x01, s01e01-02, 01x01-02, 01x01-01x02, 01x01+02
+
+ Si l'episode(s) qui sont dans le torrent sont dans la marge que vous \xEAtes int\xE9ress\xE9 dedans, alors elle sera programm\xE9e pour le envoy.
+ Si ou derri\xE8re la s\xE9rie est 0, alors il n'y a aucun d\xE9but ou derri\xE8re l'extr\xE9mit\xE9 \xE0 la gamme, respectivement.
+ Si tous les deux sont 0 puis il n'y a aucune gamme, et n'importe quelle allumette aux allumettes de filtre.
+
+@L'autre type:
+ L'autre type est pour chaque chose autrement.
+
+ Il a les options folowing:
+*Neutralisez apr\xE8s succ\xE8s
+
+!Comment peux je temporairement neutraliser un sp\xE9cifique filtrez?
+ L'arrangement actif vous permet d'activer/ temporairement le filtre courant, sans doit delete/re-add il.
+
+!Pour ce qu'est le mode utilis\xE9?
+ Le mode peut \xEAtre plac\xE9 au PASSAGE ou \xE0 l'\xC9CHOUER.
+
+ Le mode de PASSAGE d\xE9clenche le envoy pour se produire si tous les crit\xE8res sont rencontr\xE9s.
+ Le mode d'\xC9CHOUER ne cause aucun envoy, m\xEAme si les filtres suivants se seraient assortis.
+
+!Que les autres arrangements font-ils?
+*D\xE9placez-vous au dessus
+ Cet arrangement d\xE9placera le envoy au dessus de la liste, quand on l'ajoute d'abord.
+*Placez L'\xC9tat \xC0
+@ Ne faites Rien
+ Ceci en tant que lui nomm\xE9 ne sugg\xE8re, fait rien.
+@ Align\xE9
+ Quand le envoy est ajout\xE9, l'\xE9tat d'it's sera plac\xE9 \xE0 align\xE9.
+@ Envoy Obligatoire
+ Quand le envoy est ajout\xE9, l'\xE9tat d'it's sera plac\xE9 au envoy obligatoire.
+@ Arr\xEAt\xE9
+ Quand le envoy est ajout\xE9, l'\xE9tat d'it's sera plac\xE9 \xE0 arr\xEAt\xE9.
+*Vitesse d'Envoy (KB/s)
+ Quand le envoy est ajout\xE9, la vitesse d'envoy d'it's sera automatiquement soit plac\xE9e \xE0 ceci.
+*Vitesse de T\xE9l\xE9chargement (KB/s)
+ Quand le envoy est ajout\xE9, la vitesse de t\xE9l\xE9chargement d'it's sera automatiquement soit plac\xE9e \xE0 ceci.
+ Cet arrangement devient disponible dans Azuerus 2.2.0.0
+*Priorit\xE9
+ Quand le envoy est ajout\xE9, la priorit\xE9 d'it's sera automatiquement soit plac\xE9e \xE0 ceci.
+ Cet arrangement n'est plus disponible dans Azuerus 2.2.0.0
+*Placez La Cat\xE9gorie
+ Quand le envoy est ajout\xE9, il sera automatiquement assign\xE9 \xE0 cette cat\xE9gorie.
+
Added: plugins/rssfeed/org/kmallan/resource/lang/Messages.properties
===================================================================
--- plugins/rssfeed/org/kmallan/resource/lang/Messages.properties (rev 0)
+++ plugins/rssfeed/org/kmallan/resource/lang/Messages.properties 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,121 @@
+# Main Items
+RSSFeed.Name=RSSFeed
+RSSFeed.Title=RSSFeed Scanner
+# Config Items
+RSSFeed.Config=RSSFeed
+RSSFeed.Config.Enable=Automatic Reload Enabled
+RSSFeed.Config.Delay=Default Automatic Reload Delay
+RSSFeed.Config.AutoLoad=Load RSSFeed Tab on Startup
+RSSFeed.Config.KeepOld=Keep old/removed items (days)
+RSSFeed.Config.KeepMax=Maximum items to keep
+RSSFeed.Config.AutoStartManual=Start manually saved torrents
+# Tab Items
+RSSFeed.Tab.Status=Status
+RSSFeed.Tab.Options=Options
+RSSFeed.Tab.History=Download history
+RSSFeed.Tab.Help=Help
+# Status Items - List Table
+RSSFeed.Status.ListTable.Col0=Feed/Title
+RSSFeed.Status.ListTable.Col1=Status/Link
+RSSFeed.Status.ListTable.Col2=Age
+RSSFeed.Status.ListTable.Col3=Matches
+# Status Items - List Table, Menu Items
+RSSFeed.Status.ListTable.Menu.Refresh=&Refresh Feed
+RSSFeed.Status.ListTable.Menu.RefreshAll=Refresh &All Feeds
+RSSFeed.Status.ListTable.Menu.Expand=&Expand All
+RSSFeed.Status.ListTable.Menu.Collapse=&Collapse All
+RSSFeed.Status.ListTable.Menu.Download=&Save Torrent
+RSSFeed.Status.ListTable.Menu.DownloadTo=Save &Torrent As
+RSSFeed.Status.ListTable.Menu.Cancel=&Cancel Download
+RSSFeed.Status.ListTable.Menu.FilterFrom=Create &Filter
+RSSFeed.Status.ListTable.Menu.CopyLink=Copy &Link URL to Clipboard
+RSSFeed.Status.ListTable.Menu.OpenLink=&Open Link URL
+RSSFeed.Status.ListTable.Menu.ShowInfo=Show &Info
+RSSFeed.Status.ListTable.Menu.ShowInfo.Dialog.Title=Torrent Description
+RSSFeed.Status.ListTable.Menu.ShowInfo.Dialog.TitleBar=Info
+# Option Items
+RSSFeed.Options.Title=Options:
+# Option Items - Feed Table
+RSSFeed.Options.Feed.Title=RSS Feed URLs:
+RSSFeed.Options.Feed.Table.Col0=Name
+# Option Items - Feed Items
+RSSFeed.Options.Feed.urlName=Name:
+RSSFeed.Options.Feed.urlLocation=URL:
+RSSFeed.Options.Feed.urlStoreDir=Directory:
+RSSFeed.Options.Feed.urlDelay=Delay:
+RSSFeed.Options.Feed.urlSettings=Settings:
+RSSFeed.Options.Feed.Options=Options:
+RSSFeed.Options.Feed.urlObeyTTL=Obey TTL
+RSSFeed.Options.Feed.urlLocRef=Use URL as Referer For Torrents
+RSSFeed.Options.Feed.urlUseCookie=Pass Cookie's
+RSSFeed.Options.Feed.urlReferer=Custom Referer:
+RSSFeed.Options.Feed.urlCookie=Cookie's:
+RSSFeed.Options.Feed.urlActive=Active:
+RSSFeed.Options.Feed.urlEnabled=Enabled
+RSSFeed.Options.Feed.btnUrlAccept=Save
+RSSFeed.Options.Feed.btnUrlReset=Reset
+RSSFeed.Options.Feed.btnUrlCancel=Cancel
+# Option Items - Filter Table
+RSSFeed.Options.Filter.Title=Filters:
+RSSFeed.Options.Filter.Table.Col0=Name
+RSSFeed.Options.Filter.Table.Col1=Type
+RSSFeed.Options.Filter.Table.Col2=Mode
+# Option Items - Filter Items
+RSSFeed.Options.Filter.filtName=Name:
+RSSFeed.Options.Filter.filtStoreDir=Directory:
+RSSFeed.Options.Filter.filtExpression=Filter:
+RSSFeed.Options.Filter.Options=Options:
+RSSFeed.Options.Filter.Options.filtIsRegex=Filter is a Regular Expression
+RSSFeed.Options.Filter.Options.filtMatch.Title=Filter searches title
+RSSFeed.Options.Filter.Options.filtMatch.Link=Filter searches link
+RSSFeed.Options.Filter.Options.MoveTop=Move to top
+RSSFeed.Options.Filter.State=Set State To:
+RSSFeed.Options.Filter.State.Queued=Queued
+RSSFeed.Options.Filter.State.Forced=Forced Download
+RSSFeed.Options.Filter.State.Stopped=Stopped
+RSSFeed.Options.Filter.Priority=Priority:
+RSSFeed.Options.Filter.Priority.High=High
+RSSFeed.Options.Filter.Priority.Low=Low
+RSSFeed.Options.Filter.Rates=Overide Rates:
+RSSFeed.Options.Filter.Rates.UseCustom=Use Custom Rates
+RSSFeed.Options.Filter.Rates.Upload=Upload Speed (KB/s):
+RSSFeed.Options.Filter.Rates.Download=Download Speed (KB/s):
+RSSFeed.Options.Filter.filtCategory=Set Category:
+RSSFeed.Options.Filter.filtFeed=Feed:
+RSSFeed.Options.Filter.filtFeed.All=All
+RSSFeed.Options.Filter.filtType=Type:
+RSSFeed.Options.Filter.filtType.TVShow=TVShow
+RSSFeed.Options.Filter.filtType.Other=Other
+RSSFeed.Options.Filter.filtType.None=None
+RSSFeed.Options.Filter.TVShow.filtStart=From:
+RSSFeed.Options.Filter.TVShow.filtStart.Season=Series
+RSSFeed.Options.Filter.TVShow.filtStart.Episode=, Episode
+RSSFeed.Options.Filter.TVShow.filtEnd=To:
+RSSFeed.Options.Filter.TVShow.filtEnd.Season=Series
+RSSFeed.Options.Filter.TVShow.filtEnd.Episode=, Episode
+RSSFeed.Options.Filter.TVShow.Options=Options:
+RSSFeed.Options.Filter.TVShow.Options.SmartHist=Utilize Smart History:
+RSSFeed.Options.Filter.Other.Options=Options:
+RSSFeed.Options.Filter.Other.Options.Disable=Disable After Success
+RSSFeed.Options.Filter.filtActive=Active:
+RSSFeed.Options.Filter.filtEnabled=Enabled
+RSSFeed.Options.Filter.filtMode=Mode:
+RSSFeed.Options.Filter.filtMode.Pass=Pass
+RSSFeed.Options.Filter.filtMode.Fail=Fail
+RSSFeed.Options.Filter.btnFiltAccept=Save
+RSSFeed.Options.Filter.btnFiltReset=Reset
+RSSFeed.Options.Filter.btnFiltCancel=Cancel
+RSSFeed.Options.Filter.btnFiltTest=Test
+RSSFeed.Options.Filter.filtTestMatch=Test match:
+# Hist Items - Hist Table
+RSSFeed.Hist.HistTable.Col0=Download Started
+RSSFeed.Hist.HistTable.Col1=File Save Location
+RSSFeed.Hist.HistTable.Col2=Torrent Location
+RSSFeed.Hist.HistTable.Col3=Info
+# Hist Items - Hist Table, Menu Items
+RSSFeed.Hist.HistTable.Menu.CopyFile=Copy &File Save Location to Clipboard
+RSSFeed.Hist.HistTable.Menu.CopyTorrent=Copy &Torrent Location to Clipboard
+RSSFeed.Hist.HistTable.Menu.Delete=&Delete Selected Torrents
+# Info Window
+RSSFeed.InfoWin.Hide=Hide
+
Added: plugins/rssfeed/org/kmallan/resource/lang/Messages_fr_FR.properties
===================================================================
--- plugins/rssfeed/org/kmallan/resource/lang/Messages_fr_FR.properties (rev 0)
+++ plugins/rssfeed/org/kmallan/resource/lang/Messages_fr_FR.properties 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,121 @@
+# Main Items
+RSSFeed.Name=RSSFeed
+RSSFeed.Title=Module de balayage De RSSFeed
+# Config Items
+RSSFeed.Config=RSSFeed
+RSSFeed.Config.Enable=Recharge Automatique Permise
+RSSFeed.Config.Delay=La Recharge Automatique De D\xE9faut Retarde
+RSSFeed.Config.AutoLoad=\xC9tiquette de RSSFeed de charge sur le d\xE9marrage
+RSSFeed.Config.KeepOld=Keep old/removed items (days)
+RSSFeed.Config.KeepMax=Maximum items to keep
+RSSFeed.Config.AutoStartManual=Start manually saved torrents
+# Tab Items
+RSSFeed.Tab.Status=Statut
+RSSFeed.Tab.Options=Options
+RSSFeed.Tab.History=Histoire de t\xE9l\xE9chargement
+RSSFeed.Tab.Help=Aide
+# Status Items - List Table
+RSSFeed.Status.ListTable.Col0=Alimentation/Titre
+RSSFeed.Status.ListTable.Col1=Statut/Lien
+RSSFeed.Status.ListTable.Col2=Age
+RSSFeed.Status.ListTable.Col3=Allumettes
+# Status Items - List Table, Menu Items
+RSSFeed.Status.ListTable.Menu.Refresh=&R\xE9g\xE9n\xE9rez L'Alimentation
+RSSFeed.Status.ListTable.Menu.RefreshAll=R\xE9g\xE9n\xE9rez &Toute L'Alimentation
+RSSFeed.Status.ListTable.Menu.Expand=&Expand All
+RSSFeed.Status.ListTable.Menu.Collapse=&Collapse All
+RSSFeed.Status.ListTable.Menu.Download=&\xC9conomiser Le Torrent
+RSSFeed.Status.ListTable.Menu.DownloadTo=\xC9conomiser Le Torrent &As
+RSSFeed.Status.ListTable.Menu.Cancel=&D\xE9commandez Le T\xE9l\xE9chargement
+RSSFeed.Status.ListTable.Menu.FilterFrom=Cr\xE9ez Le &Filtre
+RSSFeed.Status.ListTable.Menu.CopyLink=Lien de © \xE0 la planchette
+RSSFeed.Status.ListTable.Menu.OpenLink=&Open Link URL
+RSSFeed.Status.ListTable.Menu.ShowInfo=&Montrez L'Information
+RSSFeed.Status.ListTable.Menu.ShowInfo.Dialog.Title=Description De Torrent
+RSSFeed.Status.ListTable.Menu.ShowInfo.Dialog.TitleBar=Information
+# Option Items
+RSSFeed.Options.Title=Options:
+# Option Items - Feed Table
+RSSFeed.Options.Feed.Title=Alimentation URLs de RSS:
+RSSFeed.Options.Feed.Table.Col0=Nom
+# Option Items - Feed Items
+RSSFeed.Options.Feed.urlName=Nom:
+RSSFeed.Options.Feed.urlLocation=URL:
+RSSFeed.Options.Feed.urlStoreDir=Annuaire:
+RSSFeed.Options.Feed.urlDelay=Retarde:
+RSSFeed.Options.Feed.urlSettings=Arrangements:
+RSSFeed.Options.Feed.Options=Options:
+RSSFeed.Options.Feed.urlObeyTTL=Ob\xE9issez TTL
+RSSFeed.Options.Feed.urlLocRef=Employez le URL comme Referer pour des torrents
+RSSFeed.Options.Feed.urlUseCookie=Passez Cookie's
+RSSFeed.Options.Feed.urlReferer=Referer Fait sur commande:
+RSSFeed.Options.Feed.urlCookie=Cookie's:
+RSSFeed.Options.Feed.urlActive=Actif:
+RSSFeed.Options.Feed.urlEnabled=Permis
+RSSFeed.Options.Feed.btnUrlAccept=Acceptez
+RSSFeed.Options.Feed.btnUrlReset=Remise
+RSSFeed.Options.Feed.btnUrlCancel=Annulation
+# Option Items - Filter Table
+RSSFeed.Options.Filter.Title=Filtres:
+RSSFeed.Options.Filter.Table.Col0=Nom
+RSSFeed.Options.Filter.Table.Col1=Type
+RSSFeed.Options.Filter.Table.Col2=Mode
+# Option Items - Filter Items
+RSSFeed.Options.Filter.filtName=Nom:
+RSSFeed.Options.Filter.filtStoreDir=Annuaire:
+RSSFeed.Options.Filter.filtExpression=Filtre:
+RSSFeed.Options.Filter.Options=Options:
+RSSFeed.Options.Filter.Options.filtIsRegex=Le filtre est une expression r\xE9guli\xE8re
+RSSFeed.Options.Filter.Options.filtMatch.Title=Le filtre recherche le titre
+RSSFeed.Options.Filter.Options.filtMatch.Link=Le filtre recherche le lien
+RSSFeed.Options.Filter.Options.MoveTop=D\xE9placez-vous au dessus
+RSSFeed.Options.Filter.State=Placez L'\xC9tat \xC0:
+RSSFeed.Options.Filter.State.Queued=Align\xE9
+RSSFeed.Options.Filter.State.Forced=T\xE9l\xE9chargement Obligatoire
+RSSFeed.Options.Filter.State.Stopped=Exploit\xE9 en gradins
+RSSFeed.Options.Filter.Priority=Priorit\xE9:
+RSSFeed.Options.Filter.Priority.High=Haut
+RSSFeed.Options.Filter.Priority.Low=Bas
+RSSFeed.Options.Filter.Rates=Taux D'Overide:
+RSSFeed.Options.Filter.Rates.UseCustom=Employez Les Taux Faits sur commande
+RSSFeed.Options.Filter.Rates.Upload=Vitesse d'Envoy (KB/s):
+RSSFeed.Options.Filter.Rates.Download=Vitesse de T\xE9l\xE9chargement (KB/s):
+RSSFeed.Options.Filter.filtCategory=Placez La Cat\xE9gorie:
+RSSFeed.Options.Filter.filtFeed=Alimentation:
+RSSFeed.Options.Filter.filtFeed.All=Tous
+RSSFeed.Options.Filter.filtType=Type:
+RSSFeed.Options.Filter.filtType.TVShow=TVShow
+RSSFeed.Options.Filter.filtType.Other=Autre
+RSSFeed.Options.Filter.filtType.None=Aucun
+RSSFeed.Options.Filter.TVShow.filtStart=De:
+RSSFeed.Options.Filter.TVShow.filtStart.Season=S\xE9rie
+RSSFeed.Options.Filter.TVShow.filtStart.Episode=, \xC9pisode
+RSSFeed.Options.Filter.TVShow.filtEnd=\xC0:
+RSSFeed.Options.Filter.TVShow.filtEnd.Season=S\xE9rie
+RSSFeed.Options.Filter.TVShow.filtEnd.Episode=, \xC9pisode
+RSSFeed.Options.Filter.TVShow.Options=Options:
+RSSFeed.Options.Filter.TVShow.Options.SmartHist=Gebruik Slimme Geschiedenis:
+RSSFeed.Options.Filter.Other.Options=Options:
+RSSFeed.Options.Filter.Other.Options.Disable=Neutralisez Apr\xE8s Succ\xE8s
+RSSFeed.Options.Filter.filtActive=Actif:
+RSSFeed.Options.Filter.filtEnabled=Permis
+RSSFeed.Options.Filter.filtMode=Mode:
+RSSFeed.Options.Filter.filtMode.Pass=Passage
+RSSFeed.Options.Filter.filtMode.Fail=\xC9chouer
+RSSFeed.Options.Filter.btnFiltAccept=Acceptez
+RSSFeed.Options.Filter.btnFiltReset=Remise
+RSSFeed.Options.Filter.btnFiltCancel=Annulation
+RSSFeed.Options.Filter.btnFiltTest=Test
+RSSFeed.Options.Filter.filtTestMatch=Test match:
+# Hist Items - Hist Table
+RSSFeed.Hist.HistTable.Col1=Download Started
+RSSFeed.Hist.HistTable.Col1=Le Dossier Sauvent L'Endroit
+RSSFeed.Hist.HistTable.Col2=Torrent Location
+RSSFeed.Hist.HistTable.Col3=Information
+# Hist Items - Hist Table, Menu Items
+RSSFeed.Hist.HistTable.Menu.CopyFile=&Le dossier de copy sauvent Location \xE0 la planchette
+RSSFeed.Hist.HistTable.Menu.CopyTorrent=&Torrent Location de copy \xE0 la planchette
+RSSFeed.Hist.HistTable.Menu.Delete=Torrents Choisis Par &Effacement
+# Info Window
+RSSFeed.InfoWin.Hide=Peau
+
Added: plugins/rssfeed/plugin.properties
===================================================================
--- plugins/rssfeed/plugin.properties (rev 0)
+++ plugins/rssfeed/plugin.properties 2012-03-14 15:50:25 UTC (rev 26902)
@@ -0,0 +1,5 @@
+plugin.id=rssfeed
+plugin.name=RSSFeed Scanner
+plugin.version=1.3.6
+plugin.class=org.kmallan.azureus.rssfeed.Plugin
+plugin.langfile=org.kmallan.resource.lang.Messages
|