mirror of
				https://github.com/nixietab/picodulce.git
				synced 2025-10-30 21:15:11 +00:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "7608b647fe8ba79b90f93203616f138af2c9fd5d" and "6816d9e47aa2b3b15f41bc40d33179d849978056" have entirely different histories.
		
	
	
		
			7608b647fe
			...
			6816d9e47a
		
	
		
							
								
								
									
										67
									
								
								.github/workflows/Build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										67
									
								
								.github/workflows/Build.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,67 +0,0 @@ | |||||||
| name: Version Change Action |  | ||||||
| 
 |  | ||||||
| on: |  | ||||||
|   push: |  | ||||||
|     paths: |  | ||||||
|       - version.json  # Trigger on changes to version.json |  | ||||||
| 
 |  | ||||||
| jobs: |  | ||||||
|   version-release: |  | ||||||
|     runs-on: windows-latest  # Use Windows 10 runner |  | ||||||
| 
 |  | ||||||
|     steps: |  | ||||||
|     - name: Checkout repository |  | ||||||
|       uses: actions/checkout@v3 |  | ||||||
| 
 |  | ||||||
|     - name: Set up Python |  | ||||||
|       uses: actions/setup-python@v4 |  | ||||||
|       with: |  | ||||||
|         python-version: '3.x'  # Specify the Python version you need |  | ||||||
| 
 |  | ||||||
|     - name: Install dependencies |  | ||||||
|       run: | |  | ||||||
|         python -m pip install --upgrade pip |  | ||||||
|         pip install pyqt5 requests pywin32 pyinstaller pillow  # Install specific dependencies |  | ||||||
| 
 |  | ||||||
|     - name: Create actions-temp folder |  | ||||||
|       run: mkdir actions-temp  # Create the folder called actions-temp |  | ||||||
| 
 |  | ||||||
|     - name: Download picoBuild.py script |  | ||||||
|       run: curl -L -o actions-temp/picoBuild.py https://raw.githubusercontent.com/nixietab/picodulce-build-script/refs/heads/main/picoBuild.py |  | ||||||
| 
 |  | ||||||
|     - name: Run picoBuild.py script |  | ||||||
|       run: python actions-temp/picoBuild.py |  | ||||||
| 
 |  | ||||||
|     - name: Show directory structure |  | ||||||
|       run: |  |  | ||||||
|         dir actions-temp |  | ||||||
|         dir |  | ||||||
|        |  | ||||||
|     - name: Get version and name from version.json |  | ||||||
|       id: version_info |  | ||||||
|       run: | |  | ||||||
|         $versionJson = Get-Content version.json | ConvertFrom-Json |  | ||||||
|         echo "RELEASE_NAME=Release $($versionJson.version)" >> $env:GITHUB_ENV |  | ||||||
|         echo "RELEASE_TAG=$($versionJson.version)" >> $env:GITHUB_ENV |  | ||||||
| 
 |  | ||||||
|     - name: Create GitHub Release |  | ||||||
|       id: create_release |  | ||||||
|       uses: actions/create-release@v1 |  | ||||||
|       with: |  | ||||||
|         tag_name: ${{ env.RELEASE_TAG }} |  | ||||||
|         release_name: ${{ env.RELEASE_NAME }} |  | ||||||
|         body: "This release was created automatically by a GitHub Action." |  | ||||||
|         draft: false |  | ||||||
|         prerelease: false |  | ||||||
|       env: |  | ||||||
|         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |  | ||||||
| 
 |  | ||||||
|     - name: Upload Release Asset |  | ||||||
|       uses: actions/upload-release-asset@v1 |  | ||||||
|       with: |  | ||||||
|         upload_url: ${{ steps.create_release.outputs.upload_url }} |  | ||||||
|         asset_path: build/2hsu.exe |  | ||||||
|         asset_name: 2hsu.exe |  | ||||||
|         asset_content_type: application/octet-stream |  | ||||||
|       env: |  | ||||||
|         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |  | ||||||
							
								
								
									
										339
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										339
									
								
								LICENSE
									
									
									
									
									
								
							| @ -1,339 +0,0 @@ | |||||||
|                     GNU GENERAL PUBLIC LICENSE |  | ||||||
|                        Version 2, June 1991 |  | ||||||
| 
 |  | ||||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc., |  | ||||||
|  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |  | ||||||
|  Everyone is permitted to copy and distribute verbatim copies |  | ||||||
|  of this license document, but changing it is not allowed. |  | ||||||
| 
 |  | ||||||
|                             Preamble |  | ||||||
| 
 |  | ||||||
|   The licenses for most software are designed to take away your |  | ||||||
| freedom to share and change it.  By contrast, the GNU General Public |  | ||||||
| License is intended to guarantee your freedom to share and change free |  | ||||||
| software--to make sure the software is free for all its users.  This |  | ||||||
| General Public License applies to most of the Free Software |  | ||||||
| Foundation's software and to any other program whose authors commit to |  | ||||||
| using it.  (Some other Free Software Foundation software is covered by |  | ||||||
| the GNU Lesser General Public License instead.)  You can apply it to |  | ||||||
| your programs, too. |  | ||||||
| 
 |  | ||||||
|   When we speak of free software, we are referring to freedom, not |  | ||||||
| price.  Our General Public Licenses are designed to make sure that you |  | ||||||
| have the freedom to distribute copies of free software (and charge for |  | ||||||
| this service if you wish), that you receive source code or can get it |  | ||||||
| if you want it, that you can change the software or use pieces of it |  | ||||||
| in new free programs; and that you know you can do these things. |  | ||||||
| 
 |  | ||||||
|   To protect your rights, we need to make restrictions that forbid |  | ||||||
| anyone to deny you these rights or to ask you to surrender the rights. |  | ||||||
| These restrictions translate to certain responsibilities for you if you |  | ||||||
| distribute copies of the software, or if you modify it. |  | ||||||
| 
 |  | ||||||
|   For example, if you distribute copies of such a program, whether |  | ||||||
| gratis or for a fee, you must give the recipients all the rights that |  | ||||||
| you have.  You must make sure that they, too, receive or can get the |  | ||||||
| source code.  And you must show them these terms so they know their |  | ||||||
| rights. |  | ||||||
| 
 |  | ||||||
|   We protect your rights with two steps: (1) copyright the software, and |  | ||||||
| (2) offer you this license which gives you legal permission to copy, |  | ||||||
| distribute and/or modify the software. |  | ||||||
| 
 |  | ||||||
|   Also, for each author's protection and ours, we want to make certain |  | ||||||
| that everyone understands that there is no warranty for this free |  | ||||||
| software.  If the software is modified by someone else and passed on, we |  | ||||||
| want its recipients to know that what they have is not the original, so |  | ||||||
| that any problems introduced by others will not reflect on the original |  | ||||||
| authors' reputations. |  | ||||||
| 
 |  | ||||||
|   Finally, any free program is threatened constantly by software |  | ||||||
| patents.  We wish to avoid the danger that redistributors of a free |  | ||||||
| program will individually obtain patent licenses, in effect making the |  | ||||||
| program proprietary.  To prevent this, we have made it clear that any |  | ||||||
| patent must be licensed for everyone's free use or not licensed at all. |  | ||||||
| 
 |  | ||||||
|   The precise terms and conditions for copying, distribution and |  | ||||||
| modification follow. |  | ||||||
| 
 |  | ||||||
|                     GNU GENERAL PUBLIC LICENSE |  | ||||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |  | ||||||
| 
 |  | ||||||
|   0. This License applies to any program or other work which contains |  | ||||||
| a notice placed by the copyright holder saying it may be distributed |  | ||||||
| under the terms of this General Public License.  The "Program", below, |  | ||||||
| refers to any such program or work, and a "work based on the Program" |  | ||||||
| means either the Program or any derivative work under copyright law: |  | ||||||
| that is to say, a work containing the Program or a portion of it, |  | ||||||
| either verbatim or with modifications and/or translated into another |  | ||||||
| language.  (Hereinafter, translation is included without limitation in |  | ||||||
| the term "modification".)  Each licensee is addressed as "you". |  | ||||||
| 
 |  | ||||||
| Activities other than copying, distribution and modification are not |  | ||||||
| covered by this License; they are outside its scope.  The act of |  | ||||||
| running the Program is not restricted, and the output from the Program |  | ||||||
| is covered only if its contents constitute a work based on the |  | ||||||
| Program (independent of having been made by running the Program). |  | ||||||
| Whether that is true depends on what the Program does. |  | ||||||
| 
 |  | ||||||
|   1. You may copy and distribute verbatim copies of the Program's |  | ||||||
| source code as you receive it, in any medium, provided that you |  | ||||||
| conspicuously and appropriately publish on each copy an appropriate |  | ||||||
| copyright notice and disclaimer of warranty; keep intact all the |  | ||||||
| notices that refer to this License and to the absence of any warranty; |  | ||||||
| and give any other recipients of the Program a copy of this License |  | ||||||
| along with the Program. |  | ||||||
| 
 |  | ||||||
| You may charge a fee for the physical act of transferring a copy, and |  | ||||||
| you may at your option offer warranty protection in exchange for a fee. |  | ||||||
| 
 |  | ||||||
|   2. You may modify your copy or copies of the Program or any portion |  | ||||||
| of it, thus forming a work based on the Program, and copy and |  | ||||||
| distribute such modifications or work under the terms of Section 1 |  | ||||||
| above, provided that you also meet all of these conditions: |  | ||||||
| 
 |  | ||||||
