Skip to content

Commit

Permalink
Merge branch 'testing'
Browse files Browse the repository at this point in the history
  • Loading branch information
BluABK committed Apr 26, 2019
2 parents d1d039e + 4ac5ae2 commit e2355f1
Show file tree
Hide file tree
Showing 17 changed files with 478 additions and 191 deletions.
33 changes: 32 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,35 @@
Current
v0.6.2
- Made sd warn and has-captions overlays optional (and made sd warning False by default due to recently buggy API data).
- Changed Function menu alt-key from F to u (overlapped with File menu).
- Shuffled around various settings to lessen a wasteful amount of tabs.
- Moved datestamp settings to its own Time & Date tab.
- Update text ellision values to work with the VideoTile redesign.
- Made config.ini only contain overrides instead of mirroring all defaults.
- Created (and added to UI) a FontPickerButton which lets users pick fonts and displays the current font in a
human readable format on the button.
- Changed default Fonts from Helvetica to Noto Sans (likely the same font)
- Made all font read_config entries non-literal eval (i.e. read as string).
- Added utils function for checking if a string contains unicode.
- Removed size limit from TextPickleType due to lack of support.
- PostgreSQL doesn't seem to support strings with any length limit at all.
- Added some if coverage in debug tile colouring.
- ElidedLabel is now aligned to top and added spacer between thumb and title.
- Removed redundant (and also problematic) layout alignments.
- Removed maximum height sizing logic from VideoTile.
- Made Title, Channel and Date text fields optional if cfg lines == 0.
- Changed VideoTile sizing from fixed size to fixed width and max height.
- Changed ThumbnailTile sizing from fixed size to minimum width (scaled).
- Refactor renamed (and moved) VideoTileLabel to ElidedLabel.
- Changed start with stored videos to True by default.
- Changed VideoTileLabel font handling from plaintext to QFont.fromString.
- Added accidentally omitted config hotkey to defaults and sample config.
- Fixed critical DB creation failure bug introduced in commit 2da05b2 (Caused by IDE refactor move).
- Made PyYAML dependency in requirements.txt >= instead of ==.
- Made sample cfg/hotkeys if not exist use the new create_config_file function.
- Replaced copyfile(sample, cfg) with func that uses DEFAULTS dict directly.
- Made log_handler automatically create missing dirs and files.
- Made PyQt5 pip requirements >= instead of forcing specific version.
- Renamed subs list reload item, so it's harder to confuse with subfeed refresh.
- Hotfix: disabled elision by default and instead explicitly using it during init only, due to VideoTileLabel.width()
changing drastically later on.
- Deleted deprecated debug_functions and cli arg --debug_open_1k_fds that was used for "too many file descriptors"
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.6.1
0.6.2
8 changes: 7 additions & 1 deletion config.ini.sample
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ filter_videos_days_old = -1
[Debug]
debug = False
cached_subs = True
start_with_stored_videos = False
start_with_stored_videos = True
channels_limit = -1
use_playlistitems = True
disable_tooltips = False
Expand Down Expand Up @@ -43,6 +43,12 @@ toolbar_icon_size_modifier = 1
last_style =
last_theme =

[Fonts]
video_title_font = Noto Sans,10,-1,0,75,0,0,0,0,0,Bold
video_channel_font = Noto Sans,10,-1,0,50,0,0,0,0,0,Regular
video_date_font = Noto Sans,10,-1,0,50,0,0,0,0,0,Regular
video_thumbnail_overlay_font = Noto Sans,10,-1,0,50,0,0,0,0,0,Regular

[GridView]
show_watched = False
show_dismissed = False
Expand Down
5 changes: 1 addition & 4 deletions sane_yt_subfeed/database/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@
import sqlalchemy
from sqlalchemy import TypeDecorator

SIZE = 256


class TextPickleType(TypeDecorator):
impl = sqlalchemy.Text(SIZE)
impl = sqlalchemy.Text()

