class Categories:
    #@staticmethod
    def _merge_keys(key_value_list):
        key_list = [row[KEY_INDEX] for row in key_value_list]
        keys = ""
        for i, key in enumerate(key_list):
            #if i == 0 or not key:
            if not key:
                # Skip predefined or user-defined "all" filters
                continue
            keys += key
            if (i < len(key_list) - 1):
                keys += ","

        # Use set to avoid duplicates
        key_set = set(keys.split(","))
        keys = ",".join(key_set)

        return keys

    # No filter list
    ALL = [["", _ALL_CATEGORIES_LABEL]]

    # The filter lists below consists of all categories in the first item, followed by the categories separately

    RADIO = ast.literal_eval(settings.get_config().get("radio", "categories"))
    # Prepend
    RADIO.insert(0, [_merge_keys(RADIO), _ALL_CATEGORIES_LABEL])

    TV = ast.literal_eval(settings.get_config().get("tv", "categories"))
    # Prepend
    TV.insert(0, [_merge_keys(TV), _ALL_CATEGORIES_LABEL])
class Channels:
    RADIO = _ALL_CHANNELS_LABEL + "," + settings.get_config().get(
        "radio", "channels")
    TV = _ALL_CHANNELS_LABEL + "," + settings.get_config().get(
        "tv", "channels")
    CH4 = _ALL_CHANNELS_LABEL
    ITV = _ALL_CHANNELS_LABEL
    def on_button_properties_clicked(self, button):
        # button can be None
        preset = None
        combo = self.tool_bar_box.preset_combo
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()
            #search_all = self.tool_bar_box.search_all_presets_check_button.get_active()
            #if search_all_presets:
            if string.str2bool(settings.get_config().get(
                    config.NOSECTION, "disable-presets")):
                preset = None
            else:
                preset = model[tree_iter][self.PresetComboModelColumn.PRESET]
            prog_type = model[tree_iter][self.PresetComboModelColumn.PROG_TYPE]

        proxy_disabled = string.str2bool(settings.get_config().get(
            config.NOSECTION, "disable-proxy"))

        future = self.tool_bar_box.future_check_button.get_active()

        model, tree_iter = self.main_tree_view.get_selection().get_selected()
        if tree_iter is not None:
            #index = model[tree_iter][SearchResultColumn.INDEX]
            #if index:
            pid = model[tree_iter][SearchResultColumn.PID]
            if pid:
                self.main_window.display_busy_mouse_cursor(True)
                get_iplayer_output_lines = get_iplayer.info(
                    pid,
                    None,
                    preset=preset,
                    prog_type=prog_type,
                    proxy_disabled=proxy_disabled,
                    future=future)
                self.main_window.display_busy_mouse_cursor(False)

                self.on_progress_bar_update(None)

                window = props_window.PropertiesWindow(
                    self,
                    get_iplayer_output_lines,
                    icon=self.main_window.get_icon())
                window.show_all()
            else:
                dialog = Gtk.MessageDialog(
                    self.main_window, 0, Gtk.MessageType.INFO,
                    Gtk.ButtonsType.CLOSE,
                    "No episode highlighted. A series is highlighted")
                #dialog.format_secondary_text("")
                dialog.run()
                dialog.destroy()
        else:
            dialog = Gtk.MessageDialog(self.main_window, 0,
                                       Gtk.MessageType.INFO,
                                       Gtk.ButtonsType.CLOSE,
                                       "No episode highlighted")
            #dialog.format_secondary_text("")
            dialog.run()
            dialog.destroy()
    def on_button_properties_clicked(self, button):
        # button can be None
        preset = None
        combo = self.tool_bar_box.preset_combo
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()
            #search_all = self.tool_bar_box.search_all_presets_check_button.get_active()
            #if search_all_presets:
            if string.str2bool(settings.get_config().get(config.NOSECTION, "disable-presets")):
                preset = None
            else:
                preset = model[tree_iter][self.PresetComboModelColumn.PRESET]
            prog_type = model[tree_iter][self.PresetComboModelColumn.PROG_TYPE]

        proxy_disabled = string.str2bool(settings.get_config().get(config.NOSECTION, "disable-proxy"))

        future = self.tool_bar_box.future_check_button.get_active()

        model, tree_iter = self.main_tree_view.get_selection().get_selected()
        if tree_iter is not None:
            #index = model[tree_iter][SearchResultColumn.INDEX]
            #if index:
            pid = model[tree_iter][SearchResultColumn.PID]
            if pid:
                self.main_window.display_busy_mouse_cursor(True)
                get_iplayer_output_lines = get_iplayer.info(
                                                pid, None, preset=preset, prog_type=prog_type,
                                                proxy_disabled=proxy_disabled, future=future)
                self.main_window.display_busy_mouse_cursor(False)

                self.on_progress_bar_update(None)

                window = props_window.PropertiesWindow(self, get_iplayer_output_lines, icon=self.main_window.get_icon())
                window.show_all()
            else:
                dialog = Gtk.MessageDialog(self.main_window, 0,
                                           Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
                                           "No episode highlighted. A series is highlighted")
                #dialog.format_secondary_text("")
                dialog.run()
                dialog.destroy()
        else:
            dialog = Gtk.MessageDialog(self.main_window, 0,
                                       Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
                                       "No episode highlighted")
            #dialog.format_secondary_text("")
            dialog.run()
            dialog.destroy()
def precheck(quiet=False):
    log_output = ""

    # Check required program(s)
    # Call get_iplayer directly, instead of wrapping it in "shell code", to check whether it is installed or not
    process_output = command.run(_GET_IPLAYER_PROG + " --usage",
                                 quiet=True,
                                 temp_pathname=settings.TEMP_PATHNAME)
    #TODO not Linux specific ("not found")
    if quiet and "not found" in process_output:
        # command.run() already logs the error (logger.warning())
        log_output += "WARNING:{0}".format(process_output)

    # Check get_iplayer preset files
    if not string.str2bool(settings.get_config().get(config.NOSECTION,
                                                     "disable-presets")):
        pathname = os.path.join(os.path.expanduser("~"), ".get_iplayer",
                                "presets")
        for preset in [Preset.RADIO, Preset.TV]:
            filename = os.path.join(pathname, preset)
            if not os.path.exists(filename):
                msg = "preset file {0} does not exist".format(filename)
                logger.warning(msg)
                log_output += "WARNING:{0}".format(msg)

    return log_output
Example #6
0
def precheck(quiet=False):
    log_output = ""
    
    # Check required program(s)
    # Call get_iplayer directly, instead of wrapping it in "shell code", to check whether it is installed or not    
    process_output =  command.run(_GET_IPLAYER_PROG + " --usage", quiet=True, temp_pathname=settings.TEMP_PATHNAME)
    #TODO not Linux specific ("not found")
    if quiet and "not found" in process_output:
        # command.run() already logs the error (logger.warning())
        log_output += "WARNING:{0}".format(process_output)
        
    # Check get_iplayer preset files
    if not string.str2bool(settings.get_config().get(config.NOSECTION, "disable-presets")):
        pathname = os.path.join(os.path.expanduser("~"), ".get_iplayer", "presets")
        for preset in [Preset.RADIO, Preset.TV]:
            filename = os.path.join(pathname, preset)
            if not os.path.exists(filename):
                msg = "preset file {0} does not exist".format(filename)
                logger.warning(msg)
                log_output += "WARNING:{0}".format(msg)

    return log_output
Example #7
0
""" Perform get_iplayer commands. """

import ast
import logging
import os

from get_iplayer_downloader import search_cache, settings
from get_iplayer_downloader.tools import command, command_queue, config, string

logger = logging.getLogger(__name__)

####

RADIO_DOWNLOAD_PATH = settings.get_config().get("radio", "download-path")
TV_DOWNLOAD_PATH = settings.get_config().get("tv", "download-path")

# Labels for disabled filters
ALL_CATEGORIES_LABEL = "Categories"
ALL_CHANNELS_LABEL = "Channels"
SINCE_FOREVER_LABEL = "Since"

# Indices of a key-value pair
KEY_INDEX = 0
VALUE_INDEX = 1

####

_GET_IPLAYER_PROG = "get_iplayer"

