mirror of
				https://github.com/nixietab/picodulce.git
				synced 2025-10-30 21:15:11 +00:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "6816d9e47aa2b3b15f41bc40d33179d849978056" and "7608b647fe8ba79b90f93203616f138af2c9fd5d" have entirely different histories.
		
	
	
		
			6816d9e47a
			...
			7608b647fe
		
	
		
							
								
								
									
										67
									
								
								.github/workflows/Build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								.github/workflows/Build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | |||||||
|  | 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
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,339 @@ | |||||||
|  |                     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
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								PKGBUILD
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | |||||||
|  | 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
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | |||||||
|  | <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
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								holiday.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 108 KiB | 
							
								
								
									
										156
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										156
									
								
								index.html
									
									
									
									
									
								
							| @ -1,156 +0,0 @@ | |||||||
| <!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> |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								launcher_icon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								launcher_icon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								marroc.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								marroc.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 7.2 KiB | 
							
								
								
									
										416
									
								
								marroc.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										416
									
								
								marroc.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,416 @@ | |||||||
|  | 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
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								minetest.png
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 1.2 MiB | 
							
								
								
									
										
											BIN
										
									
								
								missing.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								missing.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 330 B | 
							
								
								
									
										1785
									
								
								picodulce.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1785
									
								
								picodulce.py
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | picomc | ||||||
|  | PyQt5 | ||||||
|  | requests | ||||||
|  | pypresence | ||||||
							
								
								
									
										341
									
								
								styles.css
									
									
									
									
									
								
							
							
						
						
									
										341
									
								
								styles.css
									
									
									
									
									
								
							| @ -1,341 +0,0 @@ | |||||||
| :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
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								version.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | { | ||||||
|  |   "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