def process_bind_param(self, value, dialect):
if value is not None:
Expand Down
26 changes: 13 additions & 13 deletions sane_yt_subfeed/gui/main_window/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,16 +599,16 @@ def add_menu_function(self, menubar):
:param menubar:
:return:
"""
self.add_menu(menubar, '&Function')
self.add_menu(menubar, 'F&unction')

# Set function menu triggers
self.add_submenu('&Function', 'Copy all URLs', self.clipboard_copy_urls,
self.add_submenu('F&unction', 'Copy all URLs', self.clipboard_copy_urls,
shortcut=read_config('Global', 'copy_all_urls', custom_ini=HOTKEYS_INI,
literal_eval=HOTKEYS_EVAL),
tooltip='Copy URLs of all currently visible videos to clipboard', icon=COPY_ALL_URLS_ICON)

# refresh_list
self.toolbar_items['RefreshSubFeed'] = self.add_submenu('&Function', 'Refresh Feed',
self.toolbar_items['RefreshSubFeed'] = self.add_submenu('F&unction', 'Refresh Feed',
self.emit_signal_with_set_args,
shortcut=read_config('Global', 'refresh_feed',
custom_ini=HOTKEYS_INI,
Expand All @@ -618,53 +618,53 @@ def add_menu_function(self, menubar):
signal=self.main_model.main_window_listener.refreshVideos,
args=(LISTENER_SIGNAL_NORMAL_REFRESH,))

self.add_submenu('&Function', 'Fetch &List of Subscribed Channels',
self.add_submenu('F&unction', 'Fetch &List of Subscribed Channels',
self.main_model.main_window_listener.refreshSubs.emit,
shortcut=read_config('Global', 'reload_subslist', custom_ini=HOTKEYS_INI,
literal_eval=HOTKEYS_EVAL),
tooltip='Fetch a new subscriptions list', icon=RELOAD_SUBS_LIST_ICON)

# FIXME: icon, shortcut(alt/shift as extra modifier to the normal refresh shortcut?)
self.add_submenu('&Function', 'Deep refresh of feed', self.emit_signal_with_set_args,
self.add_submenu('F&unction', 'Deep refresh of feed', self.emit_signal_with_set_args,
shortcut=read_config('Global', 'refresh_feed_deep', custom_ini=HOTKEYS_INI,
literal_eval=HOTKEYS_EVAL),
tooltip='Deep refresh the subscription feed', icon=REFRESH_SUBFEED_DEEP_ICON,
signal=self.main_model.main_window_listener.refreshVideos,
args=(LISTENER_SIGNAL_DEEP_REFRESH,))

self.add_submenu('&Function', 'Test Channels', self.main_model.main_window_listener.testChannels.emit,
self.add_submenu('F&unction', 'Test Channels', self.main_model.main_window_listener.testChannels.emit,
tooltip='Tests the test_pages and miss_limit of channels', icon=RERUN_TEST_ICON)

if self.main_model.yt_dir_listener is not None:
self.add_submenu('&Function', 'Manual dir search', self.main_model.yt_dir_listener.manualCheck.emit,
self.add_submenu('F&unction', 'Manual dir search', self.main_model.yt_dir_listener.manualCheck.emit,
tooltip='Starts a manual search for new videos in youtube directory',
icon=MANUAL_DIR_SEARCH_ICON)

thumb_tooltip = 'Starts a manual download of thumbnails for videos currently in play view and sub feed'
self.add_submenu('&Function', 'Manual thumbnail download',
self.add_submenu('F&unction', 'Manual thumbnail download',
self.download_thumbnails_manually,
tooltip=thumb_tooltip, icon=MANUAL_THUMBS_DOWNLOAD_ICON)

self.add_submenu('&Function', 'Manual DB grab', self.update_from_db,
self.add_submenu('F&unction', 'Manual DB grab', self.update_from_db,
tooltip='Starts a manual grab of data for the model', icon=DATABASE_ICON,
shortcut=read_config('Global', 'manual_db_grab', custom_ini=HOTKEYS_INI,
literal_eval=HOTKEYS_EVAL))

# FIXME: icon, look more related to action
self.add_submenu('&Function', 'Toggle sort-by: ascending date', self.toggle_sort_by_ascending,
self.add_submenu('F&unction', 'Toggle sort-by: ascending date', self.toggle_sort_by_ascending,
tooltip='Toggles the ascending date config option, and does a manual re-grab',
icon=SORT_BY_ASC_DATE_ICON, shortcut=read_config('Playback', 'ascending_sort_toggle',
custom_ini=HOTKEYS_INI,
literal_eval=HOTKEYS_EVAL))
self.add_submenu('&Function', 'Toggle sort-by: channel', self.toggle_sort_by_channel,
self.add_submenu('F&unction', 'Toggle sort-by: channel', self.toggle_sort_by_channel,
tooltip='Toggles the ascending date config option, and does a manual re-grab',
icon=SORT_BY_CHANNEL_ICON, shortcut=read_config('Playback', 'by_channel_sort_toggle',
custom_ini=HOTKEYS_INI,
literal_eval=HOTKEYS_EVAL))

self.add_submenu('&Function', 'Log History 2.0', self.history_log,
self.add_submenu('F&unction', 'Log History 2.0', self.history_log,
tooltip='Send entire history to logger')
self.add_submenu('&Function', 'Undo', self.history_undo,
self.add_submenu('F&unction', 'Undo', self.history_undo,
tooltip='Undo previous action (if possible)',
icon=UNDO_ICON, shortcut=read_config('Global', 'history_undo_action',
custom_ini=HOTKEYS_INI, literal_eval=HOTKEYS_EVAL))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QPushButton, QFontDialog

from sane_yt_subfeed import create_logger
from sane_yt_subfeed.handlers.config_handler import read_config, set_config

FONT_WEIGHT_MAP = {'0': 'Thin', '12': 'ExtraLight', '18': 'Thi', '25': 'Light', '50': 'Regular', '54': 'Medium',
'62': 'ExtraCondensed', '63': 'DemiBold', '75': 'Bold', '81': 'ExtraBold', '87': 'Black'}
HUMAN_READABLE_KEYS = {'underline': 'Underline', 'strikeout': 'Strike out', 'fixed_pitch': 'Fixed pitch',
'raw_mode': 'RAW mode'}


class FontPickerButton(QPushButton):
def __init__(self, parent, cfg_section, cfg_option, tooltip=None, actions=None, actions_kwargs=None):
"""
A custom QPushButton that launches a QFontDialog.
:param parent: Parent ptr.
:param cfg_section: Config section.
:param cfg_option: Config Option.
:param tooltip: String to show on tooltip.
:param actions: Function to call when font is selected.
:param actions_kwargs: Keyword arguments (dict) to send in checked action calls.
"""
super(QPushButton, self).__init__(parent=parent)
self.parent = parent
self.logger = create_logger(__name__)
self.tooltip = tooltip
self.cfg_section = cfg_section
self.cfg_option = cfg_option
self.current_font = QFont()
self.current_font.fromString(read_config(self.cfg_section, self.cfg_option, literal_eval=False))
self.update_info()

self.clicked.connect(self.open_font_dialog)

def weight_map_lookup(self, weight):
"""
Checks if a weight exists in the font weight map,
if not then it reports it and returns a fallback string.
:param weight:
:return:
"""
if str(weight) in FONT_WEIGHT_MAP:
return FONT_WEIGHT_MAP[str(weight)]
else:
self.logger.error("Umatched font weight: {}!".format(weight))
return "UNDEFINED({})".format(weight)

def map_font_str(self, font_str):
"""
Maps a comma separated QFont.toString to a much more sensible dict, which it then returns.
QFont.toString composition (comma separated, always in the following order):
Family: Font family name.
Point size: Point size of the font.
-1 if the font size was specified in pixels.
Pixel size: Pixel size of the font if it was set with pixel size.
-1 if the size was set with point size.
Style hint: Affects the {QFont}{font matching} algorithm. See QFont.StyleHint and QFont constants.
Style hints are used by the {QFont}{font matching} algorithm to find an appropriate default family
if a selected font family is not available.
AnyStyle leaves the font matching algorithm to choose the family. This is the default.
0 seems to be equivalent to Helvetica and 5 is AnyStyle.
Weight: Weight of the font (0-99), usually it's a predefined enum.
Qt uses a weighting scale from 0 to 99 similar to, but not the same as, the scales used in Windows or
CSS. A weight of 0 is ultralight, whilst 99 will be an extremely black.
Style: Style of the font (enum of the different styles of glyphs that are used to display text).
Only covers the following types: Normal = 0, Italic = 1, Oblique = 2
Underline: Self-explanatory.
0 if False, 1 if True.
Strikeout: Self-explanatory.
0 if False, 1 if True.
Fixed pitch: Fixed pitch value of the matched window system font.
0 if False, 1 if True.
Useful url:
shorthand: https://bit.ly/2XIjI5B
raw (with linebreaks): https://cep.xray.aps.anl.gov/software/qt4-x11-4.2.2-browser/
d7/da1/class_q_font.html#5ab046d742a8538c2e2e50c2e03733ea
:param font_str: A string in the form of QFont.toString().
:return:
"""
font_info = font_str.split(',')
font_info_map = {'family': str(font_info[0]), 'point_size': int(font_info[1]),
'pixel_size': float(font_info[2]), 'style_hint': int(font_info[3]),
'weight': self.weight_map_lookup(font_info[4]), 'style': int(font_info[5]),
'underline': bool(int(font_info[6])), 'strikeout': bool(int(font_info[7])),
'fixed_pitch': bool(int(font_info[8])), 'raw_mode': bool(int(font_info[9])),
'font_style': str(font_info[10])}

return font_info_map

def format_qfont_str(self, font_str):
"""
Formats a QFont.toString to a more human readable string.
:param font_str:
:return:
"""
# Map the string to a font info map/dict.
f: dict = self.map_font_str(font_str)

# Make a list of enabled setting keys.
enabled_bools = []
for key, value in f.items():
if value is True:
enabled_bools.append(HUMAN_READABLE_KEYS[key])

# It is guaranteed to be either pt or px, so ternary works fine for this.
pt_or_px = "{}pt.".format(f['point_size']) if f['point_size'] != -1 else "{}px.".format(f['pixel_size'])

# Determine the enabled (boolean) settings:
bools = []
for boolean in enabled_bools:
bools.append(boolean)
bools.append(", ")

if len(bools) > 0:
# Strip trailing runaway comma-space delimiter
bools = bools[:-1]

# Wrap in parenthesis
bools.insert(0, '(')
bools.append(')')

# Retval for weight (optional): " (" + f['weight'] + ")" if f['weight'] != f['font_style'] else "",

return "{} ({}) {} {}".format(f['family'], f['font_style'], pt_or_px,
"".join(bools) if not len(bools) == 0 else "")

def update_info(self):
"""
Update info (various text/labels etc).
:return:
"""
self.setText(self.format_qfont_str(self.current_font.toString()))
if self.tooltip:
self.setToolTip(self.tooltip)

def open_font_dialog(self):
"""
Opens a QFontDialog and updates current font and config with the choice (if any).
:return:
"""
font = QFont()
font.fromString(read_config(self.cfg_section, self.cfg_option, literal_eval=False))
font, ok = QFontDialog.getFont()

# If user selected a font.
if ok:
# Update current font ref.
self.current_font = font

# Save selected font to config.
set_config(self.cfg_section, self.cfg_option, font.toString())

# Make button text reflect changes.
self.update_info()

3 changes: 1 addition & 2 deletions sane_yt_subfeed/gui/views/config_view/config_view_tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
from sane_yt_subfeed.gui.views.config_view.config_scroll_area import ConfigScrollArea
from sane_yt_subfeed.gui.views.config_view.views.config_view import ConfigViewWidget

CONFIG_TABS = ["GUI", "Views", "Model", "Requests", "Thumbnails", "Threading", "Download", "Media player",
"Default Application", "Logging", "Debug", "Advanced"]
CONFIG_TABS = ["GUI", "Views", "Download", "Apps && Players", "Time && Date", "Logging", "Advanced", "Debug"]


class ConfigViewTabs(QTabWidget):
Expand Down
31 changes: 29 additions & 2 deletions sane_yt_subfeed/gui/views/config_view/input_super.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel
from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel, QFontDialog

from sane_yt_subfeed.gui.views.config_view.config_items.font_picker_button import FontPickerButton
from sane_yt_subfeed.handlers.config_handler import read_config, set_config
from sane_yt_subfeed.gui.views.config_view.config_items.button import GenericConfigPushButton
from sane_yt_subfeed.gui.views.config_view.config_items.checkbox import GenericConfigCheckBox
Expand Down Expand Up @@ -104,7 +105,7 @@ def add_option_line_edit(self, description, cfg_section, cfg_option, cfg_validat
:param cfg_section:
:param description:
:param actions: Function to call when line gets edited.
:param actions_kwargs Keyword arguments (dict) to send in checked action calls.
:param actions_kwargs: Keyword arguments (dict) to send in checked action calls.
:return:
"""
if restart_check and actions is None:
Expand All @@ -120,6 +121,32 @@ def add_option_line_edit(self, description, cfg_section, cfg_option, cfg_validat

return value # Needed for connected listeners etc

def add_option_fontpicker(self, description, cfg_section, cfg_option, disabled=False, tooltip=None,
actions=None, actions_kwargs=None, restart_check=True):
"""
Add an option w/ value to the ConfigView layout and increment the grid offset.
:param description: Description of the option.
:param cfg_section: Config section.
:param cfg_option: Config option.
:param disabled: Sets disabled status if True.
:param tooltip: String to show on tooltip.
:param actions: Function to call when font is selected.
:param actions_kwargs: Keyword arguments (dict) to send in checked action calls.
:param restart_check: If set to false, don't check if a restart (may) be required for this option.
:return:
"""
if restart_check and actions is None:
description = "{} {}".format(description, RESTART_REQUIRED_SIGNIFIER)
option = QLabel(description)
value = FontPickerButton(self, cfg_section, cfg_option, tooltip=tooltip, actions=actions,
actions_kwargs=actions_kwargs)

if disabled:
value.setDisabled(True)
self.layout.addWidget(option, self.offset, 0)
self.layout.addWidget(value, self.offset, 1)
self.offset += 1

def add_option_inactive(self, description, cfg_section, cfg_option):
"""
Add an option w/ UNEDITABLE value to the ConfigView layout and increment the grid offset.
Expand Down
Loading

0 comments on commit e2355f1

Please sign in to comment.