#_SINCE_HOUR_MARGIN = 6
_SINCE_HOUR_MARGIN = string.str2int(settings.get_config().get(config.NOSECTION, "since-margin-hours", fallback=6))
    def _init_grid(self, controller, prop_table):
        ##min_content_height=600, min_content_width=600
        ##visible=True, can_focus=True, hscrollbar_policy=Gtk.Policy.AUTOMATIC, 
        #                               vscrollbar_policy=Gtk.Policy.AUTOMATIC
        scrolled_window = Gtk.ScrolledWindow()
        ##scrolled_window.min_content_height(700)
        ##scrolled_window.min_content_width(800)
        #scrolled_window.set_property("min-content-height", 5800)
        #scrolled_window.set_property("min-content-width", 400)
        ##self.set_default_size(400, 400)
        #scrolled_window.set_hexpand(True)
        #scrolled_window.set_vexpand(True)
        self.add(scrolled_window)

        self.grid = Gtk.Grid(orientation=Gtk.Orientation.VERTICAL, 
                             margin=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        ##self.grid.set_row_homogeneous(False)
        ##self.grid.set_column_homogeneous(False)
        scrolled_window.add_with_viewport(self.grid)

        ##

        # Find property values        
        episode = None
        longname = None
        name = None
        image_url = None
        pid = None
        title = None
        for prop_label, prop_value in prop_table:
            if prop_label == "episode":
                episode = prop_value
            if prop_label == "longname":
                longname = prop_value
            if prop_label == "name":
                name = prop_value
            #OLD if prop_label == "thumbnail" or prop_label == "thumbnail4":
            if prop_label == "thumbnail":
                image_url = prop_value
            if prop_label == "pid":
                pid = prop_value
            if prop_label == "title":
                title = prop_value
        
        locate_search_term = name
        
        #### Thumbnail, title, play button
        
        ##ALTERNATIVE
        #for i in range(len(prop_table)):
        #    if prop_table[i][InfoResultColumn.PROP_LABEL /* 0 */] == "thumbnail4":
        #        break
        #if i < len(prop_table):
        #    image_url = prop_table[i][InfoResultColumn.PROP_VALUE /* 1 */]

        if image_url is not None:
            #WORKAROUND for getting a larger image (used to be "thumbnail4")
            #image_url = re.sub("/[0-9]+x[0-9]+/", "/640x360/", image_url)
            
            if string.str2bool(settings.get_config().get(config.NOSECTION, "show-images")):
                timeout = string.str2float(settings.get_config().get(config.NOSECTION, "load-image-timeout-seconds"))
                image = Image.image(image_url, relpath="large", timeout=timeout,
                                    max_width=get_iplayer_downloader.ui.main_window.IMAGE_MAX_WIDTH,
                                    max_height=get_iplayer_downloader.ui.main_window.IMAGE_MAX_HEIGHT)
                if image is not None:
                    self.grid.add(image)

        if title is not None:
            props_title = title
        else:
            # Programme type is "podcast" or episode info is not available
            if longname is not None and episode is not None:
                props_title = longname + " : " + episode
            else:
                props_title = episode
        if props_title is not None:
            TITLE_MAX_LENGTH = int(get_iplayer_downloader.ui.main_window.WINDOW_LARGE_WIDTH / 8) + 3        # 8: gestimated character width
            if len(props_title) > TITLE_MAX_LENGTH:
                # Label1 should not exceed the grid width
                props_title = props_title[:TITLE_MAX_LENGTH] + "..."
            label1 = Gtk.Label(props_title, halign=Gtk.Align.CENTER)
            #label1.set_selectable(False)
            self.grid.add(label1)

        # The play button URL is the same as the "player" property URL
        #NOTE Do not expand/fill the button in the grid: halign=Gtk.Align.CENTER
        button = Gtk.Button(relief=Gtk.ReliefStyle.NONE, image_position=Gtk.PositionType.TOP, halign=Gtk.Align.CENTER)
        button.set_image(Gtk.Image(icon_name=Gtk.STOCK_MEDIA_PLAY))
        #button.set_label("Play")
        #if title is not None:
        #    button.set_label(title)
        button.set_tooltip_text(get_iplayer_downloader.ui.main_window.TOOLTIP_VIEW_PLAYER)
        button.connect("clicked", controller.on_button_play_clicked_by_pid, pid)
        self.grid.add(button)

        #### Property table
        
        #NOTE To expand the main grid (self.grid), expand one of its child widgets: hexpand=True
        frame = Gtk.Frame(label="Properties", label_xalign=0.01, hexpand=True,
                          margin=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        self.grid.add(frame)

        ##
        
        PROP_LABEL_LIST = ["available", "categories", "channel", "desclong", "dir",
                           "duration", "episode", "expiry", "expiryrel",
                           "firstbcast", "firstbcastrel", "index", "lastbcast",
                           "lastbcastrel", "longname", "modes", "modesizes",
                           "pid", "player", "senum", "timeadded", "title",
                           "type", "versions", "web"]

        prop_grid = Gtk.Grid(column_homogeneous=False, row_homogeneous=False,
                             margin_top=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH, 
                             margin_bottom=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        frame.add(prop_grid)
        
        #focused_label = None
        #for prop_row in prop_table:
        #for i, prop_row in enumerate(prop_table):
        for i, (prop_label, prop_value) in enumerate(prop_table):
            if prop_label in PROP_LABEL_LIST:
                if prop_label == "duration":
                    try:
                        # Convert into hours and minutes
                        #NOTE // is the integer division operator
                        #DUPLICATE
                        duration_mins = int(prop_value) // 60
                        prop_value = "{0:2}".format(duration_mins // 60) + ":" + \
                                     "{0:02}".format(duration_mins % 60)
                        prop_value = prop_value.strip()
                    except ValueError:
                        #NOTE prop_value still has its original value
                        pass
                
                label1 = Gtk.Label(prop_label, valign=Gtk.Align.START, halign=Gtk.Align.START)
                label1.set_padding(get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH, 0)
                label1.set_line_wrap(True)
                #label1.set_selectable(False)
                prop_grid.attach(label1, 0, i, 1, 1)

                label2 = Gtk.Label(markup.text2html(prop_value), margin_start=40,
                                   valign=Gtk.Align.START, halign=Gtk.Align.START, use_markup=True)
                label2.set_padding(get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH, 0)
                label2.set_line_wrap(True)
                label2.set_selectable(True)
                label2.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR)
                # Avoid centering of text, when line wrap warps at word boundaries (WORD, WORD_CHAR)
                label2.set_alignment(0, 0)
                prop_grid.attach(label2, 1, i, 1, 1)

                #if prop_label == "index" or prop_label == "title":
                #    focused_label = label2

        #if focused_label:
        #    focused_label.grab_focus()
        #    # Avoid highlighted text
        #    focused_label.select_region(0, 0)
        
        ##

        ##ALTERNATIVE array indexing and populating Gtk.Grid
        #self.table = Gtk.Table()
        #self.add(self.table)
        #for y in range((len(prop_list)):
        #    for x in range(len(prop_list[y])):
        #        label = Gtk.Label()
        #        ...
        #        self.table.attach(label, x, x+1, y, y+1)

        ##
        
        ##ALTERNATIVE however, Gtk.Grid has better geometry management
        #prop_table = Gtk.Table(len(prop_list), len(prop_list[0]), False)
        #frame.add(prop_table)
        #
        #i = 0
        #for prop_row in prop_list:
        #    label = Gtk.Label(prop_row[InfoResultColumn.PROP_LABEL /* 0 */], valign=Gtk.Align.START, halign=Gtk.Align.START)
        #    label.set_padding(4, 0)
        #    label.set_line_wrap(True)
        #    prop_table.attach(label, 0, 1, i, i+1)
        #
        #    #, use_markup=True
        #    label = Gtk.Label(prop_row[InfoResultColumn.PROP_VALUE /* 1 */], valign=Gtk.Align.START, halign=Gtk.Align.START)
        #    label.set_padding(4, 0)
        #    label.set_line_wrap(True)
        #    prop_table.attach(label, 1, 2, i, i+1)
        #    
        #    i += 1

        #### Additional Links

        frame = Gtk.Frame(label="Additional links", label_xalign=0.01, 
                          margin=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        self.grid.add(frame)

        #TODO if prog_type not in [get_iplayer.Channels.CH4, get_iplayer.Channels.ITV]:
        url = "<a href=\"http://www.bbc.co.uk/iplayer\" title=\"BBC iPlayer\">BBC iPlayer</a>"
        url += "      "

        # Add URLs to get_iplayer's pvr configuration folder and filenames
        filepath = os.path.join(os.path.expanduser("~"), ".get_iplayer", "pvr")
        url += file.files2urls(filepath)
        url += "      "

        # Add URLs to get_iplayer's presets configuration folder and filenames
        filepath = os.path.join(os.path.expanduser("~"), ".get_iplayer", "presets")
        url += file.files2urls(filepath)

        label1 = Gtk.Label(url, valign=Gtk.Align.START, halign=Gtk.Align.START, use_markup=True,
                           margin_top=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH, 
                           margin_bottom=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        label1.set_padding(get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH, 0)
        label1.set_line_wrap(True)
        #WORD_CHAR
        label1.set_line_wrap_mode(Pango.WrapMode.CHAR)
        #label1.set_selectable(False)
        frame.add(label1)

        #### Buttons
        
        box = Gtk.Box(spacing=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        self.grid.add(box)
        
        button = Gtk.Button("Close", margin=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        button.set_image(Gtk.Image(icon_name=Gtk.STOCK_CLOSE))
        button.connect("clicked", lambda user_data: self.destroy())
        box.pack_end(button, False, False, 0)

        button.grab_focus()

        if os.name == "posix":
            button = Gtk.Button("Similar", margin=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
            button.set_image(Gtk.Image(icon_name=Gtk.STOCK_FIND))
            button.set_tooltip_text(get_iplayer_downloader.ui.main_window.TOOLTIP_SEARCH_LOCATE_SIMILAR)
            button.connect("clicked", controller.on_button_similar_clicked, locate_search_term)
            box.pack_end(button, False, False, 0)
    def session_restore(self):
        restore_session = string.str2bool(settings.get_config().get(
            config.NOSECTION, "restore-session"))
        if restore_session:
            prog_type = settings.get_config().get("session", "programme-type")
            categories = settings.get_config().get("session", "categories")
            channels = settings.get_config().get("session", "channels")
            #NOTE Variables created in the try clause or except clause remain allocated after the try-except statement
            try:
                since = int(settings.get_config().get("session", "since"))
            except ValueError:
                since = 0
            search_all = string.str2bool(settings.get_config().get(
                "session", "search-all"))

            # If empty string or None (in case of an error) or ch4/itv has been disabled, then set the default value
            if not prog_type or \
                    (prog_type == "ch4" and not string.str2bool(settings.get_config().get(config.NOSECTION, "enable-ch4"))) or \
                    (prog_type == "itv" and not string.str2bool(settings.get_config().get(config.NOSECTION, "enable-itv"))):
                prog_type = get_iplayer.ProgType.RADIO
            if not categories:
                categories = ""
            if not channels:
                channels = ""

            # Don't restore when filter widget is disabled
            if not string.str2bool(settings.get_config().get(
                    config.NOSECTION, "enable-category-filter")):
                categories = None
            if not string.str2bool(settings.get_config().get(
                    config.NOSECTION, "enable-channel-filter")):
                channels = None
            if not string.str2bool(settings.get_config().get(
                    config.NOSECTION, "enable-since-filter")):
                since = -1

            # Restore values

            #ALTERNATIVE way of looping (see categories and since looping below)
            combo = self.tool_bar_box.preset_combo
            model = combo.get_model()
            if model is not None:
                tree_iter = model.get_iter_first()
                i = 0
                while tree_iter is not None:
                    value = model.get_value(tree_iter, 1)
                    if value == prog_type:
                        combo.set_active(i)
                        #NOTE combo.set_active() already causes the invocation of on_combo_preset_changed()
                        #self.on_combo_preset_changed(combo)
                        break
                    tree_iter = model.iter_next(tree_iter)
                    i += 1
                self.on_combo_preset_changed(combo)

            if categories:
                combo = self.tool_bar_box.category_combo
                model = combo.get_model()
                if model is not None:
                    # Default
                    #combo.set_active(0)
                    tree_iter = model.get_iter_first()
                    while tree_iter is not None:
                        model = combo.get_model()
                        # Find the categories key
                        if model[tree_iter][KEY_INDEX] == categories:
                            combo.set_active_iter(tree_iter)
                            break
                        tree_iter = model.iter_next(tree_iter)

            if channels:
                combo = self.tool_bar_box.channel_combo
                model = combo.get_model()
                if model is not None:
                    # Default
                    #combo.set_active(0)
                    tree_iter = model.get_iter_first()
                    while tree_iter is not None:
                        model = combo.get_model()
                        # Find the channels key
                        if model[tree_iter][KEY_INDEX] == channels:
                            combo.set_active_iter(tree_iter)
                            break
                        tree_iter = model.iter_next(tree_iter)

            if since >= 0:
                combo = self.tool_bar_box.since_combo
                model = combo.get_model()
                if model is not None:
                    # Default
                    #combo.set_active(SinceListIndex.FOREVER)
                    tree_iter = model.get_iter_first()
                    while tree_iter is not None:
                        model = combo.get_model()
                        if model[tree_iter][KEY_INDEX] == int(since):
                            combo.set_active_iter(tree_iter)
                            break
                        tree_iter = model.iter_next(tree_iter)

            self.tool_bar_box.search_all_check_button.set_active(search_all)
    def session_save(self):
        restore_session = string.str2bool(settings.get_config().get(
            config.NOSECTION, "restore-session"))
        if restore_session:
            #preset = None
            prog_type = None
            #channel = None
            combo = self.tool_bar_box.preset_combo
            tree_iter = combo.get_active_iter()
            if tree_iter is not None:
                model = combo.get_model()
                #preset = model[tree_iter][PresetComboModelColumn.PRESET]
                prog_type = model[tree_iter][
                    self.PresetComboModelColumn.PROG_TYPE]
                #channel = model[tree_iter][PresetComboModelColumn.CHANNEL]

            categories = None
            if string.str2bool(settings.get_config().get(
                    config.NOSECTION, "enable-category-filter")):
                categories = ""
                combo = self.tool_bar_box.category_combo
                tree_iter = combo.get_active_iter()
                if tree_iter is not None:
                    model = combo.get_model()
                    categories = model[tree_iter][KEY_INDEX]
                if categories.startswith(","):
                    # Remove prepended "all" filter
                    categories = categories[1:]

            channels = None
            if string.str2bool(settings.get_config().get(
                    config.NOSECTION, "enable-channel-filter")):
                channels = ""
                combo = self.tool_bar_box.channel_combo
                tree_iter = combo.get_active_iter()
                if tree_iter is not None:
                    model = combo.get_model()
                    channels = model[tree_iter][KEY_INDEX]

            since = -1
            if string.str2bool(settings.get_config().get(
                    config.NOSECTION, "enable-since-filter")):
                since = 0
                combo = self.tool_bar_box.since_combo
                tree_iter = combo.get_active_iter()
                if tree_iter is not None:
                    model = combo.get_model()
                    since = model[tree_iter][KEY_INDEX]

            search_all = self.tool_bar_box.search_all_check_button.get_active()

            # Save values

            # If not an empty string (and not None)
            if prog_type is not None:
                settings.get_config().set("session", "programme-type",
                                          prog_type)
            if categories is not None:
                settings.get_config().set("session", "categories", categories)
            if channels is not None:
                settings.get_config().set("session", "channels", channels)
            if since >= 0:
                settings.get_config().set("session", "since", str(since))
            settings.get_config().set("session", "search-all", str(search_all))

            settings.save_config()
    def on_button_find_clicked(self, button):
        # button can be None
        search_text = self.tool_bar_box.search_entry.get_text()
        search_all = self.tool_bar_box.search_all_check_button.get_active()
        disable_presets = string.str2bool(settings.get_config().get(
            config.NOSECTION, "disable-presets"))

        preset = None
        prog_type = None
        combo = self.tool_bar_box.preset_combo
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()
            if disable_presets:
                preset = None
            else:
                preset = model[tree_iter][self.PresetComboModelColumn.PRESET]
            prog_type = model[tree_iter][self.PresetComboModelColumn.PROG_TYPE]

        categories = None
        exclude_categories = None
        combo = self.tool_bar_box.category_combo
        if not search_all or combo.get_active() > 0:
            # A specific set of categories has been selected
            tree_iter = combo.get_active_iter()
            if tree_iter is not None:
                model = combo.get_model()
                #WORKAROUND see also get_iplayer.py (at least in Python 2.7)
                #    On some systems, when model[tree_iter][KEY_INDEX] == None, the following exception is raised:
                #    AttributeError: 'NoneType' object has no attribute 'decode'
                #    In the debugger, model[tree_iter][KEY_INDEX] is displayed as a unicode string.
                categories = model[tree_iter][KEY_INDEX]
                (categories, exclude_categories
                 ) = _separate_excluded_categories(categories)

        channels = None
        exclude_channels = None
        combo = self.tool_bar_box.channel_combo
        if not search_all or combo.get_active() > 0:
            # A specific set of channels has been selected
            tree_iter = combo.get_active_iter()
            if tree_iter is not None:
                model = combo.get_model()
                channels = model[tree_iter][KEY_INDEX]
                #ALTERNATIVE
                #channels = model.get_value(tree_iter, KEY_INDEX)
                (channels,
                 exclude_channels) = _separate_excluded_channels(channels)

        since = 0
        combo = self.tool_bar_box.since_combo
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()
            since = model[tree_iter][KEY_INDEX]

        future = self.tool_bar_box.future_check_button.get_active()

        self.main_window.display_busy_mouse_cursor(True)
        if self._check_first_time_find(prog_type):
            get_iplayer.refresh(preset=preset,
                                prog_type=prog_type,
                                channels=channels,
                                exclude_channels=exclude_channels,
                                future=future)
        output_lines = get_iplayer.search(
            search_text,
            preset=preset,
            prog_type=prog_type,
            channels=channels,
            exclude_channels=exclude_channels,
            categories=categories,
            exclude_categories=exclude_categories,
            since=since,
            future=future)
        self.main_window.display_busy_mouse_cursor(False)

        self.on_progress_bar_update(None)

        self.main_tree_view.set_store(output_lines)
        # Scroll to top
        adjustment = self.main_window.main_tree_view_scrollbars.get_vadjustment(
        )
        adjustment.set_value(0.0)
        adjustment.value_changed()
        #adjustment = self.main_window.main_tree_view_scrollbars.set_vadjustment(adjustment)

        #if disable_presets:
        #    prog_type = None
        self.main_window.set_window_title(prog_type=prog_type)

        # Invalidate downloaded PID list
        self.downloaded_pid_list = []

        # Disable filters when there are cached search results available
        self._set_filters_sensitive(prog_type)
    def on_button_download_clicked(self, button, pvr_queue=False):
        # button can be None
        preset = None
        prog_type = None
        alt_recording_mode = False
        combo = self.tool_bar_box.preset_combo
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()

            #NOTE Downloading in "All" preset mode will not even work when all settings (radiomode, tvmode,
            #     outputradio, outputtv, etc.) are in one file (in the options file or a single preset file).
            #     Get_iplayer.get() cannot (easily) determine the prog_type of each episode and
            #     get_iplayer does not determine the programme type by it self
            #search_all = self.tool_bar_box.search_all_presets_check_button.get_active()
            #if search_all_presets:
            if string.str2bool(settings.get_config().get(
                    config.NOSECTION, "disable-presets")):
                preset = None
            else:
                preset = model[tree_iter][self.PresetComboModelColumn.PRESET]
            prog_type = model[tree_iter][self.PresetComboModelColumn.PROG_TYPE]
            #channel = model[tree_iter][self.PresetComboModelColumn.CHANNEL]

            alt_recording_mode = self.tool_bar_box.alt_recording_mode_check_button.get_active(
            )

        dry_run = self.tool_bar_box.dry_run_check_button.get_active()
        force = self.tool_bar_box.force_check_button.get_active()
        future = self.tool_bar_box.future_check_button.get_active()

        #PVR_CHECK_BUTTON
        #pvr_queue_checkbox_state = self.tool_bar_box.pvr_queue_check_button.get_active()
        #if button is not None and not pvr_queue:
        #    # If event was raised from the tool bar download button and not from a keyboard shortcut,
        #    # then the PVR check button determines the download/queue mode
        #    pvr_queue = pvr_queue_checkbox_state

        # Search selected leaf nodes (the second level) two levels deep
        model = self.main_tree_view.get_model()
        #indices = ""
        pid_list = []
        root_iter = model.get_iter_first()
        while root_iter is not None:
            row = model[root_iter]
            if row[SearchResultColumn.DOWNLOAD] and row[
                    SearchResultColumn.PID]:
                #indices += row[SearchResultColumn.INDEX] + " "
                pid_list.append(row[SearchResultColumn.PID])

            #if model.iter_has_child(root_iter):
            child_iter = model.iter_children(root_iter)
            while child_iter is not None:
                row = model[child_iter]
                if row[SearchResultColumn.DOWNLOAD]:
                    #indices += row[SearchResultColumn.INDEX] + " "
                    pid_list.append(row[SearchResultColumn.PID])
                child_iter = model.iter_next(child_iter)
            root_iter = model.iter_next(root_iter)

        #if not indices:
        if len(pid_list) == 0:
            dialog = Gtk.MessageDialog(self.main_window, 0,
                                       Gtk.MessageType.INFO,
                                       Gtk.ButtonsType.CLOSE,
                                       "No episodes selected")
            #dialog.format_secondary_text("")
            dialog.run()
            dialog.destroy()
            #return True
            return

        ####

        ## Avoid downloading an episode twice in parallel, otherwise continue downloading
        ## twice and let get_iplayer generate an "Already in history" INFO log message.
        ## The user can download episodes in parallel without having
        ## to clear the previous download selection and therefore avoiding
        ## download errors because of two threads trying to download the same episode
        #
        #try:
        #    if os.name == "posix":
        #        #NOTE 2>/dev/null: to surpress error messages, e.g.:
        #        #    Signal 18 (CONT) caught by ps (procps-ng version 3.3.9).
        #        #    ps:display.c:66: please report this bug
        #        gipd_processes = int(command.run("echo -n $(ps xo cmd 2>/dev/null | grep 'get_iplayer_downloader' | grep 'python' | grep -v 'grep' | wc -l) ; exit 0", quiet=True))
        #    else:
        #        gipd_processes = 1
        #except ValueError:
        #    # Sometimes gipd_processes is not a valid int (empty string?)
        #    gipd_processes = 1
        #
        ## If there are more than one get_iplayer_downloader processes running,
        ## then don't perform the 'running in parallel' check (self.processes is
        ## the number of >all< the get_iplayer processes on the system).
        ## (TODO Limit self.processes to the get_iplayer processes which belong
        ## to the current get_iplayer_downloader process).
        ## TODO detect 'programme type' change
        ##PVR_CHECK_BUTTON
        ##if gipd_processes == 1 and not dry_run and not pvr_queue:
        #if gipd_processes == 1 and not dry_run:
        #    # Update self.processes now, to avoid any progress bar update delay
        #    self._update_processes_count()
        #    if self.processes > 0:
        #        #if not force:
        #        # Remove already downloaded PIDs from the PID set (copy of pid_list)
        #        pid_set = set(pid_list)
        #        downloaded_pid_set = set(self.downloaded_pid_list)
        #        pid_list = list(pid_set.difference(downloaded_pid_set))
        #    if len(pid_list) == 0:
        #        dialog = Gtk.MessageDialog(self.main_window, 0,
        #                                   Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
        #                                   "Already downloading all the selected episodes")
        #        #dialog.format_secondary_text("")
        #        dialog.run()
        #        dialog.destroy()
        #        #return True
        #        return

        ####

        self.main_window.display_busy_mouse_cursor(True)
        launched, process_output = get_iplayer.get(
            pid_list,
            pid=True,
            pvr_queue=pvr_queue,
            preset=preset,
            prog_type=prog_type,
            alt_recording_mode=alt_recording_mode,
            dry_run=dry_run,
            force=force,
            future=future)
        self.main_window.display_busy_mouse_cursor(False)

        self.on_progress_bar_update(None)

        if not launched:
            dialog = Gtk.MessageDialog(self.main_window, 0,
                                       Gtk.MessageType.INFO,
                                       Gtk.ButtonsType.CLOSE,
                                       "get_iplayer not launched")
            #dialog.format_secondary_text("")
            dialog.run()
            dialog.destroy()
        #PVR_CHECK_BUTTON
        #elif pvr_queue_checkbox_state or pvr_queue or future:
        #    # If implicitly or explicitly queuing, always show the Queued Episodes dialog window,
        #    # even if nothing will be queued
        elif dry_run or pvr_queue or future:
            if dry_run:
                if process_output is not None:
                    process_output = process_output.replace("; ", "\n") + "\n"
                message_format = "Command list"
            else:
                message_format = "Queued Episodes"

            # When queuing episodes, always show the Queued Episodes dialog window, even if nothing will be queued
            dialog = ExtendedMessageDialog(self.main_window, 0,
                                           Gtk.MessageType.INFO,
                                           Gtk.ButtonsType.CLOSE,
                                           message_format)
            #dialog.format_secondary_text("")
            dialog.set_default_response(Gtk.ResponseType.CLOSE)
            dialog.get_content_area().set_size_request(
                get_iplayer_downloader.ui.main_window.WINDOW_LARGE_WIDTH,
                get_iplayer_downloader.ui.main_window.WINDOW_LARGE_HEIGHT)
            dialog.format_tertiary_scrolled_text(
                "" if process_output is None else process_output)
            label = dialog.get_scrolled_label()
            label.set_valign(Gtk.Align.START)
            label.set_halign(Gtk.Align.START)
            label.set_selectable(True)
            #label.override_font(Pango.FontDescription("monospace small"))
            label.override_font(Pango.FontDescription("monospace 10"))
            dialog.run()
            dialog.destroy()
        else:
            #self.main_window.main_tree_view.grab_focus()
            self.downloaded_pid_list = pid_list
Example #13
0
    def _display_settings(self):
        """ Retrieve in-memory settings and put them in dialog fields. """

        self.general_clear_cache_on_exit_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION,
                                                      "clear-cache-on-exit")))
        self.general_compact_toolbar_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION,
                                                      "compact-tool-bar")))
        self.general_compact_treeview_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION,
                                                      "compact-tree-view")))
        self.general_disable_presets_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION,
                                                      "disable-presets")))
        self.general_disable_proxy_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION,
                                                      "disable-proxy")))
        self.general_refresh_cache_on_startup_check_button.set_active(
            string.str2bool(settings.get_config().get(
                config.NOSECTION, "refresh-cache-on-startup")))
        self.general_show_buttonmenu_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION,
                                                      "show-button-menu")))
        self.general_show_menubar_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION,
                                                      "show-menu-bar")))
        self.general_show_tooltip_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION,
                                                      "show-tooltip")))
        self.general_start_maximized_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION,
                                                      "start-maximized")))

        value = settings.get_config().get(config.NOSECTION,
                                          "terminal-emulator")
        if not value:
            # Get default value (as an example value) if stored value is empty
            settings.revert_config_option(config.NOSECTION,
                                          "terminal-emulator")
        self.general_terminal_emulator_entry.set_text(
            settings.get_config().get(config.NOSECTION, "terminal-emulator"))

        #

        self.radio_channels_entry.set_text(settings.get_config().get(
            "radio", "channels"))
        download_path = settings.get_config().get("radio", "download-path")
        self.radio_download_path_entry.set_text(download_path)
        if download_path:
            if not os.path.exists(download_path):
                os.makedirs(download_path)
            self.radio_download_file_chooser_button.set_filename(download_path)
        else:
            # Set to root path
            self.radio_download_file_chooser_button.set_filename(os.sep)
        self.radio_preset_file_entry.set_text(settings.get_config().get(
            "radio", "preset-file"))
        self.radio_recording_modes_entry.set_text(settings.get_config().get(
            "radio", "recording-modes"))
        self.radio_run_in_terminal_check_button.set_active(
            string.str2bool(settings.get_config().get("radio",
                                                      "run-in-terminal")))

        #

        self.tv_channels_entry.set_text(settings.get_config().get(
            "tv", "channels"))
        download_path = settings.get_config().get("tv", "download-path")
        self.tv_download_path_entry.set_text(download_path)
        if download_path:
            if not os.path.exists(download_path):
                os.makedirs(download_path)
            self.tv_download_file_chooser_button.set_filename(download_path)
        else:
            # Set to root path
            self.tv_download_file_chooser_button.set_filename(os.sep)
        self.tv_preset_file_entry.set_text(settings.get_config().get(
            "tv", "preset-file"))
        self.tv_recording_modes_entry.set_text(settings.get_config().get(
            "tv", "recording-modes"))
        self.tv_run_in_terminal_check_button.set_active(
            string.str2bool(settings.get_config().get("tv",
                                                      "run-in-terminal")))
