Version 548

closes #1320, closes #1328
This commit is contained in:
Hydrus Network Developer 2023-10-18 15:31:50 -05:00
parent 26d1184a45
commit fc0127f0d7
No known key found for this signature in database
GPG Key ID: 76249F053212133C
41 changed files with 1690 additions and 641 deletions

36
auto_update_installer.bat Normal file
View File

@ -0,0 +1,36 @@
@ECHO off
pushd "%~dp0"
ECHO r::::::::::::::::::::::::::::::::::r
ECHO : :
ECHO : :PP. :
ECHO : vBBr :
ECHO : 7BB: :
ECHO : rBB: :
ECHO : :DQRE: rBB: :gMBb: :
ECHO : :BBBi rBB: 7BBB. :
ECHO : KBB: rBB: rBBI :
ECHO : qBB: rBB: rQBU :
ECHO : qBB: rBB: iBBS :
ECHO : qBB: iBB: 7BBj :
ECHO : iBBY iBB. 2BB. :
ECHO : SBQq iBQ: EBBY :
ECHO : :MQBZMBBDRBBP. :
ECHO : .YBB7 :
ECHO : :BB. :
ECHO : 7BBi :
ECHO : rBB: :
ECHO : :
ECHO r::::::::::::::::::::::::::::::::::r
ECHO:
ECHO hydrus
ECHO:
SET /P ready="This will download the latest exe installer using winget and install it to this location! As always, make a backup before you update. Hit Enter to start."
winget install --id=HydrusNetwork.HydrusNetwork -e --location "./"
popd
SET /P done="Done!"

View File