|     a) You must cause the modified files to carry prominent notices |  | ||||||
|     stating that you changed the files and the date of any change. |  | ||||||
| 
 |  | ||||||
|     b) You must cause any work that you distribute or publish, that in |  | ||||||
|     whole or in part contains or is derived from the Program or any |  | ||||||
|     part thereof, to be licensed as a whole at no charge to all third |  | ||||||
|     parties under the terms of this License. |  | ||||||
| 
 |  | ||||||
|     c) If the modified program normally reads commands interactively |  | ||||||
|     when run, you must cause it, when started running for such |  | ||||||
|     interactive use in the most ordinary way, to print or display an |  | ||||||
|     announcement including an appropriate copyright notice and a |  | ||||||
|     notice that there is no warranty (or else, saying that you provide |  | ||||||
|     a warranty) and that users may redistribute the program under |  | ||||||
|     these conditions, and telling the user how to view a copy of this |  | ||||||
|     License.  (Exception: if the Program itself is interactive but |  | ||||||
|     does not normally print such an announcement, your work based on |  | ||||||
|     the Program is not required to print an announcement.) |  | ||||||
| 
 |  | ||||||
| These requirements apply to the modified work as a whole.  If |  | ||||||
| identifiable sections of that work are not derived from the Program, |  | ||||||
| and can be reasonably considered independent and separate works in |  | ||||||
| themselves, then this License, and its terms, do not apply to those |  | ||||||
| sections when you distribute them as separate works.  But when you |  | ||||||
| distribute the same sections as part of a whole which is a work based |  | ||||||
| on the Program, the distribution of the whole must be on the terms of |  | ||||||
| this License, whose permissions for other licensees extend to the |  | ||||||
| entire whole, and thus to each and every part regardless of who wrote it. |  | ||||||
| 
 |  | ||||||
| Thus, it is not the intent of this section to claim rights or contest |  | ||||||
| your rights to work written entirely by you; rather, the intent is to |  | ||||||
| exercise the right to control the distribution of derivative or |  | ||||||
| collective works based on the Program. |  | ||||||
| 
 |  | ||||||
| In addition, mere aggregation of another work not based on the Program |  | ||||||
| with the Program (or with a work based on the Program) on a volume of |  | ||||||
| a storage or distribution medium does not bring the other work under |  | ||||||
| the scope of this License. |  | ||||||
| 
 |  | ||||||
|   3. You may copy and distribute the Program (or a work based on it, |  | ||||||
| under Section 2) in object code or executable form under the terms of |  | ||||||
| Sections 1 and 2 above provided that you also do one of the following: |  | ||||||
| 
 |  | ||||||
|     a) Accompany it with the complete corresponding machine-readable |  | ||||||
|     source code, which must be distributed under the terms of Sections |  | ||||||
|     1 and 2 above on a medium customarily used for software interchange; or, |  | ||||||
| 
 |  | ||||||
|     b) Accompany it with a written offer, valid for at least three |  | ||||||
|     years, to give any third party, for a charge no more than your |  | ||||||
|     cost of physically performing source distribution, a complete |  | ||||||
|     machine-readable copy of the corresponding source code, to be |  | ||||||
|     distributed under the terms of Sections 1 and 2 above on a medium |  | ||||||
|     customarily used for software interchange; or, |  | ||||||
| 
 |  | ||||||
|     c) Accompany it with the information you received as to the offer |  | ||||||
|     to distribute corresponding source code.  (This alternative is |  | ||||||
|     allowed only for noncommercial distribution and only if you |  | ||||||
|     received the program in object code or executable form with such |  | ||||||
|     an offer, in accord with Subsection b above.) |  | ||||||
| 
 |  | ||||||
| The source code for a work means the preferred form of the work for |  | ||||||
| making modifications to it.  For an executable work, complete source |  | ||||||
| code means all the source code for all modules it contains, plus any |  | ||||||
| associated interface definition files, plus the scripts used to |  | ||||||
| control compilation and installation of the executable.  However, as a |  | ||||||
| special exception, the source code distributed need not include |  | ||||||
| anything that is normally distributed (in either source or binary |  | ||||||
| form) with the major components (compiler, kernel, and so on) of the |  | ||||||
| operating system on which the executable runs, unless that component |  | ||||||
| itself accompanies the executable. |  | ||||||
| 
 |  | ||||||
| If distribution of executable or object code is made by offering |  | ||||||
| access to copy from a designated place, then offering equivalent |  | ||||||
| access to copy the source code from the same place counts as |  | ||||||
| distribution of the source code, even though third parties are not |  | ||||||
| compelled to copy the source along with the object code. |  | ||||||
| 
 |  | ||||||
|   4. You may not copy, modify, sublicense, or distribute the Program |  | ||||||
| except as expressly provided under this License.  Any attempt |  | ||||||
| otherwise to copy, modify, sublicense or distribute the Program is |  | ||||||
| void, and will automatically terminate your rights under this License. |  | ||||||
| However, parties who have received copies, or rights, from you under |  | ||||||
| this License will not have their licenses terminated so long as such |  | ||||||
| parties remain in full compliance. |  | ||||||
| 
 |  | ||||||
|   5. You are not required to accept this License, since you have not |  | ||||||
| signed it.  However, nothing else grants you permission to modify or |  | ||||||
| distribute the Program or its derivative works.  These actions are |  | ||||||
| prohibited by law if you do not accept this License.  Therefore, by |  | ||||||
| modifying or distributing the Program (or any work based on the |  | ||||||
| Program), you indicate your acceptance of this License to do so, and |  | ||||||
| all its terms and conditions for copying, distributing or modifying |  | ||||||
| the Program or works based on it. |  | ||||||
| 
 |  | ||||||
|   6. Each time you redistribute the Program (or any work based on the |  | ||||||
| Program), the recipient automatically receives a license from the |  | ||||||
| original licensor to copy, distribute or modify the Program subject to |  | ||||||
| these terms and conditions.  You may not impose any further |  | ||||||
| restrictions on the recipients' exercise of the rights granted herein. |  | ||||||
| You are not responsible for enforcing compliance by third parties to |  | ||||||
| this License. |  | ||||||
| 
 |  | ||||||
|   7. If, as a consequence of a court judgment or allegation of patent |  | ||||||
| infringement or for any other reason (not limited to patent issues), |  | ||||||
| conditions are imposed on you (whether by court order, agreement or |  | ||||||
| otherwise) that contradict the conditions of this License, they do not |  | ||||||
| excuse you from the conditions of this License.  If you cannot |  | ||||||
| distribute so as to satisfy simultaneously your obligations under this |  | ||||||
| License and any other pertinent obligations, then as a consequence you |  | ||||||
| may not distribute the Program at all.  For example, if a patent |  | ||||||
| license would not permit royalty-free redistribution of the Program by |  | ||||||
| all those who receive copies directly or indirectly through you, then |  | ||||||
| the only way you could satisfy both it and this License would be to |  | ||||||
| refrain entirely from distribution of the Program. |  | ||||||
| 
 |  | ||||||
| If any portion of this section is held invalid or unenforceable under |  | ||||||
| any particular circumstance, the balance of the section is intended to |  | ||||||
| apply and the section as a whole is intended to apply in other |  | ||||||
| circumstances. |  | ||||||
| 
 |  | ||||||
| It is not the purpose of this section to induce you to infringe any |  | ||||||
| patents or other property right claims or to contest validity of any |  | ||||||
| such claims; this section has the sole purpose of protecting the |  | ||||||
| integrity of the free software distribution system, which is |  | ||||||
| implemented by public license practices.  Many people have made |  | ||||||
| generous contributions to the wide range of software distributed |  | ||||||
| through that system in reliance on consistent application of that |  | ||||||
| system; it is up to the author/donor to decide if he or she is willing |  | ||||||
| to distribute software through any other system and a licensee cannot |  | ||||||
| impose that choice. |  | ||||||
| 
 |  | ||||||
| This section is intended to make thoroughly clear what is believed to |  | ||||||
| be a consequence of the rest of this License. |  | ||||||
| 
 |  | ||||||
|   8. If the distribution and/or use of the Program is restricted in |  | ||||||
| certain countries either by patents or by copyrighted interfaces, the |  | ||||||
| original copyright holder who places the Program under this License |  | ||||||
| may add an explicit geographical distribution limitation excluding |  | ||||||
| those countries, so that distribution is permitted only in or among |  | ||||||
| countries not thus excluded.  In such case, this License incorporates |  | ||||||
| the limitation as if written in the body of this License. |  | ||||||
| 
 |  | ||||||
|   9. The Free Software Foundation may publish revised and/or new versions |  | ||||||
| of the General Public License from time to time.  Such new versions will |  | ||||||
| be similar in spirit to the present version, but may differ in detail to |  | ||||||
| address new problems or concerns. |  | ||||||
| 
 |  | ||||||
| Each version is given a distinguishing version number.  If the Program |  | ||||||
| specifies a version number of this License which applies to it and "any |  | ||||||
| later version", you have the option of following the terms and conditions |  | ||||||
| either of that version or of any later version published by the Free |  | ||||||
| Software Foundation.  If the Program does not specify a version number of |  | ||||||
| this License, you may choose any version ever published by the Free Software |  | ||||||
| Foundation. |  | ||||||
| 
 |  | ||||||
|   10. If you wish to incorporate parts of the Program into other free |  | ||||||
| programs whose distribution conditions are different, write to the author |  | ||||||
| to ask for permission.  For software which is copyrighted by the Free |  | ||||||
| Software Foundation, write to the Free Software Foundation; we sometimes |  | ||||||
| make exceptions for this.  Our decision will be guided by the two goals |  | ||||||
| of preserving the free status of all derivatives of our free software and |  | ||||||
| of promoting the sharing and reuse of software generally. |  | ||||||
| 
 |  | ||||||