class Preset:
    # "preset-file": filename in folder ~/.get_iplayer/presets
    RADIO = settings.get_config().get("radio", "preset-file")
    TV = settings.get_config().get("tv", "preset-file")
    def on_button_download_clicked(self, button, pvr_queue=False):
        # button can be None
        preset = None
        prog_type = None
        alt_recording_mode = False
        combo = self.tool_bar_box.preset_combo
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()
            
            #NOTE Downloading in "All" preset mode will not even work when all settings (radiomode, tvmode,
            #     outputradio, outputtv, etc.) are in one file (in the options file or a single preset file).
            #     Get_iplayer.get() cannot (easily) determine the prog_type of each episode and
            #     get_iplayer does not determine the programme type by it self
            #search_all = self.tool_bar_box.search_all_presets_check_button.get_active()
            #if search_all_presets:
            if string.str2bool(settings.get_config().get(config.NOSECTION, "disable-presets")):
                preset = None
            else:
                preset = model[tree_iter][self.PresetComboModelColumn.PRESET]
            prog_type = model[tree_iter][self.PresetComboModelColumn.PROG_TYPE]
            #channel = model[tree_iter][self.PresetComboModelColumn.CHANNEL]

            alt_recording_mode = self.tool_bar_box.alt_recording_mode_check_button.get_active()
    
        dry_run = self.tool_bar_box.dry_run_check_button.get_active()
        force = self.tool_bar_box.force_check_button.get_active()
        future = self.tool_bar_box.future_check_button.get_active()
        
        #PVR_CHECK_BUTTON
        #pvr_queue_checkbox_state = self.tool_bar_box.pvr_queue_check_button.get_active()
        #if button is not None and not pvr_queue:
        #    # If event was raised from the tool bar download button and not from a keyboard shortcut,
        #    # then the PVR check button determines the download/queue mode
        #    pvr_queue = pvr_queue_checkbox_state
        
        # Search selected leaf nodes (the second level) two levels deep
        model = self.main_tree_view.get_model()
        #indices = ""
        pid_list = []
        root_iter = model.get_iter_first()
        while root_iter is not None:
            row = model[root_iter]
            if row[SearchResultColumn.DOWNLOAD] and row[SearchResultColumn.PID]:
                #indices += row[SearchResultColumn.INDEX] + " "
                pid_list.append(row[SearchResultColumn.PID])
            
            #if model.iter_has_child(root_iter):
            child_iter = model.iter_children(root_iter)
            while child_iter is not None:
                row = model[child_iter]
                if row[SearchResultColumn.DOWNLOAD]:
                    #indices += row[SearchResultColumn.INDEX] + " "
                    pid_list.append(row[SearchResultColumn.PID])
                child_iter = model.iter_next(child_iter)
            root_iter = model.iter_next(root_iter)

        #if not indices:
        if len(pid_list) == 0:
            dialog = Gtk.MessageDialog(self.main_window, 0,
                                       Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
                                       "No episodes selected")
            #dialog.format_secondary_text("")
            dialog.run()
            dialog.destroy()
            #return True
            return
        
        ####
        
        ## Avoid downloading an episode twice in parallel, otherwise continue downloading
        ## twice and let get_iplayer generate an "Already in history" INFO log message.
        ## The user can download episodes in parallel without having
        ## to clear the previous download selection and therefore avoiding
        ## download errors because of two threads trying to download the same episode
        #
        #try:
        #    if os.name == "posix":
        #        #NOTE 2>/dev/null: to surpress error messages, e.g.:
        #        #    Signal 18 (CONT) caught by ps (procps-ng version 3.3.9).
        #        #    ps:display.c:66: please report this bug
        #        gipd_processes = int(command.run("echo -n $(ps xo cmd 2>/dev/null | grep 'get_iplayer_downloader' | grep 'python' | grep -v 'grep' | wc -l) ; exit 0", quiet=True))
        #    else:
        #        gipd_processes = 1
        #except ValueError:
        #    # Sometimes gipd_processes is not a valid int (empty string?)
        #    gipd_processes = 1
        #
        ## If there are more than one get_iplayer_downloader processes running,
        ## then don't perform the 'running in parallel' check (self.processes is
        ## the number of >all< the get_iplayer processes on the system).
        ## (TODO Limit self.processes to the get_iplayer processes which belong
        ## to the current get_iplayer_downloader process).
        ## TODO detect 'programme type' change
        ##PVR_CHECK_BUTTON
        ##if gipd_processes == 1 and not dry_run and not pvr_queue:
        #if gipd_processes == 1 and not dry_run:
        #    # Update self.processes now, to avoid any progress bar update delay
        #    self._update_processes_count()
        #    if self.processes > 0:
        #        #if not force:
        #        # Remove already downloaded PIDs from the PID set (copy of pid_list)
        #        pid_set = set(pid_list)
        #        downloaded_pid_set = set(self.downloaded_pid_list)
        #        pid_list = list(pid_set.difference(downloaded_pid_set))
        #    if len(pid_list) == 0:
        #        dialog = Gtk.MessageDialog(self.main_window, 0,
        #                                   Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
        #                                   "Already downloading all the selected episodes")
        #        #dialog.format_secondary_text("")
        #        dialog.run()
        #        dialog.destroy()
        #        #return True
        #        return        
        
        ####
        
        self.main_window.display_busy_mouse_cursor(True)
        launched, process_output = get_iplayer.get(pid_list, pid=True, pvr_queue=pvr_queue, preset=preset,
                                                   prog_type=prog_type, alt_recording_mode=alt_recording_mode,
                                                   dry_run=dry_run, force=force, future=future)
        self.main_window.display_busy_mouse_cursor(False)
        
        self.on_progress_bar_update(None)

        if not launched:
            dialog = Gtk.MessageDialog(self.main_window, 0,
                                       Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
                                       "get_iplayer not launched")
            #dialog.format_secondary_text("")
            dialog.run()
            dialog.destroy()
        #PVR_CHECK_BUTTON
        #elif pvr_queue_checkbox_state or pvr_queue or future:
        #    # If implicitly or explicitly queuing, always show the Queued Episodes dialog window,
        #    # even if nothing will be queued
        elif dry_run or pvr_queue or future:
            if dry_run:
                if process_output is not None:
                    process_output = process_output.replace("; ", "\n") + "\n"
                message_format = "Command list"
            else:
                message_format = "Queued Episodes"

            # When queuing episodes, always show the Queued Episodes dialog window, even if nothing will be queued
            dialog = ExtendedMessageDialog(self.main_window, 0, Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE, message_format)
            #dialog.format_secondary_text("")
            dialog.set_default_response(Gtk.ResponseType.CLOSE)
            dialog.get_content_area().set_size_request(get_iplayer_downloader.ui.main_window.WINDOW_LARGE_WIDTH,
                                                       get_iplayer_downloader.ui.main_window.WINDOW_LARGE_HEIGHT)
            dialog.format_tertiary_scrolled_text("" if process_output is None else process_output)
            label = dialog.get_scrolled_label()
            label.set_valign(Gtk.Align.START)
            label.set_halign(Gtk.Align.START)
            label.set_selectable(True)
            #label.override_font(Pango.FontDescription("monospace small"))
            label.override_font(Pango.FontDescription("monospace 10"))
            dialog.run()
            dialog.destroy()
        else:
            #self.main_window.main_tree_view.grab_focus()
            self.downloaded_pid_list = pid_list
    def _capture_settings(self):
        """ Retrieve settings from dialog fields and put them in in-memory settings. """

        settings.get_config().set(
            config.NOSECTION, "clear-cache-on-exit", str(self.general_clear_cache_on_exit_check_button.get_active())
        )
        settings.get_config().set(
            config.NOSECTION, "compact-tool-bar", str(self.general_compact_toolbar_check_button.get_active())
        )
        settings.get_config().set(
            config.NOSECTION, "compact-tree-view", str(self.general_compact_treeview_check_button.get_active())
        )
        settings.get_config().set(
            config.NOSECTION, "disable-presets", str(self.general_disable_presets_check_button.get_active())
        )
        settings.get_config().set(
            config.NOSECTION, "disable-proxy", str(self.general_disable_proxy_check_button.get_active())
        )
        settings.get_config().set(
            config.NOSECTION,
            "refresh-cache-on-startup",
            str(self.general_refresh_cache_on_startup_check_button.get_active()),
        )
        settings.get_config().set(
            config.NOSECTION, "show-button-menu", str(self.general_show_buttonmenu_check_button.get_active())
        )
        settings.get_config().set(
            config.NOSECTION, "show-menu-bar", str(self.general_show_menubar_check_button.get_active())
        )
        settings.get_config().set(
            config.NOSECTION, "show-tooltip", str(self.general_show_tooltip_check_button.get_active())
        )
        settings.get_config().set(
            config.NOSECTION, "start-maximized", str(self.general_start_maximized_check_button.get_active())
        )
        settings.get_config().set(
            config.NOSECTION, "terminal-emulator", self.general_terminal_emulator_entry.get_text()
        )

        settings.get_config().set("radio", "channels", self.radio_channels_entry.get_text())
        settings.get_config().set("radio", "download-path", self.radio_download_path_entry.get_text())
        settings.get_config().set("radio", "preset-file", self.radio_preset_file_entry.get_text())
        settings.get_config().set("radio", "recording-modes", self.radio_recording_modes_entry.get_text())
        settings.get_config().set("radio", "run-in-terminal", str(self.radio_run_in_terminal_check_button.get_active()))

        settings.get_config().set("tv", "channels", self.tv_channels_entry.get_text())
        settings.get_config().set("tv", "download-path", self.tv_download_path_entry.get_text())
        settings.get_config().set("tv", "preset-file", self.tv_preset_file_entry.get_text())
        settings.get_config().set("tv", "recording-modes", self.tv_recording_modes_entry.get_text())
        settings.get_config().set("tv", "run-in-terminal", str(self.tv_run_in_terminal_check_button.get_active()))
    def session_save(self):
        restore_session = string.str2bool(settings.get_config().get(config.NOSECTION, "restore-session"))
        if restore_session:
            #preset = None
            prog_type = None
            #channel = None
            combo = self.tool_bar_box.preset_combo
            tree_iter = combo.get_active_iter()
            if tree_iter is not None:
                model = combo.get_model()
                #preset = model[tree_iter][PresetComboModelColumn.PRESET]
                prog_type = model[tree_iter][self.PresetComboModelColumn.PROG_TYPE]
                #channel = model[tree_iter][PresetComboModelColumn.CHANNEL]

            categories = None
            if string.str2bool(settings.get_config().get(config.NOSECTION, "enable-category-filter")):
                categories = ""
                combo = self.tool_bar_box.category_combo
                tree_iter = combo.get_active_iter()
                if tree_iter is not None:
                    model = combo.get_model()
                    categories = model[tree_iter][KEY_INDEX]
                if categories.startswith(","):
                    # Remove prepended "all" filter
                    categories = categories[1:]

            channels = None
            if string.str2bool(settings.get_config().get(config.NOSECTION, "enable-channel-filter")):
                channels = ""
                combo = self.tool_bar_box.channel_combo
                tree_iter = combo.get_active_iter()
                if tree_iter is not None:
                    model = combo.get_model()
                    channels = model[tree_iter][KEY_INDEX]

            since = -1
            if string.str2bool(settings.get_config().get(config.NOSECTION, "enable-since-filter")):
                since = 0
                combo = self.tool_bar_box.since_combo
                tree_iter = combo.get_active_iter()
                if tree_iter is not None:
                    model = combo.get_model()
                    since = model[tree_iter][KEY_INDEX]

            search_all = self.tool_bar_box.search_all_check_button.get_active()

            # Save values

            # If not an empty string (and not None)
            if prog_type is not None:
                settings.get_config().set("session", "programme-type", prog_type)
            if categories is not None:
                settings.get_config().set("session", "categories", categories)
            if channels is not None:
                settings.get_config().set("session", "channels", channels)
            if since >= 0:
                settings.get_config().set("session", "since", str(since))
            settings.get_config().set("session", "search-all", str(search_all))
            
            settings.save_config()
    def session_restore(self):
        restore_session = string.str2bool(settings.get_config().get(config.NOSECTION, "restore-session"))
        if restore_session:
            prog_type = settings.get_config().get("session", "programme-type")
            categories = settings.get_config().get("session", "categories")
            channels = settings.get_config().get("session", "channels")
            #NOTE Variables created in the try clause or except clause remain allocated after the try-except statement
            try:
                since = int(settings.get_config().get("session", "since"))
            except ValueError:
                since = 0
            search_all = string.str2bool(settings.get_config().get("session", "search-all"))

            # If empty string or None (in case of an error) or ch4/itv has been disabled, then set the default value
            if not prog_type or \
                    (prog_type == "ch4" and not string.str2bool(settings.get_config().get(config.NOSECTION, "enable-ch4"))) or \
                    (prog_type == "itv" and not string.str2bool(settings.get_config().get(config.NOSECTION, "enable-itv"))):
                prog_type = get_iplayer.ProgType.RADIO
            if not categories:
                categories = ""
            if not channels:
                channels = ""

            # Don't restore when filter widget is disabled
            if not string.str2bool(settings.get_config().get(config.NOSECTION, "enable-category-filter")):
                categories = None
            if not string.str2bool(settings.get_config().get(config.NOSECTION, "enable-channel-filter")):
                channels = None
            if not string.str2bool(settings.get_config().get(config.NOSECTION, "enable-since-filter")):
                since = -1

            # Restore values
            
            #ALTERNATIVE way of looping (see categories and since looping below)
            combo = self.tool_bar_box.preset_combo
            model = combo.get_model()
            if model is not None:
                tree_iter = model.get_iter_first()
                i = 0
                while tree_iter is not None:
                    value = model.get_value(tree_iter, 1)
                    if value == prog_type:
                        combo.set_active(i)
                        #NOTE combo.set_active() already causes the invocation of on_combo_preset_changed()
                        #self.on_combo_preset_changed(combo)
                        break
                    tree_iter = model.iter_next(tree_iter)
                    i += 1
                self.on_combo_preset_changed(combo)

            if categories:
                combo = self.tool_bar_box.category_combo
                model = combo.get_model()
                if model is not None:
                    # Default
                    #combo.set_active(0)
                    tree_iter = model.get_iter_first()
                    while tree_iter is not None:
                        model = combo.get_model()
                        # Find the categories key
                        if model[tree_iter][KEY_INDEX] == categories:
                            combo.set_active_iter(tree_iter)
                            break
                        tree_iter = model.iter_next(tree_iter)

            if channels:
                combo = self.tool_bar_box.channel_combo
                model = combo.get_model()
                if model is not None:
                    # Default
                    #combo.set_active(0)
                    tree_iter = model.get_iter_first()
                    while tree_iter is not None:
                        model = combo.get_model()
                        # Find the channels key
                        if model[tree_iter][KEY_INDEX] == channels:
                            combo.set_active_iter(tree_iter)
                            break
                        tree_iter = model.iter_next(tree_iter)

            if since >= 0:
                combo = self.tool_bar_box.since_combo
                model = combo.get_model()
                if model is not None:
                    # Default
                    #combo.set_active(SinceListIndex.FOREVER)
                    tree_iter = model.get_iter_first()
                    while tree_iter is not None:
                        model = combo.get_model()
                        if model[tree_iter][KEY_INDEX] == int(since):
                            combo.set_active_iter(tree_iter)
                            break
                        tree_iter = model.iter_next(tree_iter)

            self.tool_bar_box.search_all_check_button.set_active(search_all)
