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