|                             NO WARRANTY |  | ||||||
| 
 |  | ||||||
|   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY |  | ||||||
| FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN |  | ||||||
| OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES |  | ||||||
| PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED |  | ||||||
| OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |  | ||||||
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS |  | ||||||
| TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE |  | ||||||
| PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, |  | ||||||
| REPAIR OR CORRECTION. |  | ||||||
| 
 |  | ||||||
|   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |  | ||||||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |  | ||||||
| REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, |  | ||||||
| INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING |  | ||||||
| OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED |  | ||||||
| TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY |  | ||||||
| YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER |  | ||||||
| PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE |  | ||||||
| POSSIBILITY OF SUCH DAMAGES. |  | ||||||
| 
 |  | ||||||
|                      END OF TERMS AND CONDITIONS |  | ||||||
| 
 |  | ||||||
|             How to Apply These Terms to Your New Programs |  | ||||||
| 
 |  | ||||||
|   If you develop a new program, and you want it to be of the greatest |  | ||||||
| possible use to the public, the best way to achieve this is to make it |  | ||||||
| free software which everyone can redistribute and change under these terms. |  | ||||||
| 
 |  | ||||||
|   To do so, attach the following notices to the program.  It is safest |  | ||||||
| to attach them to the start of each source file to most effectively |  | ||||||
| convey the exclusion of warranty; and each file should have at least |  | ||||||
| the "copyright" line and a pointer to where the full notice is found. |  | ||||||
| 
 |  | ||||||
|     <one line to give the program's name and a brief idea of what it does.> |  | ||||||
|     Copyright (C) <year>  <name of author> |  | ||||||
| 
 |  | ||||||
|     This program is free software; you can redistribute it and/or modify |  | ||||||
|     it under the terms of the GNU General Public License as published by |  | ||||||
|     the Free Software Foundation; either version 2 of the License, or |  | ||||||
|     (at your option) any later version. |  | ||||||
| 
 |  | ||||||
|     This program is distributed in the hope that it will be useful, |  | ||||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|     GNU General Public License for more details. |  | ||||||
| 
 |  | ||||||
|     You should have received a copy of the GNU General Public License along |  | ||||||
|     with this program; if not, write to the Free Software Foundation, Inc., |  | ||||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |  | ||||||
| 
 |  | ||||||
| Also add information on how to contact you by electronic and paper mail. |  | ||||||
| 
 |  | ||||||
| If the program is interactive, make it output a short notice like this |  | ||||||
| when it starts in an interactive mode: |  | ||||||
| 
 |  | ||||||
|     Gnomovision version 69, Copyright (C) year name of author |  | ||||||
|     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |  | ||||||
|     This is free software, and you are welcome to redistribute it |  | ||||||
|     under certain conditions; type `show c' for details. |  | ||||||
| 
 |  | ||||||
| The hypothetical commands `show w' and `show c' should show the appropriate |  | ||||||
| parts of the General Public License.  Of course, the commands you use may |  | ||||||
| be called something other than `show w' and `show c'; they could even be |  | ||||||
| mouse-clicks or menu items--whatever suits your program. |  | ||||||
| 
 |  | ||||||
| You should also get your employer (if you work as a programmer) or your |  | ||||||
| school, if any, to sign a "copyright disclaimer" for the program, if |  | ||||||
| necessary.  Here is a sample; alter the names: |  | ||||||
| 
 |  | ||||||
|   Yoyodyne, Inc., hereby disclaims all copyright interest in the program |  | ||||||
|   `Gnomovision' (which makes passes at compilers) written by James Hacker. |  | ||||||
| 
 |  | ||||||
|   <signature of Ty Coon>, 1 April 1989 |  | ||||||
|   Ty Coon, President of Vice |  | ||||||
| 
 |  | ||||||
| This General Public License does not permit incorporating your program into |  | ||||||
| proprietary programs.  If your program is a subroutine library, you may |  | ||||||
| consider it more useful to permit linking proprietary applications with the |  | ||||||
| library.  If this is what you want to do, use the GNU Lesser General |  | ||||||
| Public License instead of this License. |  | ||||||
							
								
								
									
										76
									
								
								PKGBUILD
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								PKGBUILD
									
									
									
									
									
								
							| @ -1,76 +0,0 @@ | |||||||
| pkgname=picodulce |  | ||||||
| pkgver=0.11.7 |  | ||||||
| pkgrel=1 |  | ||||||
| pkgdesc="Launcher for Minecraft based on the picomc library" |  | ||||||
| arch=('x86_64') |  | ||||||
| OPTIONS=(!strip !docs libtool emptydirs) |  | ||||||
| url="https://github.com/nixietab/picodulce" |  | ||||||
| license=('MIT')  # Replace with your project's license |  | ||||||
| depends=('python' 'python-virtualenv' 'xdg-utils') |  | ||||||
| makedepends=('git') |  | ||||||
| source=("git+https://github.com/nixietab/picodulce.git") |  | ||||||
| sha256sums=('SKIP') |  | ||||||
| 
 |  | ||||||
| package() { |  | ||||||
|     cd "$srcdir/$pkgname" |  | ||||||
| 
 |  | ||||||
|     # Create a directory for the application in the user's home directory |  | ||||||
|     install -dm755 "$pkgdir/usr/share/$pkgname" |  | ||||||
| 
 |  | ||||||
|     # Copy all project files to the created directory |  | ||||||
|     cp -r . "$pkgdir/usr/share/$pkgname" |  | ||||||
| 
 |  | ||||||
|     # Create a virtual environment |  | ||||||
|     python -m venv "$pkgdir/usr/share/$pkgname/venv" |  | ||||||
| 
 |  | ||||||
|     # Activate the virtual environment and install dependencies |  | ||||||
|     source "$pkgdir/usr/share/$pkgname/venv/bin/activate" |  | ||||||
|     pip install -r requirements.txt |  | ||||||
| 
 |  | ||||||
|     # Create a run.sh script |  | ||||||
|     install -Dm755 /dev/stdin "$pkgdir/usr/share/$pkgname/run.sh" <<EOF |  | ||||||
| #!/bin/bash |  | ||||||
| 
 |  | ||||||
| if [ ! -d "venv" ]; then |  | ||||||
|   echo "venv folder does not exist. Creating virtual environment..." |  | ||||||
|   python3 -m venv venv |  | ||||||
| 
 |  | ||||||
|   source venv/bin/activate |  | ||||||
| 
 |  | ||||||
|   echo "Installing required packages..." |  | ||||||
|   pip install -r requirements.txt |  | ||||||
| else |  | ||||||
|   source venv/bin/activate |  | ||||||
| fi |  | ||||||
| 
 |  | ||||||
| python picodulce.py |  | ||||||
| EOF |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     # Make the run.sh script executable |  | ||||||
|     chmod +x "$pkgdir/usr/share/$pkgname/run.sh" |  | ||||||
| 
 |  | ||||||
|     # Create a desktop entry for the application |  | ||||||
|     install -Dm644 /dev/stdin "$pkgdir/usr/share/applications/$pkgname.desktop" <<EOF |  | ||||||
| [Desktop Entry] |  | ||||||
| Name=Picodulce |  | ||||||
| Exec=/usr/share/picodulce/run.sh |  | ||||||
| Icon=/usr/share/picodulce/launcher_icon.ico |  | ||||||
| Terminal=true |  | ||||||
| Type=Application |  | ||||||
| Comment=Picodulce Launcher |  | ||||||
| Categories=Game; |  | ||||||
| EOF |  | ||||||
| 
 |  | ||||||
|     # Ensure the normal user has permission to write to the picodulce folder |  | ||||||
|     chown -R "$USER:$USER" "$pkgdir/usr/share/$pkgname" |  | ||||||
|     chmod -R u+w "$pkgdir/usr/share/$pkgname" |  | ||||||
| 
 |  | ||||||
|     #Install into bin |  | ||||||
|     install -Dm755 /dev/stdin "$pkgdir/usr/bin/picodulce" <<EOF |  | ||||||
| #!/bin/bash |  | ||||||
| cd /usr/share/picodulce/ |  | ||||||
| exec ./run.sh |  | ||||||
| EOF |  | ||||||
| } |  | ||||||
| # vim:set ts=2 sw=2 et: |  | ||||||
							
								
								
									
										92
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								README.md
									
									
									
									
									
								
							| @ -1,92 +0,0 @@ | |||||||
| <p align="center"> |  | ||||||
|   <img src="https://github.com/nixietab/picodulce/assets/75538775/36fee78f-fb46-400c-8b14-dda5ec6191ef" alt="launcher_icon"> |  | ||||||
| 
 |  | ||||||
| </p> |  | ||||||
| 
 |  | ||||||
| <h1 align="center">Picodulce Launcher</h1> |  | ||||||
| 
 |  | ||||||
| <p align="center">The simple FOSS launcher you been looking for</p> |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| <p align="center"> |  | ||||||
|   <a href="https://github.com/nixietab/picodulce/releases"> |  | ||||||
|     <img src="https://img.shields.io/github/v/release/nixietab/picodulce" alt="Latest Release"> |  | ||||||
|   </a> |  | ||||||
|   <a href="https://github.com/nixietab/picodulce/issues"> |  | ||||||
|     <img src="https://img.shields.io/github/issues/nixietab/picodulce" alt="Issues"> |  | ||||||
|   </a> |  | ||||||
|   <a href="https://github.com/nixietab/picodulce/pulls"> |  | ||||||
|     <img src="https://img.shields.io/github/issues-pr/nixietab/picodulce" alt="Pull Requests"> |  | ||||||
|   </a> |  | ||||||
|   <a href="https://github.com/nixietab/picodulce/blob/main/LICENSE"> |  | ||||||
|     <img src="https://img.shields.io/github/license/nixietab/picodulce" alt="License"> |  | ||||||
|   </a> |  | ||||||
|   <a href="https://github.com/nixietab/picodulce"> |  | ||||||
|     <img src="https://img.shields.io/github/stars/nixietab/picodulce?style=social" alt="GitHub Stars"> |  | ||||||
|   </a> |  | ||||||
| </p> |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   Picodulce is a feature-rich launcher for Minecraft, developed using Qt5. It serves as a graphical user interface (GUI) for the picomc project, providing users with a seamless experience in managing and launching game versions. |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|  |  | ||||||
| 
 |  | ||||||
| ## Key Features |  | ||||||
| 
 |  | ||||||
| - **Version Management**: Picodulce is designed to download and launch all available game versions, ensuring users have easy access to the latest updates as well as older versions. |  | ||||||
| - **Offline and Online Support**: Whether you're connected to Microsoft or not, Picodulce ensures you can still enjoy your game by supporting both offline and online modes. |  | ||||||
| - **Integrated Mod Manager**: Includes the [Marroc Mod Manager](https://github.com/nixietab/marroc), enabling users to effortlessly manage and customize their game with mods and texturepacks. |  | ||||||
| - **Custom Theme Support**: Create and apply personalized themes with ease. A dedicated repository and guide are [available to help you get started.](https://github.com/nixietab/picodulce-themes) |  | ||||||
| 
 |  | ||||||
| # Installation |  | ||||||
| 
 |  | ||||||
| ## Windows |  | ||||||
| For Windows systems using the [installer](https://github.com/nixietab/picodulce/releases/latest) is recommended |  | ||||||
| 
 |  | ||||||
| ## Arch Linux |  | ||||||
| The package is available in the [AUR](https://aur.archlinux.org/packages/picodulce) as ```picodulce``` |  | ||||||
| 
 |  | ||||||
| For installing on Arch without using an AUR helper a PKGBUILD is provided |  | ||||||
| ``` |  | ||||||
| git clone https://aur.archlinux.org/picodulce.git |  | ||||||
| cd picodulce |  | ||||||
| makepkg -si |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## Other OS |  | ||||||
| 
 |  | ||||||