""" Perform get_iplayer commands. """

import ast
import logging
import os

from get_iplayer_downloader import search_cache, settings
from get_iplayer_downloader.tools import command, command_queue, config, string

logger = logging.getLogger(__name__)

####

RADIO_DOWNLOAD_PATH = settings.get_config().get("radio", "download-path")
TV_DOWNLOAD_PATH = settings.get_config().get("tv", "download-path")

# Labels for disabled filters
ALL_CATEGORIES_LABEL = "Categories"
ALL_CHANNELS_LABEL = "Channels"
SINCE_FOREVER_LABEL = "Since"

# Indices of a key-value pair
KEY_INDEX = 0
VALUE_INDEX = 1

####

_GET_IPLAYER_PROG = "get_iplayer"

#_SINCE_HOUR_MARGIN = 6
_SINCE_HOUR_MARGIN = string.str2int(settings.get_config().get(
    def _init_grid(self, controller, prop_table):
        ##min_content_height=600, min_content_width=600
        ##visible=True, can_focus=True, hscrollbar_policy=Gtk.Policy.AUTOMATIC,
        #                               vscrollbar_policy=Gtk.Policy.AUTOMATIC
        scrolled_window = Gtk.ScrolledWindow()
        ##scrolled_window.min_content_height(700)
        ##scrolled_window.min_content_width(800)
        #scrolled_window.set_property("min-content-height", 5800)
        #scrolled_window.set_property("min-content-width", 400)
        ##self.set_default_size(400, 400)
        #scrolled_window.set_hexpand(True)
        #scrolled_window.set_vexpand(True)
        self.add(scrolled_window)

        self.grid = Gtk.Grid(
            orientation=Gtk.Orientation.VERTICAL,
            margin=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        ##self.grid.set_row_homogeneous(False)
        ##self.grid.set_column_homogeneous(False)
        scrolled_window.add_with_viewport(self.grid)

        ##

        # Find property values
        episode = None
        longname = None
        name = None
        image_url = None
        pid = None
        title = None
        for prop_label, prop_value in prop_table:
            if prop_label == "episode":
                episode = prop_value
            if prop_label == "longname":
                longname = prop_value
            if prop_label == "name":
                name = prop_value
            #OLD if prop_label == "thumbnail" or prop_label == "thumbnail4":
            if prop_label == "thumbnail":
                image_url = prop_value
            if prop_label == "pid":
                pid = prop_value
            if prop_label == "title":
                title = prop_value

        locate_search_term = name

        #### Thumbnail, title, play button

        ##ALTERNATIVE
        #for i in range(len(prop_table)):
        #    if prop_table[i][InfoResultColumn.PROP_LABEL /* 0 */] == "thumbnail4":
        #        break
        #if i < len(prop_table):
        #    image_url = prop_table[i][InfoResultColumn.PROP_VALUE /* 1 */]

        if image_url is not None:
            #WORKAROUND for getting a larger image (used to be "thumbnail4")
            #image_url = re.sub("/[0-9]+x[0-9]+/", "/640x360/", image_url)

            if string.str2bool(settings.get_config().get(
                    config.NOSECTION, "show-images")):
                timeout = string.str2float(settings.get_config().get(
                    config.NOSECTION, "load-image-timeout-seconds"))
                image = Image.image(image_url,
                                    relpath="large",
                                    timeout=timeout,
                                    max_width=get_iplayer_downloader.ui.
                                    main_window.IMAGE_MAX_WIDTH,
                                    max_height=get_iplayer_downloader.ui.
                                    main_window.IMAGE_MAX_HEIGHT)
                if image is not None:
                    self.grid.add(image)

        if title is not None:
            props_title = title
        else:
            # Episode info is not available
            if longname is not None and episode is not None:
                props_title = longname + " : " + episode
            else:
                props_title = episode
        if props_title is not None:
            TITLE_MAX_LENGTH = int(
                get_iplayer_downloader.ui.main_window.WINDOW_LARGE_WIDTH /
                8) + 3  # 8: gestimated character width
            if len(props_title) > TITLE_MAX_LENGTH:
                # Label1 should not exceed the grid width
                props_title = props_title[:TITLE_MAX_LENGTH] + "..."
            label1 = Gtk.Label(props_title, halign=Gtk.Align.CENTER)
            #label1.set_selectable(False)
            self.grid.add(label1)

        #NOTE Do not expand/fill the button in the grid: halign=Gtk.Align.CENTER
        button = Gtk.Button(relief=Gtk.ReliefStyle.NONE,
                            image_position=Gtk.PositionType.TOP,
                            halign=Gtk.Align.CENTER)
        button.set_image(Gtk.Image(icon_name=Gtk.STOCK_MEDIA_PLAY))
        #button.set_label("Play")
        #if title is not None:
        #    button.set_label(title)
        button.set_tooltip_text(
            get_iplayer_downloader.ui.main_window.TOOLTIP_VIEW_PLAYER)
        button.connect("clicked", controller.on_button_play_clicked_by_pid,
                       pid)
        self.grid.add(button)

        #### Property table

        #NOTE To expand the main grid (self.grid), expand one of its child widgets: hexpand=True
        frame = Gtk.Frame(
            label="Properties",
            label_xalign=0.01,
            hexpand=True,
            margin=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        self.grid.add(frame)

        ##

        PROP_LABEL_LIST = [
            "available", "categories", "channel", "desclong", "dir",
            "duration", "episode", "expiry", "expiryrel", "firstbcast",
            "firstbcastrel", "index", "lastbcast", "lastbcastrel", "longname",
            "modes", "modesizes", "pid", "player", "senum", "timeadded",
            "title", "type", "versions", "web"
        ]

        prop_grid = Gtk.Grid(column_homogeneous=False,
                             row_homogeneous=False,
                             margin_top=get_iplayer_downloader.ui.main_window.
                             WIDGET_BORDER_WIDTH,
                             margin_bottom=get_iplayer_downloader.ui.
                             main_window.WIDGET_BORDER_WIDTH)
        frame.add(prop_grid)

        #focused_label = None
        #for prop_row in prop_table:
        #for i, prop_row in enumerate(prop_table):
        for i, (prop_label, prop_value) in enumerate(prop_table):
            if prop_label in PROP_LABEL_LIST:
                if prop_label == "duration":
                    try:
                        # Convert into hours and minutes
                        #NOTE // is the integer division operator
                        #DUPLICATE
                        duration_mins = int(prop_value) // 60
                        prop_value = "{0:2}".format(duration_mins // 60) + ":" + \
                                     "{0:02}".format(duration_mins % 60)
                        prop_value = prop_value.strip()
                    except ValueError:
                        #NOTE prop_value still has its original value
                        pass

                label1 = Gtk.Label(prop_label,
                                   valign=Gtk.Align.START,
                                   halign=Gtk.Align.START)
                label1.set_padding(
                    get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH,
                    0)
                label1.set_line_wrap(True)
                #label1.set_selectable(False)
                prop_grid.attach(label1, 0, i, 1, 1)

                label2 = Gtk.Label(markup.text2html(prop_value),
                                   margin_start=40,
                                   valign=Gtk.Align.START,
                                   halign=Gtk.Align.START,
                                   use_markup=True)
                label2.set_padding(
                    get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH,
                    0)
                label2.set_line_wrap(True)
                label2.set_selectable(True)
                label2.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR)
                # Avoid centering of text, when line wrap warps at word boundaries (WORD, WORD_CHAR)
                label2.set_alignment(0, 0)
                prop_grid.attach(label2, 1, i, 1, 1)

                #if prop_label == "index" or prop_label == "title":
                #    focused_label = label2

        #if focused_label:
        #    focused_label.grab_focus()
        #    # Avoid highlighted text
        #    focused_label.select_region(0, 0)

        ##

        ##ALTERNATIVE array indexing and populating Gtk.Grid
        #self.table = Gtk.Table()
        #self.add(self.table)
        #for y in range((len(prop_list)):
        #    for x in range(len(prop_list[y])):
        #        label = Gtk.Label()
        #        ...
        #        self.table.attach(label, x, x+1, y, y+1)

        ##

        ##ALTERNATIVE however, Gtk.Grid has better geometry management
        #prop_table = Gtk.Table(len(prop_list), len(prop_list[0]), False)
        #frame.add(prop_table)
        #
        #i = 0
        #for prop_row in prop_list:
        #    label = Gtk.Label(prop_row[InfoResultColumn.PROP_LABEL /* 0 */], valign=Gtk.Align.START, halign=Gtk.Align.START)
        #    label.set_padding(4, 0)
        #    label.set_line_wrap(True)
        #    prop_table.attach(label, 0, 1, i, i+1)
        #
        #    #, use_markup=True
        #    label = Gtk.Label(prop_row[InfoResultColumn.PROP_VALUE /* 1 */], valign=Gtk.Align.START, halign=Gtk.Align.START)
        #    label.set_padding(4, 0)
        #    label.set_line_wrap(True)
        #    prop_table.attach(label, 1, 2, i, i+1)
        #
        #    i += 1

        #### Additional Links

        frame = Gtk.Frame(
            label="Additional links",
            label_xalign=0.01,
            margin=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        self.grid.add(frame)

        #TODO if prog_type not in [get_iplayer.Channels.CH4, get_iplayer.Channels.ITV]:
        url = "<a href=\"https://www.bbc.co.uk/iplayer\" title=\"BBC iPlayer\">BBC iPlayer</a>"
        url += "      "

        # Add URLs to get_iplayer's pvr configuration folder and filenames
        filepath = os.path.join(os.path.expanduser("~"), ".get_iplayer", "pvr")
        url += file.files2urls(filepath)
        url += "      "

        # Add URLs to get_iplayer's presets configuration folder and filenames
        filepath = os.path.join(os.path.expanduser("~"), ".get_iplayer",
                                "presets")
        url += file.files2urls(filepath)

        label1 = Gtk.Label(url,
                           valign=Gtk.Align.START,
                           halign=Gtk.Align.START,
                           use_markup=True,
                           margin_top=get_iplayer_downloader.ui.main_window.
                           WIDGET_BORDER_WIDTH,
                           margin_bottom=get_iplayer_downloader.ui.main_window.
                           WIDGET_BORDER_WIDTH)
        label1.set_padding(
            get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH, 0)
        label1.set_line_wrap(True)
        #WORD_CHAR
        label1.set_line_wrap_mode(Pango.WrapMode.CHAR)
        #label1.set_selectable(False)
        frame.add(label1)

        #### Buttons

        box = Gtk.Box(
            spacing=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        self.grid.add(box)

        button = Gtk.Button(
            "Close",
            margin=get_iplayer_downloader.ui.main_window.WIDGET_BORDER_WIDTH)
        button.set_image(Gtk.Image(icon_name=Gtk.STOCK_CLOSE))
        button.connect("clicked", lambda user_data: self.destroy())
        box.pack_end(button, False, False, 0)

        button.grab_focus()

        if os.name == "posix":
            button = Gtk.Button("Similar",
                                margin=get_iplayer_downloader.ui.main_window.
                                WIDGET_BORDER_WIDTH)
            button.set_image(Gtk.Image(icon_name=Gtk.STOCK_FIND))
            button.set_tooltip_text(get_iplayer_downloader.ui.main_window.
                                    TOOLTIP_SEARCH_LOCATE_SIMILAR)
            button.connect("clicked", controller.on_button_similar_clicked,
                           locate_search_term)
            box.pack_end(button, False, False, 0)
    def on_button_find_clicked(self, button):
        # button can be None
        search_text = self.tool_bar_box.search_entry.get_text()
        search_all = self.tool_bar_box.search_all_check_button.get_active()
        disable_presets = string.str2bool(settings.get_config().get(config.NOSECTION, "disable-presets"))
        
        preset = None
        prog_type = None
        combo = self.tool_bar_box.preset_combo
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()
            if disable_presets:
                preset = None
            else:
                preset = model[tree_iter][self.PresetComboModelColumn.PRESET]
            prog_type = model[tree_iter][self.PresetComboModelColumn.PROG_TYPE]

        categories = None
        exclude_categories = None
        combo = self.tool_bar_box.category_combo
        if not search_all or combo.get_active() > 0:
            # A specific set of categories has been selected
            tree_iter = combo.get_active_iter()
            if tree_iter is not None:
                model = combo.get_model()
                #WORKAROUND see also get_iplayer.py (at least in Python 2.7)
                #    On some systems, when model[tree_iter][KEY_INDEX] == None, the following exception is raised:
                #    AttributeError: 'NoneType' object has no attribute 'decode'
                #    In the debugger, model[tree_iter][KEY_INDEX] is displayed as a unicode string.
                categories = model[tree_iter][KEY_INDEX]
                (categories, exclude_categories) = _separate_excluded_categories(categories)
                
        channels = None
        exclude_channels = None
        combo = self.tool_bar_box.channel_combo
        if not search_all or combo.get_active() > 0:
            # A specific set of channels has been selected
            tree_iter = combo.get_active_iter()
            if tree_iter is not None:
                model = combo.get_model()
                channels = model[tree_iter][KEY_INDEX]
                #ALTERNATIVE
                #channels = model.get_value(tree_iter, KEY_INDEX)
                (channels, exclude_channels) = _separate_excluded_channels(channels)

        since = 0
        combo = self.tool_bar_box.since_combo
        tree_iter = combo.get_active_iter()
        if tree_iter is not None:
            model = combo.get_model()
            since = model[tree_iter][KEY_INDEX]

        future = self.tool_bar_box.future_check_button.get_active()

        self.main_window.display_busy_mouse_cursor(True)
        if self._check_first_time_find(prog_type):
            get_iplayer.refresh(preset=preset, prog_type=prog_type, channels=channels, exclude_channels=exclude_channels, future=future)
        output_lines = get_iplayer.search(search_text, preset=preset, prog_type=prog_type,
                                          channels=channels, exclude_channels=exclude_channels,
                                          categories=categories, exclude_categories=exclude_categories,
                                          since=since, future=future)
        self.main_window.display_busy_mouse_cursor(False)

        self.on_progress_bar_update(None)

        self.main_tree_view.set_store(output_lines)
        # Scroll to top
        adjustment = self.main_window.main_tree_view_scrollbars.get_vadjustment()
        adjustment.set_value(0.0)
        adjustment.value_changed()
        #adjustment = self.main_window.main_tree_view_scrollbars.set_vadjustment(adjustment)

        #if disable_presets:
        #    prog_type = None
        self.main_window.set_window_title(prog_type=prog_type)

        # Invalidate downloaded PID list
        self.downloaded_pid_list = []
        
        # Disable filters when there are cached search results available
        self._set_filters_sensitive(prog_type)
Example #22
0
def get(search_term_list, pid=True, pvr_queue=False, preset=None, prog_type=None,
        alt_recording_mode=False, dry_run=False, force=False, output_path=None,
        categories=None, future=False):
    """ Run get_iplayer --get, get_iplayer --pid or get_iplayer --pvrqueue.
        If @pid is true, then @search_term_list contains pids.
        Return tuple: launched boolean, process output string.
    """
    
    if preset == Preset.RADIO:
        output_path = RADIO_DOWNLOAD_PATH
    elif preset == Preset.TV:
        output_path = TV_DOWNLOAD_PATH
    else:
        output_path = None
        
    #WORKAROUND Preset can be None: disable-presets is true AND data models and configuration are based on presets, not on programme types
    #if preset and string.str2bool(settings.get_config().get(preset, "run-in-terminal")):
    #    terminal_prog = settings.get_config().get(config.NOSECTION, "terminal-emulator")
    #else:
    #    terminal_prog = None
    preset_fallback = None
    if preset:
        preset_fallback = preset
    else:
        # Determine preset from programme type
        if prog_type == ProgType.RADIO or prog_type == ProgType.PODCAST:
            preset_fallback = Preset.RADIO
        elif prog_type == ProgType.TV:
            preset_fallback = Preset.RADIO
    if prog_type and string.str2bool(settings.get_config().get(preset_fallback, "run-in-terminal")):
            terminal_prog = settings.get_config().get(config.NOSECTION, "terminal-emulator")
    else:
        terminal_prog = None

    if alt_recording_mode:
        if prog_type == ProgType.CH4:
            alt_radio_modes = ""
            alt_tv_modes = "flashnormal"
        elif prog_type == ProgType.ITV:
            alt_radio_modes = ""
            alt_tv_modes = "itvnormal,itvhigh,itvlow"
        else:
            alt_radio_modes = settings.get_config().get(Preset.RADIO, "recording-modes")
            alt_tv_modes = settings.get_config().get(Preset.TV, "recording-modes")
    
    #cmd = "( for i in"
    #for search_term_row in search_term_list:
    #    cmd += " " + search_term_row[SearchTermColumn.PID_OR_INDEX]
    #cmd += "; do " + _GET_IPLAYER_PROG
    cmd = ""
    for i, search_term in enumerate(search_term_list):
        cmd += _GET_IPLAYER_PROG + " --hash"
        if preset:
            cmd += " --preset=" + preset
        #WORKAROUND Preset can be None: disable-presets is true AND models and configuration are based on presets, not on programme types
        #    if alt_recording_mode:
        #        if preset == Preset.RADIO and alt_radio_modes:
        #            #cmd += " --modes=\"" + alt_radio_modes + "\""
        #            cmd += " --radiomode=\"" + alt_radio_modes + "\""
        #        elif preset == Preset.TV and alt_tv_modes:
        #            #cmd += " --modes=\"" + alt_tv_modes + "\""
        #            cmd += " --tvmode=\"" + alt_tv_modes + "\""
        if alt_recording_mode:
            if preset_fallback == Preset.RADIO and alt_radio_modes:
                #cmd += " --modes=\"" + alt_radio_modes + "\""
                cmd += " --radiomode=\"" + alt_radio_modes + "\""
            elif preset_fallback == Preset.TV and alt_tv_modes:
                #cmd += " --modes=\"" + alt_tv_modes + "\""
                cmd += " --tvmode=\"" + alt_tv_modes + "\""

        if prog_type:
            cmd += " --type=" + prog_type
        cmd += " --nocopyright"
        if force:
            cmd += " --force --overwrite"
        if output_path:
            cmd += " --output=\"" + output_path + "\""
    
        #if pvr_queue or future:
        if pvr_queue:
            if not preset:
                return False
            # Must explicitly specify programme type and PID on the command line when in pvr queue mode
            cmd += " --pvrqueue --pid="
            #cmd += " --pvr-exclude=" + ",".join(exclude_search_term_list)
        elif pid:
            cmd += " --pid="
        else:
            cmd += " --get "        
        ##cmd += "\"$i\" ; done"
        #cmd += "$i; done )"
        if search_term:
            #TEMP if search_term is a PID and the PID is numeric,
            #     then add a leading non-digit character to the PID
            #     so that get_iplayer will not assume the search_term to be an index
            if " " not in search_term and prog_type in [Channels.CH4, Channels.ITV]:
                search_term = " " + search_term

            # search_term_list could be a set of episode indices, so don't surround them with quotes
            cmd += search_term
        
        if (i < len(search_term_list) - 1):
            #cmd += "; "
            cmd += "; echo '----'; "

    if pvr_queue or dry_run:
        launched = True
        process_output = command.run(cmd, dry_run=dry_run, temp_pathname=settings.TEMP_PATHNAME)
    else:
        #CommandQueue.CommandQueue().run(...)
        launched = command_queue.run(cmd, temp_pathname=settings.TEMP_PATHNAME,
                                     terminal_prog=terminal_prog, terminal_title="get_iplayer get")
        process_output = None

    return (launched, process_output)
Example #23
0
    def _capture_settings(self):
        """ Retrieve settings from dialog fields and put them in in-memory settings. """

        settings.get_config().set(
            config.NOSECTION, "clear-cache-on-exit",
            str(self.general_clear_cache_on_exit_check_button.get_active()))
        settings.get_config().set(
            config.NOSECTION, "compact-tool-bar",
            str(self.general_compact_toolbar_check_button.get_active()))
        settings.get_config().set(
            config.NOSECTION, "compact-tree-view",
            str(self.general_compact_treeview_check_button.get_active()))
        settings.get_config().set(
            config.NOSECTION, "disable-presets",
            str(self.general_disable_presets_check_button.get_active()))
        settings.get_config().set(
            config.NOSECTION, "disable-proxy",
            str(self.general_disable_proxy_check_button.get_active()))
        settings.get_config().set(
            config.NOSECTION, "refresh-cache-on-startup",
            str(self.general_refresh_cache_on_startup_check_button.get_active(
            )))
        settings.get_config().set(
            config.NOSECTION, "show-button-menu",
            str(self.general_show_buttonmenu_check_button.get_active()))
        settings.get_config().set(
            config.NOSECTION, "show-menu-bar",
            str(self.general_show_menubar_check_button.get_active()))
        settings.get_config().set(
            config.NOSECTION, "show-tooltip",
            str(self.general_show_tooltip_check_button.get_active()))
        settings.get_config().set(
            config.NOSECTION, "start-maximized",
            str(self.general_start_maximized_check_button.get_active()))
        settings.get_config().set(
            config.NOSECTION, "terminal-emulator",
            self.general_terminal_emulator_entry.get_text())

        settings.get_config().set("radio", "channels",
                                  self.radio_channels_entry.get_text())
        settings.get_config().set("radio", "download-path",
                                  self.radio_download_path_entry.get_text())
        settings.get_config().set("radio", "preset-file",
                                  self.radio_preset_file_entry.get_text())
        settings.get_config().set("radio", "recording-modes",
                                  self.radio_recording_modes_entry.get_text())
        settings.get_config().set(
            "radio", "run-in-terminal",
            str(self.radio_run_in_terminal_check_button.get_active()))

        settings.get_config().set("tv", "channels",
                                  self.tv_channels_entry.get_text())
        settings.get_config().set("tv", "download-path",
                                  self.tv_download_path_entry.get_text())
        settings.get_config().set("tv", "preset-file",
                                  self.tv_preset_file_entry.get_text())
        settings.get_config().set("tv", "recording-modes",
                                  self.tv_recording_modes_entry.get_text())
        settings.get_config().set(
            "tv", "run-in-terminal",
            str(self.tv_run_in_terminal_check_button.get_active()))
    def _display_settings(self):
        """ Retrieve in-memory settings and put them in dialog fields. """

        self.general_clear_cache_on_exit_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION, "clear-cache-on-exit"))
        )
        self.general_compact_toolbar_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION, "compact-tool-bar"))
        )
        self.general_compact_treeview_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION, "compact-tree-view"))
        )
        self.general_disable_presets_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION, "disable-presets"))
        )
        self.general_disable_proxy_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION, "disable-proxy"))
        )
        self.general_refresh_cache_on_startup_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION, "refresh-cache-on-startup"))
        )
        self.general_show_buttonmenu_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION, "show-button-menu"))
        )
        self.general_show_menubar_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION, "show-menu-bar"))
        )
        self.general_show_tooltip_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION, "show-tooltip"))
        )
        self.general_start_maximized_check_button.set_active(
            string.str2bool(settings.get_config().get(config.NOSECTION, "start-maximized"))
        )

        value = settings.get_config().get(config.NOSECTION, "terminal-emulator")
        if not value:
            # Get default value (as an example value) if stored value is empty
            settings.revert_config_option(config.NOSECTION, "terminal-emulator")
        self.general_terminal_emulator_entry.set_text(settings.get_config().get(config.NOSECTION, "terminal-emulator"))

        #

        self.radio_channels_entry.set_text(settings.get_config().get("radio", "channels"))
        download_path = settings.get_config().get("radio", "download-path")
        self.radio_download_path_entry.set_text(download_path)
        if download_path:
            if not os.path.exists(download_path):
                os.makedirs(download_path)
            self.radio_download_file_chooser_button.set_filename(download_path)
        else:
            # Set to root path
            self.radio_download_file_chooser_button.set_filename(os.sep)
        self.radio_preset_file_entry.set_text(settings.get_config().get("radio", "preset-file"))
        self.radio_recording_modes_entry.set_text(settings.get_config().get("radio", "recording-modes"))
        self.radio_run_in_terminal_check_button.set_active(
            string.str2bool(settings.get_config().get("radio", "run-in-terminal"))
        )

        #

        self.tv_channels_entry.set_text(settings.get_config().get("tv", "channels"))
        download_path = settings.get_config().get("tv", "download-path")
        self.tv_download_path_entry.set_text(download_path)
        if download_path:
            if not os.path.exists(download_path):
                os.makedirs(download_path)
            self.tv_download_file_chooser_button.set_filename(download_path)
        else:
            # Set to root path
            self.tv_download_file_chooser_button.set_filename(os.sep)
        self.tv_preset_file_entry.set_text(settings.get_config().get("tv", "preset-file"))
        self.tv_recording_modes_entry.set_text(settings.get_config().get("tv", "recording-modes"))
        self.tv_run_in_terminal_check_button.set_active(
            string.str2bool(settings.get_config().get("tv", "run-in-terminal"))
        )
