diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e8617152..f3198697 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -110,22 +110,22 @@ jobs: - name: Remove Chonk run: | - find dist/client/ -type f -name "*.pyc" -delete - while read line; do find dist/client/ -type f -name "${line}" -delete ; done < hydrus/static/build_files/linux/files_to_delete.txt + find dist/hydrus_client/ -type f -name "*.pyc" -delete + while read line; do find dist/hydrus_client/ -type f -name "${line}" -delete ; done < hydrus/static/build_files/linux/files_to_delete.txt - name: Remove Surplus File run: | - rm -f dist/client/libxkbcommon.so* + rm -f dist/hydrus_client/libxkbcommon.so* - name: Set Permissions run: | sudo chown --recursive 1000:1000 dist/client - sudo find dist/client -type d -exec chmod 0755 {} \; - sudo chmod +x dist/client/client dist/client/server dist/client/bin/swfrender_linux + sudo find dist/hydrus_client -type d -exec chmod 0755 {} \; + sudo chmod +x dist/hydrus_client/client dist/hydrus_client/server dist/hydrus_client/bin/swfrender_linux - name: Compress Client run: | - mv dist/client "dist/Hydrus Network" + mv dist/hydrus_client "dist/Hydrus Network" tar -czvf Ubuntu-Extract.tar.gz -C dist "Hydrus Network" - name: Upload a Build Artifact @@ -187,10 +187,13 @@ jobs: run: | move hydrus\static\build_files\windows\sqlite3.dll hydrus\ move hydrus\static\build_files\windows\sqlite3.exe hydrus\db + move hydrus\static\build_files\windows\file_version_info_maker.py file_version_info_maker.py + python file_version_info_maker.py ${{ github.ref_name }} move hydrus\static\build_files\windows\client-win.spec client-win.spec move hydrus\static\build_files\windows\server-win.spec server-win.spec pyinstaller server-win.spec pyinstaller client-win.spec + move hydrus_client "Hydrus Network" dir -r - # yo pretty sure we'll need to install this manually once we are on windows server 2022 diff --git a/.gitignore b/.gitignore index 89709190..3be7ee7e 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,9 @@ venv.bak/ /client-user.bat /client-user.sh /client-user.command +/hydrus_client-user.bat +/hydrus_client-user.sh +/hydrus_client-user.command # docs builds /site/ diff --git a/db/help my db is broke.txt b/db/help my db is broke.txt index c317bbfb..8344b00f 100644 --- a/db/help my db is broke.txt +++ b/db/help my db is broke.txt @@ -22,7 +22,7 @@ For a small database, this whole repair process may take an hour. For a larger, Close the client immediately. -If you are on Windows, open task manager (Ctrl+Shift+Esc) and wait for client.exe to disappear from the list. If it takes more than a couple of minutes, forcibly close it with task manager. +If you are on Windows, open task manager (Ctrl+Shift+Esc) and wait for hydrus_client.exe to disappear from the list. If it takes more than a couple of minutes, forcibly close it with task manager. *** check integrity *** diff --git a/db/help my db is not booting.txt b/db/help my db is not booting.txt index 67b9220d..c7340652 100644 --- a/db/help my db is not booting.txt +++ b/db/help my db is not booting.txt @@ -2,8 +2,8 @@ If your client seems to hang on the database startup phase, especially after a p So, if your client seems suddenly to take a very long time to start up, just sitting on the splash screen, go make a coffee and give it time--it is probably just sorting itself out, not broken. -You can double-check this by looking at the client executable in your OS's Task Manager (Ctrl+Shift+Esc on Windows). If it is doing some CPU/HDD, there is no need to kill the process. +You can double-check this by looking at the hydrus_client executable in your OS's Task Manager (Ctrl+Shift+Esc on Windows). If it is doing some CPU/HDD, there is no need to kill the process. Please contact hydrus_dev if it really does seem stuck (say, no progress after an hour, or if CPU/HDD activity completely drops to nothing for several minutes), or if every startup is delayed like this. -One possible cause of delayed startup every time (usually a delay _before_ the splash screen appears) is overly paranoid virus scanners rechecking all of hydrus every time it starts. To relieve this, please check your anti-virus software's options and make sure, if you have an HDD, that your disk is defragged. \ No newline at end of file +One possible cause of delayed startup every time (usually a delay _before_ the splash screen appears) is overly paranoid virus scanners rechecking all of hydrus every time it starts. To relieve this, please check your anti-virus software's options and make sure, if you have an HDD, that your disk is defragged. diff --git a/docs/database_migration.md b/docs/database_migration.md index 8dae79c6..095f6dbc 100644 --- a/docs/database_migration.md +++ b/docs/database_migration.md @@ -10,7 +10,7 @@ A hydrus client consists of three components: 1. **the software installation** - This is the part that comes with the installer or extract release, with the executable and dlls and a handful of resource folders. It doesn't store any of your settings--it just knows how to present a database as a nice application. If you just run the client executable straight, it looks in its 'db' subdirectory for a database, and if one is not found, it creates a new one. If it sees a database running at a lower version than itself, it will update the database before booting it. + This is the part that comes with the installer or extract release, with the executable and dlls and a handful of resource folders. It doesn't store any of your settings--it just knows how to present a database as a nice application. If you just run the hydrus_client executable straight, it looks in its 'db' subdirectory for a database, and if one is not found, it creates a new one. If it sees a database running at a lower version than itself, it will update the database before booting it. It doesn't really matter where you put this. An SSD will load it marginally quicker the first time, but you probably won't notice. If you run it without command-line parameters, it will try to write to its own directory (to create the initial database), so if you mean to run it like that, it should not be in a protected place like _Program Files_. @@ -58,13 +58,13 @@ If you decide to move your actual database, the program will have to shut down f ## informing the software that the database is not in the default location { id="launch_parameter" } -A straight call to the client executable will look for a database in _install_dir/db_. If one is not found, it will create one. So, if you move your database and then try to run the client again, it will try to create a new empty database in the previous location! +A straight call to the hydrus_client executable will look for a database in _install_dir/db_. If one is not found, it will create one. So, if you move your database and then try to run the client again, it will try to create a new empty database in the previous location! So, pass it a -d or --db_dir command line argument, like so: -* `client -d="D:\media\my_hydrus_database"` +* `hydrus_client -d="D:\media\my_hydrus_database"` * _--or--_ -* `client --db_dir="G:\misc documents\New Folder (3)\DO NOT ENTER"` +* `hydrus_client --db_dir="G:\misc documents\New Folder (3)\DO NOT ENTER"` * _--or, for macOS--_ * `open -n -a "Hydrus Network.app" --args -d="/path/to/db"` @@ -102,7 +102,7 @@ Specifically: * Hit 'move files now' again to make this happen. This should be fast since it is just moving a bunch of folders across the same partition. * With everything now 'non-portable' and hence decoupled from the db, you can now easily migrate the install and db to 'hydrus_db' simply by shutting the client down and moving the install folder in a file explorer. -* Update your shortcut to the new client.exe location and try to boot. +* Update your shortcut to the new hydrus_client.exe location and try to boot. * Update your backup scheme to match your new locations. * Enjoy a much faster client. @@ -113,4 +113,4 @@ You should now have _something_ like this: ## p.s. running multiple clients { id="multiple_clients" } -Since you now know how to tell the software about an external database, you can, if you like, run multiple clients from the same install (and if you previously had multiple install folders, now you can now just use the one). Just make multiple shortcuts to the same client executable but with different database directories. They can run at the same time. You'll save yourself a little memory and update-hassle. I do this on my laptop client to run a regular client for my media and a separate 'admin' client to do PTR petitions and so on. +Since you now know how to tell the software about an external database, you can, if you like, run multiple clients from the same install (and if you previously had multiple install folders, now you can now just use the one). Just make multiple shortcuts to the same hydrus_client executable but with different database directories. They can run at the same time. You'll save yourself a little memory and update-hassle. I do this on my laptop client to run a regular client for my media and a separate 'admin' client to do PTR petitions and so on. diff --git a/docs/getting_started_installing.md b/docs/getting_started_installing.md index b9b2bbc0..41fc94e9 100644 --- a/docs/getting_started_installing.md +++ b/docs/getting_started_installing.md @@ -84,7 +84,7 @@ Hydrus is made by an Anon out of duct tape and string. It combines file parsing Unfortunately, we have been hit by anti-virus false positives throughout development. Every few months, one or more of the larger anti-virus programs sees some code that looks like something bad, or they run the program in a testbed and don't like something it does, and then they quarantine it. Every single instance of this so far has been a false positive. They usually go away the next week or two when the next set of definitions roll out. Some hydrus users are kind enough to report the program as a false positive to the anti-virus companies themselves, which also helps here. -Some users have never had the problem, some get hit regularly. The situation is obviously worse on Windows. If you try to extract the zip and client.exe or the whole folder suddenly disappears, please check your anti-virus software. +Some users have never had the problem, some get hit regularly. The situation is obviously worse on Windows. If you try to extract the zip and hydrus_client.exe or the whole folder suddenly disappears, please check your anti-virus software. I am interested in reports about these false-positives, just so I know what is going on. Sometimes I have been able to reduce problems by changing something in the build (one of these was, no shit, an anti-virus testbed running the installer and then opening the help html at the end, which launched Edge browser, which then triggered Windows Update, which hit UAC and was considered suspicious. I took out the 'open help' checkbox from the installer as a result). @@ -103,7 +103,7 @@ To run the client: === "Windows" * For the installer, run the Start menu shortcut it added. - * For the extract, run 'client.exe' in the base directory, or make a shortcut to it. + * For the extract, run 'hydrus_client.exe' in the base directory, or make a shortcut to it. === "macOS" @@ -123,7 +123,17 @@ To run the client: Although I put out a new version every week, you can update far less often if you prefer. The client keeps to itself, so if it does exactly what you want and a new version does nothing you care about, you can just leave it. Other users enjoy updating every week, simply because it makes for a nice schedule. Others like to stay a week or two behind what is current, just in case I mess up and cause a temporary bug in something they like. -A user has written a longer and more formal guide to updating, and information on the 334->335 step [here](update_guide.rtf). +A user has written a longer and more formal guide to updating, and information on the 334->335 step (python2 to python3) [here](update_guide.rtf). + +??? note "The 526->527 step was also important." + 527 changed the program executable name from 'client' to 'hydrus_client'. There was also a library update that caused a dll conflict with previous installs. + + If you need to update from 526 or before, then: + + * If you use the Windows installer, install as normal. Your start menu 'hydrus client' shortcut should be overwritten with one to the new executable, but if you use a custom shortcut, you will need to update that too. + * If you use one of the normal extract builds, you will have to do a 'clean install', as below. You also need to update your program shortcuts. + * If you use the macOS app, there are no special instructions. Update as normal. + * If you run from source, `git pull` as normal. If you haven't already, feel free to run setup_venv again to get the new OpenCV. Update your launch scripts to point at the new `hydrus_client.py` boot scripts. The update process: diff --git a/docs/launch_arguments.md b/docs/launch_arguments.md index ad13659d..52e8e49a 100644 --- a/docs/launch_arguments.md +++ b/docs/launch_arguments.md @@ -7,16 +7,16 @@ title: Launch Arguments You can launch the program with several different arguments to alter core behaviour. If you are not familiar with this, you are essentially putting additional text after the launch command that runs the program. You can run this straight from a terminal console (usually good to test with), or you can bundle it into an easy shortcut that you only have to double-click. An example of a launch command with arguments: ``` -C:\Hydrus Network\client.exe -d="E:\hydrus db" --no_db_temp_files +C:\Hydrus Network\hydrus_client.exe -d="E:\hydrus db" --no_db_temp_files ``` You can also add --help to your program path, like this: -- `client.py --help` -- `server.exe --help` -- `./server --help` +- `hydrus_client.py --help` +- `hydrus_server.exe --help` +- `./hydrus_server --help` -Which gives you a full listing of all below arguments, however this will not work with the built client executables, which are bundled as a non-console programs and will not give you text output to any console they are launched from. As client.exe is the most commonly run version of the program, here is the list, with some more help about each command: +Which gives you a full listing of all below arguments, however this will not work with the built hydrus_client executables, which are bundled as a non-console programs and will not give you text output to any console they are launched from. As hydrus_client.exe is the most commonly run version of the program, here is the list, with some more help about each command: ##**`-d DB_DIR, --db_dir DB_DIR`** diff --git a/docs/running_from_source.md b/docs/running_from_source.md index bcd88d60..c6fbd9a8 100644 --- a/docs/running_from_source.md +++ b/docs/running_from_source.md @@ -39,7 +39,7 @@ There are now setup scripts that make this easy on Windows and Linux. You do not Then, get the hydrus source. The github repo is [https://github.com/hydrusnetwork/hydrus](https://github.com/hydrusnetwork/hydrus). If you are familiar with git, you can just clone the repo to the location you want with `git clone https://github.com/hydrusnetwork/hydrus`, but if not, then just go to the [latest release](https://github.com/hydrusnetwork/hydrus/releases/latest) and download and extract the source code .zip somewhere. Make sure the directory has write permissions (e.g. don't put it in "Program Files"). Extracting straight to a spare drive, something like "D:\Hydrus Network", is ideal. -We will call the base extract directory, the one with 'client.py' in it, `install_dir`. +We will call the base extract directory, the one with 'hydrus_client.py' in it, `install_dir`. !!! info "Mixed Builds" Don't mix and match build extracts and source extracts. The process that runs the code gets confused if there are unexpected extra .dlls in the directory. **If you need to convert between built and source releases, perform a [clean install](getting_started_installing.md#clean_installs).** @@ -222,7 +222,7 @@ _This is for advanced users only._ _If you have never used python before, do not try this. If the easy setup scripts failed for you and you don't know what happened, please contact hydev before trying this, as the thing that went wrong there will probably go much more wrong here._ -You can also set up the environment yourself. Inside the extract should be client.py and server.py. You will be treating these basically the same as the 'client' and 'server' executables--with the right environment, you should be able to launch them the same way and they take the same launch parameters as the exes. +You can also set up the environment yourself. Inside the extract should be hydrus_client.py and hydrus_server.py. You will be treating these basically the same as the 'client' and 'server' executables--with the right environment, you should be able to launch them the same way and they take the same launch parameters as the exes. Hydrus needs a whole bunch of libraries, so let's now set your python up. I **strongly** recommend you create a virtual environment. It is easy and doesn't mess up your system python. @@ -240,7 +240,7 @@ To create a new venv environment: !!! info "venvs" That `source venv/bin/activate` line turns on your venv. You should see your terminal prompt note you are now in it. A venv is an isolated environment of python that you can install modules to without worrying about breaking something system-wide. **Ideally, you do not want to install python modules to your system python.** - This activate line will be needed every time you alter your venv or run the `client.py`/`server.py` files. You can easily tuck this into a launch script--check the easy setup files for examples. + This activate line will be needed every time you alter your venv or run the `hydrus_client.py`/`hydrus_server.py` files. You can easily tuck this into a launch script--check the easy setup files for examples. On Windows Powershell, the command is `.\venv\Scripts\activate`, but you may find the whole deal is done much easier in cmd than Powershell. When in Powershell, just type `cmd` to get an old fashioned command line. In cmd, the launch command is just `venv\scripts\activate.bat`, no leading period. @@ -311,11 +311,11 @@ If you don't have FFMPEG in your PATH and you want to import anything more fun t ### Running It { id="running_it" } -Once you have everything set up, client.py and server.py should look for and run off client.db and server.db just like the executables. You can use the 'client.bat/sh/command' scripts in the install dir or use them as inspiration for your own. In any case, you are looking at entering something like this into the terminal: +Once you have everything set up, hydrus_client.py and hydrus_server.py should look for and run off client.db and server.db just like the executables. You can use the 'client.bat/sh/command' scripts in the install dir or use them as inspiration for your own. In any case, you are looking at entering something like this into the terminal: ``` source venv/bin/activate -python client.py +python hydrus_client.py ``` This will use the 'db' directory for your database by default, but you can use the [launch arguments](launch_arguments.md) just like for the executables. For example, this could be your client-user.sh file: @@ -324,7 +324,7 @@ This will use the 'db' directory for your database by default, but you can use t #!/bin/bash source venv/bin/activate -python client.py -d="/path/to/database" +python hydrus_client.py -d="/path/to/database" ``` ### Building these Docs diff --git a/docs/server.md b/docs/server.md index f82e574f..3a01c3cc 100644 --- a/docs/server.md +++ b/docs/server.md @@ -13,7 +13,7 @@ title: Running Your Own Server I will use two terms, _server_ and _service_, to mean two distinct things: -* A **server** is an instantiation of the hydrus server executable (e.g. server.exe in Windows). It has a complicated and flexible database that can run many different services in parallel. +* A **server** is an instantiation of the hydrus server executable (e.g. hydrus_server.exe in Windows). It has a complicated and flexible database that can run many different services in parallel. * A **service** sits on a port (e.g. 45871) and responds to certain http requests (e.g. `/file` or `/update`) that the hydrus client can plug into. A service might be a repository for a certain kind of data, the administration interface to manage what services run on a server, or anything else. Setting up a hydrus server is easy compared to, say, Apache. There are no .conf files to mess about with, and everything is controlled through the client. When started, the server will place an icon in your system tray in Windows or open a small frame in Linux or macOS. To close the server, either right-click the system tray icon and select exit, or just close the frame. @@ -31,7 +31,7 @@ Let's look at these steps in more detail: ## start the server { id="start" } -Since the server and client have so much common code, I package them together. If you have the client, you have the server. If you installed in Windows, you can hit the shortcut in your start menu. Otherwise, go straight to 'server' or 'server.exe' or 'server.pyw' in your installation directory. The program will first try to take port 45870 for its administration interface, so make sure that is free. Open your firewall as appropriate. +Since the server and client have so much common code, I package them together. If you have the client, you have the server. If you installed in Windows, you can hit the shortcut in your start menu. Otherwise, go straight to 'hydrus_server' or 'hydrus_server.exe' or 'hydrus_server.py' in your installation directory. The program will first try to take port 45870 for its administration interface, so make sure that is free. Open your firewall as appropriate. ## set up the client { id="setting_up_the_client" } diff --git a/docs/youDontWantTheServer.md b/docs/youDontWantTheServer.md index 841c96bf..10a55d84 100644 --- a/docs/youDontWantTheServer.md +++ b/docs/youDontWantTheServer.md @@ -3,7 +3,7 @@ title: You don't want the server --- # You don't want the server -The server.exe/server.py is the victim of many a misconception. You don't need to use the server to use Hydrus. The vast majority of features are contained in the client itself so if you're new to Hydrus, just use that. +The hydrus_server.exe/hydrus_server.py is the victim of many a misconception. You don't need to use the server to use Hydrus. The vast majority of features are contained in the client itself so if you're new to Hydrus, just use that. The server is only really useful for a few specific cases which will not apply for the vast majority of users. diff --git a/help my client will not boot.txt b/help my client will not boot.txt index 5b698ebb..bc7ddeb8 100644 --- a/help my client will not boot.txt +++ b/help my client will not boot.txt @@ -1,4 +1,4 @@ -If running the client executable does nothing or gives you an odd error before dumping out, here are some common fixes to try: +If running the hydrus_client executable does nothing or gives you an odd error before dumping out, here are some common fixes to try: 1. Look for a 'crash.log' in your 'db' directory or user desktop. Failing that, is there a 'client - [date].log' file? Does it have an error in it? If there is something, please send it in to me, hydrus_dev (see contact.html in the help directory for my contact details). @@ -12,4 +12,4 @@ Delete everything in your install directory except the 'db' directory. The 'db' 4. Check your permissions and hard drive health. For instance, sometimes when a hard drive has a fault, Windows sets it to 'dirty' mode, which causes all sorts of problems. Linux and OS X have presented their own permissions headaches. A default client works in 'portable' mode and needs read and write access to its 'db' folder. -5. Going forward, please consider making backups before you update the software. If a future update has a serious problem, it is then easy to rollback to the working version while we figure out a fix! \ No newline at end of file +5. Going forward, please consider making backups before you update the software. If a future update has a serious problem, it is then easy to rollback to the working version while we figure out a fix! diff --git a/hydrus/client/ClientConstants.py b/hydrus/client/ClientConstants.py index 0d88af1e..fae31b89 100644 --- a/hydrus/client/ClientConstants.py +++ b/hydrus/client/ClientConstants.py @@ -187,6 +187,7 @@ MEDIA_VIEWER_ACTION_SHOW_OPEN_EXTERNALLY_BUTTON = 4 MEDIA_VIEWER_ACTION_DO_NOT_SHOW_ON_ACTIVATION_OPEN_EXTERNALLY = 5 MEDIA_VIEWER_ACTION_DO_NOT_SHOW = 6 MEDIA_VIEWER_ACTION_SHOW_WITH_MPV = 7 +MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER = 8 media_viewer_action_string_lookup = { MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE : 'show with native hydrus viewer', @@ -196,13 +197,14 @@ media_viewer_action_string_lookup = { MEDIA_VIEWER_ACTION_SHOW_OPEN_EXTERNALLY_BUTTON : 'show an \'open externally\' button', MEDIA_VIEWER_ACTION_DO_NOT_SHOW_ON_ACTIVATION_OPEN_EXTERNALLY : 'do not show in the media viewer. on thumbnail activation, open externally', MEDIA_VIEWER_ACTION_DO_NOT_SHOW : 'do not show at all', - MEDIA_VIEWER_ACTION_SHOW_WITH_MPV : 'show using mpv' + MEDIA_VIEWER_ACTION_SHOW_WITH_MPV : 'show using mpv', + MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER : 'show using Qt Media Player (EXPERIMENTAL, buggy!)' } unsupported_media_actions = [ MEDIA_VIEWER_ACTION_SHOW_OPEN_EXTERNALLY_BUTTON, MEDIA_VIEWER_ACTION_DO_NOT_SHOW_ON_ACTIVATION_OPEN_EXTERNALLY, MEDIA_VIEWER_ACTION_DO_NOT_SHOW ] static_media_actions = [ MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE ] + unsupported_media_actions -animated_media_actions = [ MEDIA_VIEWER_ACTION_SHOW_WITH_MPV ] + static_media_actions -audio_media_actions = [ MEDIA_VIEWER_ACTION_SHOW_WITH_MPV ] + unsupported_media_actions +animated_media_actions = [ MEDIA_VIEWER_ACTION_SHOW_WITH_MPV, MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER ] + static_media_actions +audio_media_actions = [ MEDIA_VIEWER_ACTION_SHOW_WITH_MPV, MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER ] + unsupported_media_actions # actions, can_start_paused, can_start_with_embed static_full_support = ( static_media_actions, False, True ) diff --git a/hydrus/client/ClientController.py b/hydrus/client/ClientController.py index 1deb9eb4..a0d273a7 100644 --- a/hydrus/client/ClientController.py +++ b/hydrus/client/ClientController.py @@ -1946,7 +1946,9 @@ class Controller( HydrusController.HydrusController ): if True in ( service.GetPort() is not None for service in services ): - HydrusData.ShowText( 'Twisted failed to import, so could not start the local booru/client api! Please contact hydrus dev!' ) + HydrusData.ShowText( 'Twisted failed to import, so could not start the local booru/client api! Specific error has been printed to log. Please contact hydrus dev!' ) + + HydrusData.Print( HG.twisted_is_broke_exception ) else: diff --git a/hydrus/client/gui/ClientGUI.py b/hydrus/client/gui/ClientGUI.py index 8ed3a258..2d2db51a 100644 --- a/hydrus/client/gui/ClientGUI.py +++ b/hydrus/client/gui/ClientGUI.py @@ -6128,11 +6128,11 @@ class FrameGUI( CAC.ApplicationCommandProcessorMixin, ClientGUITopLevelWindows.M if HC.PLATFORM_WINDOWS: - server_frozen_path = os.path.join( HC.BASE_DIR, 'server.exe' ) + server_frozen_path = os.path.join( HC.BASE_DIR, 'hydrus_server.exe' ) else: - server_frozen_path = os.path.join( HC.BASE_DIR, 'server' ) + server_frozen_path = os.path.join( HC.BASE_DIR, 'hydrus_server' ) if os.path.exists( server_frozen_path ): @@ -6143,9 +6143,9 @@ class FrameGUI( CAC.ApplicationCommandProcessorMixin, ClientGUITopLevelWindows.M python_executable = sys.executable - if python_executable.endswith( 'client.exe' ) or python_executable.endswith( 'client' ): + if python_executable.endswith( 'hydrus_client.exe' ) or python_executable.endswith( 'hydrus_client' ): - raise Exception( 'Could not automatically set up the server--could not find server executable or python executable.' ) + raise Exception( 'Could not automatically set up the server--could not find hydrus_client executable or python executable.' ) if 'pythonw' in python_executable: @@ -6153,7 +6153,7 @@ class FrameGUI( CAC.ApplicationCommandProcessorMixin, ClientGUITopLevelWindows.M python_executable = python_executable.replace( 'pythonw', 'python' ) - server_script_path = os.path.join( HC.BASE_DIR, 'server.py' ) + server_script_path = os.path.join( HC.BASE_DIR, 'hydrus_server.py' ) cmd = [ python_executable, server_script_path, db_param ] diff --git a/hydrus/client/gui/ClientGUIScrolledPanelsEdit.py b/hydrus/client/gui/ClientGUIScrolledPanelsEdit.py index e6e2ee6a..5607308c 100644 --- a/hydrus/client/gui/ClientGUIScrolledPanelsEdit.py +++ b/hydrus/client/gui/ClientGUIScrolledPanelsEdit.py @@ -2920,11 +2920,16 @@ class EditMediaViewOptionsPanel( ClientGUIScrolledPanels.EditPanel ): s = CC.media_viewer_action_string_lookup[ action ] - if action == CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV and self._mime in ( HC.IMAGE_GIF, HC.GENERAL_ANIMATION ): + if action in ( CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER ) and self._mime in ( HC.IMAGE_GIF, HC.GENERAL_ANIMATION ): s += ' (will show unanimated gifs with native viewer)' + if action == CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE and self._mime in [ HC.GENERAL_VIDEO ] + list( HC.VIDEO ): + + s += ' (no audio support)' + + self._media_show_action.addItem( s, action ) if action != CC.MEDIA_VIEWER_ACTION_DO_NOT_SHOW_ON_ACTIVATION_OPEN_EXTERNALLY: @@ -3015,7 +3020,7 @@ class EditMediaViewOptionsPanel( ClientGUIScrolledPanels.EditPanel ): QP.AddToLayout( vbox, gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR ) - if set( possible_show_actions ).isdisjoint( { CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV } ): + if set( possible_show_actions ).isdisjoint( { CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER } ): self._media_scale_up.hide() self._media_scale_down.hide() diff --git a/hydrus/client/gui/ClientGUIScrolledPanelsManagement.py b/hydrus/client/gui/ClientGUIScrolledPanelsManagement.py index c49a515c..eaa4a4c0 100644 --- a/hydrus/client/gui/ClientGUIScrolledPanelsManagement.py +++ b/hydrus/client/gui/ClientGUIScrolledPanelsManagement.py @@ -2263,7 +2263,7 @@ class ManageOptionsPanel( ClientGUIScrolledPanels.ManagePanel ): pretty_preview_show_action += ', start with embed button' - no_show = { media_show_action, preview_show_action }.isdisjoint( { CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV } ) + no_show = { media_show_action, preview_show_action }.isdisjoint( { CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER } ) if no_show: diff --git a/hydrus/client/gui/canvas/ClientGUICanvasMedia.py b/hydrus/client/gui/canvas/ClientGUICanvasMedia.py index 164afb6d..10d87bcf 100644 --- a/hydrus/client/gui/canvas/ClientGUICanvasMedia.py +++ b/hydrus/client/gui/canvas/ClientGUICanvasMedia.py @@ -4,6 +4,8 @@ import typing from qtpy import QtCore as QC from qtpy import QtWidgets as QW from qtpy import QtGui as QG +from qtpy import QtMultimediaWidgets as QMW +from qtpy import QtMultimedia as QM from hydrus.core import HydrusConstants as HC from hydrus.core import HydrusData @@ -20,6 +22,7 @@ from hydrus.client.gui import ClientGUIFunctions from hydrus.client.gui import ClientGUIMedia from hydrus.client.gui import ClientGUIMediaControls from hydrus.client.gui import ClientGUIShortcuts +from hydrus.client.gui import QtInit from hydrus.client.gui import QtPorting as QP from hydrus.client.gui.canvas import ClientGUIMPV from hydrus.client.gui.widgets import ClientGUICommon @@ -308,7 +311,7 @@ def ShouldHaveAnimationBar( media, show_action ): return False - if show_action not in ( CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV ): + if show_action not in ( CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER ): return False @@ -317,7 +320,7 @@ def ShouldHaveAnimationBar( media, show_action ): is_audio = media.GetMime() in HC.AUDIO is_video = media.GetMime() in HC.VIDEO - if show_action == CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV: + if show_action in ( CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER ): if ( is_animated_image or is_audio or is_video ) and media.HasDuration(): @@ -1162,7 +1165,7 @@ class AnimationBar( QW.QWidget ): self._media_window.GotoFrame( current_frame_index ) - elif isinstance( self._media_window, ClientGUIMPV.MPVWidget ): + elif isinstance( self._media_window, ( ClientGUIMPV.MPVWidget, QtMediaPlayer ) ): time_index_ms = int( proportion * self._duration_ms ) @@ -1448,7 +1451,7 @@ class MediaContainer( QW.QWidget ): if media_window is not None: - launch_media_viewer_classes = ( Animation, ClientGUIMPV.MPVWidget, StaticImage ) + launch_media_viewer_classes = ( Animation, ClientGUIMPV.MPVWidget, StaticImage, QtMediaPlayer ) media_window.removeEventFilter( self._additional_event_filter ) @@ -1463,9 +1466,6 @@ class MediaContainer( QW.QWidget ): pass # lmao, weird 'Failed to disconnect signal launchMediaViewer()' error I couldn't figure out, I guess some out-of-order deleteLater gubbins - - if isinstance( media_window, launch_media_viewer_classes ): - media_window.ClearMedia() if isinstance( media_window, StaticImage ): @@ -1480,6 +1480,11 @@ class MediaContainer( QW.QWidget ): HG.client_controller.gui.ReleaseMPVWidget( media_window ) + if isinstance( media_window, QtMediaPlayer ): + + media_window.deleteLater() + + else: media_window.deleteLater() @@ -1489,7 +1494,7 @@ class MediaContainer( QW.QWidget ): def _GetMaxZoomDimension( self ): - if self._show_action == CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV or isinstance( self._media_window, Animation ): + if self._show_action in ( CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER ) or isinstance( self._media_window, Animation ): return 8000 @@ -1513,7 +1518,14 @@ class MediaContainer( QW.QWidget ): HydrusData.ShowText( 'MPV is not available!' ) - if self._show_action == CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV and self._media.GetMime() == HC.IMAGE_GIF and not self._media.HasDuration(): + if self._show_action == CC.MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER and QtInit.WE_ARE_QT5: + + self._show_action = CC.MEDIA_VIEWER_ACTION_SHOW_OPEN_EXTERNALLY_BUTTON + + HydrusData.ShowText( 'Qt Media Player is only available on Qt6!' ) + + + if self._show_action in ( CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER ) and self._media.GetMime() == HC.IMAGE_GIF and not self._media.HasDuration(): self._show_action = CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE @@ -1573,6 +1585,14 @@ class MediaContainer( QW.QWidget ): self._media_window.lower() + elif self._show_action == CC.MEDIA_VIEWER_ACTION_SHOW_WITH_QMEDIAPLAYER: + + self._media_window = QtMediaPlayer( self, self._canvas_type, self._background_colour_generator ) + + self._media_window.SetMedia( self._media, start_paused = self._start_paused ) + + self._media_window.lower() + if ShouldHaveAnimationBar( self._media, self._show_action ): @@ -1590,7 +1610,7 @@ class MediaContainer( QW.QWidget ): self._media_window.installEventFilter( self._additional_event_filter ) - launch_media_viewer_classes = ( Animation, ClientGUIMPV.MPVWidget, StaticImage ) + launch_media_viewer_classes = ( Animation, ClientGUIMPV.MPVWidget, StaticImage, QtMediaPlayer ) if isinstance( self._media_window, launch_media_viewer_classes ): @@ -2888,6 +2908,278 @@ class OpenExternallyPanel( QW.QWidget ): HydrusPaths.LaunchFile( path, launch_path ) + +class QtMediaPlayer( QW.QWidget ): + + launchMediaViewer = QC.Signal() + + def __init__( self, parent: QW.QWidget, canvas_type, background_colour_generator ): + + QW.QWidget.__init__( self, parent ) + + self._canvas_type = canvas_type + self._background_colour_generator = background_colour_generator + + self._my_audio_output = QM.QAudioOutput( self ) + self._my_video_output = QMW.QVideoWidget( self ) + self._my_audio_placeholder = QW.QWidget( self ) + + QP.SetBackgroundColour( self._my_audio_placeholder, QG.QColor( 0, 0, 0 ) ) + + # perhaps this stops the always on top behaviour, says several places, but it doesn't for me! + #self._my_video_output.setAttribute( QC.Qt.WA_TranslucentBackground, False ) + + self._media_player = QM.QMediaPlayer( self ) + + self._media_player.mediaStatusChanged.connect( self._MediaStatusChanged ) + + self._we_are_initialised = True + + vbox = QP.VBoxLayout( margin = 0 ) + + QP.AddToLayout( vbox, self._my_video_output, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS ) + QP.AddToLayout( vbox, self._my_audio_placeholder, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS ) + + self.setLayout( vbox ) + + self._media = None + + self._playthrough_count = 0 + + if self._canvas_type in CC.CANVAS_MEDIA_VIEWER_TYPES: + + shortcut_set = 'media_viewer_media_window' + + else: + + shortcut_set = 'preview_media_window' + + + self._my_shortcut_handler = ClientGUIShortcuts.ShortcutsHandler( self, [ shortcut_set ], catch_mouse = True ) + + + def _MediaStatusChanged( self, status ): + + if status == QM.QMediaPlayer.MediaStatus.EndOfMedia: + + self._playthrough_count += 1 + + self._media_player.setPosition( 0 ) + + self._media_player.play() + + + + def GetAnimationBarStatus( self ): + + buffer_indices = None + + if self._media is None: + + current_frame_index = 0 + current_timestamp_ms = 0 + paused = True + + else: + + current_timestamp_ms = self._media_player.position() + + 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() ) + + paused = self.IsPaused() + + + return ( current_frame_index, current_timestamp_ms, paused, buffer_indices ) + + + def ClearMedia( self ): + + if self._media is not None: + + self._media = None + + # ok in my experience setting media_player.setSource to anything after a first load is pretty buggy! + # it can just straight up hang forever. either to a null QUrl or another file + # it seems to be it doesn't like unloading some files + # so, let's spawn a new one every time + # EDIT: ok going from one vid to another can cause crashes, so we are moving to a system where each QtMediaPlayer just gets one use. we'll make a new one every time + + self._media_player.stop() + + #self._media_player.setParent( None ) + + #QP.CallAfter( self._media_player.deleteLater ) + + #self._media_player = QM.QMediaPlayer( self ) + + #self._media_player.mediaStatusChanged.connect( self._MediaStatusChanged ) + + + + def HasPlayedOnceThrough( self ): + + return self._playthrough_count > 0 + + + def IsPaused( self ): + + return not self._media_player.isPlaying() + + + def Pause( self ): + + self._media_player.pause() + + + def PausePlay( self ): + + if self.IsPaused(): + + self.Play() + + else: + + self.Pause() + + + + def Play( self ): + + self._media_player.play() + + + def ProcessApplicationCommand( self, command: CAC.ApplicationCommand ): + + command_processed = True + + if command.IsSimpleCommand(): + + action = command.GetSimpleAction() + + if action == CAC.SIMPLE_PAUSE_MEDIA: + + self.Pause() + + elif action == CAC.SIMPLE_PAUSE_PLAY_MEDIA: + + self.PausePlay() + + elif action == CAC.SIMPLE_MEDIA_SEEK_DELTA: + + ( direction, duration_ms ) = command.GetSimpleData() + + self.SeekDelta( direction, duration_ms ) + + elif action == CAC.SIMPLE_OPEN_FILE_IN_EXTERNAL_PROGRAM: + + if self._media is not None: + + self.Pause() + + ClientGUIMedia.OpenExternally( self._media ) + + + elif action == CAC.SIMPLE_CLOSE_MEDIA_VIEWER and self._canvas_type in CC.CANVAS_MEDIA_VIEWER_TYPES: + + self.window().close() + + elif action == CAC.SIMPLE_LAUNCH_MEDIA_VIEWER and self._canvas_type == CC.CANVAS_PREVIEW: + + self.launchMediaViewer.emit() + + else: + + command_processed = False + + + else: + + command_processed = False + + + return command_processed + + + def Seek( self, position_ms ): + + self._media_player.setPosition( position_ms ) + + + def SeekDelta( self, direction, duration_ms ): + + if self._media is None: + + return + + + current_timestamp_ms = self._media_player.position() + + new_timestamp_ms = max( 0, current_timestamp_ms + ( direction * duration_ms ) ) + + if new_timestamp_ms > self._media.GetDurationMS(): + + new_timestamp_ms = 0 + + + self.Seek( new_timestamp_ms ) + + + def SetBackgroundColourGenerator( self, background_colour_generator ): + + self._background_colour_generator = background_colour_generator + + + def SetMedia( self, media: ClientMedia.MediaSingleton, start_paused = False ): + + if media == self._media: + + return + + + self.ClearMedia() + + self._media = media + + has_audio = self._media.HasAudio() + is_audio = self._media.GetMime() in HC.AUDIO + + if has_audio: + + self._media_player.setAudioOutput( self._my_audio_output ) + + + if not is_audio: + + self._media_player.setVideoOutput( self._my_video_output ) + + + self._my_video_output.setVisible( not is_audio ) + self._my_audio_placeholder.setVisible( is_audio ) + + path = HG.client_controller.client_files_manager.GetFilePath( self._media.GetHash(), self._media.GetMime() ) + + self._media_player.setSource( QC.QUrl.fromLocalFile( path ) ) + + if not start_paused: + + self._media_player.play() + + + + class StaticImage( CAC.ApplicationCommandProcessorMixin, QW.QWidget ): launchMediaViewer = QC.Signal() diff --git a/hydrus/core/HydrusConstants.py b/hydrus/core/HydrusConstants.py index a93f303e..35765379 100644 --- a/hydrus/core/HydrusConstants.py +++ b/hydrus/core/HydrusConstants.py @@ -100,7 +100,7 @@ options = {} # Misc NETWORK_VERSION = 20 -SOFTWARE_VERSION = 526 +SOFTWARE_VERSION = 527 CLIENT_API_VERSION = 44 SERVER_THUMBNAIL_DIMENSIONS = ( 200, 200 ) diff --git a/hydrus/core/HydrusGlobals.py b/hydrus/core/HydrusGlobals.py index 77f62d4f..8703de76 100644 --- a/hydrus/core/HydrusGlobals.py +++ b/hydrus/core/HydrusGlobals.py @@ -77,6 +77,7 @@ shutdown_complete = False restart = False twisted_is_broke = False +twisted_is_broke_exception = None dirty_object_lock = threading.Lock() client_busy = threading.Lock() diff --git a/hydrus/hydrus_client.py b/hydrus/hydrus_client_boot.py similarity index 98% rename from hydrus/hydrus_client.py rename to hydrus/hydrus_client_boot.py index 0dab0ee3..d7c22b42 100644 --- a/hydrus/hydrus_client.py +++ b/hydrus/hydrus_client_boot.py @@ -165,8 +165,11 @@ try: from twisted.internet import reactor - except: + except Exception as e: + import traceback + + HG.twisted_is_broke_exception = traceback.format_exc() HG.twisted_is_broke = True diff --git a/hydrus/hydrus_server.py b/hydrus/hydrus_server_boot.py similarity index 100% rename from hydrus/hydrus_server.py rename to hydrus/hydrus_server_boot.py diff --git a/hydrus/hydrus_test.py b/hydrus/hydrus_test_boot.py similarity index 100% rename from hydrus/hydrus_test.py rename to hydrus/hydrus_test_boot.py diff --git a/client.bat b/hydrus_client.bat similarity index 76% rename from client.bat rename to hydrus_client.bat index 9130c4b0..27a65e9c 100644 --- a/client.bat +++ b/hydrus_client.bat @@ -26,12 +26,12 @@ IF ERRORLEVEL 1 ( REM You can copy this file to 'client-user.bat' and add in your own launch parameters here if you like, and a git pull won't overwrite the file. REM Just tack new params on like this: -REM start "" "pythonw" client.pyw -d="E:\hydrus" +REM start "" "pythonw" hydrus_client.pyw -d="E:\hydrus" -start "" "pythonw" client.pyw +start "" "pythonw" hydrus_client.pyw -REM Here is an alternate line that will keep the console open and see live log updates. Useful for boot/live debugging. -REM python client.py +REM Here is an alternate line that will keep the console open and show live log updates. Useful for boot/live debugging: +REM python hydrus_client.py CALL venv\Scripts\deactivate.bat diff --git a/client.command b/hydrus_client.command similarity index 63% rename from client.command rename to hydrus_client.command index f276e99f..ea7d1306 100644 --- a/client.command +++ b/hydrus_client.command @@ -14,11 +14,11 @@ if ! source venv/bin/activate; then exit 1 fi -# You can copy this file to 'client-user.sh' and add in your own launch parameters here if you like, and a git pull won't overwrite the file. +# You can copy this file to 'hydrus_client-user.sh' and add in your own launch parameters here if you like, and a git pull won't overwrite the file. # Just tack new params on like this: -# python client.py -d="/path/to/hydrus/db" +# python hydrus_client.py -d="/path/to/hydrus/db" -python client.py +python hydrus_client.py deactivate diff --git a/test.py b/hydrus_client.py similarity index 73% rename from test.py rename to hydrus_client.py index ceac90ef..d1548fed 100644 --- a/test.py +++ b/hydrus_client.py @@ -4,9 +4,9 @@ # You just DO WHAT THE FUCK YOU WANT TO. # https://github.com/sirkris/WTFPL/blob/master/WTFPL.md -from hydrus import hydrus_test +from hydrus import hydrus_client_boot if __name__ == '__main__': - hydrus_test.boot() + hydrus_client_boot.boot() diff --git a/client.py b/hydrus_client.pyw similarity index 73% rename from client.py rename to hydrus_client.pyw index c46ae740..d1548fed 100644 --- a/client.py +++ b/hydrus_client.pyw @@ -4,9 +4,9 @@ # You just DO WHAT THE FUCK YOU WANT TO. # https://github.com/sirkris/WTFPL/blob/master/WTFPL.md -from hydrus import hydrus_client +from hydrus import hydrus_client_boot if __name__ == '__main__': - hydrus_client.boot() + hydrus_client_boot.boot() diff --git a/client.sh b/hydrus_client.sh similarity index 87% rename from client.sh rename to hydrus_client.sh index 982ad30a..d6adf885 100644 --- a/client.sh +++ b/hydrus_client.sh @@ -16,9 +16,9 @@ fi # You can copy this file to 'client-user.sh' and add in your own launch parameters here if you like, and a git pull won't overwrite the file. # Just tack new params on like this: -# python client.py -d="/path/to/hydrus/db" +# python hydrus_client.py -d="/path/to/hydrus/db" -python client.py +python hydrus_client.py deactivate diff --git a/client.pyw b/hydrus_server.py old mode 100755 new mode 100644 similarity index 73% rename from client.pyw rename to hydrus_server.py index c46ae740..555c4ba4 --- a/client.pyw +++ b/hydrus_server.py @@ -4,9 +4,9 @@ # You just DO WHAT THE FUCK YOU WANT TO. # https://github.com/sirkris/WTFPL/blob/master/WTFPL.md -from hydrus import hydrus_client +from hydrus import hydrus_server_boot if __name__ == '__main__': - hydrus_client.boot() + hydrus_server_boot.boot() diff --git a/server.py b/hydrus_test.py similarity index 75% rename from server.py rename to hydrus_test.py index 8aedfa54..5d489cc7 100644 --- a/server.py +++ b/hydrus_test.py @@ -4,9 +4,9 @@ # You just DO WHAT THE FUCK YOU WANT TO. # https://github.com/sirkris/WTFPL/blob/master/WTFPL.md -from hydrus import hydrus_server +from hydrus import hydrus_test_boot if __name__ == '__main__': - hydrus_server.boot() + hydrus_test_boot.boot() diff --git a/static/build_files/linux/client.spec b/static/build_files/linux/client.spec index 2d0ba101..9ebf4a71 100644 --- a/static/build_files/linux/client.spec +++ b/static/build_files/linux/client.spec @@ -7,22 +7,21 @@ cloudscraper_dir = os.path.dirname( cloudscraper.__file__ ) block_cipher = None -a = Analysis(['hydrus/client.py'], +a = Analysis(['hydrus/hydrus_client.py'], pathex=['.'], binaries=[], datas=[ ('hydrus/bin', 'bin'), ('hydrus/help', 'help'), ('hydrus/static', 'static'), - ('dist/server/server', '.'), + ('dist/hydrus_server/hydrus_server', '.'), ('hydrus/license.txt', '.'), ('hydrus/README.md', '.'), ('hydrus/help my client will not boot.txt', '.'), ('hydrus/db', 'db'), - ('hydrus/hydrus', 'hydrus'), (cloudscraper_dir, 'cloudscraper') ], - hiddenimports=['hydrus/server.py'], + hiddenimports=['hydrus/hydrus_server.py'], hookspath=[], runtime_hooks=[], excludes=[], @@ -36,7 +35,7 @@ exe = EXE(pyz, a.scripts, [], exclude_binaries=True, - name='client', + name='hydrus_client', debug=False, bootloader_ignore_signals=False, strip=False, @@ -49,4 +48,4 @@ coll = COLLECT(exe, strip=False, upx=True, upx_exclude=[], - name='client') \ No newline at end of file + name='hydrus_client') diff --git a/static/build_files/linux/requirements.txt b/static/build_files/linux/requirements.txt index 6301dbcd..99458401 100644 --- a/static/build_files/linux/requirements.txt +++ b/static/build_files/linux/requirements.txt @@ -21,7 +21,7 @@ service-identity>=18.1.0 six>=1.14.0 Twisted>=20.3.0 -opencv-python-headless==4.5.3.56 +opencv-python-headless==4.5.5.64 python-mpv==0.5.2 QtPy==2.3.0 requests==2.28.1 diff --git a/static/build_files/linux/server.spec b/static/build_files/linux/server.spec index 0804ec75..d8bec447 100644 --- a/static/build_files/linux/server.spec +++ b/static/build_files/linux/server.spec @@ -3,7 +3,7 @@ block_cipher = None -a = Analysis(['hydrus/server.py'], +a = Analysis(['hydrus/hydrus_server.py'], pathex=['.'], binaries=[], datas=[], @@ -21,7 +21,7 @@ exe = EXE(pyz, a.scripts, [], exclude_binaries=True, - name='server', + name='hydrus_server', debug=False, bootloader_ignore_signals=False, strip=False, @@ -33,4 +33,4 @@ coll = COLLECT(exe, a.datas, strip=False, upx=True, - name='server') \ No newline at end of file + name='hydrus_server') diff --git a/static/build_files/macos/pyoxidizer.bzl b/static/build_files/macos/pyoxidizer.bzl index c30694b0..611a200a 100644 --- a/static/build_files/macos/pyoxidizer.bzl +++ b/static/build_files/macos/pyoxidizer.bzl @@ -15,10 +15,10 @@ def make_client(dist, policy): python_config.module_search_paths = ["$ORIGIN", "$ORIGIN/lib"] python_config.filesystem_importer = True python_config.sys_frozen = True - python_config.run_command = "import os; import sys; exec(open(os.path.join(os.path.split(sys.executable)[0], 'client.py')).read())" + python_config.run_command = "import os; import sys; exec(open(os.path.join(os.path.split(sys.executable)[0], 'hydrus_client.py')).read())" client = dist.to_python_executable( - name="client", + name="hydrus_client", packaging_policy=policy, config=python_config, ) @@ -37,9 +37,6 @@ def make_install(client, resources): static_resources = glob(["./*.py", "./*.md", "./*txt", "./bin/**/*", "./static/**/*", "./help/**/*"], strip_prefix="{}/".format(CWD)) files.add_manifest(static_resources) - hydrus_source = glob(["./hydrus/**/*.py"], strip_prefix="{}/".format(CWD)) - files.add_manifest(hydrus_source) - return files print(BUILD_TARGET_TRIPLE) @@ -48,9 +45,9 @@ print(CWD) # Tell PyOxidizer about the build targets defined above. register_target("dist", make_dist) register_target("policy", make_packaging_policy, depends=["dist"]) -register_target("client", make_client, depends=["dist", "policy"]) -register_target("resources", make_embedded_resources, depends=["client"], default_build_script=True) -register_target("install", make_install, depends=["client", "resources"], default=True) +register_target("hydrus_client", make_client, depends=["dist", "policy"]) +register_target("resources", make_embedded_resources, depends=["hydrus_client"], default_build_script=True) +register_target("install", make_install, depends=["hydrus_client", "resources"], default=True) resolve_targets() diff --git a/static/build_files/macos/requirements.txt b/static/build_files/macos/requirements.txt index 4028c549..67e5476d 100644 --- a/static/build_files/macos/requirements.txt +++ b/static/build_files/macos/requirements.txt @@ -21,7 +21,7 @@ service-identity>=18.1.0 six>=1.14.0 Twisted>=20.3.0 -opencv-python-headless==4.5.3.56 +opencv-python-headless==4.5.5.64 python-mpv==1.0.3 QtPy==2.2.1 requests==2.28.1 diff --git a/static/build_files/windows/InnoSetup.iss b/static/build_files/windows/InnoSetup.iss index 996fc801..e28ce36f 100644 --- a/static/build_files/windows/InnoSetup.iss +++ b/static/build_files/windows/InnoSetup.iss @@ -3,13 +3,13 @@ #endif [Icons] -Name: {group}\hydrus client; Filename: {app}\client.exe; WorkingDir: {app}; Tasks: programgroupicons -Name: {group}\hydrus server; Filename: {app}\server.exe; WorkingDir: {app}; Tasks: programgroupicons -;Taking this out to stop anti-virus testbeds pursing it and launching Edge and detecting Edge update calls as suspicious DNS lmao +Name: {group}\hydrus client; Filename: {app}\hydrus_client.exe; WorkingDir: {app}; Tasks: programgroupicons +Name: {group}\hydrus server; Filename: {app}\hydrus_server.exe; WorkingDir: {app}; Tasks: programgroupicons +;Taking this out to stop anti-virus testbeds pursuing it and launching Edge and detecting Edge update calls as suspicious DNS lmao ;Name: {group}\help; Filename: {app}\help\index.html; WorkingDir: {app}; Tasks: programgroupicons Name: {group}\uninstall hydrus network; Filename: {uninstallexe}; WorkingDir: {app}; Tasks: programgroupicons; IconFilename: {app}\static\cross.ico -Name: {userdesktop}\hydrus client; Filename: {app}\client.exe; WorkingDir: {app}; Tasks: desktopicons -Name: {userdesktop}\hydrus server; Filename: {app}\server.exe; WorkingDir: {app}; Tasks: desktopicons +Name: {userdesktop}\hydrus client; Filename: {app}\hydrus_client.exe; WorkingDir: {app}; Tasks: desktopicons +Name: {userdesktop}\hydrus server; Filename: {app}\hydrus_server.exe; WorkingDir: {app}; Tasks: desktopicons [Setup] InternalCompressLevel=ultra64 OutputDir=dist @@ -39,13 +39,14 @@ Name: install; Description: Install; Types: install; Flags: fixed Name: install; Description: Install Name: extract; Description: Extract only [Run] -;Taking this out to stop anti-virus testbeds pursing it and launching Edge and detecting Edge update calls as suspicious DNS lmao +;Taking this out to stop anti-virus testbeds pursuing it and launching Edge and detecting Edge update calls as suspicious DNS lmao ;Filename: {app}\help\index.html; Description: Open help/getting started guide (highly recommended for new users); Flags: postinstall unchecked shellexec -Filename: {app}\client.exe; Description: Open the client; Flags: postinstall nowait unchecked +Filename: {app}\hydrus_client.exe; Description: Open the client; Flags: postinstall nowait unchecked [Files] Source: dist\Hydrus Network\*; DestDir: {app}; Flags: ignoreversion recursesubdirs createallsubdirs [InstallDelete] Name: {app}\Crypto; Type: filesandordirs; Components: install +Name: {app}\cv2; Type: filesandordirs; Components: install Name: {app}\tcl; Type: filesandordirs; Components: install Name: {app}\tk; Type: filesandordirs; Components: install Name: {app}\wx; Type: filesandordirs; Components: install @@ -57,6 +58,8 @@ Name: {app}\lib2to3; Type: filesandordirs; Components: install Name: {app}\mpl-data; Type: filesandordirs; Components: install Name: {app}\matplotlib; Type: filesandordirs; Components: install Name: {app}\cryptography; Type: filesandordirs; Components: install +Name: {app}\client.exe; Type: files; Components: install +Name: {app}\server.exe; Type: files; Components: install Name: {app}\opencv_ffmpeg344_64.dll; Type: files; Components: install Name: {app}\opencv_ffmpeg400_64.dll; Type: files; Components: install Name: {app}\opencv_ffmpeg410_64.dll; Type: files; Components: install diff --git a/static/build_files/windows/client-win.spec b/static/build_files/windows/client-win.spec index 157bd3fb..bdbadf5e 100644 --- a/static/build_files/windows/client-win.spec +++ b/static/build_files/windows/client-win.spec @@ -8,24 +8,24 @@ cloudscraper_dir = os.path.dirname( cloudscraper.__file__ ) block_cipher = None -a = Analysis(['hydrus\\client.pyw'], +a = Analysis(['hydrus\\hydrus_client.pyw'], pathex=['.'], - binaries=[], + binaries=[ + ('hydrus\\sqlite3.dll', '.'), + ('hydrus\\mpv-2.dll', '.') + ], datas=[ ('hydrus\\bin', 'bin'), ('hydrus\\help', 'help'), ('hydrus\\static', 'static'), - ('dist\\server\\server.exe*', '.'), + ('dist\\hydrus_server\\hydrus_server.exe*', '.'), ('hydrus\\license.txt', '.'), ('hydrus\\README.md', '.'), ('hydrus\\help my client will not boot.txt', '.'), ('hydrus\\db', 'db'), - ('hydrus\\hydrus', 'hydrus'), - ('hydrus\\sqlite3.dll', '.'), - ('hydrus\\mpv-2.dll', '.'), (cloudscraper_dir, 'cloudscraper') ], - hiddenimports=['hydrus\\server.py', 'cloudscraper'], + hiddenimports=['hydrus\\hydrus_server.py', 'cloudscraper'], hookspath=[], runtime_hooks=[], excludes=[], @@ -39,12 +39,13 @@ exe = EXE(pyz, a.scripts, [], exclude_binaries=True, - name='client', + name='hydrus_client', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, - console=False, + console=False, + version_file='client_file_version_info.txt', icon='hydrus\\static\\hydrus.ico' ) coll = COLLECT(exe, a.binaries, @@ -53,4 +54,4 @@ coll = COLLECT(exe, strip=False, upx=False, upx_exclude=[], - name='Hydrus Network') + name='hydrus_client') diff --git a/static/build_files/windows/file_version_info_maker.py b/static/build_files/windows/file_version_info_maker.py new file mode 100644 index 00000000..9982733e --- /dev/null +++ b/static/build_files/windows/file_version_info_maker.py @@ -0,0 +1,84 @@ +import re +import sys + +def string_generator( version, capitalised_name ): + + match = re.match( r'^\d+', version ) + + if match: + + version_number = int( match.group() ) + + else: + + version_number = version + + + lower_name = capitalised_name.lower() + + return f'''# UTF-8 +# +# For more details about fixed file info 'ffi' see: +# http://msdn.microsoft.com/en-us/library/ms646997.aspx +VSVersionInfo( + ffi=FixedFileInfo( + # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) + # Set not needed items to zero 0. + filevers=(0, {version_number}, 0, 0), + prodvers=(0, {version_number}, 0, 0), + # Contains a bitmask that specifies the valid bits 'flags'r + mask=0x3f, + # Contains a bitmask that specifies the Boolean attributes of the file. + flags=0x0, + # The operating system for which this file was designed. + # 0x4 - NT and there is no need to change it. + OS=0x4, + # The general type of file. + # 0x1 - the file is an application. + fileType=0x1, + # The function of the file. + # 0x0 - the function is not defined for this fileType + subtype=0x0, + # Creation date and time stamp. + date=(0, 0) + ), + kids=[ + StringFileInfo( + [ + StringTable( + '040904b0', + [StringStruct('FileDescription', 'The Hydrus Network {capitalised_name}'), + StringStruct('FileVersion', '{version}'), + StringStruct('InternalName', 'Hydrus Network {capitalised_name}'), + StringStruct('LegalCopyright', 'WTFPL'), + StringStruct('OriginalFilename', 'hydrus_{lower_name}.exe'), + StringStruct('ProductName', 'Hydrus Network {capitalised_name}'), + StringStruct('ProductVersion', '{version}')]) + ]), + VarFileInfo([VarStruct('Translation', [1033, 1200])]) + ] +)''' + +if __name__ == '__main__': + + version_with_v = sys.argv[1] + + if version_with_v.startswith( 'v' ): + + version = version_with_v[1:] + + else: + + version = version_with_v + + + with open( 'client_file_version_info.txt', 'w', encoding = 'utf-8' ) as f: + + f.write( string_generator( version, 'Client' ) ) + + + with open( 'server_file_version_info.txt', 'w', encoding = 'utf-8' ) as f: + + f.write( string_generator( version, 'Server' ) ) + + diff --git a/static/build_files/windows/requirements.txt b/static/build_files/windows/requirements.txt index c9a1ce79..71c120b4 100644 --- a/static/build_files/windows/requirements.txt +++ b/static/build_files/windows/requirements.txt @@ -21,7 +21,7 @@ service-identity>=18.1.0 six>=1.14.0 Twisted>=20.3.0 -opencv-python-headless==4.5.3.56 +opencv-python-headless==4.5.5.64 python-mpv==1.0.3 QtPy==2.3.0 requests==2.28.1 diff --git a/static/build_files/windows/server-win.spec b/static/build_files/windows/server-win.spec index afb43d9a..d816ab88 100644 --- a/static/build_files/windows/server-win.spec +++ b/static/build_files/windows/server-win.spec @@ -3,7 +3,7 @@ block_cipher = None -a = Analysis(['hydrus\\server.py'], +a = Analysis(['hydrus\\hydrus_server.py'], pathex=['.'], binaries=[], datas=[], @@ -21,12 +21,13 @@ exe = EXE(pyz, a.scripts, [], exclude_binaries=True, - name='server', + name='hydrus_server', debug=False, bootloader_ignore_signals=False, strip=False, upx=False, console=True, + version_file='server_file_version_info.txt', icon='hydrus\\static\\hydrus.ico' ) coll = COLLECT(exe, a.binaries, @@ -35,4 +36,4 @@ coll = COLLECT(exe, strip=False, upx=False, upx_exclude=[], - name='server') + name='hydrus_server') diff --git a/static/build_files/windows/sqlite3.dll b/static/build_files/windows/sqlite3.dll index bff9e0ba..857e4105 100644 Binary files a/static/build_files/windows/sqlite3.dll and b/static/build_files/windows/sqlite3.dll differ diff --git a/static/build_files/windows/sqlite3.exe b/static/build_files/windows/sqlite3.exe index 7aeaecb3..ea23d0a8 100644 Binary files a/static/build_files/windows/sqlite3.exe and b/static/build_files/windows/sqlite3.exe differ