| ### 1. Clone the repository |  | ||||||
| 
 |  | ||||||
| ``` git clone https://github.com/nixietab/picodulce ``` |  | ||||||
| 
 |  | ||||||
| ### 2. (Optional) Set Up a Virtual Environment |  | ||||||
| Setting up a virtual environment is recommended to avoid dependency conflicts. Picodulce relies on the path of the `picomc` project, and using a virtual environment helps prevent errors. |  | ||||||
| 
 |  | ||||||
| Create the virtual environment: |  | ||||||
| 
 |  | ||||||
| ``` python -m venv venv ``` |  | ||||||
| 
 |  | ||||||
| - **Linux/Mac:**   |  | ||||||
|   `source venv/bin/activate` |  | ||||||
| - **Windows:**   |  | ||||||
|   `.\\venv\\Scripts\\activate` |  | ||||||
|   |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ### Install requirements |  | ||||||
| 
 |  | ||||||
| Now on the venv you can install the requirements safely |  | ||||||
| 
 |  | ||||||
| ```pip install -r requirements.txt ``` |  | ||||||
| 
 |  | ||||||
| ### Running the launcher |  | ||||||
| 
 |  | ||||||
| On the venv run it as a normal python script |  | ||||||
| 
 |  | ||||||
| ```python picodulce.py``` |  | ||||||
| 
 |  | ||||||
| Just make sure you have Java installed for running the actual game |  | ||||||
| 
 |  | ||||||