def get(search_term_list,
        pid=True,
        pvr_queue=False,
        preset=None,
        prog_type=None,
        alt_recording_mode=False,
        dry_run=False,
        force=False,
        output_path=None,
        categories=None,
        future=False):
    """ Run get_iplayer --get, get_iplayer --pid or get_iplayer --pvrqueue.
        If @pid is true, then @search_term_list contains pids.
        Return tuple: launched boolean, process output string.
    """

    if preset == Preset.RADIO:
        output_path = RADIO_DOWNLOAD_PATH
    elif preset == Preset.TV:
        output_path = TV_DOWNLOAD_PATH
    else:
        output_path = None

    #WORKAROUND Preset can be None: disable-presets is true AND data models and configuration are based on presets, not on programme types
    #if preset and string.str2bool(settings.get_config().get(preset, "run-in-terminal")):
    #    terminal_prog = settings.get_config().get(config.NOSECTION, "terminal-emulator")
    #else:
    #    terminal_prog = None
    preset_fallback = None
    if preset:
        preset_fallback = preset
    else:
        # Determine preset from programme type
        if prog_type == ProgType.RADIO:
            preset_fallback = Preset.RADIO
        elif prog_type == ProgType.TV:
            preset_fallback = Preset.RADIO
    if prog_type and string.str2bool(settings.get_config().get(
            preset_fallback, "run-in-terminal")):
        terminal_prog = settings.get_config().get(config.NOSECTION,
                                                  "terminal-emulator")
    else:
        terminal_prog = None

    if alt_recording_mode:
        if prog_type == ProgType.CH4:
            alt_radio_modes = ""
            alt_tv_modes = "flashnormal"
        elif prog_type == ProgType.ITV:
            alt_radio_modes = ""
            alt_tv_modes = "itvnormal,itvhigh,itvlow"
        else:
            alt_radio_modes = settings.get_config().get(
                Preset.RADIO, "recording-modes")
            alt_tv_modes = settings.get_config().get(Preset.TV,
                                                     "recording-modes")

    #cmd = "( for i in"
    #for search_term_row in search_term_list:
    #    cmd += " " + search_term_row[SearchTermColumn.PID_OR_INDEX]
    #cmd += "; do " + _GET_IPLAYER_PROG
    cmd = ""
    for i, search_term in enumerate(search_term_list):
        cmd += _GET_IPLAYER_PROG + " --hash"
        if preset:
            cmd += " --preset=" + preset
        #WORKAROUND Preset can be None: disable-presets is true AND models and configuration are based on presets, not on programme types
        #    if alt_recording_mode:
        #        if preset == Preset.RADIO and alt_radio_modes:
        #            #cmd += " --modes=\"" + alt_radio_modes + "\""
        #            cmd += " --radiomode=\"" + alt_radio_modes + "\""
        #        elif preset == Preset.TV and alt_tv_modes:
        #            #cmd += " --modes=\"" + alt_tv_modes + "\""
        #            cmd += " --tvmode=\"" + alt_tv_modes + "\""
        if alt_recording_mode:
            if preset_fallback == Preset.RADIO and alt_radio_modes:
                #cmd += " --modes=\"" + alt_radio_modes + "\""
                cmd += " --radiomode=\"" + alt_radio_modes + "\""
            elif preset_fallback == Preset.TV and alt_tv_modes:
                #cmd += " --modes=\"" + alt_tv_modes + "\""
                cmd += " --tvmode=\"" + alt_tv_modes + "\""

        if prog_type:
            cmd += " --type=" + prog_type
        cmd += " --nocopyright"
        if force:
            cmd += " --force --overwrite"
        if output_path:
            cmd += " --output=\"" + output_path + "\""

        #if pvr_queue or future:
        if pvr_queue:
            if not preset:
                return False
            # Must explicitly specify programme type and PID on the command line when in pvr queue mode
            cmd += " --pvrqueue --pid="
            #cmd += " --pvr-exclude=" + ",".join(exclude_search_term_list)
        elif pid:
            cmd += " --pid="
        else:
            cmd += " --get "
        ##cmd += "\"$i\" ; done"
        #cmd += "$i; done )"
        if search_term:
            #TEMP if search_term is a PID and the PID is numeric,
            #     then add a leading non-digit character to the PID
            #     so that get_iplayer will not assume the search_term to be an index
            if " " not in search_term and prog_type in [
                    Channels.CH4, Channels.ITV
            ]:
                search_term = " " + search_term

            # search_term_list could be a set of episode indices, so don't surround them with quotes
            cmd += search_term

        if (i < len(search_term_list) - 1):
            #cmd += "; "
            cmd += "; echo '----'; "

    if pvr_queue or dry_run:
        launched = True
        process_output = command.run(cmd,
                                     dry_run=dry_run,
                                     temp_pathname=settings.TEMP_PATHNAME)
    else:
        #CommandQueue.CommandQueue().run(...)
        launched = command_queue.run(cmd,
                                     temp_pathname=settings.TEMP_PATHNAME,
                                     terminal_prog=terminal_prog,
                                     terminal_title="get_iplayer get")
        process_output = None

    return (launched, process_output)