RSS plugin by 'daddy'

This commit is contained in:
Marcos Pinto 2007-07-22 06:16:17 +00:00
parent 369c21b6f7
commit b57b07b783
4 changed files with 4544 additions and 0 deletions

View file

@ -0,0 +1,728 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.2.0 on Sat Jul 21 16:48:25 2007 by daddy-->
<glade-interface>
<widget class="GtkWindow" id="FlexRSS_MainWindow">
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="title" translatable="yes">FlexRSS</property>
<signal name="destroy" handler="on_FlexRSS_MainWindow_destroy"/>
<child>
<widget class="GtkNotebook" id="FlexRSS_MainNotebook">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="homogeneous">True</property>
<child>
<widget class="GtkVBox" id="FlexRSS_FeedsTab">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkScrolledWindow" id="FlexRSS_Feeds_Scroll">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<child>
<widget class="GtkTreeView" id="FlexRSS_Feeds">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="headers_clickable">True</property>
<signal name="popup_menu" handler="on_FlexRSS_Feeds_popup_menu"/>
<signal name="button_press_event" handler="on_FlexRSS_Feeds_button_press_event"/>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkHBox" id="FlexRSS_Feeds_Actions">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkButton" id="FlexRSS_Feeds_New">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-new</property>
<property name="use_stock">True</property>
<signal name="pressed" handler="on_FlexRSS_Feeds_New_pressed"/>
</widget>
</child>
<child>
<widget class="GtkButton" id="FlexRSS_Feeds_Save">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-save</property>
<property name="use_stock">True</property>
<signal name="pressed" handler="on_FlexRSS_Feeds_Save_pressed"/>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="FlexRSS_Feeds_Delete">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-delete</property>
<property name="use_stock">True</property>
<signal name="pressed" handler="on_FlexRSS_Feeds_Delete_pressed"/>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkTable" id="FlexRSS_Feeds_Editor">
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<child>
<widget class="GtkEntry" id="FlexRSS_EditFeed_Name">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="FlexRSS_EditFeed_URL">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="FlexRSS_EditFeed_Interval">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="text" translatable="yes">900</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_EditFeed_Name_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Name</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
<property name="x_padding">5</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_EditFeed_URL_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">URL</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
<property name="x_padding">5</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_EditFeed_Interval_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Update Interval</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
<property name="x_padding">5</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="tab_expand">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_FeedsTab_Label">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Feeds</property>
</widget>
<packing>
<property name="type">tab</property>
<property name="tab_expand">False</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="FlexRSS_FiltersTab">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkVBox" id="FlexRSS_Filters_LeftPane">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkScrolledWindow" id="FlexRSS_Filters_List_Scroll">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<child>
<widget class="GtkTreeView" id="FlexRSS_Filters_List">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="headers_visible">False</property>
<property name="headers_clickable">True</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkHBox" id="FlexRSS_Filters_Actions">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkButton" id="FlexRSS_Filters_Add">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-add</property>
<property name="use_stock">True</property>
<signal name="pressed" handler="on_FlexRSS_Filters_Add_pressed"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="FlexRSS_Filters_Delete">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-delete</property>
<property name="use_stock">True</property>
<signal name="pressed" handler="on_FlexRSS_Filters_Delete_pressed"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="FlexRSS_Filter_RightPane">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkFrame" id="FlexRSS_Filter_Info">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<child>
<widget class="GtkAlignment" id="FlexRSS_Filter_Info_Align">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkTable" id="FlexRSS_Filters_Info_Table">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<child>
<widget class="GtkScrolledWindow" id="FlexRSS_Filters_Feed_Scroll">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<child>
<widget class="GtkTreeView" id="FlexRSS_Filters_Feed">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="headers_visible">False</property>
<property name="headers_clickable">True</property>
<property name="show_expanders">False</property>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Feed_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Feed</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Type_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Type</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Name_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Name</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="FlexRSS_Filters_Type">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="items" translatable="yes">Generic
TV Show
TV Show (dated)</property>
<signal name="changed" handler="on_FlexRSS_Filters_Test_Pattern"/>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="FlexRSS_Filters_Name">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filter_Info_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">&lt;b&gt;Information&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="FlexRSS_Filter">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<child>
<widget class="GtkAlignment" id="FlexRSS_Filter_Align">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="FlexRSS_Filter_Patterns">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkVBox" id="FlexRSS_Filter_Patterns_List">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
</widget>
</child>
<child>
<widget class="GtkHBox" id="FlexRSS_Filter_Patterns_Actions">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkLayout" id="FlexRSS_Padding3">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="FlexRSS_Filter_Patern_Add">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-add</property>
<property name="use_stock">True</property>
<signal name="pressed" handler="on_FlexRSS_Filter_Patern_Add_pressed"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filter_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">&lt;b&gt;Filters&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="FlexRSS_Filter_Test">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_OUT</property>
<child>
<widget class="GtkAlignment" id="FlexRSS_Filter_Test_Align">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="FlexRSS_Filters_Test_VB">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkEntry" id="FlexRSS_Filters_Test_Pattern">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<signal name="changed" handler="on_FlexRSS_Filters_Test_Pattern"/>
</widget>
</child>
<child>
<widget class="GtkVBox" id="FlexRSS_Filters_Test_Results">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Result">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Doesn't Match</property>
</widget>
</child>
<child>
<widget class="GtkVBox" id="FlexRSS_Filters_Test_Results_V">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkTable" id="FlexRSS_Filters_Test_Results_TVShow">
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="n_rows">2</property>
<property name="n_columns">2</property>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Results_TVShow_Episode">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Results_TVShow_Series">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Results_TVShow_Episode_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Episode</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Results_TVShow_Series_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Season</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkTable" id="FlexRSS_Filters_Test_Results_TVShow_Dated">
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Results_TVShow_Dated_Day">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Results_TVShow_Dated_Month">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Results_TVShow_Dated_Year">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Results_TVShow_Dated_Day_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Day</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Results_TVShow_Dated_Month_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Month</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filters_Test_Results_TVShow_Dated_Year_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Year</property>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_Filter_Test_L">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">&lt;b&gt;Test&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkHBox" id="FlexRSS_Filter_Actions">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkLayout" id="FlexRSS_Filter_Padding2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="FlexRSS_Action_Save">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">gtk-save</property>
<property name="use_stock">True</property>
<signal name="pressed" handler="on_FlexRSS_Action_Save_pressed"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">4</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
<property name="tab_expand">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="FlexRSS_FiltersTab_Label">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Filters</property>
</widget>
<packing>
<property name="type">tab</property>
<property name="position">1</property>
<property name="tab_expand">False</property>
<property name="tab_fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View file

