hydrus/hydrus/client/gui/networking/ClientGUINetwork.py

1621 lines
61 KiB
Python

import collections
import http.cookiejar
import os
from qtpy import QtCore as QC
from qtpy import QtWidgets as QW
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusExceptions
from hydrus.core import HydrusGlobals as HG
from hydrus.core import HydrusSerialisable
from hydrus.core.networking import HydrusNetworking
from hydrus.client import ClientConstants as CC
from hydrus.client import ClientDefaults
from hydrus.client.gui import ClientGUIDragDrop
from hydrus.client.gui import ClientGUICharts
from hydrus.client.gui import ClientGUIDialogsQuick
from hydrus.client.gui import ClientGUIFunctions
from hydrus.client.gui import ClientGUIScrolledPanels
from hydrus.client.gui import ClientGUITime
from hydrus.client.gui import ClientGUITopLevelWindowsPanels
from hydrus.client.gui import QtPorting as QP
from hydrus.client.gui.lists import ClientGUIListConstants as CGLC
from hydrus.client.gui.lists import ClientGUIListCtrl
from hydrus.client.gui.widgets import ClientGUICommon
from hydrus.client.gui.widgets import ClientGUIControls
from hydrus.client.networking import ClientNetworking
from hydrus.client.networking import ClientNetworkingDomain
from hydrus.client.networking import ClientNetworkingContexts
class EditBandwidthRulesPanel( ClientGUIScrolledPanels.EditPanel ):
def __init__( self, parent: QW.QWidget, bandwidth_rules: HydrusNetworking.BandwidthRules, summary ):
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
self._bandwidth_rules_ctrl = ClientGUIControls.BandwidthRulesCtrl( self, bandwidth_rules )
vbox = QP.VBoxLayout()
intro = 'A network job exists in several contexts. It must wait for all those contexts to have free bandwidth before it can work.'
intro += os.linesep * 2
intro += 'You are currently editing:'
intro += os.linesep * 2
intro += summary
st = ClientGUICommon.BetterStaticText( self, intro )
st.setWordWrap( True )
QP.AddToLayout( vbox, st, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._bandwidth_rules_ctrl, CC.FLAGS_EXPAND_BOTH_WAYS )
self.widget().setLayout( vbox )
def GetValue( self ) -> HydrusNetworking.BandwidthRules:
return self._bandwidth_rules_ctrl.GetValue()
class EditCookiePanel( ClientGUIScrolledPanels.EditPanel ):
def __init__( self, parent: QW.QWidget, name: str, value: str, domain: str, path: str, expires: HC.noneable_int ):
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
self._name = QW.QLineEdit( self )
self._value = QW.QLineEdit( self )
self._domain = QW.QLineEdit( self )
self._path = QW.QLineEdit( self )
expires_panel = ClientGUICommon.StaticBox( self, 'expires' )
self._expires_st = ClientGUICommon.BetterStaticText( expires_panel )
self._expires_st_utc = ClientGUICommon.BetterStaticText( expires_panel )
self._expires_time_delta = ClientGUITime.TimeDeltaButton( expires_panel, min = 1200, days = True, hours = True, minutes = True )
#
self._name.setText( name )
self._value.setText( value )
self._domain.setText( domain )
self._path.setText( path )
self._expires = expires
self._expires_time_delta.SetValue( 30 * 86400 )
#
rows = []
rows.append( ( 'Actual expires as UTC Timestamp: ', self._expires_st_utc ) )
rows.append( ( 'Set expires as a delta from now: ', self._expires_time_delta ) )
gridbox = ClientGUICommon.WrapInGrid( expires_panel, rows )
expires_panel.Add( self._expires_st, CC.FLAGS_EXPAND_PERPENDICULAR )
expires_panel.Add( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox = QP.VBoxLayout()
rows = []
rows.append( ( 'name: ', self._name ) )
rows.append( ( 'value: ', self._value ) )
rows.append( ( 'domain: ', self._domain ) )
rows.append( ( 'path: ', self._path ) )
gridbox = ClientGUICommon.WrapInGrid( self, rows )
QP.AddToLayout( vbox, gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
QP.AddToLayout( vbox, expires_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
self.widget().setLayout( vbox )
#
self._UpdateExpiresText()
self._expires_time_delta.timeDeltaChanged.connect( self.EventTimeDelta )
def _UpdateExpiresText( self ):
self._expires_st.setText( HydrusData.ConvertTimestampToPrettyExpires(self._expires) )
self._expires_st_utc.setText( str(self._expires) )
def EventTimeDelta( self ):
time_delta = self._expires_time_delta.GetValue()
expires = HydrusData.GetNow() + time_delta
self._expires = expires
self._UpdateExpiresText()
def GetValue( self ):
name = self._name.text()
value = self._value.text()
domain = self._domain.text()
path = self._path.text()
expires = self._expires
return ( name, value, domain, path, expires )
class EditNetworkContextPanel( ClientGUIScrolledPanels.EditPanel ):
def __init__( self, parent: QW.QWidget, network_context: ClientNetworkingContexts.NetworkContext, limited_types = None, allow_default = True ):
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
if limited_types is None:
limited_types = ( CC.NETWORK_CONTEXT_GLOBAL, CC.NETWORK_CONTEXT_DOMAIN, CC.NETWORK_CONTEXT_HYDRUS, CC.NETWORK_CONTEXT_DOWNLOADER_PAGE, CC.NETWORK_CONTEXT_SUBSCRIPTION, CC.NETWORK_CONTEXT_WATCHER_PAGE )
self._context_type = ClientGUICommon.BetterChoice( self )
for ct in limited_types:
self._context_type.addItem( CC.network_context_type_string_lookup[ ct], ct )
self._context_type_info = ClientGUICommon.BetterStaticText( self )
self._context_data_text = QW.QLineEdit( self )
self._context_data_services = ClientGUICommon.BetterChoice( self )
for service in HG.client_controller.services_manager.GetServices( HC.REPOSITORIES ):
self._context_data_services.addItem( service.GetName(), service.GetServiceKey() )
self._context_data_subscriptions = ClientGUICommon.BetterChoice( self )
self._context_data_none = QW.QCheckBox( 'No specific data--acts as default.', self )
if not allow_default:
self._context_data_none.setVisible( False )
names = HG.client_controller.Read( 'serialisable_names', HydrusSerialisable.SERIALISABLE_TYPE_SUBSCRIPTION_LEGACY )
for name in names:
self._context_data_subscriptions.addItem( name, name )
#
self._context_type.SetValue( network_context.context_type )
self._Update()
context_type = network_context.context_type
if network_context.context_data is None:
self._context_data_none.setChecked( True )
else:
if context_type == CC.NETWORK_CONTEXT_DOMAIN:
self._context_data_text.setText( network_context.context_data )
elif context_type == CC.NETWORK_CONTEXT_HYDRUS:
self._context_data_services.SetValue( network_context.context_data )
elif context_type == CC.NETWORK_CONTEXT_SUBSCRIPTION:
self._context_data_subscriptions.SetValue( network_context.context_data )
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._context_type, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._context_type_info, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._context_data_text, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._context_data_services, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._context_data_subscriptions, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._context_data_none, CC.FLAGS_EXPAND_PERPENDICULAR )
self.widget().setLayout( vbox )
#
self._context_type.currentIndexChanged.connect( self._Update )
def _Update( self ):
self._context_type_info.setText( CC.network_context_type_description_lookup[self._context_type.GetValue()] )
context_type = self._context_type.GetValue()
self._context_data_text.setEnabled( False )
self._context_data_services.setEnabled( False )
self._context_data_subscriptions.setEnabled( False )
if context_type in ( CC.NETWORK_CONTEXT_GLOBAL, CC.NETWORK_CONTEXT_DOWNLOADER_PAGE, CC.NETWORK_CONTEXT_WATCHER_PAGE ):
self._context_data_none.setChecked( True )
else:
self._context_data_none.setChecked( False )
if context_type == CC.NETWORK_CONTEXT_DOMAIN:
self._context_data_text.setEnabled( True )
elif context_type == CC.NETWORK_CONTEXT_HYDRUS:
self._context_data_services.setEnabled( True )
elif context_type == CC.NETWORK_CONTEXT_SUBSCRIPTION:
self._context_data_subscriptions.setEnabled( True )
def GetValue( self ) -> ClientNetworkingContexts.NetworkContext:
context_type = self._context_type.GetValue()
if self._context_data_none.isChecked():
context_data = None
else:
if context_type == CC.NETWORK_CONTEXT_DOMAIN:
context_data = self._context_data_text.text()
elif context_type == CC.NETWORK_CONTEXT_HYDRUS:
context_data = self._context_data_services.GetValue()
elif context_type == CC.NETWORK_CONTEXT_SUBSCRIPTION:
context_data = self._context_data_subscriptions.GetValue()
return ClientNetworkingContexts.NetworkContext( context_type, context_data )
class EditNetworkContextCustomHeadersPanel( ClientGUIScrolledPanels.EditPanel ):
def __init__( self, parent: QW.QWidget, network_contexts_to_custom_header_dicts ):
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
self._list_ctrl_panel = ClientGUIListCtrl.BetterListCtrlPanel( self )
self._list_ctrl = ClientGUIListCtrl.BetterListCtrl( self._list_ctrl_panel, CGLC.COLUMN_LIST_NETWORK_CONTEXTS_CUSTOM_HEADERS.ID, 15, self._ConvertDataToListCtrlTuples, use_simple_delete = True, activation_callback = self._Edit )
self._list_ctrl_panel.SetListCtrl( self._list_ctrl )
self._list_ctrl_panel.AddButton( 'add', self._Add )
self._list_ctrl_panel.AddButton( 'edit', self._Edit, enabled_only_on_selection = True )
self._list_ctrl_panel.AddDeleteButton()
self._list_ctrl_panel.AddButton( 'duplicate', self._Duplicate, enabled_only_on_selection = True )
self._list_ctrl.Sort()
#
for ( network_context, custom_header_dict ) in list(network_contexts_to_custom_header_dicts.items()):
for ( key, ( value, approved, reason ) ) in list(custom_header_dict.items()):
data = ( network_context, ( key, value ), approved, reason )
self._list_ctrl.AddDatas( ( data, ) )
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._list_ctrl_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
self.widget().setLayout( vbox )
def _Add( self ):
network_context = ClientNetworkingContexts.NetworkContext( CC.NETWORK_CONTEXT_DOMAIN, 'hostname.com' )
key = 'Authorization'
value = 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='
approved = ClientNetworkingDomain.VALID_APPROVED
reason = 'EXAMPLE REASON: HTTP header login--needed for access.'
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit header' ) as dlg:
panel = self._EditPanel( dlg, network_context, key, value, approved, reason )
dlg.SetPanel( panel )
if dlg.exec() == QW.QDialog.Accepted:
( network_context, key, value, approved, reason ) = panel.GetValue()
data = ( network_context, ( key, value ), approved, reason )
self._list_ctrl.AddDatas( ( data, ) )
def _ConvertDataToListCtrlTuples( self, data ):
( network_context, ( key, value ), approved, reason ) = data
pretty_network_context = network_context.ToString()
pretty_key_value = key + ': ' + value
pretty_approved = ClientNetworkingDomain.valid_str_lookup[ approved ]
pretty_reason = reason
display_tuple = ( pretty_network_context, pretty_key_value, pretty_approved, pretty_reason )
sort_tuple = ( pretty_network_context, ( key, value ), pretty_approved, reason )
return ( display_tuple, sort_tuple )
def _Duplicate( self ):
existing_keys = { key for ( network_context, ( key, value ), approved, reason ) in self._list_ctrl.GetData() }
datas = self._list_ctrl.GetData( only_selected = True )
for ( network_context, ( key, value ), approved, reason ) in datas:
key = HydrusData.GetNonDupeName( key, existing_keys )
existing_keys.add( key )
self._list_ctrl.AddDatas( [ ( network_context, ( key, value ), approved, reason ) ] )
def _Edit( self ):
edited_datas = []
for data in self._list_ctrl.GetData( only_selected = True ):
( network_context, ( key, value ), approved, reason ) = data
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit header' ) as dlg:
panel = self._EditPanel( dlg, network_context, key, value, approved, reason )
dlg.SetPanel( panel )
if dlg.exec() == QW.QDialog.Accepted:
self._list_ctrl.DeleteDatas( ( data, ) )
( network_context, key, value, approved, reason ) = panel.GetValue()
new_data = ( network_context, ( key, value ), approved, reason )
self._list_ctrl.AddDatas( ( new_data, ) )
edited_datas.append( new_data )
else:
break
self._list_ctrl.SelectDatas( edited_datas )
def GetValue( self ):
network_contexts_to_custom_header_dicts = collections.defaultdict( dict )
for ( network_context, ( key, value ), approved, reason ) in self._list_ctrl.GetData():
network_contexts_to_custom_header_dicts[ network_context ][ key ] = ( value, approved, reason )
return network_contexts_to_custom_header_dicts
class _EditPanel( ClientGUIScrolledPanels.EditPanel ):
def __init__( self, parent: QW.QWidget, network_context: ClientNetworkingContexts.NetworkContext, key: str, value: str, approved: int, reason: str ):
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
self._network_context = NetworkContextButton( self, network_context, limited_types = ( CC.NETWORK_CONTEXT_GLOBAL, CC.NETWORK_CONTEXT_DOMAIN ), allow_default = False )
self._key = QW.QLineEdit( self )
self._value = QW.QLineEdit( self )
self._approved = ClientGUICommon.BetterChoice( self )
for a in ( ClientNetworkingDomain.VALID_APPROVED, ClientNetworkingDomain.VALID_DENIED, ClientNetworkingDomain.VALID_UNKNOWN ):
self._approved.addItem( ClientNetworkingDomain.valid_str_lookup[ a], a )
self._reason = QW.QLineEdit( self )
width = ClientGUIFunctions.ConvertTextToPixelWidth( self._reason, 60 )
self._reason.setMinimumWidth( width )
#
self._key.setText( key )
self._value.setText( value )
self._approved.SetValue( approved )
self._reason.setText( reason )
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._network_context, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._key, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._value, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._approved, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._reason, CC.FLAGS_EXPAND_PERPENDICULAR )
self.widget().setLayout( vbox )
def GetValue( self ):
network_context = self._network_context.GetValue()
key = self._key.text()
value = self._value.text()
approved = self._approved.GetValue()
reason = self._reason.text()
return ( network_context, key, value, approved, reason )
class NetworkContextButton( ClientGUICommon.BetterButton ):
def __init__( self, parent, network_context, limited_types = None, allow_default = True ):
ClientGUICommon.BetterButton.__init__( self, parent, network_context.ToString(), self._Edit )
self._network_context = network_context
self._limited_types = limited_types
self._allow_default = allow_default
def _Edit( self ):
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit network context' ) as dlg:
panel = EditNetworkContextPanel( dlg, self._network_context, limited_types = self._limited_types, allow_default = self._allow_default )
dlg.SetPanel( panel )
if dlg.exec() == QW.QDialog.Accepted:
self._network_context = panel.GetValue()
self._Update()
def _Update( self ):
self.setText( self._network_context.ToString() )
def GetValue( self ):
return self._network_context
def SetValue( self, network_context ):
self._network_context = network_context
self._Update()
class ReviewAllBandwidthPanel( ClientGUIScrolledPanels.ReviewPanel ):
def __init__( self, parent, controller ):
self._controller = controller
ClientGUIScrolledPanels.ReviewPanel.__init__( self, parent )
self._history_time_delta_threshold = ClientGUITime.TimeDeltaButton( self, days = True, hours = True, minutes = True, seconds = True )
self._history_time_delta_threshold.timeDeltaChanged.connect( self.EventTimeDeltaChanged )
self._history_time_delta_none = QW.QCheckBox( 'show all', self )
self._history_time_delta_none.clicked.connect( self.EventTimeDeltaChanged )
self._bandwidths = ClientGUIListCtrl.BetterListCtrl( self, CGLC.COLUMN_LIST_BANDWIDTH_REVIEW.ID, 20, self._ConvertNetworkContextsToListCtrlTuples, activation_callback = self.ShowNetworkContext )
self._edit_default_bandwidth_rules_button = ClientGUICommon.BetterButton( self, 'edit default bandwidth rules', self._EditDefaultBandwidthRules )
self._reset_default_bandwidth_rules_button = ClientGUICommon.BetterButton( self, 'reset default bandwidth rules', self._ResetDefaultBandwidthRules )
default_rules_help_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().help, self._ShowDefaultRulesHelp )
default_rules_help_button.setToolTip( 'Show help regarding default bandwidth rules.' )
self._delete_record_button = ClientGUICommon.BetterButton( self, 'delete selected history', self._DeleteNetworkContexts )
#
last_review_bandwidth_search_distance = self._controller.new_options.GetNoneableInteger( 'last_review_bandwidth_search_distance' )
if last_review_bandwidth_search_distance is None:
self._history_time_delta_threshold.SetValue( 86400 * 7 )
self._history_time_delta_threshold.setEnabled( False )
self._history_time_delta_none.setChecked( True )
else:
self._history_time_delta_threshold.SetValue( last_review_bandwidth_search_distance )
self._bandwidths.Sort()
self._update_job = HG.client_controller.CallRepeatingQtSafe( self, 0.5, 5.0, 'repeating all bandwidth status update', self._Update )
#
hbox = QP.HBoxLayout()
QP.AddToLayout( hbox, ClientGUICommon.BetterStaticText(self,'Show network contexts with usage in the past: '), CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, self._history_time_delta_threshold, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( hbox, self._history_time_delta_none, CC.FLAGS_CENTER_PERPENDICULAR )
vbox = QP.VBoxLayout()
button_hbox = QP.HBoxLayout()
QP.AddToLayout( button_hbox, self._edit_default_bandwidth_rules_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( button_hbox, self._reset_default_bandwidth_rules_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( button_hbox, default_rules_help_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( button_hbox, self._delete_record_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( vbox, hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
QP.AddToLayout( vbox, self._bandwidths, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( vbox, button_hbox, CC.FLAGS_ON_RIGHT )
self.widget().setLayout( vbox )
def _ConvertNetworkContextsToListCtrlTuples( self, network_context ):
bandwidth_tracker = self._controller.network_engine.bandwidth_manager.GetTracker( network_context )
has_rules = not self._controller.network_engine.bandwidth_manager.UsesDefaultRules( network_context )
sortable_network_context = ( network_context.context_type, network_context.context_data )
sortable_context_type = CC.network_context_type_string_lookup[ network_context.context_type ]
current_usage = bandwidth_tracker.GetUsage( HC.BANDWIDTH_TYPE_DATA, 1, for_user = True )
day_usage_requests = bandwidth_tracker.GetUsage( HC.BANDWIDTH_TYPE_REQUESTS, 86400 )
day_usage_data = bandwidth_tracker.GetUsage( HC.BANDWIDTH_TYPE_DATA, 86400 )
day_usage = ( day_usage_data, day_usage_requests )
month_usage_requests = bandwidth_tracker.GetUsage( HC.BANDWIDTH_TYPE_REQUESTS, None )
month_usage_data = bandwidth_tracker.GetUsage( HC.BANDWIDTH_TYPE_DATA, None )
month_usage = ( month_usage_data, month_usage_requests )
if self._history_time_delta_none.isChecked():
search_usage = 0
pretty_search_usage = ''
else:
search_delta = self._history_time_delta_threshold.GetValue()
search_usage_requests = bandwidth_tracker.GetUsage( HC.BANDWIDTH_TYPE_REQUESTS, search_delta )
search_usage_data = bandwidth_tracker.GetUsage( HC.BANDWIDTH_TYPE_DATA, search_delta )
search_usage = ( search_usage_data, search_usage_requests )
pretty_search_usage = HydrusData.ToHumanBytes( search_usage_data ) + ' in ' + HydrusData.ToHumanInt( search_usage_requests ) + ' requests'
pretty_network_context = network_context.ToString()
pretty_context_type = CC.network_context_type_string_lookup[ network_context.context_type ]
if current_usage == 0:
pretty_current_usage = ''
else:
pretty_current_usage = HydrusData.ToHumanBytes( current_usage ) + '/s'
pretty_day_usage = HydrusData.ToHumanBytes( day_usage_data ) + ' in ' + HydrusData.ToHumanInt( day_usage_requests ) + ' requests'
pretty_month_usage = HydrusData.ToHumanBytes( month_usage_data ) + ' in ' + HydrusData.ToHumanInt( month_usage_requests ) + ' requests'
if network_context == ClientNetworkingContexts.GLOBAL_NETWORK_CONTEXT:
pretty_has_rules = 'n/a'
elif has_rules:
pretty_has_rules = 'yes'
else:
pretty_has_rules = ''
( waiting_estimate, network_context_gumpf ) = self._controller.network_engine.bandwidth_manager.GetWaitingEstimateAndContext( [ network_context ] )
if waiting_estimate > 0:
pretty_blocked = HydrusData.TimeDeltaToPrettyTimeDelta( waiting_estimate )
else:
pretty_blocked = ''
display_tuple = ( pretty_network_context, pretty_context_type, pretty_current_usage, pretty_day_usage, pretty_search_usage, pretty_month_usage, pretty_has_rules, pretty_blocked )
sort_tuple = ( sortable_network_context, sortable_context_type, current_usage, day_usage, search_usage, month_usage, has_rules, waiting_estimate )
return ( display_tuple, sort_tuple )
def _DeleteNetworkContexts( self ):
selected_network_contexts = self._bandwidths.GetData( only_selected = True )
if len( selected_network_contexts ) > 0:
result = ClientGUIDialogsQuick.GetYesNo( self, 'Are you sure? This will delete all bandwidth record for the selected network contexts.' )
if result == QW.QDialog.Accepted:
self._controller.network_engine.bandwidth_manager.DeleteHistory( selected_network_contexts )
self._update_job.Wake()
def _EditDefaultBandwidthRules( self ):
network_contexts_and_bandwidth_rules = self._controller.network_engine.bandwidth_manager.GetDefaultRules()
choice_tuples = [ ( network_context.ToString() + ' (' + str( len( bandwidth_rules.GetRules() ) ) + ' rules)', ( network_context, bandwidth_rules ) ) for ( network_context, bandwidth_rules ) in network_contexts_and_bandwidth_rules ]
try:
( network_context, bandwidth_rules ) = ClientGUIDialogsQuick.SelectFromList( self, 'select network context', choice_tuples )
except HydrusExceptions.CancelledException:
return
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit bandwidth rules for ' + network_context.ToString() ) as dlg_2:
summary = network_context.GetSummary()
panel = EditBandwidthRulesPanel( dlg_2, bandwidth_rules, summary )
dlg_2.SetPanel( panel )
if dlg_2.exec() == QW.QDialog.Accepted:
bandwidth_rules = panel.GetValue()
self._controller.network_engine.bandwidth_manager.SetRules( network_context, bandwidth_rules )
def _ResetDefaultBandwidthRules( self ):
message = 'Reset your \'default\' and \'global\' bandwidth rules to default?'
result = ClientGUIDialogsQuick.GetYesNo( self, message )
if result == QW.QDialog.Accepted:
ClientDefaults.SetDefaultBandwidthManagerRules( self._controller.network_engine.bandwidth_manager )
def _ShowDefaultRulesHelp( self ):
help_text = 'Network requests act in multiple contexts. Most use the \'global\' and \'web domain\' network contexts, but a downloader page or subscription will also add a special label for itself. Each context can have its own set of bandwidth rules.'
help_text += os.linesep * 2
help_text += 'If a network context does not have some specific rules set up, it will fall back to its respective default. It is possible for a default to not have any rules. If you want to set general policy, like "Never download more than 1GB/day from any individual website," or "Limit the entire client to 2MB/s," do it through \'global\' and the defaults.'
help_text += os.linesep * 2
help_text += 'All contexts\' rules are consulted and have to pass before a request can do work. If you set a 2MB/s limit on a website domain and a 64KB/s limit on global, your download will only ever run at 64KB/s (and it fact it will probably run much slower, since everything shares the global context!). To make sense, network contexts with broader scope should have more lenient rules.'
help_text += os.linesep * 2
help_text += 'There are two special ephemeral \'instance\' contexts, for downloaders and thread watchers. These represent individual queries, either a single gallery search or a single watched thread. It can be useful to set default rules for these so your searches will gather a fast initial sample of results in the first few minutes--so you can make sure you are happy with them--but otherwise trickle the rest in over time. This keeps your CPU and other bandwidth limits less hammered and helps to avoid accidental downloads of many thousands of small bad files or a few hundred gigantic files all in one go.'
help_text += os.linesep * 2
help_text += 'Please note that this system bases its calendar dates on UTC/GMT time (it helps servers and clients around the world stay in sync a bit easier). This has no bearing on what, for instance, the \'past 24 hours\' means, but monthly transitions may occur a few hours off whatever your midnight is.'
help_text += os.linesep * 2
help_text += 'If you do not understand what is going on here, you can safely leave it alone. The default settings make for a _reasonable_ and polite profile that will not accidentally cause you to download way too much in one go or piss off servers by being too aggressive. If you want to throttle your client, the simplest way is to add a simple rule like \'500MB per day\' to the global context.'
QW.QMessageBox.information( self, 'Information', help_text )
def _Update( self ):
if self._history_time_delta_none.isChecked():
history_time_delta_threshold = None
else:
history_time_delta_threshold = self._history_time_delta_threshold.GetValue()
network_contexts = self._controller.network_engine.bandwidth_manager.GetNetworkContextsForUser( history_time_delta_threshold )
self._bandwidths.SetData( network_contexts )
def EventTimeDeltaChanged( self ):
if self._history_time_delta_none.isChecked():
self._history_time_delta_threshold.setEnabled( False )
last_review_bandwidth_search_distance = None
else:
self._history_time_delta_threshold.setEnabled( True )
last_review_bandwidth_search_distance = self._history_time_delta_threshold.GetValue()
self._controller.new_options.SetNoneableInteger( 'last_review_bandwidth_search_distance', last_review_bandwidth_search_distance )
self._update_job.Wake()
def ShowNetworkContext( self ):
for network_context in self._bandwidths.GetData( only_selected = True ):
parent = self.window().parentWidget()
frame = ClientGUITopLevelWindowsPanels.FrameThatTakesScrollablePanel( parent, 'review bandwidth for ' + network_context.ToString() )
panel = ReviewNetworkContextBandwidthPanel( frame, self._controller, network_context )
frame.SetPanel( panel )
class ReviewNetworkContextBandwidthPanel( ClientGUIScrolledPanels.ReviewPanel ):
def __init__( self, parent, controller, network_context ):
self._controller = controller
ClientGUIScrolledPanels.ReviewPanel.__init__( self, parent )
self._network_context = network_context
self._bandwidth_rules = self._controller.network_engine.bandwidth_manager.GetRules( self._network_context )
self._bandwidth_tracker = self._controller.network_engine.bandwidth_manager.GetTracker( self._network_context )
#
info_panel = ClientGUICommon.StaticBox( self, 'description' )
description = CC.network_context_type_description_lookup[ self._network_context.context_type ]
self._name = ClientGUICommon.BetterStaticText( info_panel, label = self._network_context.ToString() )
self._description = ClientGUICommon.BetterStaticText( info_panel, label = description )
#
usage_panel = ClientGUICommon.StaticBox( self, 'usage' )
self._current_usage_st = ClientGUICommon.BetterStaticText( usage_panel )
self._time_delta_usage_bandwidth_type = ClientGUICommon.BetterChoice( usage_panel )
self._time_delta_usage_time_delta = ClientGUITime.TimeDeltaButton( usage_panel, days = True, hours = True, minutes = True, seconds = True )
self._time_delta_usage_st = ClientGUICommon.BetterStaticText( usage_panel )
#
rules_panel = ClientGUICommon.StaticBox( self, 'rules' )
self._uses_default_rules_st = ClientGUICommon.BetterStaticText( rules_panel )
self._uses_default_rules_st.setAlignment( QC.Qt.AlignVCenter | QC.Qt.AlignHCenter )
self._rules_rows_panel = QW.QWidget( rules_panel )
vbox = QP.VBoxLayout()
self._rules_rows_panel.setLayout( vbox )
self._last_fetched_rule_rows = set()
self._rule_widgets = []
self._use_default_rules_button = ClientGUICommon.BetterButton( rules_panel, 'use default rules', self._UseDefaultRules )
self._edit_rules_button = ClientGUICommon.BetterButton( rules_panel, 'edit rules', self._EditRules )
#
self._time_delta_usage_time_delta.SetValue( 86400 )
for bandwidth_type in ( HC.BANDWIDTH_TYPE_DATA, HC.BANDWIDTH_TYPE_REQUESTS ):
self._time_delta_usage_bandwidth_type.addItem( HC.bandwidth_type_string_lookup[ bandwidth_type], bandwidth_type )
self._time_delta_usage_bandwidth_type.SetValue( HC.BANDWIDTH_TYPE_DATA )
monthly_usage = self._bandwidth_tracker.GetMonthlyDataUsage()
if len( monthly_usage ) > 0:
if ClientGUICharts.QT_CHARTS_OK:
self._barchart_canvas = ClientGUICharts.BarChartBandwidthHistory( usage_panel, monthly_usage )
self._barchart_canvas.setMinimumSize( 640, 480 )
else:
self._barchart_canvas = ClientGUICommon.BetterStaticText( usage_panel, 'QtCharts not available, so no bandwidth chart here.' )
else:
self._barchart_canvas = ClientGUICommon.BetterStaticText( usage_panel, 'No usage yet, so no usage history to show.' )
#
info_panel.Add( self._name, CC.FLAGS_EXPAND_PERPENDICULAR )
info_panel.Add( self._description, CC.FLAGS_EXPAND_PERPENDICULAR )
#
hbox = QP.HBoxLayout()
QP.AddToLayout( hbox, self._time_delta_usage_bandwidth_type, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, ClientGUICommon.BetterStaticText(usage_panel,' in the past '), CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, self._time_delta_usage_time_delta, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, self._time_delta_usage_st, CC.FLAGS_EXPAND_BOTH_WAYS )
usage_panel.Add( self._current_usage_st, CC.FLAGS_EXPAND_PERPENDICULAR )
usage_panel.Add( hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
usage_panel.Add( self._barchart_canvas, CC.FLAGS_EXPAND_BOTH_WAYS )
#
hbox = QP.HBoxLayout()
QP.AddToLayout( hbox, self._edit_rules_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, self._use_default_rules_button, CC.FLAGS_CENTER_PERPENDICULAR )
rules_panel.Add( self._uses_default_rules_st, CC.FLAGS_EXPAND_PERPENDICULAR )
rules_panel.Add( self._rules_rows_panel, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
rules_panel.Add( hbox, CC.FLAGS_ON_RIGHT )
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, info_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, usage_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( vbox, rules_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
self.widget().setLayout( vbox )
#
self._rules_job = HG.client_controller.CallRepeatingQtSafe( self, 0.5, 5.0, 'repeating bandwidth rules update', self._UpdateRules )
self._update_job = HG.client_controller.CallRepeatingQtSafe( self, 0.5, 1.0, 'repeating bandwidth status update', self._Update )
def _EditRules( self ):
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit bandwidth rules for ' + self._network_context.ToString() ) as dlg:
summary = self._network_context.GetSummary()
panel = EditBandwidthRulesPanel( dlg, self._bandwidth_rules, summary )
dlg.SetPanel( panel )
if dlg.exec() == QW.QDialog.Accepted:
self._bandwidth_rules = panel.GetValue()
self._controller.network_engine.bandwidth_manager.SetRules( self._network_context, self._bandwidth_rules )
self._UpdateRules()
def _Update( self ):
current_usage = self._bandwidth_tracker.GetUsage( HC.BANDWIDTH_TYPE_DATA, 1, for_user = True )
pretty_current_usage = 'current usage: ' + HydrusData.ToHumanBytes( current_usage ) + '/s'
self._current_usage_st.setText( pretty_current_usage )
#
bandwidth_type = self._time_delta_usage_bandwidth_type.GetValue()
time_delta = self._time_delta_usage_time_delta.GetValue()
time_delta_usage = self._bandwidth_tracker.GetUsage( bandwidth_type, time_delta )
if bandwidth_type == HC.BANDWIDTH_TYPE_DATA:
converter = HydrusData.ToHumanBytes
elif bandwidth_type == HC.BANDWIDTH_TYPE_REQUESTS:
converter = HydrusData.ToHumanInt
pretty_time_delta_usage = ': ' + converter( time_delta_usage )
self._time_delta_usage_st.setText( pretty_time_delta_usage )
def _UpdateRules( self ):
if self._network_context.IsDefault() or self._network_context == ClientNetworkingContexts.GLOBAL_NETWORK_CONTEXT:
if self._use_default_rules_button.isVisible():
self._uses_default_rules_st.hide()
self._use_default_rules_button.hide()
else:
if self._controller.network_engine.bandwidth_manager.UsesDefaultRules( self._network_context ):
self._uses_default_rules_st.setText( 'uses default rules' )
self._edit_rules_button.setText( 'set specific rules' )
if self._use_default_rules_button.isVisible():
self._use_default_rules_button.hide()
else:
self._uses_default_rules_st.setText( 'has its own rules' )
self._edit_rules_button.setText( 'edit rules' )
if not self._use_default_rules_button.isVisible():
self._use_default_rules_button.show()
rule_rows = self._bandwidth_rules.GetBandwidthStringsAndGaugeTuples( self._bandwidth_tracker, threshold = 0 )
if rule_rows != self._last_fetched_rule_rows:
self._last_fetched_rule_rows = rule_rows
vbox = self._rules_rows_panel.layout()
for rule_widget in self._rule_widgets:
vbox.removeWidget( rule_widget )
rule_widget.deleteLater()
self._rule_widgets = []
for ( status, ( v, r ) ) in rule_rows:
tg = ClientGUICommon.TextAndGauge( self._rules_rows_panel )
tg.SetValue( status, v, r )
self._rule_widgets.append( tg )
QP.AddToLayout( vbox, tg, CC.FLAGS_EXPAND_PERPENDICULAR )
def _UseDefaultRules( self ):
result = ClientGUIDialogsQuick.GetYesNo( self, 'Are you sure you want to revert to using the default rules for this context?' )
if result == QW.QDialog.Accepted:
self._controller.network_engine.bandwidth_manager.DeleteRules( self._network_context )
self._bandwidth_rules = self._controller.network_engine.bandwidth_manager.GetRules( self._network_context )
self._rules_job.Wake()
class ReviewNetworkJobs( ClientGUIScrolledPanels.ReviewPanel ):
def __init__( self, parent, controller ):
self._controller = controller
ClientGUIScrolledPanels.ReviewPanel.__init__( self, parent )
self._list_ctrl_panel = ClientGUIListCtrl.BetterListCtrlPanel( self )
self._list_ctrl = ClientGUIListCtrl.BetterListCtrl( self._list_ctrl_panel, CGLC.COLUMN_LIST_NETWORK_JOBS_REVIEW.ID, 20, self._ConvertDataToListCtrlTuples )
self._list_ctrl_panel.SetListCtrl( self._list_ctrl )
# button to stop jobs en-masse
self._list_ctrl_panel.AddButton( 'refresh snapshot', self._RefreshSnapshot )
#
self._list_ctrl.Sort()
self._RefreshSnapshot()
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._list_ctrl_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
self.widget().setLayout( vbox )
def _ConvertDataToListCtrlTuples( self, job_row ):
( network_engine_status, job ) = job_row
position = network_engine_status
url = job.GetURL()
( status, current_speed, num_bytes_read, num_bytes_to_read ) = job.GetStatus()
progress = ( num_bytes_read, num_bytes_to_read )
pretty_position = ClientNetworking.job_status_str_lookup[ position ]
pretty_url = url
pretty_status = status
pretty_current_speed = HydrusData.ToHumanBytes( current_speed ) + '/s'
pretty_progress = HydrusData.ConvertValueRangeToBytes( num_bytes_read, num_bytes_to_read )
display_tuple = ( pretty_position, pretty_url, pretty_status, pretty_current_speed, pretty_progress )
sort_tuple = ( position, url, status, current_speed, progress )
return ( display_tuple, sort_tuple )
def _RefreshSnapshot( self ):
job_rows = self._controller.network_engine.GetJobsSnapshot()
self._list_ctrl.SetData( job_rows )
class ReviewNetworkSessionsPanel( ClientGUIScrolledPanels.ReviewPanel ):
def __init__( self, parent, session_manager ):
ClientGUIScrolledPanels.ReviewPanel.__init__( self, parent )
self._session_manager = session_manager
listctrl_panel = ClientGUIListCtrl.BetterListCtrlPanel( self )
self._listctrl = ClientGUIListCtrl.BetterListCtrl( listctrl_panel, CGLC.COLUMN_LIST_REVIEW_NETWORK_SESSIONS.ID, 32, self._ConvertNetworkContextToListCtrlTuples, delete_key_callback = self._Clear, activation_callback = self._Review )
self._listctrl.Sort()
listctrl_panel.SetListCtrl( self._listctrl )
listctrl_panel.AddButton( 'create new', self._Add )
listctrl_panel.AddButton( 'import cookies.txt (drag and drop also works!)', self._ImportCookiesTXT )
listctrl_panel.AddButton( 'review', self._Review, enabled_only_on_selection = True )
listctrl_panel.AddButton( 'clear', self._Clear, enabled_only_on_selection = True )
listctrl_panel.AddSeparator()
listctrl_panel.AddButton( 'refresh', self._Update )
listctrl_panel.installEventFilter( ClientGUIDragDrop.FileDropTarget( listctrl_panel, filenames_callable = self._ImportCookiesTXTPaths ) )
self._show_empty = QW.QCheckBox( 'show empty', self )
#
self._Update()
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, listctrl_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( vbox, self._show_empty, CC.FLAGS_ON_RIGHT )
self.widget().setLayout( vbox )
self._show_empty.clicked.connect( self._Update )
def _Add( self ):
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'enter new network context' ) as dlg:
network_context = ClientNetworkingContexts.NetworkContext( CC.NETWORK_CONTEXT_DOMAIN, 'example.com' )
panel = EditNetworkContextPanel( dlg, network_context, limited_types = ( CC.NETWORK_CONTEXT_DOMAIN, CC.NETWORK_CONTEXT_HYDRUS ), allow_default = False )
dlg.SetPanel( panel )
if dlg.exec() == QW.QDialog.Accepted:
network_context = panel.GetValue()
self._AddNetworkContext( network_context )
self._show_empty.setChecked( True )
self._Update()
def _AddNetworkContext( self, network_context ):
# this establishes a bare session
self._session_manager.GetSession( network_context )
def _Clear( self ):
result = ClientGUIDialogsQuick.GetYesNo( self, 'Clear these sessions? This will delete them completely.' )
if result != QW.QDialog.Accepted:
return
for network_context in self._listctrl.GetData( only_selected = True ):
self._session_manager.ClearSession( network_context )
self._Update()
def _ConvertNetworkContextToListCtrlTuples( self, network_context ):
session = self._session_manager.GetSession( network_context )
pretty_network_context = network_context.ToString()
number_of_cookies = len( session.cookies )
pretty_number_of_cookies = HydrusData.ToHumanInt( number_of_cookies )
expires_numbers = [ c.expires for c in session.cookies if c.expires is not None ]
if len( expires_numbers ) == 0:
if number_of_cookies > 0:
expiry = 0
pretty_expiry = 'session'
else:
expiry = -1
pretty_expiry = ''
else:
try:
expiry = max( expires_numbers )
pretty_expiry = HydrusData.ConvertTimestampToPrettyExpires( expiry )
except:
expiry = -1
pretty_expiry = 'Unusual expiry numbers'
display_tuple = ( pretty_network_context, pretty_number_of_cookies, pretty_expiry )
sort_tuple = ( pretty_network_context, number_of_cookies, expiry )
return ( display_tuple, sort_tuple )
# this method is thanks to a user's contribution!
def _ImportCookiesTXT( self ):
with QP.FileDialog( self, 'select cookies.txt', acceptMode = QW.QFileDialog.AcceptOpen ) as f_dlg:
if f_dlg.exec() == QW.QDialog.Accepted:
path = f_dlg.GetPath()
self._ImportCookiesTXTPaths( ( path, ) )
def _ImportCookiesTXTPaths( self, paths ):
num_added = 0
for path in paths:
cj = http.cookiejar.MozillaCookieJar()
try:
cj.load( path, ignore_discard = True, ignore_expires = True )
except Exception as e:
HydrusData.ShowException( e )
QW.QMessageBox.critical( self, 'Error', 'It looks like that cookies.txt failed to load. Unfortunately, not all formats are supported (for now!).' )
return
for cookie in cj:
session = self._session_manager.GetSessionForDomain( cookie.domain )
session.cookies.set_cookie( cookie )
num_added += 1
QW.QMessageBox.information( self, 'Information', 'Added '+HydrusData.ToHumanInt(num_added)+' cookies!' )
self._Update()
def _Review( self ):
for network_context in self._listctrl.GetData( only_selected = True ):
parent = self.window().parentWidget()
frame = ClientGUITopLevelWindowsPanels.FrameThatTakesScrollablePanel( parent, 'review session for ' + network_context.ToString() )
panel = ReviewNetworkSessionPanel( frame, self._session_manager, network_context )
frame.SetPanel( panel )
def _Update( self ):
network_contexts = [ network_context for network_context in self._session_manager.GetNetworkContexts() if network_context.context_type in ( CC.NETWORK_CONTEXT_DOMAIN, CC.NETWORK_CONTEXT_HYDRUS ) ]
if not self._show_empty.isChecked():
non_empty_network_contexts = []
for network_context in network_contexts:
session = self._session_manager.GetSession( network_context )
if len( session.cookies ) > 0:
non_empty_network_contexts.append( network_context )
network_contexts = non_empty_network_contexts
self._listctrl.SetData( network_contexts )
class ReviewNetworkSessionPanel( ClientGUIScrolledPanels.ReviewPanel ):
def __init__( self, parent, session_manager, network_context ):
ClientGUIScrolledPanels.ReviewPanel.__init__( self, parent )
self._session_manager = session_manager
self._network_context = network_context
self._session = self._session_manager.GetSession( self._network_context )
self._description = ClientGUICommon.BetterStaticText( self, network_context.ToString() )
listctrl_panel = ClientGUIListCtrl.BetterListCtrlPanel( self )
self._listctrl = ClientGUIListCtrl.BetterListCtrl( listctrl_panel, CGLC.COLUMN_LIST_REVIEW_NETWORK_SESSION.ID, 8, self._ConvertCookieToListCtrlTuples, delete_key_callback = self._Delete, activation_callback = self._Edit )
self._listctrl.Sort()
listctrl_panel.SetListCtrl( self._listctrl )
listctrl_panel.AddButton( 'add', self._Add )
listctrl_panel.AddButton( 'import cookies.txt (drag and drop also works!)', self._ImportCookiesTXT )
listctrl_panel.AddButton( 'edit', self._Edit, enabled_only_on_selection = True )
listctrl_panel.AddDeleteButton()
listctrl_panel.AddSeparator()
listctrl_panel.AddButton( 'refresh', self._Update )
listctrl_panel.installEventFilter( ClientGUIDragDrop.FileDropTarget( listctrl_panel, filenames_callable = self._ImportCookiesTXTPaths ) )
#
self._Update()
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._description, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, listctrl_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
self.widget().setLayout( vbox )
def _Add( self ):
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit cookie' ) as dlg:
name = 'name'
value = '123'
if self._network_context.context_type == CC.NETWORK_CONTEXT_DOMAIN:
domain = '.' + self._network_context.context_data
else:
domain = 'service domain'
path = '/'
expires = HydrusData.GetNow() + 30 * 86400
panel = EditCookiePanel( dlg, name, value, domain, path, expires )
dlg.SetPanel( panel )
if dlg.exec() == QW.QDialog.Accepted:
( name, value, domain, path, expires ) = panel.GetValue()
self._SetCookie( name, value, domain, path, expires )
self._session_manager.SetSessionDirty( self._network_context )
self._Update()
def _ConvertCookieToListCtrlTuples( self, cookie ):
name = cookie.name
pretty_name = name
value = cookie.value
pretty_value = value
domain = cookie.domain
pretty_domain = domain
path = cookie.path
pretty_path = path
expiry = cookie.expires
if expiry is None:
pretty_expiry = 'session'
else:
pretty_expiry = HydrusData.ConvertTimestampToPrettyExpires( expiry )
sort_expiry = ClientGUIListCtrl.SafeNoneInt( expiry )
display_tuple = ( pretty_name, pretty_value, pretty_domain, pretty_path, pretty_expiry )
sort_tuple = ( name, value, domain, path, sort_expiry )
return ( display_tuple, sort_tuple )
def _Delete( self ):
result = ClientGUIDialogsQuick.GetYesNo( self, 'Delete all selected cookies?' )
if result == QW.QDialog.Accepted:
for cookie in self._listctrl.GetData( only_selected = True ):
domain = cookie.domain
path = cookie.path
name = cookie.name
self._session.cookies.clear( domain, path, name )
self._session_manager.SetSessionDirty( self._network_context )
self._Update()
def _Edit( self ):
for cookie in self._listctrl.GetData( only_selected = True ):
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit cookie' ) as dlg:
name = cookie.name
value = cookie.value
domain = cookie.domain
path = cookie.path
expires = cookie.expires
panel = EditCookiePanel( dlg, name, value, domain, path, expires )
dlg.SetPanel( panel )
if dlg.exec() == QW.QDialog.Accepted:
( name, value, domain, path, expires ) = panel.GetValue()
self._SetCookie( name, value, domain, path, expires )
self._session_manager.SetSessionDirty( self._network_context )
else:
break
self._Update()
# these methods are thanks to user's contribution!
def _ImportCookiesTXT( self ):
with QP.FileDialog( self, 'select cookies.txt', acceptMode = QW.QFileDialog.AcceptOpen ) as f_dlg:
if f_dlg.exec() == QW.QDialog.Accepted:
path = f_dlg.GetPath()
self._ImportCookiesTXTPaths( ( path, ) )
def _ImportCookiesTXTPaths( self, paths ):
num_added = 0
for path in paths:
cj = http.cookiejar.MozillaCookieJar()
try:
cj.load( path, ignore_discard = True, ignore_expires = True )
except Exception as e:
HydrusData.ShowException( e )
QW.QMessageBox.critical( self, 'Error', 'It looks like that cookies.txt failed to load. Unfortunately, not all formats are supported (for now!).' )
return
for cookie in cj:
self._session.cookies.set_cookie( cookie )
num_added += 1
QW.QMessageBox.information( self, 'Information', 'Added '+HydrusData.ToHumanInt(num_added)+' cookies!' )
self._Update()
def _SetCookie( self, name, value, domain, path, expires ):
version = 0
port = None
port_specified = False
domain_specified = True
domain_initial_dot = domain.startswith( '.' )
path_specified = True
secure = False
discard = False
comment = None
comment_url = None
rest = {}
cookie = http.cookiejar.Cookie( version, name, value, port, port_specified, domain, domain_specified, domain_initial_dot, path, path_specified, secure, expires, discard, comment, comment_url, rest )
self._session.cookies.set_cookie( cookie )
def _Update( self ):
self._session = self._session_manager.GetSession( self._network_context )
cookies = list( self._session.cookies )
self._listctrl.SetData( cookies )