@ -7,6 +7,46 @@ title: Changelog
!!! note
This is the new changelog, only the most recent builds. For all versions, see the [old changelog](old_changelog.html).
## [Version 548](https://github.com/hydrusnetwork/hydrus/releases/tag/v548)
### user contributions
* thanks to a user, krita files are now renderable! we've got the defaults set like psds for now, where the preview viewer will show 'open externally', but the media viewer tries to load the full thing. let's see how it goes, and as always, if you have one that doesn't work, please send it in! note that krita are now eligible for the similar files system, so I've queued them up to get entered into it
* thanks to a user, setting an IPFS 'nocopy' path including your home directory (~) should now expand correctly (issue #1320)
* thanks to a user, newly-IPFS-pinned files are properly aware of their multihashes now (previously you needed a client restart or media reload after a delay) (issue #1328)
* thanks to a user, the url and hdd downloaders now have 'stop/abort' buttons, which will stop current work and cancel the rest of the queue. I added a yes/no dialog where you can choose to skip or delete the remainder of the queue and a couple of bells and whistles like disabling the button when the current queue has no remaining work
### misc
* fixed an issue with successive drag and drop file exports that gave different files the same filename. previously, the successive files were being replaced with the first instance with the shared name (basically the original files were not being 'overwritten'), but it should be fixed now!
* various places that were sorting services pseudorandomly now do so alphabetically (the F9 new page selector was doing this with local file domains (the first buttons in 'file search'), if you had multiple set up. sorry if I mess with your muscle memory here, but things should be more reliable here going forward!)
* added a first version of an auto-update script, `auto_update_installer.bat`, to the main install directory. it will download the latest Windows exe installer using winget and install it to the current location. if you use the installer, you might want to experiment with it (make a backup first!) as an easy hands-free update solution. let me know how it goes, and if there are no problems in a couple of weeks, I'll add it to the help
* added some more mpv error handling. if the mainloop behind your mpv window halts (which happens on various internal problems), we now detect it and more gracefully disable the viewer and its commands (previously it would escalate to error popups and try to keep working)
* fixed an issue in the newer 'missing file storage recovery' code if there is more than one base location missing
### thumbnail shortcuts
* I converted all the old hardcoded thumbnail keyboard shortcuts (thumbnail focus movement, open-media-viewer, and select-files) to the newer user-editable system under _file->shortcuts_, under a new set called 'thumbnails'. there are some new file-filters too, so you can set up 'select inbox' and similar beyond the default ctrl+a to 'select all' and escape to 'select none'
* I don't expect many people will want to even touch the giganto list of (shift+)(numpad)left/right/up/down/page up/page down/home/end selection combinations, but if you want to, you can!
* the thumbnails set also now allows 'launch the archive/delete filter', which had an odd home in 'media' before. new users now start with F12 set up in 'thumbnails', not 'media'
* I removed the jank semi-secret 'ctrl+space' hardcoded 'deselect current focused thumbnail' shortcut. that tech will probably return when I figure out more sensible logic and user settings around shift+ and ctrl+ behaviour
* this cleanup reduces three different shortcut handling routines down to one, and it particularly clears the last place where I was using ancient grandfathered wx-based 'accelerator table' tech. it should be easier to update the thumbnail shortcuts in future, and I hope to plug the mouse into it also, so you can edit middle-click to launch media etc..
### client api
* after much discussion and personal vacillating, I have decided to include the `version` and `hydrus_version` in every JSON Client API response. CBOR responses are not affected. if you need to hook into these numbers for a completely stateless interface, it is now super convenient. I'm not delighted with the spamminess of this, but it is just a handful of characters and it adds value for several situations, so I'm willing to try it out
* updated the documentation and unit tests regarding this
* the client api version is now 54
### boring stuff
* file filter objects are now serialisable
* application commands can now hold serialisable objects in their 'simple data' slot
* I made a new 'slightly more than simple' application command to hold a 'thumbnail move' that has both a direction and a selection status. I expect it will be expanded in future to handle ctrl+ selection and other logic preferences
* I made a new application command to hold the file filter. I just pre-populate the UI with a dropdown with commond choices for now, but in future it could hold a customisable file filter, once, ha ha, I have some UI to actually edit one!
* cleaned up various shortcut code
* misc linting cleanup
## [Version 547](https://github.com/hydrusnetwork/hydrus/releases/tag/v547)
### mpv crash fixes
@ -356,53 +396,3 @@ title: Changelog
* a bunch of simple `image`->`animation` renames, like IMAGE_APNG is now ANIMATION_APNG
* cleaned up some other confusing code handles for 'image' vs 'static image', to handle whether we are talking about strictly images or viewable raster image-likes (for now including PSD files) but I think it'll need more work
* deleted some ancient and no longer used imageboard profile code
## [Version 538](https://github.com/hydrusnetwork/hydrus/releases/tag/v538)
### important note on index regeneration
* **if you get a note on update about missing indices that need to be regenerated, don't panic! everything is fine, nothing to worry about, let it do its work**
### new libraries today
* **if you run from source, I recommend you rebuild your venv today. the setup script points at new versions of Qt, OpenCV, and a HEIF module that adds new filetype support**
### new Qt and OpenCV
* all release builds and normal source installations move up to PySide6 (Qt) 6.5.2 today. we've done a good bit of testing in different situations, and it seems to be a good and reliable upgrade from 6.4.1, which has given us a mix of annoying trouble at times, like mismatched UI scaling and mpv-related flickering
* let me know if you have any trouble with the overall feel of the program, particularly if you are running on an older or un-updated version of your OS
* the last version of Qt that was generally without caveats was 6.3.1. if you do have trouble with today's release (I suspect old and un-updated OSes, or source users on older Python), one option is to move to running from source and using this older version, which I have updated my setup_venv scripts to offer as a stable 'Qt6 (o)lder' option
* similarly, we are moving from OpenCV (an image library) 4.5.5.64 to 4.7.0.72. we've tested this in several rounds of future-builds and had no reports of trouble, and this also improves some build compatibility with FFMPEG 5.0 (issue #1419)
* the 'test' version of Qt stays at 6.5.2 for now, since this is the latest version
* the 'old' OpenCV compatability version remains at 4.5.3.56, the new 'test' version is now 4.8.0.74
### deferred delete system
* the first full version of the deferred delete system is complete. your no-longer-needed tables lying around after a big operation like a PTR delete/reset will now be shrunk in the background until they are small enough to delete in trivial time
* the menu entry under _database->database maintenance_ has a new submenu for the job and 'work in idle/normal' time checkboxes just like file maintenance
* the new review window UI is now fleshed out. it can refresh itself, and automitically does so on changes, and the 'work hard' button functions
* I discovered a bug in last week's code that stopped some indices from being recreated in certain regeneration jobs. if you did a 'regenerate tag text search cache' or similar operation last week, you'll encounter the above 'need to regen some indices' note. no worries, it'll all fix itself, and, if you noticed any slowdown, the affected system should work at the proper speed again
### user contributions
* thanks to a user, we now have full support for HEIF, HEIC, and AVIF image files. they will import and render just like any other image. furthermore, we have support for HEIF, HEIC, and AVIF 'sequences', which are basically like an animated gif or apng and are under the 'animations' filetype category (and they seem to play in mpv great! although I don't have an example HEIC sequence to test with, lol). all users who use the normal build will get this on update--anyone running from source will want to rebuild their venv this week to get the functionality. you can double-check _help->about_ to see if you have the required 'pillow-heif' library
* thanks to a user, the various help links in the program now redirect to the online help (and/or direct to a guide to build the local help) if the local help is missing (fixes #1360)
* thanks to a user, an addititonal final network transfer size check is now in place. if a server says it will deliver x bytes and actually delivers y, the job now raises an error. this can happen with various twitter solutions, where vid downloads will sometimes stealth-stop-working, leaving a valid but truncated mp4. fingers crossed this will now catch that situation and trigger a re-attempt
* thanks to a user, fixed TIFF files not showing EXIF correctly. just to be safe, all tiffs will be scheduled for a 'has EXIF?' rescan on update, and I silenced another bit of tiff-related PIL warning-logspam
* mkv files with AV1 video (and no/worbis/opus audio) are now correctly identified as webms. all mkvs will be scheduled for a metadata rescan on update
### misc
* when transferring mappings, _tags->migrate tags_ now supports a full location context file filter (like the file domain button you see in an autocomplete). previously it was just a list of single locations to pick from, but now, if you want to grab tags for all files deleted from x, or all files in either y or z, it is simple to set up. relatedly, the 'multiple/deleted' dialog picker launched from that menu now sizes itself to try and fit all its stuff in, rather than always being scrolled
* fixed a bug that meant you could ok the 'edit predicate' dialog despite the regex string being invalid when editing an existing 'system:known url=(regex)' predicate. the 'check valid' test is now caught correctly and cancels dialog ok, rather than escalating to the popup message catcher
* fixed a bug in table analyze code that was causing empty tables to be unintentionally re-analysed over good existing data
* a file_system_type-checking call that is used in file-export is now cached. previously it was hit for every pending file path to be calculated, and on systems with a 50ms response time to this call (I presume because of NAS/RAID-style gubbins), it meant opening the file export window could take minutes (issue #1413)
* APNG metadata parsing no longer requires FFMPEG, greatly accelerating their import
* I think I fixed the root cause of a weird bug we encountered and hacked around a couple weeks ago, where if a certain sort of downloaded page produced nothing via its parser, and it was detected initially as actually a valid file to import, but then that file import failed (e.g. ffmpeg went full bananas and thought a json file was an mp4), the import attempt would loop. the error handling now catches the unusual import failure gracefully, and the import object should be set to 'skipped' appropriately
* fixed a harmless but annoying desync error popup that sometimes occurs when deleting a repository service
### misc boring notes
* to deal with the deferred delete system clashing with SQLite not allowing index renames, I moved the database index testing and creation system to a dynamic name format. it works but is a little hacky, so maybe we'll move to direct sqlite_master interrogation in future
* unfortunately, the table shrink method I had planned to employ was not feasible (I wanted to do 'delete n rows', but it turns out that isn't compiled by default in all normal SQLite releases wew). I then experimented with several other strategies and settled on the KISS of 'select n, delete these n' in two queries, which worked out far better than my cleverer attempts anyway. the thing doesn't use much CPU time, and it cautiously autothrottles itself, and I've tested it in a bunch of situations, and I'm super happy with the performance, but if you do happen to get noticeable bumps of lag, most likely in PTR removal when the current_mappings giga-table is shrunk, turn off all database maintenance under the menu, for both idle and normal time, and let me know, and we'll figure it out
* refactored APNG parsing code to the new 'HydrusAnimationHandling.py' and took out the ffmpeg code. now OpenCV/PIL figures out the resolution

View File

@ -46,7 +46,7 @@ In general, the API deals with standard UTF-8 JSON. POST requests and 200 OK res
```
The API returns JSON for everything except actual file/thumbnail requests. For errors, you'll typically get 400 for a missing/invalid parameter, 401/403/419 for missing/insufficient/expired access, and 500 for a real deal serverside error.
The API returns JSON for everything except actual file/thumbnail requests. Every JSON response includes the `version` of the Client API and `hydrus_version` of the Client hosting it (for brevity, these values are not included in the example responses in this help). For errors, you'll typically get 400 for a missing/invalid parameter, 401/403/419 for missing/insufficient/expired access, and 500 for a real deal serverside error.
!!! note
For any request sent to the API, the total size of the initial request line (this includes the URL and any parameters) and the headers must not be larger than 2 megabytes.
@ -309,7 +309,7 @@ Note: If you need to do some quick testing, you should be able to copy the `serv
### **GET `/api_version`** { id="api_version" }
_Gets the current API version. I will increment this every time I alter the API._
_Gets the current API version. This increments every time I alter the API._
Restricted access: NO.
@ -319,7 +319,10 @@ Arguments: n/a
Response:
: Some simple JSON describing the current api version (and hydrus client version, if you are interested).
: Note that this is mostly obselete now, since the 'Server' header of every response (and a duplicated 'Hydrus-Server' one, if you have a complicated proxy situation that overwrites 'Server') are now in the form "client api/{client_api_version} ({software_version})", e.g. "client api/32 (497)".
: Note that this is not very useful any more, for two reasons:
: 1. The 'Server' header of every response (and a duplicated 'Hydrus-Server' one, if you have a complicated proxy situation that overwrites 'Server') are now in the form "client api/{client_api_version} ({software_version})", e.g. "client api/32 (497)".
: 2. **Every JSON response explicitly includes this now.**
```json title="Example response"
{

View File

@ -113,7 +113,7 @@ So, when you delete a file from 'my files', none of its tag mappings in 'my tags
This is an important part of how the PTR works--when you sync with the PTR, your client downloads a couple billion mappings for files you do not have yet. Then, when you happen to import one of those files, it appears in your importer with its PTR tags 'apparently' already set--in truth, it always had them.
When you feel like playing with some more advanced concepts, turn on _help->advanced mode_ and open a new search page. Change the file domain from 'my files' to 'all known files' or 'deleted from my files' and start typing a common tag--you'll get autocomplete results with counts! You can even run the search, and you'll get a ton of 'non-local' and therefore non-viewable files that are typically given a default hydrus thumbnail. These are files that your client is aware of, but does not currently have. You can run the _manage x_ dialogs and edit the metadata of these ghost files just as you can your real ones.
When you feel like playing with some more advanced concepts, turn on _help->advanced mode_ and open a new search page. Change the file domain from 'my files' to 'all known files' or 'deleted from my files' and start typing a common tag--you'll get autocomplete results with counts! You can even run the search, and you'll get a ton of 'non-local' and therefore non-viewable files that are typically given a default hydrus thumbnail. These are files that your client is aware of, but does not currently have. You can run the _manage x_ dialogs and edit the metadata of these ghost files just as you can your real ones. The only thing hydrus ever needs to attach metadata to a file is the file's SHA256 hash.
If you really want to delete the tags or other data for some files you deleted, then:

View File

@ -34,6 +34,39 @@
<div class="content">
<h1 id="changelog"><a href="#changelog">changelog</a></h1>
<ul>
<li>
<h2 id="version_548"><a href="#version_548">version 548</a></h2>
<ul>
<li><h3>user contributions</h3></li>
<li>thanks to a user, krita files are now renderable! we've got the defaults set like psds for now, where the preview viewer will show 'open externally', but the media viewer tries to load the full thing. let's see how it goes, and as always, if you have one that doesn't work, please send it in! note that krita are now eligible for the similar files system, so I've queued them up to get entered into it</li>
<li>thanks to a user, setting an IPFS 'nocopy' path including your home directory (~) should now expand correctly (issue #1320)</li>
<li>thanks to a user, newly-IPFS-pinned files are properly aware of their multihashes now (previously you needed a client restart or media reload after a delay) (issue #1328)</li>
<li>thanks to a user, the url and hdd downloaders now have 'stop/abort' buttons, which will stop current work and cancel the rest of the queue. I added a yes/no dialog where you can choose to skip or delete the remainder of the queue and a couple of bells and whistles like disabling the button when the current queue has no remaining work</li>
<li><h3>misc</h3></li>
<li>fixed an issue with successive drag and drop file exports that gave different files the same filename. previously, the successive files were being replaced with the first instance with the shared name (basically the original files were not being 'overwritten'), but it should be fixed now!</li>
<li>various places that were sorting services pseudorandomly now do so alphabetically (the F9 new page selector was doing this with local file domains (the first buttons in 'file search'), if you had multiple set up. sorry if I mess with your muscle memory here, but things should be more reliable here going forward!)</li>
<li>added a first version of an auto-update script, `auto_update_installer.bat`, to the main install directory. it will download the latest Windows exe installer using winget and install it to the current location. if you use the installer, you might want to experiment with it (make a backup first!) as an easy hands-free update solution. let me know how it goes, and if there are no problems in a couple of weeks, I'll add it to the help</li>
<li>added some more mpv error handling. if the mainloop behind your mpv window halts (which happens on various internal problems), we now detect it and more gracefully disable the viewer and its commands (previously it would escalate to error popups and try to keep working)</li>
<li>fixed an issue in the newer 'missing file storage recovery' code if there is more than one base location missing</li>
<li><h3>thumbnail shortcuts</h3></li>
<li>I converted all the old hardcoded thumbnail keyboard shortcuts (thumbnail focus movement, open-media-viewer, and select-files) to the newer user-editable system under _file->shortcuts_, under a new set called 'thumbnails'. there are some new file-filters too, so you can set up 'select inbox' and similar beyond the default ctrl+a to 'select all' and escape to 'select none'</li>
<li>I don't expect many people will want to even touch the giganto list of (shift+)(numpad)left/right/up/down/page up/page down/home/end selection combinations, but if you want to, you can!</li>
<li>the thumbnails set also now allows 'launch the archive/delete filter', which had an odd home in 'media' before. new users now start with F12 set up in 'thumbnails', not 'media'</li>
<li>I removed the jank semi-secret 'ctrl+space' hardcoded 'deselect current focused thumbnail' shortcut. that tech will probably return when I figure out more sensible logic and user settings around shift+ and ctrl+ behaviour</li>
<li>this cleanup reduces three different shortcut handling routines down to one, and it particularly clears the last place where I was using ancient grandfathered wx-based 'accelerator table' tech. it should be easier to update the thumbnail shortcuts in future, and I hope to plug the mouse into it also, so you can edit middle-click to launch media etc..</li>
<li><h3>client api</h3></li>
<li>after much discussion and personal vacillating, I have decided to include the `version` and `hydrus_version` in every JSON Client API response. CBOR responses are not affected. if you need to hook into these numbers for a completely stateless interface, it is now super convenient. I'm not delighted with the spamminess of this, but it is just a handful of characters and it adds value for several situations, so I'm willing to try it out</li>
<li>updated the documentation and unit tests regarding this</li>
<li>the client api version is now 54</li>
<li><h3>boring stuff</h3></li>
<li>file filter objects are now serialisable</li>
<li>application commands can now hold serialisable objects in their 'simple data' slot</li>
<li>I made a new 'slightly more than simple' application command to hold a 'thumbnail move' that has both a direction and a selection status. I expect it will be expanded in future to handle ctrl+ selection and other logic preferences</li>
<li>I made a new application command to hold the file filter. I just pre-populate the UI with a dropdown with commond choices for now, but in future it could hold a customisable file filter, once, ha ha, I have some UI to actually edit one!</li>
<li>cleaned up various shortcut code</li>
<li>misc linting cleanup</li>
</ul>
</li>
<li>
<h2 id="version_547"><a href="#version_547">version 547</a></h2>
<ul>

View File

@ -1,3 +1,5 @@
import typing
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusGlobals as HG
@ -5,6 +7,8 @@ from hydrus.core import HydrusExceptions
from hydrus.core import HydrusSerialisable
from hydrus.core import HydrusTime
from hydrus.client import ClientConstants as CC
SIMPLE_ARCHIVE_DELETE_FILTER_BACK = 0
SIMPLE_ARCHIVE_DELETE_FILTER_DELETE = 1
SIMPLE_ARCHIVE_DELETE_FILTER_KEEP = 2
@ -153,6 +157,36 @@ SIMPLE_SHOW_DUPLICATES = 144
SIMPLE_MANAGE_FILE_TIMESTAMPS = 145
SIMPLE_OPEN_FILE_IN_FILE_EXPLORER = 146
SIMPLE_COPY_LITTLE_BMP = 147
SIMPLE_MOVE_THUMBNAIL_FOCUS = 148
SIMPLE_SELECT_FILES = 149
MOVE_HOME = 0
MOVE_END = 1
MOVE_LEFT = 2
MOVE_RIGHT = 3
MOVE_UP = 4
MOVE_DOWN = 5
MOVE_PAGE_UP = 6
MOVE_PAGE_DOWN = 7
move_enum_to_str_lookup = {
MOVE_HOME : 'home',
MOVE_END : 'end',
MOVE_LEFT : 'left',
MOVE_RIGHT : 'right',
MOVE_UP : 'up',
MOVE_DOWN : 'down',
MOVE_PAGE_UP : 'page up',
MOVE_PAGE_DOWN : 'page down'
}
SELECTION_STATUS_NORMAL = 0
SELECTION_STATUS_SHIFT = 1
selection_status_enum_to_str_lookup = {
SELECTION_STATUS_NORMAL : 'move',
SELECTION_STATUS_SHIFT : 'shift-select'
}
simple_enum_to_str_lookup = {
SIMPLE_ARCHIVE_DELETE_FILTER_BACK : 'archive/delete filter: back',
@ -302,7 +336,9 @@ simple_enum_to_str_lookup = {
SIMPLE_MEDIA_SEEK_DELTA : 'seek media',
SIMPLE_GLOBAL_PROFILE_MODE_FLIP : 'flip profile mode on/off',
SIMPLE_GLOBAL_FORCE_ANIMATION_SCANBAR_SHOW : 'force the animation scanbar to show (flip on/off)',
SIMPLE_OPEN_COMMAND_PALETTE : 'open the command palette'
SIMPLE_OPEN_COMMAND_PALETTE : 'open the command palette',
SIMPLE_MOVE_THUMBNAIL_FOCUS : 'move the thumbnail focus',
SIMPLE_SELECT_FILES : 'select files'
}
legacy_simple_str_to_enum_lookup = {
@ -419,7 +455,7 @@ class ApplicationCommand( HydrusSerialisable.SerialisableBase ):
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_APPLICATION_COMMAND
SERIALISABLE_NAME = 'Application Command'
SERIALISABLE_VERSION = 4
SERIALISABLE_VERSION = 5
def __init__( self, command_type = None, data = None ):
@ -458,9 +494,21 @@ class ApplicationCommand( HydrusSerialisable.SerialisableBase ):
def _GetSerialisableInfo( self ):
# TODO: I recently moved to the data_dict here so the simple type could have serialisables in its 'simple_data', let's move the content command type to this too
# I don't _think_ this was an overcomplicated mistake, but it is a little ugly atm
# it'll be better when all working on the same system. perhaps command_type too
# and maybe ditch the object's self._data variable too, which is crushed as anything. maybe just have a serialisable dict mate
if self._command_type == APPLICATION_COMMAND_TYPE_SIMPLE:
serialisable_data = self._data
( simple_action, simple_data ) = self._data
data_dict = HydrusSerialisable.SerialisableDictionary()
data_dict[ 'simple_action' ] = simple_action
data_dict[ 'simple_data' ] = simple_data
serialisable_data = data_dict.GetSerialisableTuple()
elif self._command_type == APPLICATION_COMMAND_TYPE_CONTENT:
@ -487,7 +535,10 @@ class ApplicationCommand( HydrusSerialisable.SerialisableBase ):
if self._command_type == APPLICATION_COMMAND_TYPE_SIMPLE:
( simple_action, simple_data ) = serialisable_data
data_dict = HydrusSerialisable.CreateFromSerialisableTuple( serialisable_data )
simple_action = data_dict[ 'simple_action' ]
simple_data = data_dict[ 'simple_data' ]
if isinstance( simple_data, list ):
@ -574,6 +625,27 @@ class ApplicationCommand( HydrusSerialisable.SerialisableBase ):
return ( 4, new_serialisable_info )
if version == 4:
( command_type, serialisable_data ) = old_serialisable_info
if command_type == APPLICATION_COMMAND_TYPE_SIMPLE:
( simple_action, simple_data ) = serialisable_data
data_dict = HydrusSerialisable.SerialisableDictionary()
data_dict[ 'simple_action' ] = simple_action
data_dict[ 'simple_data' ] = simple_data
serialisable_data = data_dict.GetSerialisableTuple()
new_serialisable_info = ( command_type, serialisable_data )
return ( 5, new_serialisable_info )
def GetCommandType( self ):
@ -592,7 +664,7 @@ class ApplicationCommand( HydrusSerialisable.SerialisableBase ):
return simple_action
def GetSimpleData( self ):
def GetSimpleData( self ) -> typing.Any:
if self._command_type != APPLICATION_COMMAND_TYPE_SIMPLE:
@ -662,19 +734,29 @@ class ApplicationCommand( HydrusSerialisable.SerialisableBase ):
duplicate_type = self.GetSimpleData()
s = '{} {}'.format( s, HC.duplicate_type_string_lookup[ duplicate_type ] )
s = f'{s} {HC.duplicate_type_string_lookup[ duplicate_type ]}'
elif action == SIMPLE_MEDIA_SEEK_DELTA:
data = self.GetSimpleData()
( direction, ms ) = data
( direction, ms ) = self.GetSimpleData()
direction_s = 'back' if direction == -1 else 'forwards'
ms_s = HydrusTime.TimeDeltaToPrettyTimeDelta( ms / 1000 )
s = '{} ({} {})'.format( s, direction_s, ms_s )
s = f'{s} ({direction_s} {ms_s})'
elif action == SIMPLE_MOVE_THUMBNAIL_FOCUS:
( move_direction, selection_status ) = self.GetSimpleData()
s = f'{s} ({selection_status_enum_to_str_lookup[selection_status]} {move_enum_to_str_lookup[move_direction]})'
elif action == SIMPLE_SELECT_FILES:
file_filter = self.GetSimpleData()
s = f'{s} ({file_filter.ToString()})'
return s
@ -770,6 +852,7 @@ class ApplicationCommand( HydrusSerialisable.SerialisableBase ):
return ApplicationCommand( APPLICATION_COMMAND_TYPE_SIMPLE, ( simple_action, simple_data ) )
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_APPLICATION_COMMAND ] = ApplicationCommand
class ApplicationCommandProcessorMixin( object ):

View File

@ -190,15 +190,15 @@ def MergeCounts( min_a: int, max_a: int, min_b: int, max_b: int ):
def OrdIsSensibleASCII( o ):
return 32 <= o and o <= 127
return 32 <= o <= 127
def OrdIsAlphaLower( o ):
return 97 <= o and o <= 122
return 97 <= o <= 122
def OrdIsAlphaUpper( o ):
return 65 <= o and o <= 90
return 65 <= o <= 90
def OrdIsAlpha( o ):
@ -206,7 +206,7 @@ def OrdIsAlpha( o ):
def OrdIsNumber( o ):
return 48 <= o and o <= 57
return 48 <= o <= 57
def ShowExceptionClient( e, do_wait = True ):

View File

@ -184,34 +184,87 @@ def GetDefaultShortcuts():
global_shortcuts = ClientGUIShortcuts.ShortcutSet( 'global' )
global_shortcuts.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'G' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_GLOBAL_AUDIO_MUTE_FLIP ) )
global_shortcuts.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'G' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_GLOBAL_AUDIO_MUTE_FLIP )
)
shortcuts.append( global_shortcuts )
archive_delete_filter = ClientGUIShortcuts.ShortcutSet( 'archive_delete_filter' )
archive_delete_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_KEEP ) )
archive_delete_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_DOUBLE_CLICK, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_KEEP ) )
archive_delete_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_DELETE ) )
archive_delete_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_MIDDLE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_BACK ) )
archive_delete_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_KEEP )
)
archive_delete_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_DOUBLE_CLICK, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_KEEP )
)
archive_delete_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_DELETE )
)
archive_delete_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_MIDDLE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_BACK )
)
archive_delete_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_SPACE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_KEEP ) )
archive_delete_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F7, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_KEEP ) )
archive_delete_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DELETE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_DELETE ) )
archive_delete_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_BACKSPACE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_BACK ) )
archive_delete_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_SKIP ) )
archive_delete_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_SPACE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_KEEP )
)
archive_delete_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F7, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_KEEP )
)
archive_delete_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DELETE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_DELETE )
)
archive_delete_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_BACKSPACE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_BACK )
)
archive_delete_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_SKIP )
)
archive_delete_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F12, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER )
)
shortcuts.append( archive_delete_filter )
duplicate_filter = ClientGUIShortcuts.ShortcutSet( 'duplicate_filter' )
duplicate_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_THIS_IS_BETTER_AND_DELETE_OTHER ) )
duplicate_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_DOUBLE_CLICK, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_THIS_IS_BETTER_AND_DELETE_OTHER ) )
duplicate_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_ALTERNATES ) )
duplicate_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_MIDDLE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_BACK ) )
duplicate_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_THIS_IS_BETTER_AND_DELETE_OTHER )
)
duplicate_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_DOUBLE_CLICK, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_THIS_IS_BETTER_AND_DELETE_OTHER )
)
duplicate_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_ALTERNATES )
)
duplicate_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_MIDDLE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_BACK )
)
duplicate_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_SPACE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_THIS_IS_BETTER_AND_DELETE_OTHER ) )
duplicate_filter.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_SKIP ) )
duplicate_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_SPACE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_THIS_IS_BETTER_AND_DELETE_OTHER )
)
duplicate_filter.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_SKIP )
)
shortcuts.append( duplicate_filter )
@ -222,14 +275,18 @@ def GetDefaultShortcuts():
for delete_key in ClientGUIShortcuts.DELETE_KEYS_HYDRUS:
shortcut = ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, delete_key, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] )
shortcut =(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, delete_key, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] )
)
if media.GetCommand( shortcut ) is None:
media.SetCommand( shortcut, delete_command )
shortcut = ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, delete_key, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] )
shortcut =(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, delete_key, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] )
)
if media.GetCommand( shortcut ) is None:
@ -237,131 +294,501 @@ def GetDefaultShortcuts():
media.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F4, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MANAGE_FILE_RATINGS ) )
media.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F3, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MANAGE_FILE_TAGS ) )
media.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F4, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MANAGE_FILE_RATINGS )
)
media.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F3, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MANAGE_FILE_TAGS )
)
media.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F7, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_FILE ) )
media.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F7, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_INBOX_FILE ) )
media.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F7, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_FILE )
)
media.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F7, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_INBOX_FILE )
)
media.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'E' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_OPEN_FILE_IN_EXTERNAL_PROGRAM ) )
media.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'E' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_OPEN_FILE_IN_EXTERNAL_PROGRAM )
)
media.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'R' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_REMOVE_FILE_FROM_VIEW ) )
media.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'R' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_REMOVE_FILE_FROM_VIEW )
)
media.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F12, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_LAUNCH_THE_ARCHIVE_DELETE_FILTER ) )
media.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'C' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_COPY_FILE ) )
media.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'C' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_COPY_FILE )
)
shortcuts.append( media )
tags_autocomplete = ClientGUIShortcuts.ShortcutSet( 'tags_autocomplete' )
tags_autocomplete.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_SPACE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_FORCE_FETCH ) )
tags_autocomplete.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_INSERT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IME_MODE ) )
tags_autocomplete.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_SPACE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_FORCE_FETCH )
)
tags_autocomplete.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_INSERT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IME_MODE )
)
tags_autocomplete.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_TAB_LEFT ) )
tags_autocomplete.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_TAB_RIGHT ) )
tags_autocomplete.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_PAGE_LEFT ) )
tags_autocomplete.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_PAGE_RIGHT ) )
tags_autocomplete.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_MEDIA_PREVIOUS ) )
tags_autocomplete.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_MEDIA_NEXT ) )
tags_autocomplete.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_TAB_LEFT )
)
tags_autocomplete.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_TAB_RIGHT )
)
tags_autocomplete.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_PAGE_LEFT )
)
tags_autocomplete.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_PAGE_RIGHT )
)
tags_autocomplete.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_MEDIA_PREVIOUS )
)
tags_autocomplete.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_AUTOCOMPLETE_IF_EMPTY_MEDIA_NEXT )
)
tags_autocomplete.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'I' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SYNCHRONISED_WAIT_SWITCH ) )
tags_autocomplete.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'I' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SYNCHRONISED_WAIT_SWITCH )
)
shortcuts.append( tags_autocomplete )
main_gui = ClientGUIShortcuts.ShortcutSet( 'main_gui' )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F5, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_REFRESH ) )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F9, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_NEW_PAGE ) )
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F5, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_REFRESH )
)
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F9, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_NEW_PAGE )
)
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'M' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SET_MEDIA_FOCUS ) )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'R' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL, ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SHOW_HIDE_SPLITTERS ) )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'S' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SET_SEARCH_FOCUS ) )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'T' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_NEW_PAGE ) )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'U' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_UNCLOSE_PAGE ) )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'W' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_PAGE ) )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'Y' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_REDO ) )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'Z' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_UNDO ) )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'P' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_OPEN_COMMAND_PALETTE ) )
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'M' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SET_MEDIA_FOCUS )
)
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'R' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL, ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SHOW_HIDE_SPLITTERS )
)
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'S' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SET_SEARCH_FOCUS )
)
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'T' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_NEW_PAGE )
)
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'U' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_UNCLOSE_PAGE )
)
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'W' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_PAGE )
)
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'Y' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_REDO )
)
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'Z' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_UNDO )
)
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'P' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_OPEN_COMMAND_PALETTE )
)
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_PAGES_SELECTION_LEFT ) )
main_gui.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_PAGES_SELECTION_RIGHT ) )
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_PAGES_SELECTION_LEFT )
)
main_gui.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_PAGES_SELECTION_RIGHT )
)
shortcuts.append( main_gui )
media_viewer_browser = ClientGUIShortcuts.ShortcutSet( 'media_viewer_browser' )
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_PREVIOUS ) )
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_PREVIOUS ) )
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_PREVIOUS ) )
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_PREVIOUS )
)
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_PREVIOUS )
)
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_PREVIOUS )
)
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_RELEASE, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SHOW_MENU ) )
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_RELEASE, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SHOW_MENU )
)
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_SCROLL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_PREVIOUS ) )
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_SCROLL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_PREVIOUS )
)
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_NEXT ) )
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_NEXT ) )
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_NEXT ) )
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_NEXT )
)
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_NEXT )
)
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_NEXT )
)
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_SCROLL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_NEXT ) )
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_SCROLL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_NEXT )
)
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_HOME, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_FIRST ) )
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_HOME, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_FIRST )
)
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_END, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_LAST ) )
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_END, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_LAST )
)
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_DOUBLE_CLICK, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER ) )
media_viewer_browser.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_MIDDLE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER ) )
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_DOUBLE_CLICK, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER )
)
media_viewer_browser.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_MIDDLE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER )
)
shortcuts.append( media_viewer_browser )
media_viewer = ClientGUIShortcuts.ShortcutSet( 'media_viewer' )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_SPACE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAUSE_PLAY_MEDIA ) )
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_SPACE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAUSE_PLAY_MEDIA )
)
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MEDIA_SEEK_DELTA, simple_data = ( -1, 2500 ) ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MEDIA_SEEK_DELTA, simple_data = ( 1, 5000 ) ) )
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MEDIA_SEEK_DELTA, simple_data = ( -1, 2500 ) )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MEDIA_SEEK_DELTA, simple_data = ( 1, 5000 ) )
)
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'B' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_ANIMATION_TO_PREVIOUS_FRAME ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'N' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_ANIMATION_TO_NEXT_FRAME ) )
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'B' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_ANIMATION_TO_PREVIOUS_FRAME )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'N' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_ANIMATION_TO_NEXT_FRAME )
)
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'F' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SWITCH_BETWEEN_FULLSCREEN_BORDERLESS_AND_REGULAR_FRAMED_WINDOW ) )
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'F' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SWITCH_BETWEEN_FULLSCREEN_BORDERLESS_AND_REGULAR_FRAMED_WINDOW )
)
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'Z' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SWITCH_BETWEEN_100_PERCENT_AND_CANVAS_ZOOM ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( '+' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ZOOM_IN ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( '-' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ZOOM_OUT ) )
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'Z' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SWITCH_BETWEEN_100_PERCENT_AND_CANVAS_ZOOM )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( '+' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ZOOM_IN )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( '-' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ZOOM_OUT )
)
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_SCROLL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ZOOM_IN ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_SCROLL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ZOOM_OUT ) )
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_SCROLL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ZOOM_IN )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_SCROLL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ZOOM_OUT )
)
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAN_UP ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAN_DOWN ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAN_LEFT ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAN_RIGHT ) )
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAN_UP )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAN_DOWN )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAN_LEFT )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAN_RIGHT )
)
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_ENTER, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_ENTER, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RETURN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RETURN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER ) )
media_viewer.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_ESCAPE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER ) )
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_ENTER, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_ENTER, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RETURN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RETURN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER )
)
media_viewer.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_ESCAPE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_CLOSE_MEDIA_VIEWER )
)
shortcuts.append( media_viewer )
media_viewer_video_audio_player = ClientGUIShortcuts.ShortcutSet( 'media_viewer_media_window' )
media_viewer_video_audio_player.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAUSE_PLAY_MEDIA ) )
media_viewer_video_audio_player.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAUSE_PLAY_MEDIA )
)
shortcuts.append( media_viewer_video_audio_player )
preview_video_audio_player = ClientGUIShortcuts.ShortcutSet( 'preview_media_window' )
preview_video_audio_player.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAUSE_PLAY_MEDIA ) )
preview_video_audio_player.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_DOUBLE_CLICK, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_LAUNCH_MEDIA_VIEWER ) )
preview_video_audio_player.SetCommand( ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_MIDDLE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ), CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_LAUNCH_MEDIA_VIEWER ) )
preview_video_audio_player.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAUSE_PLAY_MEDIA )
)
preview_video_audio_player.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_DOUBLE_CLICK, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_LAUNCH_MEDIA_VIEWER )
)
preview_video_audio_player.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_MOUSE, ClientGUIShortcuts.SHORTCUT_MOUSE_MIDDLE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_LAUNCH_MEDIA_VIEWER )
)
shortcuts.append( preview_video_audio_player )
thumbnails = ClientGUIShortcuts.ShortcutSet( 'thumbnails' )
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_ENTER, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_LAUNCH_MEDIA_VIEWER )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_ENTER, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_LAUNCH_MEDIA_VIEWER )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RETURN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_LAUNCH_MEDIA_VIEWER )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RETURN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_LAUNCH_MEDIA_VIEWER )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_F12, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_LAUNCH_THE_ARCHIVE_DELETE_FILTER )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_HOME, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_HOME, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_HOME, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_HOME, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_HOME, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_HOME, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_HOME, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD, ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_HOME, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_END, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_END, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_END, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_END, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_END, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_END, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_END, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD, ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_END, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_LEFT, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_LEFT, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_LEFT, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_LEFT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD, ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_LEFT, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_RIGHT, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_RIGHT, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_RIGHT, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_RIGHT, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD, ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_RIGHT, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_UP, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_UP, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_UP, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD, ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_UP, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_DOWN, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_DOWN, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_DOWN, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD, ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_DOWN, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_PAGE_UP, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_PAGE_UP, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_PAGE_UP, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_UP, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD, ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_PAGE_UP, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_PAGE_DOWN, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_PAGE_DOWN, CAC.SELECTION_STATUS_NORMAL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_PAGE_DOWN, CAC.SELECTION_STATUS_SHIFT ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_PAGE_DOWN, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_KEYPAD, ClientGUIShortcuts.SHORTCUT_MODIFIER_SHIFT ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS, simple_data = ( CAC.MOVE_PAGE_DOWN, CAC.SELECTION_STATUS_SHIFT ) )
)
from hydrus.client.media import ClientMediaFileFilter
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_CHARACTER, ord( 'A' ), ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [ ClientGUIShortcuts.SHORTCUT_MODIFIER_CTRL ] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SELECT_FILES, simple_data = ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_ALL ) )
)
thumbnails.SetCommand(
ClientGUIShortcuts.Shortcut( ClientGUIShortcuts.SHORTCUT_TYPE_KEYBOARD_SPECIAL, ClientGUIShortcuts.SHORTCUT_KEY_SPECIAL_ESCAPE, ClientGUIShortcuts.SHORTCUT_PRESS_TYPE_PRESS, [] ),
CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SELECT_FILES, simple_data = ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_NONE ) )
)
shortcuts.append( thumbnails )
return shortcuts
def GetDefaultSimpleDownloaderFormulae():
dir_path = os.path.join( HC.STATIC_DIR, 'default', 'simple_downloader_formulae' )

View File

@ -156,7 +156,7 @@ regen_file_enum_to_job_weight_lookup = {
REGENERATE_FILE_DATA_JOB_FILE_INTEGRITY_DATA_TRY_URL_ELSE_REMOVE_RECORD : 100,
REGENERATE_FILE_DATA_JOB_FILE_INTEGRITY_DATA_SILENT_DELETE : 100,
REGENERATE_FILE_DATA_JOB_FIX_PERMISSIONS : 25,
REGENERATE_FILE_DATA_JOB_CHECK_SIMILAR_FILES_MEMBERSHIP : 20,
REGENERATE_FILE_DATA_JOB_CHECK_SIMILAR_FILES_MEMBERSHIP : 1,
REGENERATE_FILE_DATA_JOB_SIMILAR_FILES_METADATA : 100,
REGENERATE_FILE_DATA_JOB_FILE_MODIFIED_TIMESTAMP : 10,
REGENERATE_FILE_DATA_JOB_FILE_HAS_EXIF : 25,
@ -1094,7 +1094,7 @@ class ClientFilesManager( object ):
missing_dict = HydrusData.BuildKeyToListDict( [ ( subfolder.base_location, subfolder.prefix ) for subfolder in self._missing_subfolders ] )
missing_base_locations = sorted( missing_dict.keys() )
missing_base_locations = sorted( missing_dict.keys(), key = lambda b_l: b_l.path )
missing_string = ''

View File

@ -603,7 +603,7 @@ class RasterContainerVideo( RasterContainer ):
max_streaming_buffer_size = max( 48, int( num_frames_in_video / ( duration / 3.0 ) ) ) # 48 or 3 seconds
if max_streaming_buffer_size < frame_buffer_length and frame_buffer_length < num_frames_in_video:
if max_streaming_buffer_size < frame_buffer_length < num_frames_in_video:
frame_buffer_length = max_streaming_buffer_size

View File

@ -3640,7 +3640,7 @@ class ServicesManager( object ):
with self._lock:
filtered_service_keys = [ service_key for ( service_key, service ) in self._keys_to_services.items() if service.GetServiceType() in desired_types ]
filtered_service_keys = [ service.GetServiceKey() for service in self._services_sorted if service.GetServiceType() in desired_types ]
return filtered_service_keys

View File

@ -9754,8 +9754,6 @@ class DB( HydrusDB.HydrusDB ):
with self._MakeTemporaryIntegerTable( all_local_hash_ids, 'hash_id' ) as temp_hash_ids_table_name:
hash_ids = self._STS( self._Execute( f'SELECT hash_id FROM {temp_hash_ids_table_name} CROSS JOIN files_info USING ( hash_id ) WHERE mime IN ( ?, ? );', ( HC.APPLICATION_PSD, HC.IMAGE_GIF ) ) )
self.modules_files_maintenance_queue.AddJobs( hash_ids, ClientFiles.REGENERATE_FILE_DATA_JOB_PIXEL_HASH )
self.modules_files_maintenance_queue.AddJobs( hash_ids, ClientFiles.REGENERATE_FILE_DATA_JOB_SIMILAR_FILES_METADATA )
self.modules_files_maintenance_queue.AddJobs( hash_ids, ClientFiles.REGENERATE_FILE_DATA_JOB_CHECK_SIMILAR_FILES_MEMBERSHIP )
hash_ids = self._STS( self._Execute( f'SELECT hash_id FROM {temp_hash_ids_table_name} CROSS JOIN files_info USING ( hash_id ) WHERE mime = ?;', ( HC.IMAGE_PNG, ) ) )
@ -9961,6 +9959,40 @@ class DB( HydrusDB.HydrusDB ):
if version == 547:
list_of_shortcuts = ClientDefaults.GetDefaultShortcuts()
for shortcuts in list_of_shortcuts:
if shortcuts.GetName() == 'thumbnails':
self.modules_serialisable.SetJSONDump( shortcuts )
try:
self._controller.frame_splash_status.SetSubtext( f'scheduling some maintenance work' )
all_local_hash_ids = self.modules_files_storage.GetCurrentHashIdsList( self.modules_services.combined_local_file_service_id )
with self._MakeTemporaryIntegerTable( all_local_hash_ids, 'hash_id' ) as temp_hash_ids_table_name:
hash_ids = self._STS( self._Execute( f'SELECT hash_id FROM {temp_hash_ids_table_name} CROSS JOIN files_info USING ( hash_id ) WHERE mime = ?;', ( HC.APPLICATION_KRITA, ) ) )
self.modules_files_maintenance_queue.AddJobs( hash_ids, ClientFiles.REGENERATE_FILE_DATA_JOB_CHECK_SIMILAR_FILES_MEMBERSHIP )
except Exception as e:
HydrusData.PrintException( e )
message = 'Some file updates failed to schedule! This is not super important, but hydev would be interested in seeing the error that was printed to the log.'
self.pub_initial_message( message )
self._controller.frame_splash_status.SetTitleText( 'updated db to v{}'.format( HydrusData.ToHumanInt( version + 1 ) ) )
self._Execute( 'UPDATE version SET version = ?;', ( version + 1, ) )

View File

@ -808,7 +808,7 @@ class ClientDBFilesDuplicates( ClientDBModule.ClientDBModule ):
def filter_func( count ):
return lower_bound < count and count < upper_bound
return lower_bound < count < upper_bound
elif operator == '<':

View File

@ -8,8 +8,8 @@ from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusGlobals as HG
from hydrus.core import HydrusPaths
from hydrus.core import HydrusTemp
from hydrus.core import HydrusText
from hydrus.core import HydrusTime
from hydrus.client.exporting import ClientExportingFiles
from hydrus.client.gui import ClientGUIFunctions
@ -75,7 +75,11 @@ def DoFileExportDragDrop( window, page_key, media, alt_down ):
discord_dnd_fix_possible = new_options.GetBoolean( 'discord_dnd_fix' ) and len( original_paths ) <= 50 and total_size < 200 * 1048576
temp_dir = HG.client_controller.temp_dir
# TODO: figure out regular cleaning of these DnD subfolders
# ok I don't want to leave hundreds of MB of no-longer-useful files in our temp dir. we want to delete them regularly
# HOWEVER, we can't do it on every DnD because what if a user is setting up a bulk upload of ten files with four separate DnDs? if the browser doesn't copy the files to its cache immediately, we'd be killing the original source
# so I think we'd probably be looking at some sort of thing that regularly runs, scans the temp dir for 'DnDxxxx' folders, and deletes any with a creation date more than twelve hours or something. tricky question
dnd_temp_dir = HydrusTemp.GetSubTempDir( prefix = 'DnD' )
if do_secret_discord_dnd_fix:
@ -83,7 +87,7 @@ def DoFileExportDragDrop( window, page_key, media, alt_down ):
flags = QC.Qt.MoveAction
elif discord_dnd_fix_possible and os.path.exists( temp_dir ):
elif discord_dnd_fix_possible and os.path.exists( dnd_temp_dir ):
seen_export_filenames = set()
@ -108,16 +112,16 @@ def DoFileExportDragDrop( window, page_key, media, alt_down ):
for ( i, ( m, original_path ) ) in enumerate( media_and_original_paths ):
filename = ClientExportingFiles.GenerateExportFilename( temp_dir, m, filename_terms, i + 1, do_not_use_filenames = seen_export_filenames )
filename = ClientExportingFiles.GenerateExportFilename( dnd_temp_dir, m, filename_terms, i + 1, do_not_use_filenames = seen_export_filenames )
if filename == HC.mime_ext_lookup[ m.GetMime() ]:
filename = ClientExportingFiles.GenerateExportFilename( temp_dir, m, fallback_filename_terms, i + 1, do_not_use_filenames = seen_export_filenames )
filename = ClientExportingFiles.GenerateExportFilename( dnd_temp_dir, m, fallback_filename_terms, i + 1, do_not_use_filenames = seen_export_filenames )
seen_export_filenames.add( filename )
dnd_path = os.path.join( temp_dir, filename )
dnd_path = os.path.join( dnd_temp_dir, filename )
if not os.path.exists( dnd_path ):

View File

@ -394,11 +394,11 @@ class EditLoginsPanel( ClientGUIScrolledPanels.EditPanel ):
login_access_text = ClientNetworkingLogin.login_access_type_default_description_lookup[ login_access_type ]
with ClientGUIDialogs.DialogTextEntry( self, 'edit the access description, if needed', default = login_access_text, allow_blank = False ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'edit the access description, if needed', default = login_access_text, allow_blank = False ) as dlg_2:
if dlg.exec() == QW.QDialog.Accepted:
if dlg_2.exec() == QW.QDialog.Accepted:
login_access_text = dlg.GetValue()
login_access_text = dlg_2.GetValue()
else:

View File

@ -4311,17 +4311,17 @@ class ManageOptionsPanel( ClientGUIScrolledPanels.ManagePanel ):
return
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'set weight' ) as dlg:
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'set weight' ) as dlg_2:
panel = ClientGUIScrolledPanels.EditSingleCtrlPanel( dlg )
panel = ClientGUIScrolledPanels.EditSingleCtrlPanel( dlg_2 )
control = ClientGUICommon.BetterSpinBox( panel, initial = 100, min = 0, max = 10000 )
panel.SetControl( control )
dlg.SetPanel( panel )
dlg_2.SetPanel( panel )
if dlg.exec() == QW.QDialog.Accepted:
if dlg_2.exec() == QW.QDialog.Accepted:
weight = control.value()

View File

@ -219,12 +219,13 @@ shortcut_names_to_pretty_names = {
'main_gui' : 'the main window',
'tags_autocomplete' : 'tag autocomplete',
'media' : 'media actions, either thumbnails or the viewer',
'thumbnails' : 'thumbnails',
'media_viewer' : 'media viewers - all',
'media_viewer_browser' : 'media viewers - \'normal\' browser',
'archive_delete_filter' : 'media viewers - archive/delete filter',
'duplicate_filter' : 'media viewers - duplicate filter',
'preview_media_window' : 'the actual media in a preview window (mouse only)',
'media_viewer_media_window' : 'the actual media in a media viewer (mouse only)'
'media_viewer_media_window' : 'the actual media in a media viewer (mouse only)',
}
shortcut_names_sorted = [
@ -232,6 +233,7 @@ shortcut_names_sorted = [
'main_gui',
'tags_autocomplete',
'media',
'thumbnails',
'media_viewer',
'media_viewer_browser',
'archive_delete_filter',
@ -245,6 +247,7 @@ shortcut_names_to_descriptions = {
'archive_delete_filter' : 'Navigation actions for the media viewer during an archive/delete filter. Mouse shortcuts should work.',
'duplicate_filter' : 'Navigation actions for the media viewer during a duplicate filter. Mouse shortcuts should work.',
'media' : 'Actions to alter metadata for media in the media viewer or the thumbnail grid.',
'thumbnails' : 'Actions that interact with the grid of thumbnails in a normal file page.',
'main_gui' : 'Actions to control pages in the main window of the program.',
'tags_autocomplete' : 'Actions to control tag autocomplete when its input text box is focused.',
'media_viewer_browser' : 'Navigation actions for the regular browsable media viewer.',
@ -255,7 +258,7 @@ shortcut_names_to_descriptions = {
# shortcut commands
SHORTCUTS_RESERVED_NAMES = [ 'global', 'archive_delete_filter', 'duplicate_filter', 'media', 'tags_autocomplete', 'main_gui', 'media_viewer_browser', 'media_viewer', 'media_viewer_media_window', 'preview_media_window' ]
SHORTCUTS_RESERVED_NAMES = [ 'global', 'archive_delete_filter', 'duplicate_filter', 'media', 'thumbnails', 'tags_autocomplete', 'main_gui', 'media_viewer_browser', 'media_viewer', 'media_viewer_media_window', 'preview_media_window' ]
SHORTCUTS_GLOBAL_ACTIONS = [
CAC.SIMPLE_GLOBAL_AUDIO_MUTE,
@ -430,6 +433,15 @@ SHORTCUTS_PREVIEW_VIDEO_AUDIO_PLAYER_ACTIONS = [
CAC.SIMPLE_LAUNCH_MEDIA_VIEWER
]
SHORTCUTS_THUMBNAILS_ACTIONS = [
CAC.SIMPLE_LAUNCH_MEDIA_VIEWER,
CAC.SIMPLE_LAUNCH_THE_ARCHIVE_DELETE_FILTER,
CAC.SIMPLE_OPEN_FILE_IN_EXTERNAL_PROGRAM,
CAC.SIMPLE_OPEN_FILE_IN_FILE_EXPLORER,
CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS,
CAC.SIMPLE_SELECT_FILES
]
simple_shortcut_name_to_action_lookup = {
'global' : SHORTCUTS_GLOBAL_ACTIONS,
'media' : SHORTCUTS_MEDIA_ACTIONS,
@ -441,6 +453,7 @@ simple_shortcut_name_to_action_lookup = {
'archive_delete_filter' : SHORTCUTS_ARCHIVE_DELETE_FILTER_ACTIONS,
'media_viewer_media_window' : SHORTCUTS_MEDIA_VIEWER_VIDEO_AUDIO_PLAYER_ACTIONS,
'preview_media_window' : SHORTCUTS_PREVIEW_VIDEO_AUDIO_PLAYER_ACTIONS,
'thumbnails' : SHORTCUTS_THUMBNAILS_ACTIONS,
'custom' : SHORTCUTS_MEDIA_ACTIONS + SHORTCUTS_MEDIA_VIEWER_ACTIONS
}

View File

@ -454,11 +454,11 @@ class StringToStringDictControl( QW.QWidget ):
return
with ClientGUIDialogs.DialogTextEntry( self, 'enter the ' + self._value_name, allow_blank = True ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'enter the ' + self._value_name, allow_blank = True ) as dlg_2:
if dlg.exec() == QW.QDialog.Accepted:
if dlg_2.exec() == QW.QDialog.Accepted:
value = dlg.GetValue()
value = dlg_2.GetValue()
data = ( key, value )
@ -622,15 +622,15 @@ class StringToStringMatchDictControl( QW.QWidget ):
return
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit match' ) as dlg:
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit match' ) as dlg_2:
string_match = ClientStrings.StringMatch()
panel = ClientGUIStringPanels.EditStringMatchPanel( dlg, string_match )
panel = ClientGUIStringPanels.EditStringMatchPanel( dlg_2, string_match )
dlg.SetPanel( panel )
dlg_2.SetPanel( panel )
if dlg.exec() == QW.QDialog.Accepted:
if dlg_2.exec() == QW.QDialog.Accepted:
string_match = panel.GetValue()

View File

@ -286,7 +286,15 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
MPVHellBasket.instance().emergencyDumpOut.connect( self.EmergencyDumpOut )
self._player.loadfile( self._black_png_path )
try:
self._player.loadfile( self._black_png_path )
except mpv.ShutdownError:
# fugg, libmpv core probably shut down already. not much we can do but panic
self._currently_in_media_load_error_state = True
def _GetAudioOptionNames( self ):
@ -316,7 +324,15 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
self._file_header_is_loaded = False
self._currently_in_media_load_error_state = True
self._player.loadfile( self._hydrus_png_path )
try:
self._player.loadfile( self._hydrus_png_path )
except mpv.ShutdownError:
# libmpv core probably shut down
HydrusData.ShowText( 'While trying to handle another error, the mpv window could not show the error fallback png! Program may be unstable, restart ASAP recommended.' )
if self._media is not None:
@ -369,28 +385,35 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
# so we need to detect when the data is actually loaded, after the .path was (briefly) something valid, and then switches back to None
# thankfully, it seems on the dump-out unload, the playlist is unset, and this appears to be the most reliable indicator of a problem and an mpv with nothing currently loaded!
if self._player.path is None:
try:
playlist = self._player.playlist
if len( playlist ) == 0:
if self._player.path is None:
playlist = self._player.playlist
if len( playlist ) == 0:
return True
for item in playlist:
if 'current' in item:
return False
return True
for item in playlist:
if 'current' in item:
return False
return False
except mpv.ShutdownError:
return True
return False
def ClearMedia( self ):
@ -449,6 +472,10 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
self.setVisible( False )
except mpv.ShutdownError:
return True
except Exception as e:
HydrusData.ShowException( e )
@ -518,40 +545,47 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
self._HandleLoadError()
if self._media is None or not self._file_header_is_loaded or self._currently_in_media_load_error_state:
try:
return None
else:
current_timestamp_s = self._player.time_pos
if current_timestamp_s is None:
if self._media is None or not self._file_header_is_loaded or self._currently_in_media_load_error_state:
current_frame_index = 0
current_timestamp_ms = None
return None
else:
current_timestamp_ms = current_timestamp_s * 1000
current_timestamp_s = self._player.time_pos
num_frames = self._media.GetNumFrames()
if num_frames is None or num_frames == 1:
if current_timestamp_s is None:
current_frame_index = 0
current_timestamp_ms = None
else:
current_frame_index = int( round( ( current_timestamp_ms / self._media.GetDurationMS() ) * num_frames ) )
current_timestamp_ms = current_timestamp_s * 1000
current_frame_index = min( current_frame_index, num_frames - 1 )
num_frames = self._media.GetNumFrames()
if num_frames is None or num_frames == 1:
current_frame_index = 0
else:
current_frame_index = int( round( ( current_timestamp_ms / self._media.GetDurationMS() ) * num_frames ) )
current_frame_index = min( current_frame_index, num_frames - 1 )
current_timestamp_ms = min( current_timestamp_ms, self._media.GetDurationMS() )
current_timestamp_ms = min( current_timestamp_ms, self._media.GetDurationMS() )
paused = self._player.pause
paused = self._player.pause
except mpv.ShutdownError:
return None
buffer_indices = None
@ -582,7 +616,14 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
command = 'frame-back-step'
self._player.command( command )
try:
self._player.command( command )
except mpv.ShutdownError:
pass
def HasPlayedOnceThrough( self ):
@ -597,7 +638,15 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
return True
return self._player.pause
try:
return self._player.pause
except:
# libmpv core probably shut down
return True
def paintEvent(self, event):
@ -612,7 +661,15 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
return
self._player.pause = True
try:
self._player.pause = True
except mpv.ShutdownError:
# libmpv core probably shut down
pass
def PausePlay( self ):
@ -622,7 +679,15 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
return
self._player.pause = not self._player.pause
try:
self._player.pause = not self._player.pause
except mpv.ShutdownError:
# libmpv core probably shut down
pass
def Play( self ):
@ -632,7 +697,15 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
return
self._player.pause = False
try:
self._player.pause = False
except mpv.ShutdownError:
# libmpv core probably shut down
pass
def ProcessApplicationCommand( self, command: CAC.ApplicationCommand ):
@ -740,7 +813,16 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
return
current_timestamp_s = self._player.time_pos
try:
current_timestamp_s = self._player.time_pos
except mpv.ShutdownError:
# libmpv core probably shut down
return
if current_timestamp_s is None:
@ -775,7 +857,15 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
def SetLogLevel( self, level: str ):
self._player.set_loglevel( level )
try:
self._player.set_loglevel( level )
except mpv.ShutdownError:
# libmpv core probably shut down
pass
def SetMedia( self, media: typing.Optional[ ClientMedia.MediaSingleton ], start_paused = False ):
@ -802,78 +892,87 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
self._media = media
if self._media is None:
try:
self._player.pause = True
self._player.loadfile( self._black_png_path )
# old method. this does 'work', but null seems to be subtly dangerous in these cursed lands
'''
if len( self._player.playlist ) > 0:
if self._media is None:
self._player.pause = True
self._player.loadfile( self._black_png_path )
# old method. this does 'work', but null seems to be subtly dangerous in these cursed lands
'''
if len( self._player.playlist ) > 0:
try:
self._player.command( 'stop' )
# used to have this, it could raise errors if the load failed
# self._player.command( 'playlist-remove', 'current' )
except Exception as e:
HydrusData.PrintException( e )
pass
'''
else:
self._have_shown_human_error_on_this_file = False
hash = self._media.GetHash()
mime = self._media.GetMime()
# some videos have an audio channel that is silent. hydrus thinks these dudes are 'no audio', but when we throw them at mpv, it may play audio for them
# would be fine, you think, except in one reported case this causes scratches and pops and hell whitenoise
# so let's see what happens here
mute_override = not self._media.HasAudio()
client_files_manager = HG.client_controller.client_files_manager
path = client_files_manager.GetFilePath( hash, mime )
self._player.visibility = 'always'
self._stop_for_slideshow = False
self._player.pause = True
if mime in HC.ANIMATIONS and not HG.client_controller.new_options.GetBoolean( 'always_loop_gifs' ):
if mime == HC.ANIMATION_GIF:
self._times_to_play_animation = HydrusAnimationHandling.GetTimesToPlayPILAnimation( path )
elif mime == HC.ANIMATION_APNG:
self._times_to_play_animation = HydrusAnimationHandling.GetTimesToPlayAPNG( path )
try:
self._player.command( 'stop' )
# used to have this, it could raise errors if the load failed
# self._player.command( 'playlist-remove', 'current' )
self._player.loadfile( path )
except Exception as e:
HydrusData.PrintException( e )
pass
HydrusData.ShowException( e )
'''
else:
self._have_shown_human_error_on_this_file = False
hash = self._media.GetHash()
mime = self._media.GetMime()
# some videos have an audio channel that is silent. hydrus thinks these dudes are 'no audio', but when we throw them at mpv, it may play audio for them
# would be fine, you think, except in one reported case this causes scratches and pops and hell whitenoise
# so let's see what happens here
mute_override = not self._media.HasAudio()
client_files_manager = HG.client_controller.client_files_manager
path = client_files_manager.GetFilePath( hash, mime )
self._player.visibility = 'always'
self._stop_for_slideshow = False
self._player.pause = True
if mime in HC.ANIMATIONS and not HG.client_controller.new_options.GetBoolean( 'always_loop_gifs' ):
if mime == HC.ANIMATION_GIF:
self._times_to_play_animation = HydrusAnimationHandling.GetTimesToPlayPILAnimation( path )
elif mime == HC.ANIMATION_APNG:
self._times_to_play_animation = HydrusAnimationHandling.GetTimesToPlayAPNG( path )
self._player.volume = ClientGUIMediaVolume.GetCorrectCurrentVolume( self._canvas_type )
self._player.mute = mute_override or ClientGUIMediaVolume.GetCorrectCurrentMute( self._canvas_type )
self._player.pause = start_paused
try:
self._player.loadfile( path )
except Exception as e:
HydrusData.ShowException( e )
self._player.volume = ClientGUIMediaVolume.GetCorrectCurrentVolume( self._canvas_type )
self._player.mute = mute_override or ClientGUIMediaVolume.GetCorrectCurrentMute( self._canvas_type )
self._player.pause = start_paused
except mpv.ShutdownError:
# libmpv core probably shut down
pass
@ -889,7 +988,16 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
return
self._player.mute = ClientGUIMediaVolume.GetCorrectCurrentMute( self._canvas_type )
try:
self._player.mute = ClientGUIMediaVolume.GetCorrectCurrentMute( self._canvas_type )
except mpv.ShutdownError:
# libmpv core probably shut down
pass
def UpdateAudioVolume( self ):
@ -899,7 +1007,15 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
return
self._player.volume = ClientGUIMediaVolume.GetCorrectCurrentVolume( self._canvas_type )
try:
self._player.volume = ClientGUIMediaVolume.GetCorrectCurrentVolume( self._canvas_type )
except mpv.ShutdownError:
# libmpv core probably shut down
pass
def UpdateConf( self ):
@ -948,6 +1064,10 @@ class MPVWidget( CAC.ApplicationCommandProcessorMixin, QW.QWidget ):
load_f( self._player.handle, mpv_config_path.encode( 'utf-8' ) ) # pylint: disable=E1102
except mpv.ShutdownError:
pass
except Exception as e:
HydrusData.ShowText( 'MPV could not load its configuration file! This was probably due to an invalid parameter value inside the conf. The error follows:' )

View File

@ -1175,11 +1175,10 @@ class ManagementPanelImporterHDD( ManagementPanelImporter ):
self._pause_button = ClientGUICommon.BetterBitmapButton( self._import_queue_panel, CC.global_pixmaps().file_pause, self.Pause )
self._pause_button.setToolTip( 'pause/play imports' )
self._abort_button = ClientGUICommon.BetterBitmapButton( self._import_queue_panel, CC.global_pixmaps().stop, self.Abort )
self._abort_button.setToolTip( 'abort imports' )
self._hdd_import: ClientImportLocal.HDDImport = self._management_controller.GetVariable( 'hdd_import' )
file_import_options = self._hdd_import.GetFileImportOptions()
@ -1240,6 +1239,8 @@ class ManagementPanelImporterHDD( ManagementPanelImporter ):
self._current_action.setText( current_action )
self._abort_button.setEnabled( self._hdd_import.GetFileSeedCache().WorkToDo() )
def CheckAbleToClose( self ):
@ -1249,9 +1250,33 @@ class ManagementPanelImporterHDD( ManagementPanelImporter ):
def Abort( self ):
self._hdd_import.AbortImport()
if not self._hdd_import.GetFileSeedCache().WorkToDo():
return
text = 'Stop the import here? You can either set the remainder of the queue to "skipped" or delete them.'
yes_tuples = []
yes_tuples.append( ( 'set to skipped', 'skip' ) )
yes_tuples.append( ( 'delete them', 'delete' ) )
try:
result = ClientGUIDialogsQuick.GetYesYesNo( self, text, yes_tuples = yes_tuples, no_label = 'forget it' )
except HydrusExceptions.CancelledException:
return
do_delete = result == 'delete'
self._hdd_import.AbortImport( do_delete = do_delete )
self._UpdateImportStatus()
def Pause( self ):
@ -3682,8 +3707,8 @@ class ManagementPanelImporterURLs( ManagementPanelImporter ):
self._pause_button = ClientGUICommon.BetterBitmapButton( self._import_queue_panel, CC.global_pixmaps().file_pause, self.Pause )
self._pause_button.setToolTip( 'pause/play files' )
self._abort_button = ClientGUICommon.BetterBitmapButton( self._import_queue_panel, CC.global_pixmaps().stop, self.Abort)
self._abort_button = ClientGUICommon.BetterBitmapButton( self._import_queue_panel, CC.global_pixmaps().stop, self.Abort )
self._abort_button.setToolTip( 'abort files' )
self._file_download_control = ClientGUINetworkJobControl.NetworkJobControl( self._import_queue_panel )
@ -3819,6 +3844,8 @@ class ManagementPanelImporterURLs( ManagementPanelImporter ):
self._gallery_download_control.SetNetworkJob( gallery_network_job )
self._abort_button.setEnabled( self._urls_import.GetFileSeedCache().WorkToDo() )
def CheckAbleToClose( self ):
@ -3829,9 +3856,33 @@ class ManagementPanelImporterURLs( ManagementPanelImporter ):
def Abort( self ):
self._urls_import.AbortImport()
if not self._urls_import.GetFileSeedCache().WorkToDo():
return
text = 'Stop the import here? You can either set the remainder of the queue to "skipped" or delete them.'
yes_tuples = []
yes_tuples.append( ( 'set to skipped', 'skip' ) )
yes_tuples.append( ( 'delete them', 'delete' ) )
try:
result = ClientGUIDialogsQuick.GetYesYesNo( self, text, yes_tuples = yes_tuples, no_label = 'forget it' )
except HydrusExceptions.CancelledException:
return
do_delete = result == 'delete'
self._urls_import.AbortImport( do_delete = do_delete )
self._UpdateImportStatus()
def Pause( self ):

View File

@ -1697,7 +1697,7 @@ class PagesNotebook( QP.TabWidgetWithDnD ):
def _SendPageToNewNotebook( self, index ):
if 0 <= index and index <= self.count() - 1:
if 0 <= index <= self.count() - 1:
page = self.widget( index )
@ -1751,7 +1751,7 @@ class PagesNotebook( QP.TabWidgetWithDnD ):
return
if 0 <= new_page_index and new_page_index <= self.count() - 1:
if 0 <= new_page_index <= self.count() - 1:
page_is_selected = self.currentIndex() == page_index

View File

@ -100,7 +100,7 @@ class MediaPanel( CAC.ApplicationCommandProcessorMixin, ClientMedia.ListeningMed
self._had_changes_to_tag_presentation_while_hidden = False
self._my_shortcut_handler = ClientGUIShortcuts.ShortcutsHandler( self, [ 'media' ] )
self._my_shortcut_handler = ClientGUIShortcuts.ShortcutsHandler( self, [ 'media', 'thumbnails' ] )
self.setWidget( self._InnerWidget( self ) )
self.setWidgetResizable( True )
@ -836,7 +836,6 @@ class MediaPanel( CAC.ApplicationCommandProcessorMixin, ClientMedia.ListeningMed
self._SetFocusedMedia( None )
self._EndShiftSelect()
else:
@ -2382,6 +2381,10 @@ class MediaPanel( CAC.ApplicationCommandProcessorMixin, ClientMedia.ListeningMed
self._GetSimilarTo( CC.HAMMING_SPECULATIVE )
elif action == CAC.SIMPLE_LAUNCH_MEDIA_VIEWER:
self._LaunchMediaViewer()
elif action == CAC.SIMPLE_OPEN_FILE_IN_EXTERNAL_PROGRAM:
self._OpenExternally()
@ -2620,12 +2623,8 @@ class MediaPanelThumbnails( MediaPanel ):
# there's a job in qt to-do to sort all this out and fix other scroll issues
self._widget_event_filter.EVT_SIZE( self.EventResize )
self._widget_event_filter.EVT_KEY_DOWN( self.EventKeyDown )
self.widget().setMinimumSize( 50, 50 )
self.RefreshAcceleratorTable()
self._UpdateScrollBars()
HG.client_controller.sub( self, 'MaintainPageCache', 'memory_maintenance_pulse' )
@ -2633,7 +2632,6 @@ class MediaPanelThumbnails( MediaPanel ):
HG.client_controller.sub( self, 'NewThumbnails', 'new_thumbnails' )
HG.client_controller.sub( self, 'ThumbnailsReset', 'notify_complete_thumbnail_reset' )
HG.client_controller.sub( self, 'RedrawAllThumbnails', 'refresh_all_tag_presentation_gui' )
HG.client_controller.sub( self, 'RefreshAcceleratorTable', 'notify_new_options' )
HG.client_controller.sub( self, 'WaterfallThumbnails', 'waterfall_thumbnails' )
@ -3018,7 +3016,7 @@ class MediaPanelThumbnails( MediaPanel ):
return True
def _MoveFocusedThumbnail( self, rows, columns, shift ):
def _MoveThumbnailFocus( self, rows, columns, shift ):
if self._last_hit_media is not None:
@ -3334,6 +3332,62 @@ class MediaPanelThumbnails( MediaPanel ):
def contextMenuEvent( self, event ):
if event.reason() == QG.QContextMenuEvent.Keyboard:
self.ShowMenu()
def EventMouseFullScreen( self, event ):
t = self._GetThumbnailUnderMouse( event )
if t is not None:
locations_manager = t.GetLocationsManager()
if locations_manager.IsLocal():
self._LaunchMediaViewer( t )
else:
can_download = not locations_manager.GetCurrent().isdisjoint( HG.client_controller.services_manager.GetRemoteFileServiceKeys() )
if can_download:
self._DownloadHashes( t.GetHashes() )
def EventResize( self, event ):
self._ReinitialisePageCacheIfNeeded()
self._RecalculateVirtualSize( called_from_resize_event = True )
self._last_size = QP.ScrollAreaVisibleRect( self ).size()
def GetTotalFileSize( self ):
return sum( ( m.GetSize() for m in self._sorted_media ) )
def MaintainPageCache( self ):
if not HG.client_controller.gui.IsCurrentPage( self._page_key ):
self._DirtyAllPages()
self._DeleteAllDirtyPages()
def mouseMoveEvent( self, event ):
if event.buttons() & QC.Qt.LeftButton:
@ -3389,81 +3443,6 @@ class MediaPanelThumbnails( MediaPanel ):
event.ignore()
def EventKeyDown( self, event ):
# accelerator tables can't handle escape key in windows, gg
if event.key() == QC.Qt.Key_Escape:
self._Select( ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_NONE ) )
elif event.key() in ( QC.Qt.Key_PageUp, QC.Qt.Key_PageDown ):
if event.key() == QC.Qt.Key_PageUp:
direction = -1
elif event.key() == QC.Qt.Key_PageDown:
direction = 1
shift = event.modifiers() & QC.Qt.ShiftModifier
self._MoveFocusedThumbnail( self._num_rows_per_actual_page * direction, 0, shift )
else:
return True # was: event.ignore()
def EventMouseFullScreen( self, event ):
t = self._GetThumbnailUnderMouse( event )
if t is not None:
locations_manager = t.GetLocationsManager()
if locations_manager.IsLocal():
self._LaunchMediaViewer( t )
else:
can_download = not locations_manager.GetCurrent().isdisjoint( HG.client_controller.services_manager.GetRemoteFileServiceKeys() )
if can_download:
self._DownloadHashes( t.GetHashes() )
def showEvent( self, event ):
self._UpdateScrollBars()
def EventResize( self, event ):
self._ReinitialisePageCacheIfNeeded()
self._RecalculateVirtualSize( called_from_resize_event = True )
self._last_size = QP.ScrollAreaVisibleRect( self ).size()
def contextMenuEvent( self, event ):
if event.reason() == QG.QContextMenuEvent.Keyboard:
self.ShowMenu()
def mouseReleaseEvent( self, event ):
if event.button() != QC.Qt.RightButton:
@ -3476,21 +3455,6 @@ class MediaPanelThumbnails( MediaPanel ):
self.ShowMenu()
def GetTotalFileSize( self ):
return sum( ( m.GetSize() for m in self._sorted_media ) )
def MaintainPageCache( self ):
if not HG.client_controller.gui.IsCurrentPage( self._page_key ):
self._DirtyAllPages()
self._DeleteAllDirtyPages()
def NewThumbnails( self, hashes ):
affected_thumbnails = self._GetMedia( hashes )
@ -3529,6 +3493,96 @@ class MediaPanelThumbnails( MediaPanel ):
HG.client_controller.CallToThread( do_it, self, do_it, affected_hashes )
def ProcessApplicationCommand( self, command: CAC.ApplicationCommand ):
command_processed = True
if command.IsSimpleCommand():
action = command.GetSimpleAction()
if action == CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS:
( move_direction, selection_status ) = command.GetSimpleData()
shift = selection_status == CAC.SELECTION_STATUS_SHIFT
if move_direction in ( CAC.MOVE_HOME, CAC.MOVE_END ):
if move_direction == CAC.MOVE_HOME:
self._ScrollHome( shift )
else: # MOVE_END
self._ScrollEnd( shift )
elif move_direction in ( CAC.MOVE_PAGE_UP, CAC.MOVE_PAGE_DOWN ):
if move_direction == CAC.MOVE_PAGE_UP:
direction = -1
else: # MOVE_PAGE_DOWN
direction = 1
self._MoveThumbnailFocus( self._num_rows_per_actual_page * direction, 0, shift )
else:
if move_direction == CAC.MOVE_LEFT:
rows = 0
columns = -1
elif move_direction == CAC.MOVE_RIGHT:
rows = 0
columns = 1
elif move_direction == CAC.MOVE_UP:
rows = -1
columns = 0
else: # MOVE_DOWN
rows = 1
columns = 0
self._MoveThumbnailFocus( rows, columns, shift )
elif action == CAC.SIMPLE_SELECT_FILES:
file_filter = command.GetSimpleData()
self._Select( file_filter )
else:
command_processed = False
else:
command_processed = False
if not command_processed:
return MediaPanel.ProcessApplicationCommand( self, command )
else:
return command_processed
def RedrawAllThumbnails( self ):
self._DirtyAllPages()
@ -3546,60 +3600,6 @@ class MediaPanelThumbnails( MediaPanel ):
self.widget().update()
def RefreshAcceleratorTable( self ):
if not self or not QP.isValid( self ):
return
# Remove old shortcuts
for child in self.children():
if isinstance( child, QW.QShortcut ):
child.setParent( None )
child.deleteLater()
def ctrl_space_callback( self ):
if self._focused_media is not None:
self._HitMedia( self._focused_media, True, False )
QP.AddShortcut( self, QC.Qt.NoModifier, QC.Qt.Key_Home, self._ScrollHome, False )
QP.AddShortcut( self, QC.Qt.KeypadModifier, QC.Qt.Key_Home, self._ScrollHome, False )
QP.AddShortcut( self, QC.Qt.NoModifier, QC.Qt.Key_End, self._ScrollEnd, False )
QP.AddShortcut( self, QC.Qt.KeypadModifier, QC.Qt.Key_End, self._ScrollEnd, False )
QP.AddShortcut( self, QC.Qt.NoModifier, QC.Qt.Key_Return, self._LaunchMediaViewer )
QP.AddShortcut( self, QC.Qt.KeypadModifier, QC.Qt.Key_Enter, self._LaunchMediaViewer )
QP.AddShortcut( self, QC.Qt.NoModifier, QC.Qt.Key_Up, self._MoveFocusedThumbnail, -1, 0, False )
QP.AddShortcut( self, QC.Qt.KeypadModifier, QC.Qt.Key_Up, self._MoveFocusedThumbnail, -1, 0, False )
QP.AddShortcut( self, QC.Qt.NoModifier, QC.Qt.Key_Down, self._MoveFocusedThumbnail, 1, 0, False )
QP.AddShortcut( self, QC.Qt.KeypadModifier, QC.Qt.Key_Down, self._MoveFocusedThumbnail, 1, 0, False )
QP.AddShortcut( self, QC.Qt.NoModifier, QC.Qt.Key_Left, self._MoveFocusedThumbnail, 0, -1, False )
QP.AddShortcut( self, QC.Qt.KeypadModifier, QC.Qt.Key_Left, self._MoveFocusedThumbnail, 0, -1, False )
QP.AddShortcut( self, QC.Qt.NoModifier, QC.Qt.Key_Right, self._MoveFocusedThumbnail, 0, 1, False )
QP.AddShortcut( self, QC.Qt.KeypadModifier, QC.Qt.Key_Right, self._MoveFocusedThumbnail, 0, 1, False )
QP.AddShortcut( self, QC.Qt.ShiftModifier, QC.Qt.Key_Home, self._ScrollHome, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier | QC.Qt.KeypadModifier, QC.Qt.Key_Home, self._ScrollHome, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier, QC.Qt.Key_End, self._ScrollEnd, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier | QC.Qt.KeypadModifier, QC.Qt.Key_End, self._ScrollEnd, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier, QC.Qt.Key_Up, self._MoveFocusedThumbnail, -1, 0, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier | QC.Qt.KeypadModifier, QC.Qt.Key_Up, self._MoveFocusedThumbnail, -1, 0, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier, QC.Qt.Key_Down, self._MoveFocusedThumbnail, 1, 0, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier | QC.Qt.KeypadModifier, QC.Qt.Key_Down, self._MoveFocusedThumbnail, 1, 0, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier, QC.Qt.Key_Left, self._MoveFocusedThumbnail, 0, -1, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier | QC.Qt.KeypadModifier, QC.Qt.Key_Left, self._MoveFocusedThumbnail, 0, -1, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier, QC.Qt.Key_Right, self._MoveFocusedThumbnail, 0, 1, True )
QP.AddShortcut( self, QC.Qt.ShiftModifier | QC.Qt.KeypadModifier, QC.Qt.Key_Right, self._MoveFocusedThumbnail, 0, 1, True )
QP.AddShortcut( self, QC.Qt.ControlModifier, QC.Qt.Key_A, self._Select, ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_ALL ) )
QP.AddShortcut( self, QC.Qt.ControlModifier, QC.Qt.Key_Space, ctrl_space_callback, self )
def SetFocusedMedia( self, media ):
MediaPanel.SetFocusedMedia( self, media )
@ -3625,6 +3625,11 @@ class MediaPanelThumbnails( MediaPanel ):
def showEvent( self, event ):
self._UpdateScrollBars()
def ShowMenu( self, do_not_show_just_return = False ):
new_options = HG.client_controller.new_options
@ -4720,23 +4725,23 @@ def AddRemoveMenu( win: MediaPanel, menu, filter_counts, all_specific_file_domai
if 0 < selected_count < file_filter_all.GetCount( win, filter_counts ):
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_selected.ToString( win, filter_counts ), 'Remove all the selected files from the current view.', win._Remove, file_filter_selected )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_selected.ToStringWithCount( win, filter_counts ), 'Remove all the selected files from the current view.', win._Remove, file_filter_selected )
if file_filter_all.GetCount( win, filter_counts ) > 0:
ClientGUIMenus.AppendSeparator( remove_menu )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_all.ToString( win, filter_counts ), 'Remove all the files from the current view.', win._Remove, file_filter_all )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_all.ToStringWithCount( win, filter_counts ), 'Remove all the files from the current view.', win._Remove, file_filter_all )
if file_filter_inbox.GetCount( win, filter_counts ) > 0 and file_filter_archive.GetCount( win, filter_counts ) > 0:
ClientGUIMenus.AppendSeparator( remove_menu )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_inbox.ToString( win, filter_counts ), 'Remove all the inbox files from the current view.', win._Remove, file_filter_inbox )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_inbox.ToStringWithCount( win, filter_counts ), 'Remove all the inbox files from the current view.', win._Remove, file_filter_inbox )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_archive.ToString( win, filter_counts ), 'Remove all the archived files from the current view.', win._Remove, file_filter_archive )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_archive.ToStringWithCount( win, filter_counts ), 'Remove all the archived files from the current view.', win._Remove, file_filter_archive )
if len( all_specific_file_domains ) > 1:
@ -4751,7 +4756,7 @@ def AddRemoveMenu( win: MediaPanel, menu, filter_counts, all_specific_file_domai
file_filter = ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_FILE_SERVICE, file_service_key )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter.ToString( win, filter_counts ), 'Remove all the files that are in this file domain.', win._Remove, file_filter )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter.ToStringWithCount( win, filter_counts ), 'Remove all the files that are in this file domain.', win._Remove, file_filter )
@ -4762,8 +4767,8 @@ def AddRemoveMenu( win: MediaPanel, menu, filter_counts, all_specific_file_domai
ClientGUIMenus.AppendSeparator( remove_menu )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_local.ToString( win, filter_counts ), 'Remove all the files that are in this client.', win._Remove, file_filter_local )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_remote.ToString( win, filter_counts ), 'Remove all the files that are not in this client.', win._Remove, file_filter_remote )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_local.ToStringWithCount( win, filter_counts ), 'Remove all the files that are in this client.', win._Remove, file_filter_local )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_remote.ToStringWithCount( win, filter_counts ), 'Remove all the files that are not in this client.', win._Remove, file_filter_remote )
not_selected_count = file_filter_not_selected.GetCount( win, filter_counts )
@ -4772,7 +4777,7 @@ def AddRemoveMenu( win: MediaPanel, menu, filter_counts, all_specific_file_domai
ClientGUIMenus.AppendSeparator( remove_menu )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_not_selected.ToString( win, filter_counts ), 'Remove all the not selected files from the current view.', win._Remove, file_filter_not_selected )
ClientGUIMenus.AppendMenuItem( remove_menu, file_filter_not_selected.ToStringWithCount( win, filter_counts ), 'Remove all the not selected files from the current view.', win._Remove, file_filter_not_selected )
ClientGUIMenus.AppendMenu( menu, remove_menu, 'remove' )
@ -4802,16 +4807,16 @@ def AddSelectMenu( win: MediaPanel, menu, filter_counts, all_specific_file_domai
ClientGUIMenus.AppendSeparator( select_menu )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_all.ToString( win, filter_counts ), 'Select all the files in the current view.', win._Select, file_filter_all )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_all.ToStringWithCount( win, filter_counts ), 'Select all the files in the current view.', win._Select, file_filter_all )
if file_filter_inbox.GetCount( win, filter_counts ) > 0 and file_filter_archive.GetCount( win, filter_counts ) > 0:
ClientGUIMenus.AppendSeparator( select_menu )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_inbox.ToString( win, filter_counts ), 'Select all the inbox files in the current view.', win._Select, file_filter_inbox )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_inbox.ToStringWithCount( win, filter_counts ), 'Select all the inbox files in the current view.', win._Select, file_filter_inbox )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_archive.ToString( win, filter_counts ), 'Select all the archived files in the current view.', win._Select, file_filter_archive )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_archive.ToStringWithCount( win, filter_counts ), 'Select all the archived files in the current view.', win._Select, file_filter_archive )
if len( all_specific_file_domains ) > 1:
@ -4826,7 +4831,7 @@ def AddSelectMenu( win: MediaPanel, menu, filter_counts, all_specific_file_domai
file_filter = ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_FILE_SERVICE, file_service_key )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter.ToString( win, filter_counts ), 'Select all the files in this file domain.', win._Select, file_filter )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter.ToStringWithCount( win, filter_counts ), 'Select all the files in this file domain.', win._Select, file_filter )
@ -4837,8 +4842,8 @@ def AddSelectMenu( win: MediaPanel, menu, filter_counts, all_specific_file_domai
ClientGUIMenus.AppendSeparator( select_menu )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_local.ToString( win, filter_counts ), 'Remove all the files that are in this client.', win._Select, file_filter_local )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_remote.ToString( win, filter_counts ), 'Remove all the files that are not in this client.', win._Select, file_filter_remote )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_local.ToStringWithCount( win, filter_counts ), 'Remove all the files that are in this client.', win._Select, file_filter_local )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_remote.ToStringWithCount( win, filter_counts ), 'Remove all the files that are not in this client.', win._Select, file_filter_remote )
file_filter_selected = ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_SELECTED )
@ -4852,12 +4857,12 @@ def AddSelectMenu( win: MediaPanel, menu, filter_counts, all_specific_file_domai
ClientGUIMenus.AppendSeparator( select_menu )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_not_selected.ToString( win, filter_counts ), 'Swap what is and is not selected.', win._Select, file_filter_not_selected )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_not_selected.ToStringWithCount( win, filter_counts ), 'Swap what is and is not selected.', win._Select, file_filter_not_selected )
ClientGUIMenus.AppendSeparator( select_menu )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_none.ToString( win, filter_counts ), 'Deselect everything selected.', win._Select, file_filter_none )
ClientGUIMenus.AppendMenuItem( select_menu, file_filter_none.ToStringWithCount( win, filter_counts ), 'Deselect everything selected.', win._Select, file_filter_none )
ClientGUIMenus.AppendMenu( menu, select_menu, 'select' )

View File

@ -1600,7 +1600,7 @@ class EditServiceIPFSSubPanel( ClientGUICommon.StaticBox ):
portable_hydrus_path = HydrusPaths.ConvertAbsPathToPortablePath( hydrus_path )
portable_dict[ portable_hydrus_path ] = os.path.expanduser(ipfs_path)
portable_dict[ portable_hydrus_path ] = os.path.expanduser( ipfs_path )
dictionary_part[ 'nocopy_abs_path_translations' ] = portable_dict

View File

@ -13,6 +13,7 @@ from hydrus.client.gui import ClientGUIShortcuts
from hydrus.client.gui import QtPorting as QP
from hydrus.client.gui.search import ClientGUIACDropdown
from hydrus.client.gui.widgets import ClientGUICommon
from hydrus.client.media import ClientMediaFileFilter
class LocalFilesSubPanel( QW.QWidget ):
@ -428,6 +429,14 @@ class SimpleSubPanel( QW.QWidget ):
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._duplicate_type, CC.FLAGS_EXPAND_BOTH_WAYS )
self._duplicates_type_panel.setLayout( vbox )
#
self._seek_panel = QW.QWidget( self )
choices = [
@ -449,14 +458,6 @@ class SimpleSubPanel( QW.QWidget ):
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._duplicate_type, CC.FLAGS_EXPAND_BOTH_WAYS )
self._duplicates_type_panel.setLayout( vbox )
#
hbox = QP.HBoxLayout()
QP.AddToLayout( hbox, self._seek_direction, CC.FLAGS_EXPAND_BOTH_WAYS )
@ -469,11 +470,65 @@ class SimpleSubPanel( QW.QWidget ):
#
self._thumbnail_move_panel = QW.QWidget( self )
choices = [ ( CAC.selection_status_enum_to_str_lookup[ s ], s ) for s in [ CAC.SELECTION_STATUS_NORMAL, CAC.SELECTION_STATUS_SHIFT ] ]
self._selection_status = ClientGUICommon.BetterRadioBox( self._thumbnail_move_panel, choices = choices )
self._selection_status.SetValue( CAC.SELECTION_STATUS_NORMAL )
self._move_direction = ClientGUICommon.BetterChoice( self._thumbnail_move_panel )
for m in [ CAC.MOVE_LEFT, CAC.MOVE_RIGHT, CAC.MOVE_UP, CAC.MOVE_DOWN, CAC.MOVE_HOME, CAC.MOVE_END, CAC.MOVE_PAGE_UP, CAC.MOVE_PAGE_DOWN ]:
self._move_direction.addItem( CAC.move_enum_to_str_lookup[ m ], m )
#
hbox = QP.HBoxLayout()
QP.AddToLayout( hbox, self._selection_status, CC.FLAGS_CENTER )
QP.AddToLayout( hbox, self._move_direction, CC.FLAGS_CENTER )
self._thumbnail_move_panel.setLayout( hbox )
#
self._file_filter_panel = QW.QWidget( self )
self._file_filter = ClientGUICommon.BetterChoice( self._file_filter_panel )
for file_filter in [
ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_ALL ),
ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_NONE ),
ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_INBOX ),
ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_ARCHIVE ),
ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_LOCAL ),
ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_FILE_SERVICE, filter_data = CC.TRASH_SERVICE_KEY )
]:
self._file_filter.addItem( file_filter.ToString(), file_filter )
#
hbox = QP.HBoxLayout()
QP.AddToLayout( hbox, self._file_filter, CC.FLAGS_CENTER )
self._file_filter_panel.setLayout( hbox )
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._simple_actions, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
QP.AddToLayout( vbox, self._duplicates_type_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
QP.AddToLayout( vbox, self._seek_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
QP.AddToLayout( vbox, self._thumbnail_move_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
QP.AddToLayout( vbox, self._file_filter_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
self.setLayout( vbox )
@ -488,6 +543,8 @@ class SimpleSubPanel( QW.QWidget ):
self._duplicates_type_panel.setVisible( action == CAC.SIMPLE_SHOW_DUPLICATES )
self._seek_panel.setVisible( action == CAC.SIMPLE_MEDIA_SEEK_DELTA )
self._thumbnail_move_panel.setVisible( action == CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS )
self._file_filter_panel.setVisible( action == CAC.SIMPLE_SELECT_FILES )
def GetValue( self ):
@ -515,6 +572,19 @@ class SimpleSubPanel( QW.QWidget ):
simple_data = ( direction, ms )
elif action == CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS:
move_direction = self._move_direction.GetValue()
selection_status = self._selection_status.GetValue()
simple_data = ( move_direction, selection_status )
elif action == CAC.SIMPLE_SELECT_FILES:
file_filter = self._file_filter.GetValue()
simple_data = file_filter
else:
simple_data = None
@ -549,6 +619,19 @@ class SimpleSubPanel( QW.QWidget ):
self._seek_duration_s.setValue( s )
self._seek_duration_ms.setValue( ms )
elif action == CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS:
( move_direction, selection_status ) = command.GetSimpleData()
self._move_direction.SetValue( move_direction )
self._selection_status.SetValue( selection_status )
elif action == CAC.SIMPLE_SELECT_FILES:
file_filter = command.GetSimpleData()
self._file_filter.SetValue( file_filter )
self._UpdateControls()

View File

@ -173,12 +173,6 @@ class HDDImport( HydrusSerialisable.SerialisableBase ):
return ( 3, new_serialisable_info )
def _EmptyFileSeedCache( self, status: typing.Collection[int] = (CC.STATUS_UNKNOWN,) ):
self._file_seed_cache.RemoveFileSeedsByStatus( status )
time.sleep( ClientImporting.DID_SUBSTANTIAL_FILE_WORK_MINIMUM_SLEEP_TIME )
def _WorkOnFiles( self ):
@ -372,20 +366,31 @@ class HDDImport( HydrusSerialisable.SerialisableBase ):
self._SerialisableChangeMade()
def AbortImport( self ):
if self.CurrentlyWorking():
self.PausePlay()
self._EmptyFileSeedCache()
def AbortImport( self, do_delete = False ):
if do_delete:
self._file_seed_cache.RemoveFileSeedsByStatus( ( CC.STATUS_UNKNOWN, ) )
else:
file_seeds = self._file_seed_cache.GetFileSeeds( CC.STATUS_UNKNOWN )
for file_seed in file_seeds:
file_seed.SetStatus( CC.STATUS_SKIPPED, note = 'import abandoned by user' )
self._file_seed_cache.NotifyFileSeedsUpdated( file_seeds )
self._paused = False
with self._lock:
self._files_status = 'aborted'
self._SerialisableChangeMade()

View File

@ -1008,11 +1008,6 @@ class URLsImport( HydrusSerialisable.SerialisableBase ):
return ( 4, new_serialisable_info )
def _EmptyFileSeedCache( self, status: typing.Collection[int] = (CC.STATUS_UNKNOWN,) ):
self._file_seed_cache.RemoveFileSeedsByStatus( status )
time.sleep( ClientImporting.DID_SUBSTANTIAL_FILE_WORK_MINIMUM_SLEEP_TIME )
def _WorkOnFiles( self ):
@ -1248,19 +1243,30 @@ class URLsImport( HydrusSerialisable.SerialisableBase ):
self._SerialisableChangeMade()
def AbortImport( self ):
def AbortImport( self, do_delete = False ):
if self.CurrentlyWorking():
if do_delete:
self.PausePlay()
self._file_seed_cache.RemoveFileSeedsByStatus( ( CC.STATUS_UNKNOWN, ) )
else:
file_seeds = self._file_seed_cache.GetFileSeeds( CC.STATUS_UNKNOWN )
for file_seed in file_seeds:
file_seed.SetStatus( CC.STATUS_SKIPPED, note = 'import abandoned by user' )
self._file_seed_cache.NotifyFileSeedsUpdated( file_seeds )
self._EmptyFileSeedCache()
self._paused = False
with self._lock:
self._files_status = 'aborted'
self._SerialisableChangeMade()
def PendURLs( self, urls, filterable_tags = None, additional_service_keys_to_tags = None ):

View File

@ -5,6 +5,7 @@ from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusText
from hydrus.core import HydrusData
from hydrus.core import HydrusGlobals as HG
from hydrus.core import HydrusSerialisable
from hydrus.client import ClientConstants as CC
from hydrus.client import ClientThreading
@ -39,9 +40,15 @@ file_filter_str_lookup = {
quick_inverse_lookups = {}
class FileFilter( object ):
class FileFilter( HydrusSerialisable.SerialisableBase ):
def __init__( self, filter_type, filter_data = None ):
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_FILE_FILTER
SERIALISABLE_NAME = 'File Filter'
SERIALISABLE_VERSION = 1
def __init__( self, filter_type = None, filter_data = None ):
HydrusSerialisable.SerialisableBase.__init__( self )
self.filter_type = filter_type
self.filter_data = filter_data
@ -69,6 +76,54 @@ class FileFilter( object ):
def _GetSerialisableInfo( self ):
if self.filter_type == FILE_FILTER_FILE_SERVICE:
file_service_key = self.filter_data
serialisable_filter_data = file_service_key.hex()
elif self.filter_type == FILE_FILTER_TAGS:
( tag_service_key, and_or_or, select_tags ) = self.filter_data
serialisable_filter_data = ( tag_service_key.hex(), and_or_or, select_tags )
else:
serialisable_filter_data = self.filter_data
return ( self.filter_type, serialisable_filter_data )
def _InitialiseFromSerialisableInfo( self, serialisable_info ):
( self.filter_type, serialisable_filter_data ) = serialisable_info
if self.filter_type == FILE_FILTER_FILE_SERVICE:
serialisable_file_service_key = serialisable_filter_data
file_service_key = bytes.fromhex( serialisable_file_service_key )
self.filter_data = file_service_key
elif self.filter_type == FILE_FILTER_TAGS:
( serialisable_tag_service_key, and_or_or, select_tags ) = serialisable_filter_data
tag_service_key = bytes.fromhex( serialisable_tag_service_key )
self.filter_data = ( tag_service_key, and_or_or, select_tags )
else:
self.filter_data = serialisable_filter_data
def GetMediaListFileCount( self, media_list: ClientMedia.MediaList ):
if self.filter_type == FILE_FILTER_ALL:
@ -324,7 +379,7 @@ class FileFilter( object ):
return filter_counts[ self ]
def ToString( self, media_list: ClientMedia.MediaList, filter_counts: dict ):
def ToString( self ):
if self.filter_type == FILE_FILTER_FILE_SERVICE:
@ -356,6 +411,13 @@ class FileFilter( object ):
s = file_filter_str_lookup[ self.filter_type ]
return s
def ToStringWithCount( self, media_list: ClientMedia.MediaList, filter_counts: dict ):
s = self.ToString()
self.PopulateFilterCounts( media_list, filter_counts )
my_count = filter_counts[ self ]
@ -391,6 +453,8 @@ class FileFilter( object ):
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_FILE_FILTER ] = FileFilter
quick_inverse_lookups.update( {
FileFilter( FILE_FILTER_INBOX ) : FileFilter( FILE_FILTER_ARCHIVE ),
FileFilter( FILE_FILTER_ARCHIVE ) : FileFilter( FILE_FILTER_INBOX ),

View File

@ -1114,9 +1114,10 @@ class LocationsManager( object ):
if service_type == HC.IPFS:
(file_info_manager, multihash) = row
( file_info_manager, multihash ) = row
self._service_keys_to_filenames[ service_key ] = multihash
self._service_keys_to_filenames[service_key] = multihash
elif action == HC.CONTENT_UPDATE_DELETE:

View File

@ -92,9 +92,22 @@ def Dumps( data, mime ):
return cbor2.dumps( data )
else:
if isinstance( data, dict ):
if 'version' not in data:
data[ 'version' ] = HC.CLIENT_API_VERSION
if 'hydrus_version' not in data:
data[ 'hydrus_version' ] = HC.SOFTWARE_VERSION
return json.dumps( data )
@ -1665,6 +1678,7 @@ class HydrusResourceClientAPIRestrictedAddFiles( HydrusResourceClientAPIRestrict
request.client_api_permissions.CheckPermission( ClientAPI.CLIENT_API_PERMISSION_ADD_FILES )
class HydrusResourceClientAPIRestrictedAddFilesAddFile( HydrusResourceClientAPIRestrictedAddFiles ):
def _threadDoPOSTJob( self, request: HydrusServerRequest.HydrusRequest ):
@ -2668,6 +2682,7 @@ class HydrusResourceClientAPIRestrictedGetFiles( HydrusResourceClientAPIRestrict
request.client_api_permissions.CheckPermission( ClientAPI.CLIENT_API_PERMISSION_SEARCH_FILES )
class HydrusResourceClientAPIRestrictedGetFilesSearchFiles( HydrusResourceClientAPIRestrictedGetFiles ):
def _threadDoGETJob( self, request: HydrusServerRequest.HydrusRequest ):

View File

@ -11,6 +11,14 @@ def ExtractSingleFileFromZip( path_to_zip, filename_to_extract, extract_into_fil
with open( extract_into_file_path, "wb" ) as writer:
writer.write( reader.read() )
def GetSingleFileFromZipBytes( path_to_zip, path_in_zip ):
return GetZipAsPath( path_to_zip, path_in_zip = path_in_zip ).read_bytes()
def GetZipAsPath( path_to_zip, path_in_zip="" ):

View File

@ -103,8 +103,8 @@ options = {}
# Misc
NETWORK_VERSION = 20
SOFTWARE_VERSION = 547
CLIENT_API_VERSION = 53
SOFTWARE_VERSION = 548
CLIENT_API_VERSION = 54
SERVER_THUMBNAIL_DIMENSIONS = ( 200, 200 )

View File

@ -114,13 +114,14 @@ def GenerateThumbnailNumPy( path, target_resolution, mime, duration, num_frames,
try:
thumbnail_numpy = HydrusKritaHandling.GenerateThumbnailNumPyFromKraPath( path, target_resolution, clip_rect = clip_rect )
except Exception as e:
if not isinstance( e, HydrusExceptions.NoThumbnailFileException ):
HydrusData.Print( 'Problem generating thumbnail for "{}":'.format( path ) )
HydrusData.PrintException( e )
thumb_path = os.path.join( HC.STATIC_DIR, 'krita.png' )

View File

@ -1,3 +1,4 @@
import io
import typing
from hydrus.core import HydrusArchiveHandling
@ -7,51 +8,53 @@ from hydrus.core.images import HydrusImageHandling
from PIL import Image as PILImage
import xml.etree.ElementTree as ET
KRITA_FILE_THUMB = "preview.png"
KRITA_FILE_MERGED = "mergedimage.png"
def MergedPILImageFromKra(path):
def MergedPILImageFromKra( path ):
try:
file_obj = HydrusArchiveHandling.GetZipAsPath( path, KRITA_FILE_MERGED ).open('rb')
return HydrusImageHandling.GeneratePILImage( file_obj )
zip_path_file_obj = HydrusArchiveHandling.GetZipAsPath( path, KRITA_FILE_MERGED ).open( 'rb' )
return HydrusImageHandling.GeneratePILImage( zip_path_file_obj )
except FileNotFoundError:
raise HydrusExceptions.UnsupportedFileException( f'Could not read {KRITA_FILE_MERGED} from this Krita file' )
def ThumbnailPILImageFromKra(path):
try:
file_obj = HydrusArchiveHandling.GetZipAsPath( path, KRITA_FILE_THUMB ).open('rb')
return HydrusImageHandling.GeneratePILImage( file_obj )
zip_path_file_obj = HydrusArchiveHandling.GetZipAsPath( path, KRITA_FILE_THUMB ).open( 'rb' )
return HydrusImageHandling.GeneratePILImage( zip_path_file_obj )
except FileNotFoundError:
raise HydrusExceptions.NoThumbnailFileException( f'Could not read {KRITA_FILE_THUMB} from this Krita file' )
def GenerateThumbnailNumPyFromKraPath( path: str, target_resolution: typing.Tuple[int, int], clip_rect = None ) -> bytes:
try:
pil_image = MergedPILImageFromKra( path )
except:
pil_image = ThumbnailPILImageFromKra( path )
if clip_rect is not None:
pil_image = HydrusImageHandling.ClipPILImage( pil_image, clip_rect )
thumbnail_pil_image = pil_image.resize( target_resolution, PILImage.LANCZOS )
numpy_image = HydrusImageHandling.GenerateNumPyImageFromPILImage( thumbnail_pil_image )
@ -63,21 +66,23 @@ def GenerateThumbnailNumPyFromKraPath( path: str, target_resolution: typing.Tupl
def GetKraProperties( path ):
DOCUMENT_INFO_FILE = "maindoc.xml"
try:
data_file = HydrusArchiveHandling.GetZipAsPath( path, DOCUMENT_INFO_FILE ).open('rb')
root = ET.parse(data_file)
image_tag = root.find('{http://www.calligra.org/DTD/krita}IMAGE')
width = int(image_tag.attrib['width'])
height = int(image_tag.attrib['height'])
data_file = HydrusArchiveHandling.GetZipAsPath( path, DOCUMENT_INFO_FILE ).open( 'rb' )
root = ET.parse( data_file )
image_tag = root.find( '{http://www.calligra.org/DTD/krita}IMAGE' )
width = int( image_tag.attrib[ 'width' ] )
height = int( image_tag.attrib[ 'height' ] )
return ( width, height )
except:
raise HydrusExceptions.NoResolutionFileException( f'This krita file had no {DOCUMENT_INFO_FILE} or it contains no resolution!' )

View File

@ -32,7 +32,7 @@ def GetProcreatePlist( path ):
with HydrusArchiveHandling.GetZipAsPath( path, PROCREATE_DOCUMENT_ARCHIVE ).open('rb') as document:
return plistlib.load(document)
return plistlib.load( document )

View File

@ -141,6 +141,7 @@ SERIALISABLE_TYPE_METADATA_SINGLE_FILE_EXPORTER_MEDIA_TIMESTAMPS = 122
SERIALISABLE_TYPE_METADATA_SINGLE_FILE_IMPORTER_MEDIA_TIMESTAMPS = 123
SERIALISABLE_TYPE_PETITION_HEADER = 124
SERIALISABLE_TYPE_STRING_JOINER = 125
SERIALISABLE_TYPE_FILE_FILTER = 126
SERIALISABLE_TYPES_TO_OBJECT_TYPES = {}

View File

@ -437,39 +437,6 @@ class TagFilter( HydrusSerialisable.SerialisableBase ):
def _TagOK( self, tag, apply_unnamespaced_rules_to_namespaced_tags = False ):
# old method, has a bunch of overhead due to iteration
'''
blacklist_encountered = False
for tag_slice in self._IterateTagSlices( tag, apply_unnamespaced_rules_to_namespaced_tags = apply_unnamespaced_rules_to_namespaced_tags ):
if tag_slice in self._tag_slices_to_rules:
rule = self._tag_slices_to_rules[ tag_slice ]
if rule == HC.FILTER_WHITELIST:
return True # there is an exception for this class of tag
elif rule == HC.FILTER_BLACKLIST: # there is a rule against this class of tag
blacklist_encountered = True
if blacklist_encountered: # rule against and no exceptions
return False
else:
return True # no rules against or explicitly for, so permitted
'''
#
# since this is called a whole bunch and overhead piles up, we are now splaying the logic out to hardcoded tests
blacklist_encountered = False

View File

@ -125,6 +125,13 @@ def SetEnvTempDir( path ):
tempfile.tempdir = path
def GetSubTempDir( prefix = '' ):
global HYDRUS_TEMP_DIR
return tempfile.mkdtemp( prefix = prefix, dir = HYDRUS_TEMP_DIR )
def GetTempPath( suffix = '', dir = None ):
global HYDRUS_TEMP_DIR

View File

@ -147,14 +147,16 @@ def GenerateNumPyImage( path, mime, force_pil = False ) -> numpy.array:
if mime == HC.APPLICATION_KRITA:
if HG.media_load_report_mode:
HydrusData.ShowText( 'Loading KRA' )
pil_image = HydrusKritaHandling.MergedPILImageFromKra( path )
return GenerateNumPyImageFromPILImage( pil_image )
if mime in PIL_ONLY_MIMETYPES:
@ -280,7 +282,7 @@ def GenerateNumPyImageFromPILImage( pil_image: PILImage.Image ) -> numpy.array:
'''
def GeneratePILImage( path, dequantize = True ) -> PILImage.Image:
def GeneratePILImage( path: typing.Union[ str, typing.BinaryIO ], dequantize = True ) -> PILImage.Image:
pil_image = HydrusImageOpening.RawOpenPILImage( path )

View File

@ -1,8 +1,9 @@
import typing
from PIL import Image as PILImage
from hydrus.core import HydrusExceptions
def RawOpenPILImage( path ) -> PILImage.Image:
def RawOpenPILImage( path: typing.Union[ str, typing.BinaryIO ] ) -> PILImage.Image:
try:

View File

@ -605,14 +605,15 @@ class HydrusResource( Resource ):
content_disposition_type = 'inline'
max_age = response_context.GetMaxAge()
if max_age is not None:
request.setHeader( 'Expires', time.strftime( '%a, %d %b %Y %H:%M:%S GMT', time.gmtime( time.time() + max_age ) ) )
request.setHeader( 'Cache-Control', 'max-age={}'.format( max_age ) )
if response_context.HasPath():
path = response_context.GetPath()
@ -889,7 +890,9 @@ class HydrusResource( Resource ):
body_dict = {
'error' : error_summary,
'exception_type' : str( type( e ).__name__ ),
'status_code' : status_code
'status_code' : status_code,
'version' : HC.CLIENT_API_VERSION,
'hydrus_version' : HC.SOFTWARE_VERSION
}
body = json.dumps( body_dict )

View File

@ -44,6 +44,15 @@ try:
except:
pass
def wash_example_json_response( obj ):
if isinstance( obj, dict ):
obj[ 'version' ] = HC.CLIENT_API_VERSION
obj[ 'hydrus_version' ] = HC.SOFTWARE_VERSION
def GetExampleServicesDict():
services_dict = {
@ -211,13 +220,17 @@ class TestClientAPI( unittest.TestCase ):
url = 'http://safebooru.org/index.php?page=post&s=view&id=2753608'
normalised_url = 'https://safebooru.org/index.php?id=2753608&page=post&s=view'
expected_answer = {}
expected_result = {}
expected_answer[ 'normalised_url' ] = normalised_url
expected_answer[ 'url_type' ] = HC.URL_TYPE_POST
expected_answer[ 'url_type_string' ] = 'post url'
expected_answer[ 'match_name' ] = 'safebooru file page'
expected_answer[ 'can_parse' ] = True
expected_result[ 'normalised_url' ] = normalised_url
expected_result[ 'url_type' ] = HC.URL_TYPE_POST
expected_result[ 'url_type_string' ] = 'post url'
expected_result[ 'match_name' ] = 'safebooru file page'
expected_result[ 'can_parse' ] = True
cbor_expected_result = dict( expected_result )
wash_example_json_response( expected_result )
hash = os.urandom( 32 )
@ -238,7 +251,7 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
self.assertEqual( d, expected_answer )
self.assertEqual( d, expected_result )
# explicit GET cbor by arg
@ -255,7 +268,7 @@ class TestClientAPI( unittest.TestCase ):
d = cbor2.loads( data )
self.assertEqual( d, expected_answer )
self.assertEqual( d, cbor_expected_result )
# explicit GET json by Accept
@ -274,7 +287,7 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
self.assertEqual( d, expected_answer )
self.assertEqual( d, expected_result )
# explicit GET cbor by Accept
@ -291,7 +304,7 @@ class TestClientAPI( unittest.TestCase ):
d = cbor2.loads( data )
self.assertEqual( d, expected_answer )
self.assertEqual( d, cbor_expected_result )
def _test_client_api_basics( self, connection ):
@ -722,7 +735,7 @@ class TestClientAPI( unittest.TestCase ):
should_work = { set_up_permissions[ 'everything' ], set_up_permissions[ 'add_files' ], set_up_permissions[ 'add_tags' ], set_up_permissions[ 'manage_pages' ], set_up_permissions[ 'search_all_files' ], set_up_permissions[ 'search_green_files' ] }
should_break = { set_up_permissions[ 'add_urls' ], set_up_permissions[ 'manage_headers' ] }
expected_answer = {
expected_result = {
'local_tags' : [
{
'name' : 'my tags',
@ -811,6 +824,8 @@ class TestClientAPI( unittest.TestCase ):
'services' : GetExampleServicesDict()
}
wash_example_json_response( expected_result )
get_service_expected_result = {
'service' : {
'name' : 'repository updates',
@ -820,6 +835,8 @@ class TestClientAPI( unittest.TestCase ):
}
}
wash_example_json_response( get_service_expected_result )
for api_permissions in should_work.union( should_break ):
access_key_hex = api_permissions.GetAccessKey().hex()
@ -844,7 +861,7 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
self.assertEqual( d, expected_answer )
self.assertEqual( d, expected_result )
else:
@ -979,6 +996,8 @@ class TestClientAPI( unittest.TestCase ):
expected_result = { 'status' : CC.STATUS_SUCCESSFUL_AND_NEW, 'hash' : hash.hex() , 'note' : 'test note' }
wash_example_json_response( expected_result )
self.assertEqual( response_json, expected_result )
# do hydrus png as path
@ -1012,6 +1031,8 @@ class TestClientAPI( unittest.TestCase ):
expected_result = { 'status' : CC.STATUS_SUCCESSFUL_AND_NEW, 'hash' : hash.hex() , 'note' : 'test note' }
wash_example_json_response( expected_result )
self.assertEqual( response_json, expected_result )
@ -1975,15 +1996,17 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = {}
expected_result = {}
clean_tags = [ "bikini", "blue eyes", "character:samus aran", "::)", "10", "11", "9", "wew", "flower" ]
clean_tags = HydrusTags.SortNumericTags( clean_tags )
expected_answer[ 'tags' ] = clean_tags
expected_result[ 'tags' ] = clean_tags
self.assertEqual( d, expected_answer )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
# add tags
@ -2274,7 +2297,7 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = {
expected_result = {
'services' : GetExampleServicesDict(),
'tags' : {}
}
@ -2293,10 +2316,12 @@ class TestClientAPI( unittest.TestCase ):
}
expected_answer[ 'tags' ][ tag ] = tag_dict
expected_result[ 'tags' ][ tag ] = tag_dict
self.assertEqual( expected_answer, d )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
def _test_add_tags_search_tags( self, connection, set_up_permissions ):
@ -2332,7 +2357,7 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = {
expected_result = {
'tags' : [
{
'value' : 'green',
@ -2341,7 +2366,9 @@ class TestClientAPI( unittest.TestCase ):
]
}
self.assertEqual( expected_answer, d )
wash_example_json_response( expected_result )
self.assertEqual( expected_result, d )
#
@ -2367,11 +2394,13 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = {
expected_result = {
'tags' : []
}
self.assertEqual( expected_answer, d )
wash_example_json_response( expected_result )
self.assertEqual( expected_result, d )
( args, kwargs ) = HG.test_controller.GetRead( 'autocomplete_predicates' )[-1]
@ -2394,7 +2423,7 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
# note this also tests sort
expected_answer = {
expected_result = {
'tags' : [
{
'value' : 'green car',
@ -2407,7 +2436,9 @@ class TestClientAPI( unittest.TestCase ):
]
}
self.assertEqual( expected_answer, d )
wash_example_json_response( expected_result )
self.assertEqual( expected_result, d )
( args, kwargs ) = HG.test_controller.GetRead( 'autocomplete_predicates' )[-1]
@ -2430,7 +2461,7 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
# note this also tests sort
expected_answer = {
expected_result = {
'tags' : [
{
'value' : 'green car',
@ -2443,7 +2474,9 @@ class TestClientAPI( unittest.TestCase ):
]
}
self.assertEqual( expected_answer, d )
wash_example_json_response( expected_result )
self.assertEqual( expected_result, d )
( args, kwargs ) = HG.test_controller.GetRead( 'autocomplete_predicates' )[-1]
@ -2467,11 +2500,13 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
# note this also tests sort
expected_answer = {
expected_result = {
'tags' : []
}
self.assertEqual( expected_answer, d )
wash_example_json_response( expected_result )
self.assertEqual( expected_result, d )
def _test_add_urls( self, connection, set_up_permissions ):
@ -2504,12 +2539,14 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = {}
expected_result = {}
expected_answer[ 'normalised_url' ] = url
expected_answer[ 'url_file_statuses' ] = []
expected_result[ 'normalised_url' ] = url
expected_result[ 'url_file_statuses' ] = []
self.assertEqual( d, expected_answer )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
# some
@ -2537,12 +2574,14 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = {}
expected_result = {}
expected_answer[ 'normalised_url' ] = normalised_url
expected_answer[ 'url_file_statuses' ] = json_url_file_statuses
expected_result[ 'normalised_url' ] = normalised_url
expected_result[ 'url_file_statuses' ] = json_url_file_statuses
self.assertEqual( d, expected_answer )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
# get url info
@ -2570,16 +2609,18 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = {}
expected_result = {}
expected_answer[ 'normalised_url' ] = url
expected_answer[ 'url_type' ] = HC.URL_TYPE_UNKNOWN
expected_answer[ 'url_type_string' ] = 'unknown url'
expected_answer[ 'match_name' ] = 'unknown url'
expected_answer[ 'can_parse' ] = False
expected_answer[ 'cannot_parse_reason' ] = 'unknown url class'
expected_result[ 'normalised_url' ] = url
expected_result[ 'url_type' ] = HC.URL_TYPE_UNKNOWN
expected_result[ 'url_type_string' ] = 'unknown url'
expected_result[ 'match_name' ] = 'unknown url'
expected_result[ 'can_parse' ] = False
expected_result[ 'cannot_parse_reason' ] = 'unknown url class'
self.assertEqual( d, expected_answer )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
# known
@ -2601,15 +2642,17 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = {}
expected_result = {}
expected_answer[ 'normalised_url' ] = normalised_url
expected_answer[ 'url_type' ] = HC.URL_TYPE_WATCHABLE
expected_answer[ 'url_type_string' ] = 'watchable url'
expected_answer[ 'match_name' ] = '8chan thread'
expected_answer[ 'can_parse' ] = True
expected_result[ 'normalised_url' ] = normalised_url
expected_result[ 'url_type' ] = HC.URL_TYPE_WATCHABLE
expected_result[ 'url_type_string' ] = 'watchable url'
expected_result[ 'match_name' ] = '8chan thread'
expected_result[ 'can_parse' ] = True
self.assertEqual( d, expected_answer )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
# known post url
@ -2632,15 +2675,17 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = {}
expected_result = {}
expected_answer[ 'normalised_url' ] = normalised_url
expected_answer[ 'url_type' ] = HC.URL_TYPE_POST
expected_answer[ 'url_type_string' ] = 'post url'
expected_answer[ 'match_name' ] = 'safebooru file page'
expected_answer[ 'can_parse' ] = True
expected_result[ 'normalised_url' ] = normalised_url
expected_result[ 'url_type' ] = HC.URL_TYPE_POST
expected_result[ 'url_type_string' ] = 'post url'
expected_result[ 'match_name' ] = 'safebooru file page'
expected_result[ 'can_parse' ] = True
self.assertEqual( d, expected_answer )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
# add url
@ -3124,6 +3169,8 @@ class TestClientAPI( unittest.TestCase ):
}
}
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
#
@ -3179,6 +3226,8 @@ class TestClientAPI( unittest.TestCase ):
}
}
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
#
@ -3234,6 +3283,8 @@ class TestClientAPI( unittest.TestCase ):
}
}
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
#
@ -3264,6 +3315,8 @@ class TestClientAPI( unittest.TestCase ):
'headers' : {}
}
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
#
@ -3310,6 +3363,8 @@ class TestClientAPI( unittest.TestCase ):
}
}
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
#
@ -3356,6 +3411,8 @@ class TestClientAPI( unittest.TestCase ):
}
}
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
#
@ -3400,6 +3457,8 @@ class TestClientAPI( unittest.TestCase ):
'headers' : {}
}
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
@ -4077,9 +4136,11 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = { 'file_ids' : list( sample_hash_ids ) }
expected_result = { 'file_ids' : list( sample_hash_ids ) }
self.assertEqual( d, expected_answer )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
[ ( args, kwargs ) ] = HG.test_controller.GetRead( 'file_query_ids' )
@ -4633,13 +4694,15 @@ class TestClientAPI( unittest.TestCase ):
d = json.loads( text )
expected_answer = {
expected_result = {
'hashes' : {
md5_hash.hex() : sha256_hash.hex()
}
}
self.assertEqual( d, expected_answer )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
def _test_file_metadata( self, connection, set_up_permissions ):
@ -4670,6 +4733,8 @@ class TestClientAPI( unittest.TestCase ):
expected_identifier_result = { 'metadata' : metadata, 'services' : GetExampleServicesDict() }
wash_example_json_response( expected_identifier_result )
media_results = []
file_info_managers = []
@ -4945,6 +5010,12 @@ class TestClientAPI( unittest.TestCase ):
expected_only_return_basic_information_result = { 'metadata' : only_return_basic_information_metadata, 'services' : GetExampleServicesDict() }
expected_only_return_basic_information_but_blurhash_too_result = { 'metadata' : only_return_basic_information_metadata_but_blurhash_too, 'services' : GetExampleServicesDict() }
wash_example_json_response( expected_metadata_result )
wash_example_json_response( expected_detailed_known_urls_metadata_result )
wash_example_json_response( expected_notes_metadata_result )
wash_example_json_response( expected_only_return_basic_information_result )
wash_example_json_response( expected_only_return_basic_information_but_blurhash_too_result )
HG.test_controller.SetRead( 'hash_ids_to_hashes', file_ids_to_hashes )
HG.test_controller.SetRead( 'media_results', media_results )
HG.test_controller.SetRead( 'media_results_from_ids', media_results )
@ -5063,6 +5134,8 @@ class TestClientAPI( unittest.TestCase ):
expected_result[ 'metadata' ].sort( key = lambda basic: expected_order.index( basic[ 'file_id' ] ) )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
# metadata from file_ids
@ -5155,6 +5228,8 @@ class TestClientAPI( unittest.TestCase ):
expected_result[ 'metadata' ].sort( key = lambda basic: expected_order.index( basic[ 'file_id' ] ) )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
for ( row_a, row_b ) in zip( d[ 'metadata' ], expected_result[ 'metadata' ] ):
@ -5215,6 +5290,8 @@ class TestClientAPI( unittest.TestCase ):
expected_result[ 'metadata' ].sort( key = lambda basic: expected_order.index( basic[ 'file_id' ] ) )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
# basic metadata from hashes
@ -5257,6 +5334,8 @@ class TestClientAPI( unittest.TestCase ):
expected_result[ 'metadata' ].sort( key = lambda basic: expected_order.index( basic[ 'file_id' ] ) )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
# metadata from hashes
@ -5297,6 +5376,8 @@ class TestClientAPI( unittest.TestCase ):
expected_result[ 'metadata' ].sort( key = lambda basic: expected_order.index( basic[ 'file_id' ] ) )
wash_example_json_response( expected_result )
self.assertEqual( d, expected_result )
# fails on borked hashes
@ -5394,6 +5475,8 @@ class TestClientAPI( unittest.TestCase ):
expected_result[ 'metadata' ].sort( key = lambda m_dict: hashes_in_test.index( bytes.fromhex( m_dict[ 'hash' ] ) ) )
wash_example_json_response( expected_result )
path = '/get_files/file_metadata?hashes={}&include_services_object=false'.format( urllib.parse.quote( json.dumps( [ hash.hex() for hash in hashes_in_test ] ) ) )
connection.request( 'GET', path, headers = headers )