@ -0,0 +1,24 @@
plugin_name = "FlexRSS"
plugin_author = "Daddy"
plugin_version = "0.0.1"
plugin_description = """
Advanced RSS scraper
This plugin is similar in purpose to Mark Adamson's excellent RSS Broadcatcher, but targets a more advanced audience. It is extremely powerful, configurable, unforgiving, and difficult.
Filters use regular expressions with named patterns and strptime(3)-like format filters to match items."""
from FlexRSS.plugin import plugin_FlexRSS
def deluge_init(deluge_path):
global path
path = deluge_path
def enable(core, interface):
global path
return plugin_FlexRSS(path, core, interface)
FlexyRSS_DEFAULTS = {
}

File diff suppressed because it is too large Load diff

934
plugins/FlexRSS/plugin.py Normal file
View file

@ -0,0 +1,934 @@
class plugin_FlexRSS_Config:
feeds_counter = 0
filters_counter = 0
feeds = None
filters = None
# def listFilters(self):
# if not self.filters:
# return
# print 'Filters:'
# for filter in self.filters:
# print '+ id: %d' % filter['id']
# print ' name: %s' % filter['name']
# print ' type: %s' % filter['type']
# print ' patterns:'
# for p in filter['patterns']:
# print ' + [%s]' % p[1]
# print ' %s' % p[0]
# def listFeeds(self):
# if not self.feeds:
# return
# print 'Feeds:'
# for feed in self.feeds:
# print '+ id: %d' % feed['id']
# print ' name: %s' % feed['name']
# print ' url: %s' % feed['url']
# print ' interval: %d' % feed['interval']
def getFilter(self, id):
if not self.filters:
return None
for filter in self.filters:
if filter['id'] == id:
return filter
return None
def setFilter(self, id, key, value):
filter = self.getFilter(id)
if not filter:
return False
else:
filter[key] = value
return True
def addFilter(self, name, type, patterns, feeds):
id = self.feeds_counter + 1
self.feeds_counter = id
if not self.filters:
self.filters = []
filter = { "id" : id,
"name" : name,
"type" : type,
"patterns" : patterns,
"feeds" : feeds,
"history" : {} }
self.filters.append(filter)
return id
def deleteFilter(self, id):
if not self.filters:
return False
i = 0
while i < len(self.filters):
if self.filters[i]['id'] == id:
del self.filters[i]
return True
i = i + 1
def checkHistory(self, id, type, data):
filter = self.getFilter(id)
if not filter:
return False
try:
if type == 'TV Show':
filter['history'][type][data['series']].index(data['episode'])
return True
elif type == 'TV Show (dated)':
filter['history'][type][data['year']][data['month']].index(data['day'])
return True
else:
filter['history'][type].index(data['url'])
return True
except:
return False
def addHistory(self, id, type, data):
filter = self.getFilter(id)
if not filter:
return False
if type == 'TV Show':
if not filter['history'].has_key(type):
filter['history'][type] = {}
if not filter['history'][type].has_key(data['series']):
filter['history'][type][data['series']] = []
filter['history'][type][data['series']].append(data['episode'])
elif type == 'TV Show (dated)':
if not filter['history'].has_key(type):
filter['history'][type] = {}
if not filter['history'][type].has_key(data['year']):
filter['history'][type][data['year']] = {}
if not filter['history'][type][data['year']].has_key(data['month']):
filter['history'][type][data['year']][data['month']] = []
filter['history'][type][data['year']][data['month']].append(data['day'])
else:
if not filter['history'].has_key(type):
filter['history'][type] = []
filter['history'][type].append(data['url'])
def getFeed(self, id):
if not self.feeds:
return None
for feed in self.feeds:
if feed['id'] == id:
return feed
return None
def setFeed(self, id, key, value):
feed = self.getFeed(id)
if not feed:
return False
else:
feed[key] = value
return True
def addFeed(self, name, url, interval):
# Uhhh... no ++? WTF is the increment operator?
id = self.feeds_counter + 1
self.feeds_counter = id
if not self.feeds:
self.feeds = []
self.feeds.append({ "id" : id,
"name" : name,
"url" : url,
"interval" : interval })
return id
def deleteFeed(self, id):
if not self.feeds:
return False
i = 0
while i < len(self.feeds):
if self.feeds[i]['id'] == id:
del self.feeds[i]
return True
i = i + 1
class plugin_FlexRSS:
config = None
glade = None
feeds = None
def load_config(self):
import deluge.common, os
file = deluge.common.CONFIG_DIR + "/flexrss.dat"
if os.path.isfile(file):
import pickle
fd = open(file, 'r')
self.config = pickle.load(fd)
fd.close()
else:
self.config = plugin_FlexRSS_Config()
def write_config(self):
import deluge.common, os, pickle
file = deluge.common.CONFIG_DIR + "/flexrss.dat"
fd = open(file, 'w')
pickle.dump(self.config, fd)
fd.close()
def configure_cb_closed(self, args):
self.glade = None
def configure_cb_feed_new(self, args):
feed = { "name" : 'Untitled',
"url" : 'http://',
"interval" : 900,
"id" : 0 }
feed["id"] = self.config.addFeed(feed["name"], feed["url"], feed["interval"])
view = self.glade.get_widget("FlexRSS_Feeds")
model = view.get_model()
view.get_selection().select_iter(model.append(None, (feed["id"], feed["name"], feed["url"])))
def configure_cb_feed_selected(self, selection):
model, iter = selection.get_selected()
if not iter:
return
parent = model.iter_parent(iter)
if parent: # Selected a filter
iter = parent
# We want to edit a feed.
feed = self.config.getFeed(model.get_value(iter, 0))
if not feed:
print 'Error: could not find feed #' + str(model.get_value(iter, 0))
return
self.glade.get_widget("FlexRSS_EditFeed_Name").set_text(feed["name"])
self.glade.get_widget("FlexRSS_EditFeed_URL").set_text(feed["url"])
self.glade.get_widget("FlexRSS_EditFeed_Interval").set_text(str(feed["interval"]))
self.glade.get_widget('FlexRSS_Feeds_Editor').show()
def configure_cb_feed_delete(self, arg, id=None):
if not id:
# Which feed is selected?
selection = self.glade.get_widget("FlexRSS_Feeds").get_selection()
model, iter = selection.get_selected()
if not iter:
return
id = model.get_value(iter, 0)
else:
model = self.glade.get_widget("FlexRSS_Feeds").get_model()
iter = model.get_iter_first()
while iter:
if model.get_value(iter, 0) == id:
break
iter = model.iter_next(iter)
if not iter:
print 'Couldn\'t find feed.'
return
# Remove from config
if not self.config.deleteFeed(id):
print 'Unable to delete feed #' + str(id)
return
# Remove from UI
model.remove(iter)
self.write_config()
# We are no longer editing a feed, so hide the editing widgets.
self.glade.get_widget('FlexRSS_Feeds_Editor').hide()
def configure_cb_feed_save(self, arg, id=None):
if not id:
# Which feed is selected?
selection = self.glade.get_widget("FlexRSS_Feeds").get_selection()
model, iter = selection.get_selected()
if not iter:
return
id = model.get_value(iter, 0)
else:
model = self.glade.get_widget("FlexRSS_Feeds").get_model()
iter = model.iter_first()
while iter:
if model.get_value(iter, 0) == id:
break
iter = iter.iter_next(iter)
if not iter:
print 'Couldn\'t find feed.'
return
# Update configuration
self.config.setFeed(id, "name", self.glade.get_widget("FlexRSS_EditFeed_Name").get_text())
self.config.setFeed(id, "url", self.glade.get_widget("FlexRSS_EditFeed_URL").get_text())
self.config.setFeed(id, "interval", int(self.glade.get_widget("FlexRSS_EditFeed_Interval").get_text()))
self.write_config()
# Update UI
feed = self.config.getFeed(id)
model.set_value(iter, 0, feed["id"])
model.set_value(iter, 1, feed["name"])
model.set_value(iter, 2, feed["url"])
if not self.feeds.has_key(id):
self.feeds[id] = { 'cfg' : feed,
'updated' : 0,
'data' : [] }
def configure_cb_filter_new(self, arg, test_pattern=None):
filter = { "name" : "Untitled",
"type" : "Generic",
"patterns" : [('', 'Title')],
"feeds" : [0],
"id" : 0 }
if test_pattern:
# Try to guess a good pattern
import re, string
trans_table = string.maketrans(' ', '.')
# TV Show
exp = re.compile('(.*).([0-9]+)x([0-9]+)', re.IGNORECASE)
match = exp.match(test_pattern)
if match:
pattern = match.group(1).lower().translate(trans_table) + '.%sx%e'
filter['patterns'][0] = (pattern, 'Title')
filter['name'] = match.group(1)
filter['type'] = 'TV Show'
if not match:
exp = re.compile('(.*).S([0-9]+)E([0-9]+)', re.IGNORECASE)
match = exp.match(test_pattern)
if match:
pattern = match.group(1).lower().translate(trans_table) + '.S%sE%e'
filter['patterns'][0] = (pattern, 'Title')
filter['name'] = match.group(1)
filter['type'] = 'TV Show'
if not match:
exp = re.compile('(.*).([0-9]{4}).([0-9]{1,2}).([0-9]{1,2})', re.IGNORECASE)
match = exp.match(test_pattern)
if match:
pattern = None
if ((int(match.group(3)) <= 12) and (int(match.group(4)) <= 31)):
pattern = match.group(1).lower().translate(trans_table) + '.%Y.%m.%d'
elif ((int(match.group(3)) <= 31) and (int(match.group(4)) <= 12)):
pattern = match.group(1).lower().translate(trans_table) + '.%Y.%d.%m'
if pattern:
filter['patterns'][0] = (pattern, 'Title')
filter['name'] = match.group(1)
filter['type'] = 'TV Show (dated)'
else:
match = None
if not match:
exp = re.compile('(.*).([0-9]+)', re.IGNORECASE)
match = exp.match(test_pattern)
if match:
pattern = match.group(1).lower().translate(trans_table) + '.%e'
filter['patterns'][0] = (pattern, 'Title')
filter['name'] = match.group(1)
filter['type'] = 'TV Show'
# Add to config
filter['id'] = self.config.addFilter(filter['name'], filter['type'], filter['patterns'], 'feeds')
# Add to UI
self.configure_ui_add_filter(self.config.getFilter(filter['id']), test_pattern)
def configure_cb_filter_selected(self, selection):
model, iter = selection.get_selected()
if not iter:
return
# We want to edit a filter.
filter = self.config.getFilter(model.get_value(iter, 0))
if not filter:
print 'Error: could not find filter #' + str(model.get_value(iter, 0))
return
self.glade.get_widget('FlexRSS_Filters_Name').set_text(filter['name'])
if filter['type'] == 'TV Show':
type_i = 1
elif filter['type'] == 'TV Show (dated)':
type_i = 2
else:
type_i = 0
self.glade.get_widget('FlexRSS_Filters_Type').set_active(type_i)
selection = self.glade.get_widget('FlexRSS_Filters_Feed').get_selection()
selection.unselect_all()
feed_model = self.glade.get_widget('FlexRSS_Filters_Feed').get_model()
for i in filter['feeds']:
if i == 0:
selection.select_all()
else:
iter = feed_model.get_iter_first()
while iter:
if feed_model.get_value(iter, 0) == i:
selection.select_iter(iter)
iter = feed_model.iter_next(iter)
filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List')
for child in filter_patterns.get_children():
child.destroy()
for pattern in filter['patterns']:
self.configure_ui_add_pattern(pattern)
def configure_cb_filter_save(self, arg):
# Which feed is selected?
selection = self.glade.get_widget("FlexRSS_Filters_List").get_selection()
model, iter = selection.get_selected()
if not iter:
return
id = model.get_value(iter, 0)
name = self.glade.get_widget('FlexRSS_Filters_Name').get_text()
self.config.setFilter(id, 'name', name)
iter = model.get_iter_first()
while iter:
if model.get_value(iter, 0) == id:
model.set_value(iter, 1, name)
iter = model.iter_next(iter)
type = self.glade.get_widget('FlexRSS_Filters_Type').get_active()
if type == 1:
type_s = 'TV Show'
elif type == 2:
type_s = 'TV Show (dated)'
else:
type_s = 'Generic'
self.config.setFilter(id, 'type', type_s)
model, paths = self.glade.get_widget('FlexRSS_Filters_Feed').get_selection().get_selected_rows()
feeds = []
for path in paths:
feeds.append(model.get_value(model.get_iter(path), 0))
if len(feeds) == 0:
feeds.append(0)
self.config.setFilter(id, 'feeds', feeds)
patterns = []
filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List')
for i in filter_patterns.get_children():
data = i.get_children()
pattern = data[0].get_text()
if data[2].get_active() == 1:
type = 'Link'
else:
type = 'Title'
patterns.append((pattern, type))
self.config.setFilter(id, 'patterns', patterns)
self.write_config()
def configure_cb_remove_pattern(self, arg):
arg.get_parent().destroy()
def configure_ui_add_pattern(self, pattern):
import gtk, gobject
filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List')
hbox = gtk.HBox()
filter_patterns.pack_start(hbox)
input = gtk.Entry()
input.set_text(pattern[0])
input.connect("changed", self.configure_cb_test_filter)
on = gtk.Label()
on.set_text('On')
on.show()
combo = gtk.combo_box_new_text()
combo.append_text('Title')
combo.append_text('Link')
if pattern[1] == 'Link':
combo.set_active(1)
else:
combo.set_active(0)
remove = gtk.Button(stock=gtk.STOCK_REMOVE)
remove.connect("pressed", self.configure_cb_remove_pattern)
hbox.pack_start(input)
hbox.pack_start(on, expand=False)
hbox.pack_start(combo, expand=False)
hbox.pack_start(remove, expand=False)
hbox.show_all()
def configure_cb_add_pattern(self, args):
self.configure_ui_add_pattern(('', 'Title'))
def configure_ui_add_filter(self, filter, test_pattern=None):
if not filter:
print 'No filter to add'
return None
model = self.glade.get_widget("FlexRSS_Filters_List").get_model()
iter = model.append(None, (filter['id'], filter['name']))
if not iter:
return
view = self.glade.get_widget("FlexRSS_Filters_List")
model = view.get_model()
view.get_selection().select_iter(iter)
if test_pattern:
self.glade.get_widget('FlexRSS_Filters_Test_Pattern').set_text(test_pattern)
self.configure_cb_test_filter(None)
self.glade.get_widget('FlexRSS_MainNotebook').set_current_page(1)
def configure_ui_test_result(self, result):
if result:
self.glade.get_widget('FlexRSS_Filters_Test_Result').set_text('Match')
else:
self.glade.get_widget('FlexRSS_Filters_Test_Result').set_text('Doesn\'t match')
type = self.glade.get_widget('FlexRSS_Filters_Type').get_active()
if type == 0: # Generic
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide()
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide()
elif type == 1: # TV Show
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').show()
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide()
if result:
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Series').set_text(str(result['series']))
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Episode').set_text(str(result['episode']))
else:
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Series').set_text('0')
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Episode').set_text('0')
else: # TV Show (dated)
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide()
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').show()
if result:
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Year').set_text(str(result['year']))
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Month').set_text(str(result['month']))
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Day').set_text(str(result['day']))
else:
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Year').set_text('0')
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Month').set_text('0')
self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Day').set_text('0')
def configure_cb_test_filter(self, filter):
subject = self.glade.get_widget('FlexRSS_Filters_Test_Pattern').get_text()
if len(subject) > 1:
type = self.glade.get_widget('FlexRSS_Filters_Type').get_active()
if type == 1:
type_s = 'TV Show'
elif type == 2:
type_s = 'TV Show (dated)'
else:
type_s = 'Generic'
filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List')
for i in filter_patterns.get_children():
data = i.get_children()
pattern = data[0].get_text()
if len(pattern):
result = self.test_pattern(type_s, subject, pattern)
if result:
self.configure_ui_test_result(result)
return
self.configure_ui_test_result(False)
def configure_cb_delete_filter(self, arg):
# Which filter is selected?
selection = self.glade.get_widget("FlexRSS_Filters_List").get_selection()
model, iter = selection.get_selected()
if not iter:
return
id = model.get_value(iter, 0)
# Remove from config
if not self.config.deleteFilter(id):
print 'Unable to delete filter #' + str(id)
return
self.write_config()
# Remove from UI
model.remove(iter)
# Fuck it--just leave the crap in the widgets. Todo: fix it so
# the save button will create a new filter if it must.
def configure_cb_feed_refresh(self, caller, id=None):
if not id:
selection = self.glade.get_widget("FlexRSS_Feeds").get_selection()
model, iter = selection.get_selected()
if not iter:
return
id = model.get_value(iter, 0)
if id:
self.parse_feed(id)
def configure_cb_feed_popup(self, view, event):
if event.button != 3:
return
model = view.get_model()
coords = event.get_coords()
path = view.get_path_at_pos(int(coords[0]), int(coords[1]))
if path:
iter = model.get_iter(path[0])
else:
iter = None
import gtk
popup = gtk.Menu()
if iter:
id = model.get_value(iter, 0)
if id: # Feed
item_refresh = gtk.MenuItem("Refresh")
item_refresh.connect("activate", self.configure_cb_feed_refresh, id)
popup.append(item_refresh)
item_delete = gtk.MenuItem("Delete")
item_delete.connect("activate", self.configure_cb_feed_delete, id)
popup.append(item_delete)
else: # Filter
item_filter = gtk.MenuItem("Create filter")
item_filter.connect("activate", self.configure_cb_filter_new, model.get_value(iter, 1))
popup.append(item_filter)
else: # Neither
item_new = gtk.MenuItem("New feed")
item_new.connect("activate", self.configure_cb_feed_new)
popup.append(item_new)
popup.popup(None, None, None, event.button, event.time)
popup.show_all()
def configure(self):
if self.glade: # Dialog already running
return
import gtk, gtk.glade, gobject
self.glade = gtk.glade.XML(self.path + "/FlexRSS.glade")
# Intialize feed lists
feeds_model = gtk.TreeStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING)
feeds_view = self.glade.get_widget("FlexRSS_Feeds")
filters_feeds_view = self.glade.get_widget("FlexRSS_Filters_Feed")
feeds_view.set_model(feeds_model)
filters_feeds_view.set_model(feeds_model)
# Setup columns for feeds tab
renderer_name = gtk.CellRendererText()
column_name = gtk.TreeViewColumn("Name", renderer_name, text=1)
feeds_view.append_column(column_name)
renderer_url = gtk.CellRendererText()
column_url = gtk.TreeViewColumn("URL", renderer_url, text=2)
feeds_view.append_column(column_url)
# Set callback for when selection is changed in feeds tab
# I can't figure out how to do this in Glade
feeds_view.get_selection().connect("changed", self.configure_cb_feed_selected)
# Setup columns for feed list on filters tab
renderer_name = gtk.CellRendererText()
column_name = gtk.TreeViewColumn("Name", renderer_name, text=1)
filters_feeds_view.append_column(column_name)
# Allow multiple selections of feeds in filters tab
# I can't figure out how to do this in Glade
filters_feeds_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
# Populate feed lists
if self.config.feeds:
for feed in self.config.feeds:
this_feed = feeds_model.append(None, (feed['id'], feed['name'], feed['url']))
for item in self.feeds[feed['id']]['data']:
feeds_model.append(this_feed, (0, item['title'], item['link']))
# Initialize filters list
filters_model = gtk.TreeStore(gobject.TYPE_INT, gobject.TYPE_STRING)
filters_view = self.glade.get_widget("FlexRSS_Filters_List")
filters_view.set_model(filters_model)
# Setup columns for filters list
renderer_name = gtk.CellRendererText()
column_name = gtk.TreeViewColumn("Name", renderer_name, text=1)
filters_view.append_column(column_name)
# Set callback for when selection is changed in feeds tab
# I can't figure out how to do this in Glade
filters_view.get_selection().connect("changed", self.configure_cb_filter_selected)
# Populate filters list
if self.config.filters:
for filter in self.config.filters:
filters_model.append(None, (filter['id'], filter['name']))
# Callbacks for UI events
actions = { # Feeds tab
"on_FlexRSS_MainWindow_destroy" : self.configure_cb_closed,
"on_FlexRSS_Feeds_New_pressed" : self.configure_cb_feed_new,
"on_FlexRSS_Feeds_Save_pressed" : self.configure_cb_feed_save,
"on_FlexRSS_Feeds_Delete_pressed" : self.configure_cb_feed_delete,
"on_FlexRSS_Feeds_button_press_event" : self.configure_cb_feed_popup,
# Filters tab
"on_FlexRSS_Filters_Add_pressed" : self.configure_cb_filter_new,
"on_FlexRSS_Action_Save_pressed" : self.configure_cb_filter_save,
"on_FlexRSS_Filter_Patern_Add_pressed" : self.configure_cb_add_pattern,
"on_FlexRSS_Filters_Test_Pattern" : self.configure_cb_test_filter,
"on_FlexRSS_Filters_Delete_pressed" : self.configure_cb_delete_filter }
self.glade.signal_autoconnect(actions)
self.glade.get_widget("FlexRSS_MainWindow").show()
def cmp_history(a, b):
try:
if a.has_key('series'):
if a['series'] > b['series']:
return 1
elif a['series'] < b['series']:
return -1
else:
if a['episode'] > b['episode']:
return 1
elif a['episode'] < b['episode']:
return -1
else:
return 0
except:
return 0
def strptime2regex(self, input):
# Does'n exactly live up to its name yet. Currently just
# replaces %y,%Y,%m,%d with named patterns. In the future, it
# would be nice to allow escaping (e.g., %%Y means literal %Y)
# and expand it to support other formats.
patterns = [('%Y', '(?P<Y>[0-9]{4})'),
('%y', '(?P<y>[0-9]{2})'),
('%m', '(?P<m>[0-9]{1,2})'),
('%d', '(?P<d>[0-9]{1,2})')]
out = input
for p in patterns:
out = out.replace(p[0], p[1])
return out
def replace_tv_show_patterns(self, input):
patterns = [('%s', '(?P<series>[0-9]+)'),
('%e', '(?P<episode>[0-9]+)')]
out = input
for p in patterns:
out = out.replace(p[0], p[1])
return out
def test_pattern(self, type, subject, pattern):
import re, time
result = False
if type == 'TV Show (dated)':
pattern = self.strptime2regex(pattern)
elif type == 'TV Show':
pattern = self.replace_tv_show_patterns(pattern)
# Wow, so this is lame...
if pattern[0] != '^':
pattern = '.*' + pattern
try:
exp = re.compile(pattern, re.IGNORECASE)
except:
print 'Broken expression: ' + pattern
return False
match = exp.match(subject)
if match:
print 'Match: ' + subject
print ' ' + pattern
if type == 'TV Show':
try:
series = int(match.group('series'))
except:
try:
series = int(match.group('season'))
except:
series = 0
try:
episode = int(match.group('episode'))
except:
episode = 0
result = { 'series' : series,
'episode' : episode }
elif type == 'TV Show (dated)':
try:
year = int(match.group('Y'))
except:
try:
year = int(match.group('y'))
if year > 70:
year += 1900
else:
year += 2000
except:
year = 0
try:
month = int(match.group('m'))
except:
month = 0
try:
day = int(match.group('d'))
except:
day = 0
result = { 'year' : year,
'month' : month,
'day' : day }
else:
result = True
return result
def parse_feed(self, id):
import time, feedparser
feed = self.config.getFeed(id)
print 'Updating feed #' + str(id)
parsed = feedparser.parse(feed['url'])
if (not parsed) or (not parsed.entries):
print 'Unable to parse feed: ' + feed['url']
return
data = []
for entry in parsed.entries:
try:
data.append({ 'title' : entry['title'],
'link' : entry.links[0]['href'] })
except:
continue
if self.config.filters:
for filter in self.config.filters:
if not ((feed['id'] in filter['feeds']) or (0 in filter['feeds'])):
continue
for pattern in filter['patterns']:
# (setq python-indent 4
# tab-width 4)
# Okay, I dislike python substantially less now.
try:
if pattern[1] == 'Title':
subject = entry['title']
else:
subject = entry['links'][0]['href']
except:
print 'Unable to find subject.'
match = self.test_pattern(filter['type'], subject, pattern[0])
if match:
# Filter matched. Check history to see if
# we should download it.
if filter['type'] == 'Generic': # Dirty hack.
match = { 'url' : entry.links[0]['href'] }
if not self.config.checkHistory(filter['id'], filter['type'], match):
self.config.addHistory(filter['id'], filter['type'], match)
self.write_config()
print 'Downloading'
self.interface.interactive_add_torrent_url(entry.links[0]['href'])
else:
print 'Skipping (history)'
self.feeds[feed['id']]['data'] = data
if self.glade: # Update config window...
# Todo: Fix this. It was just easier to clear
# everything and rebuild from scratch
feeds_model = self.glade.get_widget("FlexRSS_Feeds").get_model()
feeds_model.clear()
for feed in self.config.feeds:
this_feed = feeds_model.append(None, (feed['id'], feed['name'], feed['url']))
for item in self.feeds[feed['id']]['data']:
feeds_model.append(this_feed, (0, item['title'], item['link']))
def update(self):
import time
current_time = time.time()
# I feel dirty for this. Oh, how I miss C.
for id in self.feeds:
if (current_time - self.feeds[id]['cfg']['interval']) > self.feeds[id]['updated']:
self.feeds[id]['updated'] = current_time
self.parse_feed(self.feeds[id]['cfg']['id'])
def __init__(self, path, core, interface):
self.path = path
self.core = core
self.interface = interface
self.load_config()
self.feeds = {}
if self.config.feeds:
for feed in self.config.feeds:
self.feeds[feed['id']] = { 'cfg' : feed,
'updated' : 0,
'data' : [] }
# Debugging stuff
# self.configure()
# self.config.listFilters()
# self.config.listFeeds()