| ### About the name |  | ||||||
| The name "Picodulce" comes from a popular Argentinian candy. This reflects the enjoyable and user-friendly experience that the launcher aims to provide, making game management straightforward and pleasant. |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								holiday.ico
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								holiday.ico
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 108 KiB | 
							
								
								
									
										156
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,156 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|  |     <meta name="description" content="Picodulce Launcher is a feature-rich Fully Open-Source Qt5-based Minecraft launcher."> | ||||||
|  |     <title>Picodulce Launcher - Simple FOSS Minecraft Launcher</title> | ||||||
|  |     <link rel="stylesheet" href="styles.css"> | ||||||
|  |     <link rel="icon" href="https://github.com/nixietab/picodulce/assets/75538775/36fee78f-fb46-400c-8b14-dda5ec6191ef" type="image/png"> | ||||||
|  |     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> | ||||||
|  |     <script> | ||||||
|  |         document.addEventListener('DOMContentLoaded', (event) => { | ||||||
|  |             document.querySelectorAll('.step h3').forEach(header => { | ||||||
|  |                 header.addEventListener('click', () => { | ||||||
|  |                     const content = header.nextElementSibling; | ||||||
|  |                     if (content.style.display === 'none' || content.style.display === '') { | ||||||
|  |                         content.style.display = 'block'; | ||||||
|  |                         content.classList.add('unfold'); | ||||||
|  |                     } else { | ||||||
|  |                         content.style.display = 'none'; | ||||||
|  |                         content.classList.remove('unfold'); | ||||||
|  |                     } | ||||||
|  |                     header.querySelector('i').classList.toggle('rotate'); | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     </script> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  |     <nav class="navbar"> | ||||||
|  |         <div class="nav-brand"> | ||||||
|  |             <img src="https://github.com/nixietab/picodulce/assets/75538775/36fee78f-fb46-400c-8b14-dda5ec6191ef" alt="Picodulce Logo" class="logo"> | ||||||
|  |             <span class="project-name">Picodulce</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="nav-links"> | ||||||
|  |             <a href="#features">Features</a> | ||||||
|  |             <a href="#installation">Installation</a> | ||||||
|  |             <a href="https://github.com/nixietab/picodulce-themes">Themes</a> | ||||||
|  |             <a href="https://github.com/nixietab/picodulce" class="github-link"> | ||||||
|  |                 <i class="fab fa-github"></i> GitHub | ||||||
|  |             </a> | ||||||
|  |         </div> | ||||||
|  |     </nav> | ||||||
|  | 
 | ||||||
|  |     <header id="home" class="hero"> | ||||||
|  |         <div class="hero-content"> | ||||||
|  |             <h1>Picodulce Launcher</h1> | ||||||
|  |             <p class="hero-subtitle">The simple FOSS launcher you've been looking for</p> | ||||||
|  |             <div class="stats"> | ||||||
|  |             </div> | ||||||
|  |             <div class="cta-buttons"> | ||||||
|  |                 <a href="https://github.com/nixietab/picodulce/releases/latest" class="cta-button primary">Download</a> | ||||||
|  |                 <a href="#installation" class="cta-button secondary">Installation Guide</a> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </header> | ||||||
|  | 
 | ||||||
|  |     <main> | ||||||
|  |         <section id="features" class="features"> | ||||||
|  |             <h2>Features</h2> | ||||||
|  |             <div class="feature-grid"> | ||||||
|  |                 <div class="feature-card"> | ||||||
|  |                     <i class="fas fa-gamepad"></i> | ||||||
|  |                     <h3>Version Management</h3> | ||||||
|  |                     <p>Download and launch all available game versions, from the latest updates to older versions.</p> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="feature-card"> | ||||||
|  |                     <i class="fas fa-users"></i> | ||||||
|  |                     <h3>Online & Offline Support</h3> | ||||||
|  |                     <p>Play with or without Microsoft connection - enjoy your game in both offline and online modes.</p> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="feature-card"> | ||||||
|  |                     <i class="fas fa-puzzle-piece"></i> | ||||||
|  |                     <h3>Mod Manager</h3> | ||||||
|  |                     <p>Built-in Marroc Mod Manager for effortless mod and texturepack management.</p> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="feature-card"> | ||||||
|  |                     <i class="fas fa-paint-brush"></i> | ||||||
|  |                     <h3>Custom Themes</h3> | ||||||
|  |                     <p>Create and apply your own personalized themes with our theming system.</p> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </section> | ||||||
|  | 
 | ||||||
|  |         <section id="installation" class="installation"> | ||||||
|  |             <h2>Installation</h2> | ||||||
|  |             <div class="installation-steps"> | ||||||
|  |                 <div class="step windows"> | ||||||
|  |                     <h3><i class="fas fa-angle-down"></i> <i class="fab fa-windows"></i> Windows</h3> | ||||||
|  |                     <div style="display: none;"> | ||||||
|  |                         <p>Download and run the installer from our latest release:</p> | ||||||
|  |                         <a href="https://github.com/nixietab/picodulce/releases/latest" class="install-button">Download Installer</a> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                  | ||||||
|  |                 <div class="step arch"> | ||||||
|  |                     <h3><i class="fas fa-angle-down"></i> <i class="fab fa-linux"></i> Arch Linux</h3> | ||||||
|  |                     <div style="display: none;"> | ||||||
|  |                         <p>Install from AUR:</p> | ||||||
|  |                         <pre><code>yay -S picodulce</code></pre> | ||||||
|  |                         <p>Or manually:</p> | ||||||
|  |                         <pre><code>git clone https://aur.archlinux.org/picodulce.git | ||||||
|  | cd picodulce | ||||||
|  | makepkg -si</code></pre> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  | 
 | ||||||
|  |                 <div class="step other"> | ||||||
|  |                     <h3><i class="fas fa-angle-down"></i> <i class="fas fa-code"></i> Any OS</h3> | ||||||
|  |                     <div style="display: none;"> | ||||||
|  |                         <pre><code># 1. Clone the repository | ||||||
|  | git clone https://github.com/nixietab/picodulce | ||||||
|  | 
 | ||||||
|  | # 2. Create virtual environment | ||||||
|  | python -m venv venv | ||||||
|  | 
 | ||||||
|  | # 3. Activate virtual environment | ||||||
|  | # Linux/Mac: | ||||||
|  | source venv/bin/activate | ||||||
|  | # Windows: | ||||||
|  | .\\venv\\Scripts\\activate | ||||||
|  | 
 | ||||||
|  | # 4. Install requirements | ||||||
|  | pip install -r requirements.txt | ||||||
|  | 
 | ||||||
|  | # 5. Run the launcher | ||||||
|  | python picodulce.py</code></pre> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </section> | ||||||
|  |     </main> | ||||||
|  | 
 | ||||||
|  |     <footer> | ||||||
|  |         <div class="footer-content"> | ||||||
|  |             <div class="footer-section"> | ||||||
|  |                 <h4>Resources</h4> | ||||||
|  |                 <a href="https://github.com/nixietab/picodulce-themes"><i class="fas fa-palette"></i> Themes Repository</a> | ||||||
|  |                 <a href="https://github.com/nixietab/marroc"><i class="fas fa-cube"></i> Marroc Mod Manager</a> | ||||||
|  |             </div> | ||||||
|  |             <div class="footer-section"> | ||||||
|  |                 <h4>Community</h4> | ||||||
|  |                 <a href="https://github.com/nixietab/picodulce/issues"><i class="fas fa-bug"></i> Report Issues</a> | ||||||
|  |                 <a href="https://github.com/nixietab/picodulce/pulls"><i class="fas fa-code-branch"></i> Contribute</a> | ||||||
|  |             </div> | ||||||
|  |             <div class="footer-section"> | ||||||
|  |                 <h4>About</h4> | ||||||
|  |                 <p class="about-text">Picodulce, named after a popular Argentinian candy, is a feature-rich Qt5-based Minecraft launcher providing a seamless gaming experience.</p> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="footer-bottom"> | ||||||
|  |             <p>© 2025 Picodulce Launcher. Licensed under GNU General Public License v2.0.</p> | ||||||
|  |         </div> | ||||||
|  |     </footer> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 5.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								marroc.ico
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								marroc.ico
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 7.2 KiB | 
							
								
								
									
										416
									
								
								marroc.py
									
									
									
									
									
								
							
							
						
						
									
										416
									
								
								marroc.py
									
									
									
									
									
								
							| @ -1,416 +0,0 @@ | |||||||
| import sys |  | ||||||
| import os |  | ||||||
| import shutil |  | ||||||
| import json |  | ||||||
| import threading |  | ||||||
| import requests |  | ||||||
| from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QListWidget, QListWidgetItem, QMessageBox, QComboBox, QDialog, QTabWidget, QMainWindow, QSpacerItem, QSizePolicy |  | ||||||
| from PyQt5.QtCore import Qt, QSize, QObject, pyqtSignal |  | ||||||
| from PyQt5.QtGui import QIcon, QPalette, QColor, QPixmap |  | ||||||
| 
 |  | ||||||
| CONFIG_FILE = "config.json" |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class IconLoader(QObject, threading.Thread): |  | ||||||
|     icon_loaded = pyqtSignal(QPixmap) |  | ||||||
| 
 |  | ||||||
|     def __init__(self, icon_url): |  | ||||||
|         super().__init__() |  | ||||||
|         threading.Thread.__init__(self) |  | ||||||
|         self.icon_url = icon_url |  | ||||||
| 
 |  | ||||||
|     def run(self): |  | ||||||
|         try: |  | ||||||
|             response = requests.get(self.icon_url) |  | ||||||
|             if response.status_code == 200: |  | ||||||
|                 pixmap = QPixmap() |  | ||||||
|                 pixmap.loadFromData(response.content) |  | ||||||
|                 self.icon_loaded.emit(pixmap.scaled(QSize(42, 42), Qt.KeepAspectRatio, Qt.SmoothTransformation)) |  | ||||||
|             else: |  | ||||||
|                 self.icon_loaded.emit(QPixmap("missing.png")) |  | ||||||
|         except Exception as e: |  | ||||||
|             print("Error loading icon:", e) |  | ||||||
|             self.icon_loaded.emit(QPixmap("missing.png")) |  | ||||||
| 
 |  | ||||||
| class ModrinthSearchApp(QWidget): |  | ||||||
|     def __init__(self): |  | ||||||
|         super().__init__() |  | ||||||
| 
 |  | ||||||
|         self.setWindowTitle("Marroc Mod Manager") |  | ||||||
|         self.setGeometry(100, 100, 500, 400) |  | ||||||
|         self.ensure_directories_exist() |  | ||||||
| 
 |  | ||||||
|         layout = QVBoxLayout() |  | ||||||
| 
 |  | ||||||
|         tab_widget = QTabWidget() |  | ||||||
|         self.search_tab = QWidget() |  | ||||||
|         self.mods_tab = QWidget() |  | ||||||
| 
 |  | ||||||
|         tab_widget.addTab(self.search_tab, "Search") |  | ||||||
|         tab_widget.addTab(self.mods_tab, "Manager") |  | ||||||
| 
 |  | ||||||
|         self.init_search_tab() |  | ||||||
|         self.init_mods_tab() |  | ||||||
| 
 |  | ||||||
|         layout.addWidget(tab_widget) |  | ||||||
| 
 |  | ||||||
|         self.setLayout(layout) |  | ||||||
| 
 |  | ||||||
|     def keyPressEvent(self, event): |  | ||||||
|         focus_widget = self.focusWidget() |  | ||||||
|         if event.key() == Qt.Key_Down: |  | ||||||
|             self.focusNextChild()  # Move focus to the next widget |  | ||||||
|         elif event.key() == Qt.Key_Up: |  | ||||||
|             self.focusPreviousChild()  # Move focus to the previous widget |  | ||||||
|         elif event.key() in [Qt.Key_Return, Qt.Key_Enter]: |  | ||||||
|             if isinstance(focus_widget, QPushButton): |  | ||||||
|                 focus_widget.click()  # Trigger the button click |  | ||||||
|             elif isinstance(focus_widget, QComboBox): |  | ||||||
|                 focus_widget.showPopup()  # Show dropdown for combo box |  | ||||||
|         else: |  | ||||||
|             super().keyPressEvent(event) |  | ||||||
| 
 |  | ||||||
|     def ensure_directories_exist(self): |  | ||||||
|         directories = ["marroc/mods", "marroc/resourcepacks"] |  | ||||||
|         for directory in directories: |  | ||||||
|             if not os.path.exists(directory): |  | ||||||
|                 os.makedirs(directory) |  | ||||||
| 
 |  | ||||||
|     def init_search_tab(self): |  | ||||||
|         layout = QVBoxLayout() |  | ||||||
| 
 |  | ||||||
|         search_layout = QHBoxLayout()   |  | ||||||
|         self.search_input = QLineEdit() |  | ||||||
|         self.search_input.setPlaceholderText("Enter a search term...") |  | ||||||
|         search_layout.addWidget(self.search_input) |  | ||||||
| 
 |  | ||||||
|         self.search_button = QPushButton("Search") |  | ||||||
|         self.search_button.clicked.connect(self.search_mods) |  | ||||||
|         search_layout.addWidget(self.search_button) |  | ||||||
| 
 |  | ||||||
|         self.search_type_dropdown = QComboBox()   |  | ||||||
|         self.search_type_dropdown.addItems(["Mod", "Texture Pack"]) |  | ||||||
|         search_layout.addWidget(self.search_type_dropdown) |  | ||||||
| 
 |  | ||||||
|         layout.addLayout(search_layout) |  | ||||||
| 
 |  | ||||||
|         self.mods_list = QListWidget() |  | ||||||
|         layout.addWidget(self.mods_list) |  | ||||||
| 
 |  | ||||||
|         self.select_button = QPushButton("Select") |  | ||||||
|         self.select_button.clicked.connect(self.show_mod_details_window) |  | ||||||
|         layout.addWidget(self.select_button) |  | ||||||
| 
 |  | ||||||
|         self.selected_mod = None |  | ||||||
| 
 |  | ||||||
|         self.search_tab.setLayout(layout) |  | ||||||
| 
 |  | ||||||
|     def init_mods_tab(self): |  | ||||||
|         layout = QVBoxLayout() |  | ||||||
|         self.mod_manager_window = ModManagerWindow()   |  | ||||||
|         layout.addWidget(self.mod_manager_window) |  | ||||||
|         self.mods_tab.setLayout(layout) |  | ||||||
| 
 |  | ||||||
|     def search_mods(self): |  | ||||||
|         self.mods_list.clear() |  | ||||||
|         mod_name = self.search_input.text() |  | ||||||
|         search_type = self.search_type_dropdown.currentText().lower()   |  | ||||||
|         if search_type == "texture pack": |  | ||||||
|             api_url = f"https://api.modrinth.com/v2/search?query={mod_name}&limit=20&facets=%5B%5B%22project_type%3Aresourcepack%22%5D%5D" |  | ||||||
|         else: |  | ||||||
|             api_url = f"https://api.modrinth.com/v2/search?query={mod_name}&limit=20&facets=%5B%5B%22project_type%3A{search_type}%22%5D%5D" |  | ||||||
|         response = requests.get(api_url) |  | ||||||
|         if response.status_code == 200: |  | ||||||
|             mods_data = json.loads(response.text) |  | ||||||
|             for mod in mods_data['hits']: |  | ||||||
|                 mod_name = mod['title'] |  | ||||||
|                 mod_description = mod['description'] |  | ||||||
|                 icon_url = mod['icon_url'] |  | ||||||
|                 item = QListWidgetItem(f"Title: {mod_name}\nDescription: {mod_description}") |  | ||||||
|                 item.setSizeHint(QSize(200, 50))   |  | ||||||
|                 icon_loader = IconLoader(icon_url) |  | ||||||
|                 icon_loader.icon_loaded.connect(lambda pixmap, item=item: self.set_item_icon(item, pixmap)) |  | ||||||
|                 icon_loader.start() |  | ||||||
|                 item.mod_data = mod |  | ||||||
|                 self.mods_list.addItem(item) |  | ||||||
|         else: |  | ||||||
|             self.mods_list.addItem("Failed to fetch mods. Please try again later.") |  | ||||||
| 
 |  | ||||||
|     def set_item_icon(self, item, pixmap): |  | ||||||
|         if pixmap: |  | ||||||
|             item.setData(Qt.DecorationRole, pixmap) |  | ||||||
|         else: |  | ||||||
|             # Set a default icon if loading failed |  | ||||||
|             item.setIcon(QIcon("missing.png")) |  | ||||||
| 
 |  | ||||||
|     def show_mod_details_window(self): |  | ||||||
|         selected_item = self.mods_list.currentItem() |  | ||||||
|         if selected_item is not None: |  | ||||||
|             mod_data = selected_item.mod_data |  | ||||||
|             mod_slug = mod_data.get('slug') |  | ||||||
|             if mod_slug: |  | ||||||
|                 api_url = f"https://api.modrinth.com/v2/project/{mod_slug}" |  | ||||||
|                 response = requests.get(api_url) |  | ||||||
|                 if response.status_code == 200: |  | ||||||
|                     mod_info = json.loads(response.text) |  | ||||||
|                     icon_url = mod_info.get('icon_url') |  | ||||||
|                     mod_versions = self.get_mod_versions(mod_slug) |  | ||||||
|                     mod_details_window = ModDetailsWindow(mod_data, icon_url, mod_versions) |  | ||||||
|                     mod_details_window.exec_() |  | ||||||
|                 else: |  | ||||||
|                     QMessageBox.warning(self, "Failed to Fetch Mod Details", "Failed to fetch mod details. Please try again later.") |  | ||||||
|             else: |  | ||||||
|                 QMessageBox.warning(self, "No Mod Slug", "Selected mod has no slug.") |  | ||||||
|         else: |  | ||||||
|             QMessageBox.warning(self, "No Mod Selected", "Please select a mod first.") |  | ||||||
| 
 |  | ||||||
|     def get_mod_versions(self, mod_slug): |  | ||||||
|         api_url = f"https://api.modrinth.com/v2/project/{mod_slug}/version" |  | ||||||
|         response = requests.get(api_url) |  | ||||||
|         if response.status_code == 200: |  | ||||||
|             versions = json.loads(response.text) |  | ||||||
|             mod_versions = [] |  | ||||||
|             for version in versions: |  | ||||||
|                 version_name = version['name'] |  | ||||||
|                 version_files = version.get('files', []) |  | ||||||
|                 if version_files: |  | ||||||
|                     file_urls = [file['url'] for file in version_files] |  | ||||||
|                     mod_versions.append({'version': version_name, 'files': file_urls}) |  | ||||||
|                 else: |  | ||||||
|                     mod_versions.append({'version': version_name, 'files': []}) |  | ||||||
|             return mod_versions |  | ||||||
|         else: |  | ||||||
|             return [] |  | ||||||
| 
 |  | ||||||
| class ModManagerWindow(QMainWindow): |  | ||||||
|     def __init__(self): |  | ||||||
|         super().__init__() |  | ||||||
|         self.setWindowTitle("Mod Manager") |  | ||||||
|         self.setGeometry(100, 100, 600, 400) |  | ||||||
| 
 |  | ||||||
|         self.central_widget = QWidget() |  | ||||||
|         self.setCentralWidget(self.central_widget) |  | ||||||
| 
 |  | ||||||
|         self.layout = QHBoxLayout(self.central_widget) |  | ||||||
| 
 |  | ||||||
|         self.file_type_combo_box = QComboBox() |  | ||||||
|         self.file_type_combo_box.addItems(["Mods", "Resource Packs"]) |  | ||||||
|         self.file_type_combo_box.currentIndexChanged.connect(self.load_files) |  | ||||||
| 
 |  | ||||||
|         self.available_files_widget = QListWidget() |  | ||||||
| 
 |  | ||||||
|         self.installed_files_widget = QListWidget() |  | ||||||
| 
 |  | ||||||
|         self.button_dropdown_layout = QVBoxLayout() |  | ||||||
|         self.button_dropdown_layout.addWidget(self.file_type_combo_box) |  | ||||||
|         self.button_dropdown_layout.addSpacerItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) |  | ||||||
|         self.move_right_button = QPushButton(">") |  | ||||||
|         self.move_right_button.clicked.connect(self.move_right) |  | ||||||
|         self.button_dropdown_layout.addWidget(self.move_right_button) |  | ||||||
|         self.move_left_button = QPushButton("<") |  | ||||||
|         self.move_left_button.clicked.connect(self.move_left) |  | ||||||
|         self.button_dropdown_layout.addWidget(self.move_left_button) |  | ||||||
|         self.delete_button = QPushButton("Delete") |  | ||||||
|         self.delete_button.clicked.connect(self.delete_selected_item) |  | ||||||
|         self.button_dropdown_layout.addWidget(self.delete_button) |  | ||||||
|         self.button_dropdown_layout.addSpacerItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) |  | ||||||
| 
 |  | ||||||
|         self.layout.addWidget(self.available_files_widget) |  | ||||||
|         self.layout.addLayout(self.button_dropdown_layout) |  | ||||||
|         self.layout.addWidget(self.installed_files_widget) |  | ||||||
| 
 |  | ||||||
|         self.load_files() |  | ||||||
| 
 |  | ||||||
|     def load_files(self): |  | ||||||
|         file_type = self.file_type_combo_box.currentText() |  | ||||||
|         if file_type == "Mods": |  | ||||||
|             self.load_mods() |  | ||||||
|         elif file_type == "Resource Packs": |  | ||||||
|             self.load_resource_packs() |  | ||||||
| 
 |  | ||||||
|     def load_mods(self): |  | ||||||
|         mods_directory = "marroc/mods" |  | ||||||
|         if os.path.exists(mods_directory) and os.path.isdir(mods_directory): |  | ||||||
|             mods = os.listdir(mods_directory) |  | ||||||
|             self.available_files_widget.clear() |  | ||||||
|             self.available_files_widget.addItems(mods) |  | ||||||
|         self.load_installed_mods("mods") |  | ||||||
| 
 |  | ||||||
|     def load_resource_packs(self): |  | ||||||
|         resource_packs_directory = "marroc/resourcepacks" |  | ||||||
|         if os.path.exists(resource_packs_directory) and os.path.isdir(resource_packs_directory): |  | ||||||
|             resource_packs = os.listdir(resource_packs_directory) |  | ||||||
|             self.available_files_widget.clear() |  | ||||||
|             self.available_files_widget.addItems(resource_packs) |  | ||||||
|         self.load_installed_mods("resourcepacks") |  | ||||||
| 
 |  | ||||||
|     def load_installed_mods(self, file_type): |  | ||||||
|         if sys.platform.startswith('linux'): |  | ||||||
|             minecraft_directory = os.path.expanduser("~/.local/share/picomc/instances/default/minecraft") |  | ||||||
|         elif sys.platform.startswith('win'): |  | ||||||
|             minecraft_directory = os.path.join(os.getenv('APPDATA'), '.picomc/instances/default/minecraft') |  | ||||||
|         else: |  | ||||||
|             minecraft_directory = "" |  | ||||||
|         if minecraft_directory: |  | ||||||
|             installed_files_directory = os.path.join(minecraft_directory, file_type) |  | ||||||
|             if os.path.exists(installed_files_directory) and os.path.isdir(installed_files_directory): |  | ||||||
|                 installed_files = os.listdir(installed_files_directory) |  | ||||||
|                 self.installed_files_widget.clear() |  | ||||||
|                 self.installed_files_widget.addItems(installed_files) |  | ||||||
| 
 |  | ||||||
|     def move_right(self): |  | ||||||
|         selected_item = self.available_files_widget.currentItem() |  | ||||||
|         if selected_item: |  | ||||||
|             source_directory = self.get_source_directory() |  | ||||||
|             destination_directory = self.get_destination_directory() |  | ||||||
|             file_name = selected_item.text() |  | ||||||
|             source_path = os.path.join(source_directory, file_name) |  | ||||||
|             destination_path = os.path.join(destination_directory, file_name) |  | ||||||
|             shutil.move(source_path, destination_path) |  | ||||||
|             self.load_files() |  | ||||||
| 
 |  | ||||||
|     def move_left(self): |  | ||||||
|         selected_item = self.installed_files_widget.currentItem() |  | ||||||
|         if selected_item: |  | ||||||
|             source_directory = self.get_destination_directory() |  | ||||||
|             destination_directory = self.get_source_directory() |  | ||||||
|             file_name = selected_item.text() |  | ||||||
|             source_path = os.path.join(source_directory, file_name) |  | ||||||
|             destination_path = os.path.join(destination_directory, file_name) |  | ||||||
|             shutil.move(source_path, destination_path) |  | ||||||
|             self.load_files() |  | ||||||
| 
 |  | ||||||
|     def delete_selected_item(self): |  | ||||||
|         selected_item = self.available_files_widget.currentItem() or self.installed_files_widget.currentItem() |  | ||||||
|         if selected_item: |  | ||||||
|             file_name = selected_item.text() |  | ||||||
|             reply = QMessageBox.question(self, 'Delete Item', f'Are you sure you want to delete "{file_name}"?', |  | ||||||
|                                          QMessageBox.Yes | QMessageBox.No, QMessageBox.No) |  | ||||||
|             if reply == QMessageBox.Yes: |  | ||||||
|                 file_type = self.file_type_combo_box.currentText() |  | ||||||
|                 if file_type == "Mods": |  | ||||||
|                     directory = "marroc/mods" |  | ||||||
|                 elif file_type == "Resource Packs": |  | ||||||
|                     directory = "marroc/resourcepacks" |  | ||||||
|                 else: |  | ||||||
|                     return |  | ||||||
|                 file_path = os.path.join(directory, file_name) |  | ||||||
|                 if os.path.exists(file_path): |  | ||||||
|                     os.remove(file_path) |  | ||||||
|                     self.load_files() |  | ||||||
|                 else: |  | ||||||
|                     QMessageBox.warning(self, 'File Not Found', 'The selected file does not exist.') |  | ||||||
| 
 |  | ||||||
|     def get_source_directory(self): |  | ||||||
|         file_type = self.file_type_combo_box.currentText() |  | ||||||
|         if file_type == "Mods": |  | ||||||
|             return "marroc/mods" |  | ||||||
|         elif file_type == "Resource Packs": |  | ||||||
|             return "marroc/resourcepacks" |  | ||||||
|         else: |  | ||||||
|             return "" |  | ||||||
| 
 |  | ||||||
|     def get_destination_directory(self): |  | ||||||
|         file_type = self.file_type_combo_box.currentText() |  | ||||||
|         if file_type == "Mods": |  | ||||||
|             if sys.platform.startswith('linux'): |  | ||||||
|                 return os.path.expanduser("~/.local/share/picomc/instances/default/minecraft/mods") |  | ||||||
|             elif sys.platform.startswith('win'): |  | ||||||
|                 return os.path.join(os.getenv('APPDATA'), '.picomc/instances/default/minecraft/mods') |  | ||||||
|         elif file_type == "Resource Packs": |  | ||||||
|             if sys.platform.startswith('linux'): |  | ||||||
|                 return os.path.expanduser("~/.local/share/picomc/instances/default/minecraft/resourcepacks") |  | ||||||
|             elif sys.platform.startswith('win'): |  | ||||||
|                 return os.path.join(os.getenv('APPDATA'), '.picomc/instances/default/minecraft/resourcepacks') |  | ||||||
|         else: |  | ||||||
|             return "" |  | ||||||
| 
 |  | ||||||
| class ModDetailsWindow(QDialog): |  | ||||||
|     def __init__(self, mod_data, icon_url, mod_versions): |  | ||||||
|         super().__init__() |  | ||||||
| 
 |  | ||||||
|         self.setWindowTitle("Mod Details") |  | ||||||
|         self.setGeometry(100, 100, 400, 300) |  | ||||||
| 
 |  | ||||||
|         self.mod_data = mod_data   |  | ||||||
| 
 |  | ||||||
|         layout = QVBoxLayout() |  | ||||||
| 
 |  | ||||||
|         mod_name_label = QLabel(f"<h2>{mod_data['title']}</h2>") |  | ||||||
|         mod_name_label.setAlignment(Qt.AlignCenter) |  | ||||||
|         layout.addWidget(mod_name_label) |  | ||||||
| 
 |  | ||||||
|         mod_description_label = QLabel(mod_data['description']) |  | ||||||
|         mod_description_label.setWordWrap(True) |  | ||||||
|         layout.addWidget(mod_description_label) |  | ||||||
| 
 |  | ||||||
|         icon_pixmap = self.load_icon(icon_url) |  | ||||||
|         icon_label = QLabel() |  | ||||||
|         if icon_pixmap: |  | ||||||
|             icon_label.setPixmap(icon_pixmap) |  | ||||||
|             icon_label.setAlignment(Qt.AlignCenter) |  | ||||||
|             layout.addWidget(icon_label) |  | ||||||
| 
 |  | ||||||
|         self.version_dropdown = QComboBox() |  | ||||||
|         for version in mod_versions: |  | ||||||
|             self.version_dropdown.addItem(version['version']) |  | ||||||
|             self.version_dropdown.setItemData(self.version_dropdown.count() - 1, version['files'], Qt.UserRole) |  | ||||||
|         layout.addWidget(self.version_dropdown) |  | ||||||
| 
 |  | ||||||
|         self.download_button = QPushButton("Download") |  | ||||||
|         self.download_button.clicked.connect(self.download_mod) |  | ||||||
|         layout.addWidget(self.download_button) |  | ||||||
| 
 |  | ||||||
|         self.download_url_label = QLabel() |  | ||||||
|         self.download_url_label.setAlignment(Qt.AlignCenter) |  | ||||||
|         layout.addWidget(self.download_url_label) |  | ||||||
| 
 |  | ||||||
|         layout.addStretch(1) |  | ||||||
| 
 |  | ||||||
|         self.setLayout(layout) |  | ||||||
| 
 |  | ||||||
|     def load_icon(self, icon_url): |  | ||||||
|         try: |  | ||||||
|             response = requests.get(icon_url) |  | ||||||
|             if response.status_code == 200: |  | ||||||
|                 pixmap = QPixmap() |  | ||||||
|                 pixmap.loadFromData(response.content) |  | ||||||
|                 return pixmap.scaled(QSize(128, 128), Qt.KeepAspectRatio, Qt.SmoothTransformation) |  | ||||||
|             else: |  | ||||||
|                 return None |  | ||||||
|         except Exception as e: |  | ||||||
|             print("Error loading icon:", e) |  | ||||||
|             return None |  | ||||||
| 
 |  | ||||||
|     def download_mod(self): |  | ||||||
|         selected_version_index = self.version_dropdown.currentIndex() |  | ||||||
|         selected_version_files = self.version_dropdown.itemData(selected_version_index, Qt.UserRole) |  | ||||||
|         if selected_version_files: |  | ||||||
|             for file_url in selected_version_files: |  | ||||||
|                 filename = os.path.basename(file_url) |  | ||||||
|                 try: |  | ||||||
|                     response = requests.get(file_url) |  | ||||||
|                     response.raise_for_status() |  | ||||||
|                     save_dir = "marroc/mods" if filename.endswith('.jar') else "marroc/resourcepacks" |  | ||||||
|                     with open(os.path.join(save_dir, filename), 'wb') as f: |  | ||||||
|                         f.write(response.content) |  | ||||||
|                     QMessageBox.information(self, "Download Mod", f"Downloaded {filename} successfully.") |  | ||||||
|                     return |  | ||||||
|                 except requests.exceptions.RequestException as e: |  | ||||||
|                     QMessageBox.warning(self, "Download Error", f"Error downloading mod: {e}") |  | ||||||
|                     return |  | ||||||
|         QMessageBox.warning(self, "Download Mod", "Failed to download the mod.") |  | ||||||
| 
 |  | ||||||
| if __name__ == "__main__": |  | ||||||
|     app = QApplication(sys.argv) |  | ||||||
|     app_icon = QIcon('marroc.ico')   |  | ||||||
|     app.setWindowIcon(app_icon)   |  | ||||||
|     window = ModrinthSearchApp() |  | ||||||
|     window.show() |  | ||||||
|     sys.exit(app.exec_()) |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								minetest.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								minetest.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.2 MiB | 
							
								
								
									
										
											BIN
										
									
								
								missing.png
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								missing.png
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 330 B | 
							
								
								
									
										1785
									
								
								picodulce.py
									
									
									
									
									
								
							
							
						
						
									
										1785
									
								
								picodulce.py
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,4 +0,0 @@ | |||||||
| picomc |  | ||||||
| PyQt5 |  | ||||||
| requests |  | ||||||
| pypresence |  | ||||||
							
								
								
									
										341
									
								
								styles.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								styles.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,341 @@ | |||||||
|  | :root { | ||||||
|  |     --primary-color: #111314; | ||||||
|  |     --secondary-color: #4bb679; | ||||||
|  |     --accent-color: #4bb679; | ||||||
|  |     --background-color: #141d26; | ||||||
|  |     --text-color: #ecf0f1; | ||||||
|  |     --card-background: #0f1214; | ||||||
|  |     --feature-hover: #4bb679; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | * { | ||||||
|  |     margin: 0; | ||||||
|  |     padding: 0; | ||||||
|  |     box-sizing: border-box; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | body { | ||||||
|  |     font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | ||||||
|  |     line-height: 1.6; | ||||||
|  |     color: var(--text-color); | ||||||
|  |     background-color: var(--background-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Navbar Styles */ | ||||||
|  | .navbar { | ||||||
|  |     background-color: var(--primary-color); | ||||||
|  |     padding: 0.8rem 2rem; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: space-between; | ||||||
|  |     align-items: center; | ||||||
|  |     position: fixed; | ||||||
|  |     width: 100%; | ||||||
|  |     top: 0; | ||||||
|  |     z-index: 1000; | ||||||
|  |     box-shadow: 0 2px 5px rgba(0,0,0,0.1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .nav-brand { | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     gap: 1rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .logo { | ||||||
|  |     width: 32px; | ||||||
|  |     height: 32px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .project-name { | ||||||
|  |     color: white; | ||||||
|  |     font-size: 1.3rem; | ||||||
|  |     font-weight: bold; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .nav-links { | ||||||
|  |     display: flex; | ||||||
|  |     gap: 2rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .nav-links a { | ||||||
|  |     color: white; | ||||||
|  |     text-decoration: none; | ||||||
|  |     transition: color 0.3s ease; | ||||||
|  |     font-weight: 500; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .nav-links a:hover { | ||||||
|  |     color: var(--secondary-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Hero Section */ | ||||||
|  | .hero { | ||||||
|  |     position: relative; | ||||||
|  |     background: linear-gradient(rgba(17, 19, 20, 0.1), rgba(17, 19, 20, 0.9)), | ||||||
|  |                 url('minetest.png') center/cover; | ||||||
|  |     height: 100vh; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     justify-content: center; | ||||||
|  |     text-align: center; | ||||||
|  |     color: white; | ||||||
|  |     padding: 2rem; | ||||||
|  |     margin-top: 0; | ||||||
|  |     overflow: hidden; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .hero-content { | ||||||
|  |     max-width: 800px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .hero-content h1 { | ||||||
|  |     font-size: 4rem; | ||||||
|  |     margin-bottom: 1rem; | ||||||
|  |     text-shadow: 2px 2px 4px rgba(0,0,0,0.7); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .hero-subtitle { | ||||||
|  |     font-size: 1.5rem; | ||||||
|  |     margin-bottom: 2rem; | ||||||
|  |     opacity: 0.9; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .stats { | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  |     gap: 2rem; | ||||||
|  |     margin-bottom: 2rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .stats span { | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     gap: 0.5rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .cta-buttons { | ||||||
|  |     display: flex; | ||||||
|  |     gap: 1rem; | ||||||
|  |     justify-content: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .cta-button { | ||||||
|  |     padding: 1rem 2rem; | ||||||
|  |     border-radius: 5px; | ||||||
|  |     text-decoration: none; | ||||||
|  |     font-weight: bold; | ||||||
|  |     transition: all 0.3s ease; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .cta-button:hover { | ||||||
|  |     transform: translateY(-2px); | ||||||
|  |     box-shadow: 0 4px 8px rgba(0,0,0,0.2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .primary { | ||||||
|  |     background-color: var(--secondary-color); | ||||||
|  |     color: white; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .secondary { | ||||||
|  |     background-color: transparent; | ||||||
|  |     border: 2px solid white; | ||||||
|  |     color: white; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Features Section */ | ||||||
|  | .features { | ||||||
|  |     padding: 5rem 2rem; | ||||||
|  |     background-color: var(--card-background); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .features h2 { | ||||||
|  |     text-align: center; | ||||||
|  |     margin-bottom: 3rem; | ||||||
|  |     font-size: 2.5rem; | ||||||
|  |     color: var(--text-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .feature-grid { | ||||||
|  |     display: grid; | ||||||
|  |     grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | ||||||
|  |     gap: 2rem; | ||||||
|  |     max-width: 1200px; | ||||||
|  |     margin: 0 auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .feature-card { | ||||||
|  |     padding: 2rem; | ||||||
|  |     text-align: center; | ||||||
|  |     background-color: var(--background-color); | ||||||
|  |     border-radius: 10px; | ||||||
|  |     transition: all 0.3s ease; | ||||||
|  |     cursor: pointer; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .feature-card:hover { | ||||||
|  |     transform: translateY(-5px); | ||||||
|  |     background-color: var(--feature-hover); | ||||||
|  |     color: white; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .feature-card:hover i { | ||||||
|  |     color: white; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .feature-card i { | ||||||
|  |     font-size: 2.5rem; | ||||||
|  |     color: var(--secondary-color); | ||||||
|  |     margin-bottom: 1rem; | ||||||
|  |     transition: color 0.3s ease; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Installation Section */ | ||||||
|  | .installation { | ||||||
|  |     padding: 5rem 2rem; | ||||||
|  |     background-color: var(--background-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .installation h2 { | ||||||
|  |     text-align: center; | ||||||
|  |     margin-bottom: 3rem; | ||||||
|  |     font-size: 2.5rem; | ||||||
|  |     color: var(--text-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .installation-steps { | ||||||
|  |     max-width: 800px; | ||||||
|  |     margin: 0 auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .step { | ||||||
|  |     background-color: var(--card-background); | ||||||
|  |     padding: 2rem; | ||||||
|  |     margin-bottom: 2rem; | ||||||
|  |     border-radius: 10px; | ||||||
|  |     box-shadow: 0 2px 5px rgba(0,0,0,0.1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .step h3 { | ||||||
|  |     color: var(--text-color); | ||||||
|  |     margin-bottom: 1rem; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     gap: 0.5rem; | ||||||
|  |     cursor: pointer; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .step h3 i.fas.fa-angle-down { | ||||||
|  |     transition: transform 0.3s ease; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .step h3 i.fas.fa-angle-down.rotate { | ||||||
|  |     transform: rotate(180deg); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .step div { | ||||||
|  |     display: none; | ||||||
|  |     overflow: hidden; | ||||||
|  |     transition: max-height 0.5s ease, opacity 0.5s ease; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .step div.unfold { | ||||||
|  |     display: block; | ||||||
|  |     max-height: 1000px; | ||||||
|  |     opacity: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .install-button { | ||||||
|  |     display: inline-block; | ||||||
|  |     padding: 0.8rem 1.5rem; | ||||||
|  |     background-color: var(--secondary-color); | ||||||
|  |     color: white; | ||||||
|  |     text-decoration: none; | ||||||
|  |     border-radius: 5px; | ||||||
|  |     margin-top: 1rem; | ||||||
|  |     transition: all 0.3s ease; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .install-button:hover { | ||||||
|  |     background-color: var(--feature-hover); | ||||||
|  |     transform: translateY(-2px); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pre { | ||||||
|  |     background-color: #1f2a35; | ||||||
|  |     padding: 1rem; | ||||||
|  |     border-radius: 5px; | ||||||
|  |     overflow-x: auto; | ||||||
|  |     margin: 1rem 0; | ||||||
|  |     border: 1px solid #141d26; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | code { | ||||||
|  |     font-family: 'Consolas', 'Monaco', monospace; | ||||||
|  |     font-size: 0.9rem; | ||||||
|  |     color: #ecf0f1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Footer Styles */ | ||||||
|  | footer { | ||||||
|  |     background-color: var(--primary-color); | ||||||
|  |     color: white; | ||||||
|  |     padding: 4rem 2rem 2rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .footer-content { | ||||||
|  |     display: grid; | ||||||
|  |     grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | ||||||
|  |     gap: 2rem; | ||||||
|  |     max-width: 1200px; | ||||||
|  |     margin: 0 auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .footer-section h4 { | ||||||
|  |     margin-bottom: 1rem; | ||||||
|  |     color: var (--secondary-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .footer-section a { | ||||||
|  |     display: block; | ||||||
|  |     color: white; | ||||||
|  |     text-decoration: none; | ||||||
|  |     margin-bottom: 0.5rem; | ||||||
|  |     opacity: 0.8; | ||||||
|  |     transition: opacity 0.3s ease; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .footer-section a i { | ||||||
|  |     margin-right: 0.5rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .footer-section a:hover { | ||||||
|  |     opacity: 1; | ||||||
|  |     color: var(--secondary-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .about-text { | ||||||
|  |     opacity: 0.8; | ||||||
|  |     font-size: 0.9rem; | ||||||
|  |     line-height: 1.6; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .footer-bottom { | ||||||
|  |     text-align: center; | ||||||
|  |     margin-top: 3rem; | ||||||
|  |     padding-top: 2rem; | ||||||
|  |     border-top: 1px solid rgba(255, 255, 255, 0.1); | ||||||
|  |     opacity: 0.8; | ||||||
|  |     font-size: 0.9rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Responsive Design */ | ||||||
|  | @media (max-width: 768px) { | ||||||
|  |     .nav-links { | ||||||
|  |         display: none; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     .hero-content h1 { | ||||||
|  |         font-size: 3rem; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								version.json
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								version.json
									
									
									
									
									
								
							| @ -1,11 +0,0 @@ | |||||||
| { |  | ||||||
|   "version": "0.11.8", |  | ||||||
|   "links": [ |  | ||||||
|     "https://raw.githubusercontent.com/nixietab/picodulce/main/version.json", |  | ||||||
|     "https://raw.githubusercontent.com/nixietab/picodulce/main/picodulce.py", |  | ||||||
|     "https://raw.githubusercontent.com/nixietab/picodulce/main/requirements.txt", |  | ||||||
|     "https://raw.githubusercontent.com/nixietab/picodulce/main/drums.gif", |  | ||||||
|     "https://raw.githubusercontent.com/nixietab/picodulce/main/marroc.py", |  | ||||||
|     "https://raw.githubusercontent.com/nixietab/picodulce/main/holiday.ico" |  | ||||||
|   ] |  | ||||||
| } |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user