diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..bc48256
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,11 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "pip" # See documentation for possible values
+ directory: "/" # Location of package manifests
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 0000000..56f1639
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,25 @@
+name: Lint
+
+on: workflow_call
+
+permissions:
+ contents: read
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.11"
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install flake8
+
+ - name: Run linters
+ run: flake8 .
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..bebcf98
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,24 @@
+name: Main branch pipeline
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+permissions:
+ actions: read
+ contents: write
+ id-token: write
+
+concurrency:
+ group: ci-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ tests:
+ uses: ./.github/workflows/tests.yml
+ secrets: inherit
+ lint:
+ uses: ./.github/workflows/lint.yml
+ secrets: inherit
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..aebf8e8
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,54 @@
+# .github/workflows/release.yml
+name: Release
+
+on:
+ push:
+ branches: [main]
+
+permissions:
+ contents: write
+
+jobs:
+ build-release:
+ name: Build artifacts
+ runs-on: ubuntu-latest
+ container:
+ image: docker.io/batonogov/pyinstaller-linux:latest
+ env:
+ SS_DEV_ID: ${{ secrets.SS_DEV_ID }}
+ SS_DEV_PASSWORD: ${{ secrets.SS_DEV_PASSWORD }}
+ steps:
+ - name: Check out the repo
+ uses: actions/checkout@v2
+
+ - name: Build package
+ run: |
+ echo "Creating Linux artifact"
+ apt-get update && apt-get install -y zip
+ pip install -r ./requirements.txt
+ pyinstaller --onefile ./src/app.py
+ zip -r Artie.zip ./src/dist/app assets ./config.json ./launch.sh
+ cp Artie.zip ./src/Artie.zip
+
+ publish-release:
+ name: Publish Artie.zip
+ runs-on: ubuntu-latest
+ needs: build-release
+ steps:
+ - name: Check out the repo
+ uses: actions/checkout@v2
+
+ - name: Upload Artie.zip
+ uses: actions/upload-artifact@v3
+ with:
+ name: Artie
+ path: ./src/Artie.zip
+
+ - name: Create GitHub Release
+ uses: softprops/action-gh-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ files: ./src/Artie.zip
+ tag_name: ${{ github.ref }}
+ release_name: Release ${{ github.ref }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0a11d13
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+__pycache__
+roms
+dist
+build
+app.spec
+.DS_Store
+build.sh
diff --git a/Artie Scraper.sh b/Artie Scraper.sh
new file mode 100644
index 0000000..cac4308
--- /dev/null
+++ b/Artie Scraper.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+progdir=$(
+ cd $(dirname "$0")
+ pwd
+)
+
+program=./${progdir}/.artie/artie
+log_file="${progdir}/artie/log.txt"
+
+$program >"$log_file" 2>&1
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 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
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ 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 3 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, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU 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. But first, please read
+.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5794cd9
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# Artie
diff --git a/assets/Roboto-BoldCondensed.ttf b/assets/Roboto-BoldCondensed.ttf
new file mode 100644
index 0000000..d7ea883
Binary files /dev/null and b/assets/Roboto-BoldCondensed.ttf differ
diff --git a/assets/Roboto-Condensed.ttf b/assets/Roboto-Condensed.ttf
new file mode 100644
index 0000000..6e7575a
Binary files /dev/null and b/assets/Roboto-Condensed.ttf differ
diff --git a/assets/artie.png b/assets/artie.png
new file mode 100644
index 0000000..c5b0add
Binary files /dev/null and b/assets/artie.png differ
diff --git a/assets/bg.bmp b/assets/bg.bmp
new file mode 100644
index 0000000..5273ce4
Binary files /dev/null and b/assets/bg.bmp differ
diff --git a/assets/bg_overlay.bmp b/assets/bg_overlay.bmp
new file mode 100644
index 0000000..538db8a
Binary files /dev/null and b/assets/bg_overlay.bmp differ
diff --git a/assets/logos/3DS.png b/assets/logos/3DS.png
new file mode 100644
index 0000000..3e64736
Binary files /dev/null and b/assets/logos/3DS.png differ
diff --git a/assets/logos/64DD.png b/assets/logos/64DD.png
new file mode 100644
index 0000000..e4b55f5
Binary files /dev/null and b/assets/logos/64DD.png differ
diff --git a/assets/logos/ADAM.png b/assets/logos/ADAM.png
new file mode 100644
index 0000000..c3d8642
Binary files /dev/null and b/assets/logos/ADAM.png differ
diff --git a/assets/logos/ADVISION.png b/assets/logos/ADVISION.png
new file mode 100644
index 0000000..62803d3
Binary files /dev/null and b/assets/logos/ADVISION.png differ
diff --git a/assets/logos/ALPHADENSHI.png b/assets/logos/ALPHADENSHI.png
new file mode 100644
index 0000000..2d7c1bc
Binary files /dev/null and b/assets/logos/ALPHADENSHI.png differ
diff --git a/assets/logos/AMIGA.png b/assets/logos/AMIGA.png
new file mode 100644
index 0000000..44bf59a
Binary files /dev/null and b/assets/logos/AMIGA.png differ
diff --git a/assets/logos/AMIGA1000.png b/assets/logos/AMIGA1000.png
new file mode 100644
index 0000000..416617a
Binary files /dev/null and b/assets/logos/AMIGA1000.png differ
diff --git a/assets/logos/AMIGA1200.png b/assets/logos/AMIGA1200.png
new file mode 100644
index 0000000..9983072
Binary files /dev/null and b/assets/logos/AMIGA1200.png differ
diff --git a/assets/logos/AMIGA3000.png b/assets/logos/AMIGA3000.png
new file mode 100644
index 0000000..5f5bcb4
Binary files /dev/null and b/assets/logos/AMIGA3000.png differ
diff --git a/assets/logos/AMIGA4000.png b/assets/logos/AMIGA4000.png
new file mode 100644
index 0000000..8f87871
Binary files /dev/null and b/assets/logos/AMIGA4000.png differ
diff --git a/assets/logos/AMIGA500.png b/assets/logos/AMIGA500.png
new file mode 100644
index 0000000..d9ae547
Binary files /dev/null and b/assets/logos/AMIGA500.png differ
diff --git a/assets/logos/AMIGA500P.png b/assets/logos/AMIGA500P.png
new file mode 100644
index 0000000..4507fda
Binary files /dev/null and b/assets/logos/AMIGA500P.png differ
diff --git a/assets/logos/AMIGA600.png b/assets/logos/AMIGA600.png
new file mode 100644
index 0000000..7e283df
Binary files /dev/null and b/assets/logos/AMIGA600.png differ
diff --git a/assets/logos/AMIGACD.png b/assets/logos/AMIGACD.png
new file mode 100644
index 0000000..ad667f5
Binary files /dev/null and b/assets/logos/AMIGACD.png differ
diff --git a/assets/logos/AMIGACDTV.png b/assets/logos/AMIGACDTV.png
new file mode 100644
index 0000000..6035edd
Binary files /dev/null and b/assets/logos/AMIGACDTV.png differ
diff --git a/assets/logos/AMSTRADGX4000.png b/assets/logos/AMSTRADGX4000.png
new file mode 100644
index 0000000..1a47043
Binary files /dev/null and b/assets/logos/AMSTRADGX4000.png differ
diff --git a/assets/logos/APFM1000.png b/assets/logos/APFM1000.png
new file mode 100644
index 0000000..2d1c223
Binary files /dev/null and b/assets/logos/APFM1000.png differ
diff --git a/assets/logos/APPLE2.png b/assets/logos/APPLE2.png
new file mode 100644
index 0000000..925aa11
Binary files /dev/null and b/assets/logos/APPLE2.png differ
diff --git a/assets/logos/APPLE2GS.png b/assets/logos/APPLE2GS.png
new file mode 100644
index 0000000..d4e6878
Binary files /dev/null and b/assets/logos/APPLE2GS.png differ
diff --git a/assets/logos/ARCADE.png b/assets/logos/ARCADE.png
new file mode 100644
index 0000000..1ae3278
Binary files /dev/null and b/assets/logos/ARCADE.png differ
diff --git a/assets/logos/ARCADIA.png b/assets/logos/ARCADIA.png
new file mode 100644
index 0000000..7ad46a3
Binary files /dev/null and b/assets/logos/ARCADIA.png differ
diff --git a/assets/logos/ARCHIMEDES.png b/assets/logos/ARCHIMEDES.png
new file mode 100644
index 0000000..605f58c
Binary files /dev/null and b/assets/logos/ARCHIMEDES.png differ
diff --git a/assets/logos/ARDUBOY.png b/assets/logos/ARDUBOY.png
new file mode 100644
index 0000000..79af199
Binary files /dev/null and b/assets/logos/ARDUBOY.png differ
diff --git a/assets/logos/ASTROCADE.png b/assets/logos/ASTROCADE.png
new file mode 100644
index 0000000..7d729f9
Binary files /dev/null and b/assets/logos/ASTROCADE.png differ
diff --git a/assets/logos/ATARI.png b/assets/logos/ATARI.png
new file mode 100644
index 0000000..5b1c677
Binary files /dev/null and b/assets/logos/ATARI.png differ
diff --git a/assets/logos/ATARI2600.png b/assets/logos/ATARI2600.png
new file mode 100644
index 0000000..b775490
Binary files /dev/null and b/assets/logos/ATARI2600.png differ
diff --git a/assets/logos/ATARI5200.png b/assets/logos/ATARI5200.png
new file mode 100644
index 0000000..fdf7581
Binary files /dev/null and b/assets/logos/ATARI5200.png differ
diff --git a/assets/logos/ATARI7800.png b/assets/logos/ATARI7800.png
new file mode 100644
index 0000000..fd170d1
Binary files /dev/null and b/assets/logos/ATARI7800.png differ
diff --git a/assets/logos/ATARI800.png b/assets/logos/ATARI800.png
new file mode 100644
index 0000000..b4cbf27
Binary files /dev/null and b/assets/logos/ATARI800.png differ
diff --git a/assets/logos/ATARIJAGUAR.png b/assets/logos/ATARIJAGUAR.png
new file mode 100644
index 0000000..4f78ee0
Binary files /dev/null and b/assets/logos/ATARIJAGUAR.png differ
diff --git a/assets/logos/ATARIJAGUARCD.png b/assets/logos/ATARIJAGUARCD.png
new file mode 100644
index 0000000..8400be6
Binary files /dev/null and b/assets/logos/ATARIJAGUARCD.png differ
diff --git a/assets/logos/ATARILYNX.png b/assets/logos/ATARILYNX.png
new file mode 100644
index 0000000..156e0a1
Binary files /dev/null and b/assets/logos/ATARILYNX.png differ
diff --git a/assets/logos/ATARIST.png b/assets/logos/ATARIST.png
new file mode 100644
index 0000000..18a3e91
Binary files /dev/null and b/assets/logos/ATARIST.png differ
diff --git a/assets/logos/ATLUS.png b/assets/logos/ATLUS.png
new file mode 100644
index 0000000..bfca0e3
Binary files /dev/null and b/assets/logos/ATLUS.png differ
diff --git a/assets/logos/ATOM.png b/assets/logos/ATOM.png
new file mode 100644
index 0000000..37da5f5
Binary files /dev/null and b/assets/logos/ATOM.png differ
diff --git a/assets/logos/ATOMISWAVE.png b/assets/logos/ATOMISWAVE.png
new file mode 100644
index 0000000..2529ec5
Binary files /dev/null and b/assets/logos/ATOMISWAVE.png differ
diff --git a/assets/logos/BBCMICRO.png b/assets/logos/BBCMICRO.png
new file mode 100644
index 0000000..0cb3a8b
Binary files /dev/null and b/assets/logos/BBCMICRO.png differ
diff --git a/assets/logos/C128.png b/assets/logos/C128.png
new file mode 100644
index 0000000..21f06e7
Binary files /dev/null and b/assets/logos/C128.png differ
diff --git a/assets/logos/C16.png b/assets/logos/C16.png
new file mode 100644
index 0000000..c8b4337
Binary files /dev/null and b/assets/logos/C16.png differ
diff --git a/assets/logos/C20.png b/assets/logos/C20.png
new file mode 100644
index 0000000..9dc73a7
Binary files /dev/null and b/assets/logos/C20.png differ
diff --git a/assets/logos/C64.png b/assets/logos/C64.png
new file mode 100644
index 0000000..02d1395
Binary files /dev/null and b/assets/logos/C64.png differ
diff --git a/assets/logos/CAMPLYNX.png b/assets/logos/CAMPLYNX.png
new file mode 100644
index 0000000..4484e98
Binary files /dev/null and b/assets/logos/CAMPLYNX.png differ
diff --git a/assets/logos/CANNONBALL.png b/assets/logos/CANNONBALL.png
new file mode 100644
index 0000000..5bfef20
Binary files /dev/null and b/assets/logos/CANNONBALL.png differ
diff --git a/assets/logos/CAPCOM.png b/assets/logos/CAPCOM.png
new file mode 100644
index 0000000..5e42b2e
Binary files /dev/null and b/assets/logos/CAPCOM.png differ
diff --git a/assets/logos/CDI.png b/assets/logos/CDI.png
new file mode 100644
index 0000000..0f4cdf1
Binary files /dev/null and b/assets/logos/CDI.png differ
diff --git a/assets/logos/CGENIUS.png b/assets/logos/CGENIUS.png
new file mode 100644
index 0000000..e222195
Binary files /dev/null and b/assets/logos/CGENIUS.png differ
diff --git a/assets/logos/CHAILOVE.png b/assets/logos/CHAILOVE.png
new file mode 100644
index 0000000..37d54ca
Binary files /dev/null and b/assets/logos/CHAILOVE.png differ
diff --git a/assets/logos/CHANNELF.png b/assets/logos/CHANNELF.png
new file mode 100644
index 0000000..9a6a99d
Binary files /dev/null and b/assets/logos/CHANNELF.png differ
diff --git a/assets/logos/CHIHIRO.png b/assets/logos/CHIHIRO.png
new file mode 100644
index 0000000..c298ea3
Binary files /dev/null and b/assets/logos/CHIHIRO.png differ
diff --git a/assets/logos/COCO.png b/assets/logos/COCO.png
new file mode 100644
index 0000000..730e39b
Binary files /dev/null and b/assets/logos/COCO.png differ
diff --git a/assets/logos/CODEMASTERS.png b/assets/logos/CODEMASTERS.png
new file mode 100644
index 0000000..e70b7cb
Binary files /dev/null and b/assets/logos/CODEMASTERS.png differ
diff --git a/assets/logos/COLECO.png b/assets/logos/COLECO.png
new file mode 100644
index 0000000..bfd0bdd
Binary files /dev/null and b/assets/logos/COLECO.png differ
diff --git a/assets/logos/COLSGM.png b/assets/logos/COLSGM.png
new file mode 100644
index 0000000..cd911e7
Binary files /dev/null and b/assets/logos/COLSGM.png differ
diff --git a/assets/logos/CONTRA.png b/assets/logos/CONTRA.png
new file mode 100644
index 0000000..8da934d
Binary files /dev/null and b/assets/logos/CONTRA.png differ
diff --git a/assets/logos/CPC.png b/assets/logos/CPC.png
new file mode 100644
index 0000000..d79a5d4
Binary files /dev/null and b/assets/logos/CPC.png differ
diff --git a/assets/logos/CPET.png b/assets/logos/CPET.png
new file mode 100644
index 0000000..12748a8
Binary files /dev/null and b/assets/logos/CPET.png differ
diff --git a/assets/logos/CPLUS4.png b/assets/logos/CPLUS4.png
new file mode 100644
index 0000000..9cfad0f
Binary files /dev/null and b/assets/logos/CPLUS4.png differ
diff --git a/assets/logos/CPS1.png b/assets/logos/CPS1.png
new file mode 100644
index 0000000..28b64d8
Binary files /dev/null and b/assets/logos/CPS1.png differ
diff --git a/assets/logos/CPS2.png b/assets/logos/CPS2.png
new file mode 100644
index 0000000..97fe9a7
Binary files /dev/null and b/assets/logos/CPS2.png differ
diff --git a/assets/logos/CPS3.png b/assets/logos/CPS3.png
new file mode 100644
index 0000000..6966d24
Binary files /dev/null and b/assets/logos/CPS3.png differ
diff --git a/assets/logos/CREATIVISION.png b/assets/logos/CREATIVISION.png
new file mode 100644
index 0000000..ed8002b
Binary files /dev/null and b/assets/logos/CREATIVISION.png differ
diff --git a/assets/logos/DAPHNE.png b/assets/logos/DAPHNE.png
new file mode 100644
index 0000000..19bde67
Binary files /dev/null and b/assets/logos/DAPHNE.png differ
diff --git a/assets/logos/DC.png b/assets/logos/DC.png
new file mode 100644
index 0000000..bc6218c
Binary files /dev/null and b/assets/logos/DC.png differ
diff --git a/assets/logos/DEVILUTIONX.png b/assets/logos/DEVILUTIONX.png
new file mode 100644
index 0000000..1df988e
Binary files /dev/null and b/assets/logos/DEVILUTIONX.png differ
diff --git a/assets/logos/DINOTHAWR.png b/assets/logos/DINOTHAWR.png
new file mode 100644
index 0000000..7d0c9cb
Binary files /dev/null and b/assets/logos/DINOTHAWR.png differ
diff --git a/assets/logos/DOOM.png b/assets/logos/DOOM.png
new file mode 100644
index 0000000..0be88ca
Binary files /dev/null and b/assets/logos/DOOM.png differ
diff --git a/assets/logos/DOS.png b/assets/logos/DOS.png
new file mode 100644
index 0000000..9b3a420
Binary files /dev/null and b/assets/logos/DOS.png differ
diff --git a/assets/logos/DRAGON32.png b/assets/logos/DRAGON32.png
new file mode 100644
index 0000000..0cccae7
Binary files /dev/null and b/assets/logos/DRAGON32.png differ
diff --git a/assets/logos/DUKENUKEM.png b/assets/logos/DUKENUKEM.png
new file mode 100644
index 0000000..b51228e
Binary files /dev/null and b/assets/logos/DUKENUKEM.png differ
diff --git a/assets/logos/EASPORTS.png b/assets/logos/EASPORTS.png
new file mode 100644
index 0000000..cc3fd71
Binary files /dev/null and b/assets/logos/EASPORTS.png differ
diff --git a/assets/logos/EASYRPG.png b/assets/logos/EASYRPG.png
new file mode 100644
index 0000000..26f5387
Binary files /dev/null and b/assets/logos/EASYRPG.png differ
diff --git a/assets/logos/ECWOLF.png b/assets/logos/ECWOLF.png
new file mode 100644
index 0000000..72109ca
Binary files /dev/null and b/assets/logos/ECWOLF.png differ
diff --git a/assets/logos/EDUKE32.png b/assets/logos/EDUKE32.png
new file mode 100644
index 0000000..ab21246
Binary files /dev/null and b/assets/logos/EDUKE32.png differ
diff --git a/assets/logos/ELECTRON.png b/assets/logos/ELECTRON.png
new file mode 100644
index 0000000..e950f99
Binary files /dev/null and b/assets/logos/ELECTRON.png differ
diff --git a/assets/logos/FAMICOM.png b/assets/logos/FAMICOM.png
new file mode 100644
index 0000000..3c8e545
Binary files /dev/null and b/assets/logos/FAMICOM.png differ
diff --git a/assets/logos/FBA.png b/assets/logos/FBA.png
new file mode 100644
index 0000000..18a65e2
Binary files /dev/null and b/assets/logos/FBA.png differ
diff --git a/assets/logos/FBN.png b/assets/logos/FBN.png
new file mode 100644
index 0000000..e504d2d
Binary files /dev/null and b/assets/logos/FBN.png differ
diff --git a/assets/logos/FBNEO.png b/assets/logos/FBNEO.png
new file mode 100644
index 0000000..e504d2d
Binary files /dev/null and b/assets/logos/FBNEO.png differ
diff --git a/assets/logos/FC.png b/assets/logos/FC.png
new file mode 100644
index 0000000..2a73d50
Binary files /dev/null and b/assets/logos/FC.png differ
diff --git a/assets/logos/FDS.png b/assets/logos/FDS.png
new file mode 100644
index 0000000..17efbab
Binary files /dev/null and b/assets/logos/FDS.png differ
diff --git a/assets/logos/FLASH.png b/assets/logos/FLASH.png
new file mode 100644
index 0000000..b9c6990
Binary files /dev/null and b/assets/logos/FLASH.png differ
diff --git a/assets/logos/FLASHBACK.png b/assets/logos/FLASHBACK.png
new file mode 100644
index 0000000..0db9fba
Binary files /dev/null and b/assets/logos/FLASHBACK.png differ
diff --git a/assets/logos/FLATPAK.png b/assets/logos/FLATPAK.png
new file mode 100644
index 0000000..e806ccb
Binary files /dev/null and b/assets/logos/FLATPAK.png differ
diff --git a/assets/logos/FM7.png b/assets/logos/FM7.png
new file mode 100644
index 0000000..6eae99d
Binary files /dev/null and b/assets/logos/FM7.png differ
diff --git a/assets/logos/FMTOWNS.png b/assets/logos/FMTOWNS.png
new file mode 100644
index 0000000..3d33a4a
Binary files /dev/null and b/assets/logos/FMTOWNS.png differ
diff --git a/assets/logos/FMTOWNSMARTY.png b/assets/logos/FMTOWNSMARTY.png
new file mode 100644
index 0000000..8a5db2b
Binary files /dev/null and b/assets/logos/FMTOWNSMARTY.png differ
diff --git a/assets/logos/FREEJ2ME.png b/assets/logos/FREEJ2ME.png
new file mode 100644
index 0000000..76f3e13
Binary files /dev/null and b/assets/logos/FREEJ2ME.png differ
diff --git a/assets/logos/FURY.png b/assets/logos/FURY.png
new file mode 100644
index 0000000..d573f74
Binary files /dev/null and b/assets/logos/FURY.png differ
diff --git a/assets/logos/GAELCO.png b/assets/logos/GAELCO.png
new file mode 100644
index 0000000..041ed09
Binary files /dev/null and b/assets/logos/GAELCO.png differ
diff --git a/assets/logos/GAMATE.png b/assets/logos/GAMATE.png
new file mode 100644
index 0000000..8a63f67
Binary files /dev/null and b/assets/logos/GAMATE.png differ
diff --git a/assets/logos/GAMEANDWATCH.png b/assets/logos/GAMEANDWATCH.png
new file mode 100644
index 0000000..ab3dc0a
Binary files /dev/null and b/assets/logos/GAMEANDWATCH.png differ
diff --git a/assets/logos/GAMECOM.png b/assets/logos/GAMECOM.png
new file mode 100644
index 0000000..10b22c1
Binary files /dev/null and b/assets/logos/GAMECOM.png differ
diff --git a/assets/logos/GAMECUBE.png b/assets/logos/GAMECUBE.png
new file mode 100644
index 0000000..a97efc5
Binary files /dev/null and b/assets/logos/GAMECUBE.png differ
diff --git a/assets/logos/GAMEGEAR.png b/assets/logos/GAMEGEAR.png
new file mode 100644
index 0000000..fd2c670
Binary files /dev/null and b/assets/logos/GAMEGEAR.png differ
diff --git a/assets/logos/GAMEPOCK.png b/assets/logos/GAMEPOCK.png
new file mode 100644
index 0000000..7c6fc5d
Binary files /dev/null and b/assets/logos/GAMEPOCK.png differ
diff --git a/assets/logos/GB.png b/assets/logos/GB.png
new file mode 100644
index 0000000..9e0d47d
Binary files /dev/null and b/assets/logos/GB.png differ
diff --git a/assets/logos/GB2PLAYERS.png b/assets/logos/GB2PLAYERS.png
new file mode 100644
index 0000000..769acce
Binary files /dev/null and b/assets/logos/GB2PLAYERS.png differ
diff --git a/assets/logos/GBA.png b/assets/logos/GBA.png
new file mode 100644
index 0000000..ceb30c6
Binary files /dev/null and b/assets/logos/GBA.png differ
diff --git a/assets/logos/GBA2PLAYERS.png b/assets/logos/GBA2PLAYERS.png
new file mode 100644
index 0000000..8ef74c4
Binary files /dev/null and b/assets/logos/GBA2PLAYERS.png differ
diff --git a/assets/logos/GBAH.png b/assets/logos/GBAH.png
new file mode 100644
index 0000000..76431c3
Binary files /dev/null and b/assets/logos/GBAH.png differ
diff --git a/assets/logos/GBAHACK.png b/assets/logos/GBAHACK.png
new file mode 100644
index 0000000..dca7d18
Binary files /dev/null and b/assets/logos/GBAHACK.png differ
diff --git a/assets/logos/GBC.png b/assets/logos/GBC.png
new file mode 100644
index 0000000..27f489c
Binary files /dev/null and b/assets/logos/GBC.png differ
diff --git a/assets/logos/GBC2PLAYERS.png b/assets/logos/GBC2PLAYERS.png
new file mode 100644
index 0000000..e5a20c7
Binary files /dev/null and b/assets/logos/GBC2PLAYERS.png differ
diff --git a/assets/logos/GBCH.png b/assets/logos/GBCH.png
new file mode 100644
index 0000000..1324f3f
Binary files /dev/null and b/assets/logos/GBCH.png differ
diff --git a/assets/logos/GBH.png b/assets/logos/GBH.png
new file mode 100644
index 0000000..107be3a
Binary files /dev/null and b/assets/logos/GBH.png differ
diff --git a/assets/logos/GC.png b/assets/logos/GC.png
new file mode 100644
index 0000000..9a26447
Binary files /dev/null and b/assets/logos/GC.png differ
diff --git a/assets/logos/GEMRB.png b/assets/logos/GEMRB.png
new file mode 100644
index 0000000..150f756
Binary files /dev/null and b/assets/logos/GEMRB.png differ
diff --git a/assets/logos/GENESIS.png b/assets/logos/GENESIS.png
new file mode 100644
index 0000000..4b7f814
Binary files /dev/null and b/assets/logos/GENESIS.png differ
diff --git a/assets/logos/GENH.png b/assets/logos/GENH.png
new file mode 100644
index 0000000..dd96023
Binary files /dev/null and b/assets/logos/GENH.png differ
diff --git a/assets/logos/GEX.png b/assets/logos/GEX.png
new file mode 100644
index 0000000..0c51284
Binary files /dev/null and b/assets/logos/GEX.png differ
diff --git a/assets/logos/GG.png b/assets/logos/GG.png
new file mode 100644
index 0000000..acda99b
Binary files /dev/null and b/assets/logos/GG.png differ
diff --git a/assets/logos/GGH.png b/assets/logos/GGH.png
new file mode 100644
index 0000000..adac44c
Binary files /dev/null and b/assets/logos/GGH.png differ
diff --git a/assets/logos/GMASTER.png b/assets/logos/GMASTER.png
new file mode 100644
index 0000000..0027217
Binary files /dev/null and b/assets/logos/GMASTER.png differ
diff --git a/assets/logos/GP32.png b/assets/logos/GP32.png
new file mode 100644
index 0000000..84b2868
Binary files /dev/null and b/assets/logos/GP32.png differ
diff --git a/assets/logos/GT.png b/assets/logos/GT.png
new file mode 100644
index 0000000..efd66eb
Binary files /dev/null and b/assets/logos/GT.png differ
diff --git a/assets/logos/GW.png b/assets/logos/GW.png
new file mode 100644
index 0000000..385137f
Binary files /dev/null and b/assets/logos/GW.png differ
diff --git a/assets/logos/GX4000.png b/assets/logos/GX4000.png
new file mode 100644
index 0000000..1a47043
Binary files /dev/null and b/assets/logos/GX4000.png differ
diff --git a/assets/logos/GZDOOM.png b/assets/logos/GZDOOM.png
new file mode 100644
index 0000000..8da339d
Binary files /dev/null and b/assets/logos/GZDOOM.png differ
diff --git a/assets/logos/HBMAME.png b/assets/logos/HBMAME.png
new file mode 100644
index 0000000..5d0d602
Binary files /dev/null and b/assets/logos/HBMAME.png differ
diff --git a/assets/logos/HCL.png b/assets/logos/HCL.png
new file mode 100644
index 0000000..3cc08e4
Binary files /dev/null and b/assets/logos/HCL.png differ
diff --git a/assets/logos/HIKARU.png b/assets/logos/HIKARU.png
new file mode 100644
index 0000000..e1f9e80
Binary files /dev/null and b/assets/logos/HIKARU.png differ
diff --git a/assets/logos/HURRICAN.png b/assets/logos/HURRICAN.png
new file mode 100644
index 0000000..e02509a
Binary files /dev/null and b/assets/logos/HURRICAN.png differ
diff --git a/assets/logos/IGS.png b/assets/logos/IGS.png
new file mode 100644
index 0000000..f2ce840
Binary files /dev/null and b/assets/logos/IGS.png differ
diff --git a/assets/logos/IREM.png b/assets/logos/IREM.png
new file mode 100644
index 0000000..a3bca95
Binary files /dev/null and b/assets/logos/IREM.png differ
diff --git a/assets/logos/JAGUAR.png b/assets/logos/JAGUAR.png
new file mode 100644
index 0000000..d08623e
Binary files /dev/null and b/assets/logos/JAGUAR.png differ
diff --git a/assets/logos/JALECO.png b/assets/logos/JALECO.png
new file mode 100644
index 0000000..0cf39ba
Binary files /dev/null and b/assets/logos/JALECO.png differ
diff --git a/assets/logos/KANEKO.png b/assets/logos/KANEKO.png
new file mode 100644
index 0000000..2632084
Binary files /dev/null and b/assets/logos/KANEKO.png differ
diff --git a/assets/logos/KODI.png b/assets/logos/KODI.png
new file mode 100644
index 0000000..c3c0f3f
Binary files /dev/null and b/assets/logos/KODI.png differ
diff --git a/assets/logos/KONAMI.png b/assets/logos/KONAMI.png
new file mode 100644
index 0000000..f39381b
Binary files /dev/null and b/assets/logos/KONAMI.png differ
diff --git a/assets/logos/LASER310.png b/assets/logos/LASER310.png
new file mode 100644
index 0000000..a4945b1
Binary files /dev/null and b/assets/logos/LASER310.png differ
diff --git a/assets/logos/LCDGAMES.png b/assets/logos/LCDGAMES.png
new file mode 100644
index 0000000..a6f6296
Binary files /dev/null and b/assets/logos/LCDGAMES.png differ
diff --git a/assets/logos/LEGO.png b/assets/logos/LEGO.png
new file mode 100644
index 0000000..aa63f76
Binary files /dev/null and b/assets/logos/LEGO.png differ
diff --git a/assets/logos/LIBRARY.png b/assets/logos/LIBRARY.png
new file mode 100644
index 0000000..55b1427
Binary files /dev/null and b/assets/logos/LIBRARY.png differ
diff --git a/assets/logos/LIGHTGUN.png b/assets/logos/LIGHTGUN.png
new file mode 100644
index 0000000..e67ca58
Binary files /dev/null and b/assets/logos/LIGHTGUN.png differ
diff --git a/assets/logos/LINDBERGH.png b/assets/logos/LINDBERGH.png
new file mode 100644
index 0000000..e4564ee
Binary files /dev/null and b/assets/logos/LINDBERGH.png differ
diff --git a/assets/logos/LOOPY.png b/assets/logos/LOOPY.png
new file mode 100644
index 0000000..47a4da0
Binary files /dev/null and b/assets/logos/LOOPY.png differ
diff --git a/assets/logos/LOVE.png b/assets/logos/LOVE.png
new file mode 100644
index 0000000..8195841
Binary files /dev/null and b/assets/logos/LOVE.png differ
diff --git a/assets/logos/LOWRESNX.png b/assets/logos/LOWRESNX.png
new file mode 100644
index 0000000..48f77c4
Binary files /dev/null and b/assets/logos/LOWRESNX.png differ
diff --git a/assets/logos/LYNX.png b/assets/logos/LYNX.png
new file mode 100644
index 0000000..bfe5a34
Binary files /dev/null and b/assets/logos/LYNX.png differ
diff --git a/assets/logos/MAME.png b/assets/logos/MAME.png
new file mode 100644
index 0000000..c5e8c99
Binary files /dev/null and b/assets/logos/MAME.png differ
diff --git a/assets/logos/MAME2003PLUS.png b/assets/logos/MAME2003PLUS.png
new file mode 100644
index 0000000..452824c
Binary files /dev/null and b/assets/logos/MAME2003PLUS.png differ
diff --git a/assets/logos/MAME2010.png b/assets/logos/MAME2010.png
new file mode 100644
index 0000000..21e196c
Binary files /dev/null and b/assets/logos/MAME2010.png differ
diff --git a/assets/logos/MARK3.png b/assets/logos/MARK3.png
new file mode 100644
index 0000000..20d86bc
Binary files /dev/null and b/assets/logos/MARK3.png differ
diff --git a/assets/logos/MASTERSYSTEM.png b/assets/logos/MASTERSYSTEM.png
new file mode 100644
index 0000000..042c3e2
Binary files /dev/null and b/assets/logos/MASTERSYSTEM.png differ
diff --git a/assets/logos/MD.png b/assets/logos/MD.png
new file mode 100644
index 0000000..fae746a
Binary files /dev/null and b/assets/logos/MD.png differ
diff --git a/assets/logos/MEGACD.png b/assets/logos/MEGACD.png
new file mode 100644
index 0000000..4293271
Binary files /dev/null and b/assets/logos/MEGACD.png differ
diff --git a/assets/logos/MEGADRIVE-JAPAN.png b/assets/logos/MEGADRIVE-JAPAN.png
new file mode 100644
index 0000000..5117eed
Binary files /dev/null and b/assets/logos/MEGADRIVE-JAPAN.png differ
diff --git a/assets/logos/MEGADRIVE-MSU.png b/assets/logos/MEGADRIVE-MSU.png
new file mode 100644
index 0000000..7dff182
Binary files /dev/null and b/assets/logos/MEGADRIVE-MSU.png differ
diff --git a/assets/logos/MEGADUCK.png b/assets/logos/MEGADUCK.png
new file mode 100644
index 0000000..d6fc9fa
Binary files /dev/null and b/assets/logos/MEGADUCK.png differ
diff --git a/assets/logos/MESS.png b/assets/logos/MESS.png
new file mode 100644
index 0000000..60ca195
Binary files /dev/null and b/assets/logos/MESS.png differ
diff --git a/assets/logos/MODEL2.png b/assets/logos/MODEL2.png
new file mode 100644
index 0000000..6f1d03e
Binary files /dev/null and b/assets/logos/MODEL2.png differ
diff --git a/assets/logos/MODEL3.png b/assets/logos/MODEL3.png
new file mode 100644
index 0000000..b3e0f2c
Binary files /dev/null and b/assets/logos/MODEL3.png differ
diff --git a/assets/logos/MRBOOM.png b/assets/logos/MRBOOM.png
new file mode 100644
index 0000000..8105bf8
Binary files /dev/null and b/assets/logos/MRBOOM.png differ
diff --git a/assets/logos/MS.png b/assets/logos/MS.png
new file mode 100644
index 0000000..27ced21
Binary files /dev/null and b/assets/logos/MS.png differ
diff --git a/assets/logos/MSU-MD.png b/assets/logos/MSU-MD.png
new file mode 100644
index 0000000..88ac869
Binary files /dev/null and b/assets/logos/MSU-MD.png differ
diff --git a/assets/logos/MSX.png b/assets/logos/MSX.png
new file mode 100644
index 0000000..fc07aaf
Binary files /dev/null and b/assets/logos/MSX.png differ
diff --git a/assets/logos/MSX1.png b/assets/logos/MSX1.png
new file mode 100644
index 0000000..6df69a6
Binary files /dev/null and b/assets/logos/MSX1.png differ
diff --git a/assets/logos/MSX2+.png b/assets/logos/MSX2+.png
new file mode 100644
index 0000000..8b40867
Binary files /dev/null and b/assets/logos/MSX2+.png differ
diff --git a/assets/logos/MSX2.png b/assets/logos/MSX2.png
new file mode 100644
index 0000000..8b40867
Binary files /dev/null and b/assets/logos/MSX2.png differ
diff --git a/assets/logos/MSX2PLUS.png b/assets/logos/MSX2PLUS.png
new file mode 100644
index 0000000..8b40867
Binary files /dev/null and b/assets/logos/MSX2PLUS.png differ
diff --git a/assets/logos/MSXLASERDISK.png b/assets/logos/MSXLASERDISK.png
new file mode 100644
index 0000000..4609bf1
Binary files /dev/null and b/assets/logos/MSXLASERDISK.png differ
diff --git a/assets/logos/MSXTURBOR.png b/assets/logos/MSXTURBOR.png
new file mode 100644
index 0000000..a276c61
Binary files /dev/null and b/assets/logos/MSXTURBOR.png differ
diff --git a/assets/logos/MUGEN.png b/assets/logos/MUGEN.png
new file mode 100644
index 0000000..1d0c401
Binary files /dev/null and b/assets/logos/MUGEN.png differ
diff --git a/assets/logos/MULTIVISION.png b/assets/logos/MULTIVISION.png
new file mode 100644
index 0000000..8a6a16b
Binary files /dev/null and b/assets/logos/MULTIVISION.png differ
diff --git a/assets/logos/N3DS.png b/assets/logos/N3DS.png
new file mode 100644
index 0000000..3e64736
Binary files /dev/null and b/assets/logos/N3DS.png differ
diff --git a/assets/logos/N64.png b/assets/logos/N64.png
new file mode 100644
index 0000000..73fb56d
Binary files /dev/null and b/assets/logos/N64.png differ
diff --git a/assets/logos/N64DD.png b/assets/logos/N64DD.png
new file mode 100644
index 0000000..e4b55f5
Binary files /dev/null and b/assets/logos/N64DD.png differ
diff --git a/assets/logos/NAOMI.png b/assets/logos/NAOMI.png
new file mode 100644
index 0000000..3f9a0db
Binary files /dev/null and b/assets/logos/NAOMI.png differ
diff --git a/assets/logos/NAOMI2.png b/assets/logos/NAOMI2.png
new file mode 100644
index 0000000..2504527
Binary files /dev/null and b/assets/logos/NAOMI2.png differ
diff --git a/assets/logos/NDS.png b/assets/logos/NDS.png
new file mode 100644
index 0000000..b8cc8e7
Binary files /dev/null and b/assets/logos/NDS.png differ
diff --git a/assets/logos/NEOCD.png b/assets/logos/NEOCD.png
new file mode 100644
index 0000000..b5615b0
Binary files /dev/null and b/assets/logos/NEOCD.png differ
diff --git a/assets/logos/NEOGEO.png b/assets/logos/NEOGEO.png
new file mode 100644
index 0000000..7823cc6
Binary files /dev/null and b/assets/logos/NEOGEO.png differ
diff --git a/assets/logos/NEOGEO64.png b/assets/logos/NEOGEO64.png
new file mode 100644
index 0000000..1c58ad2
Binary files /dev/null and b/assets/logos/NEOGEO64.png differ
diff --git a/assets/logos/NEOGEOCD.png b/assets/logos/NEOGEOCD.png
new file mode 100644
index 0000000..1357fe0
Binary files /dev/null and b/assets/logos/NEOGEOCD.png differ
diff --git a/assets/logos/NEOGEOMINI.png b/assets/logos/NEOGEOMINI.png
new file mode 100644
index 0000000..2fd056f
Binary files /dev/null and b/assets/logos/NEOGEOMINI.png differ
diff --git a/assets/logos/NEOGEOMVS.png b/assets/logos/NEOGEOMVS.png
new file mode 100644
index 0000000..e9648d0
Binary files /dev/null and b/assets/logos/NEOGEOMVS.png differ
diff --git a/assets/logos/NEOGEOX.png b/assets/logos/NEOGEOX.png
new file mode 100644
index 0000000..b9ae512
Binary files /dev/null and b/assets/logos/NEOGEOX.png differ
diff --git a/assets/logos/NGAGE.png b/assets/logos/NGAGE.png
new file mode 100644
index 0000000..f06afa5
Binary files /dev/null and b/assets/logos/NGAGE.png differ
diff --git a/assets/logos/NGC.png b/assets/logos/NGC.png
new file mode 100644
index 0000000..6ed1e5b
Binary files /dev/null and b/assets/logos/NGC.png differ
diff --git a/assets/logos/NGP.png b/assets/logos/NGP.png
new file mode 100644
index 0000000..b7b58c7
Binary files /dev/null and b/assets/logos/NGP.png differ
diff --git a/assets/logos/NGPC.png b/assets/logos/NGPC.png
new file mode 100644
index 0000000..6ed1e5b
Binary files /dev/null and b/assets/logos/NGPC.png differ
diff --git a/assets/logos/ODYSSEY.png b/assets/logos/ODYSSEY.png
new file mode 100644
index 0000000..d2a387b
Binary files /dev/null and b/assets/logos/ODYSSEY.png differ
diff --git a/assets/logos/OPENBOR.png b/assets/logos/OPENBOR.png
new file mode 100644
index 0000000..6081204
Binary files /dev/null and b/assets/logos/OPENBOR.png differ
diff --git a/assets/logos/OPENJAZZ.png b/assets/logos/OPENJAZZ.png
new file mode 100644
index 0000000..d0ddb7a
Binary files /dev/null and b/assets/logos/OPENJAZZ.png differ
diff --git a/assets/logos/ORIC.png b/assets/logos/ORIC.png
new file mode 100644
index 0000000..72bbf36
Binary files /dev/null and b/assets/logos/ORIC.png differ
diff --git a/assets/logos/ORICATMOS.png b/assets/logos/ORICATMOS.png
new file mode 100644
index 0000000..cc90d12
Binary files /dev/null and b/assets/logos/ORICATMOS.png differ
diff --git a/assets/logos/PALM.png b/assets/logos/PALM.png
new file mode 100644
index 0000000..7cc8a57
Binary files /dev/null and b/assets/logos/PALM.png differ
diff --git a/assets/logos/PALMOS.png b/assets/logos/PALMOS.png
new file mode 100644
index 0000000..7cc8a57
Binary files /dev/null and b/assets/logos/PALMOS.png differ
diff --git a/assets/logos/PANASONIC.png b/assets/logos/PANASONIC.png
new file mode 100644
index 0000000..96fcc83
Binary files /dev/null and b/assets/logos/PANASONIC.png differ
diff --git a/assets/logos/PC.png b/assets/logos/PC.png
new file mode 100644
index 0000000..b6678b6
Binary files /dev/null and b/assets/logos/PC.png differ
diff --git a/assets/logos/PC88.png b/assets/logos/PC88.png
new file mode 100644
index 0000000..f9bb572
Binary files /dev/null and b/assets/logos/PC88.png differ
diff --git a/assets/logos/PC98.png b/assets/logos/PC98.png
new file mode 100644
index 0000000..457a6d0
Binary files /dev/null and b/assets/logos/PC98.png differ
diff --git a/assets/logos/PCE.png b/assets/logos/PCE.png
new file mode 100644
index 0000000..5f9062f
Binary files /dev/null and b/assets/logos/PCE.png differ
diff --git a/assets/logos/PCECD.png b/assets/logos/PCECD.png
new file mode 100644
index 0000000..90c968b
Binary files /dev/null and b/assets/logos/PCECD.png differ
diff --git a/assets/logos/PCENGINECD.png b/assets/logos/PCENGINECD.png
new file mode 100644
index 0000000..1f5ef2c
Binary files /dev/null and b/assets/logos/PCENGINECD.png differ
diff --git a/assets/logos/PCFX.png b/assets/logos/PCFX.png
new file mode 100644
index 0000000..fc888d2
Binary files /dev/null and b/assets/logos/PCFX.png differ
diff --git a/assets/logos/PGM.png b/assets/logos/PGM.png
new file mode 100644
index 0000000..786566e
Binary files /dev/null and b/assets/logos/PGM.png differ
diff --git a/assets/logos/PICO8.png b/assets/logos/PICO8.png
new file mode 100644
index 0000000..77304c4
Binary files /dev/null and b/assets/logos/PICO8.png differ
diff --git a/assets/logos/PINBALLFX3.png b/assets/logos/PINBALLFX3.png
new file mode 100644
index 0000000..1bfdf86
Binary files /dev/null and b/assets/logos/PINBALLFX3.png differ
diff --git a/assets/logos/POCKETSTATION.png b/assets/logos/POCKETSTATION.png
new file mode 100644
index 0000000..013710b
Binary files /dev/null and b/assets/logos/POCKETSTATION.png differ
diff --git a/assets/logos/POKEMINI.png b/assets/logos/POKEMINI.png
new file mode 100644
index 0000000..4c4e823
Binary files /dev/null and b/assets/logos/POKEMINI.png differ
diff --git a/assets/logos/POKEMON.png b/assets/logos/POKEMON.png
new file mode 100644
index 0000000..f6ceb17
Binary files /dev/null and b/assets/logos/POKEMON.png differ
diff --git a/assets/logos/PORTS.png b/assets/logos/PORTS.png
new file mode 100644
index 0000000..432e24e
Binary files /dev/null and b/assets/logos/PORTS.png differ
diff --git a/assets/logos/PRBOOM.png b/assets/logos/PRBOOM.png
new file mode 100644
index 0000000..0be88ca
Binary files /dev/null and b/assets/logos/PRBOOM.png differ
diff --git a/assets/logos/PRINCEOFPERSIA.png b/assets/logos/PRINCEOFPERSIA.png
new file mode 100644
index 0000000..5e01874
Binary files /dev/null and b/assets/logos/PRINCEOFPERSIA.png differ
diff --git a/assets/logos/PS.png b/assets/logos/PS.png
new file mode 100644
index 0000000..140683f
Binary files /dev/null and b/assets/logos/PS.png differ
diff --git a/assets/logos/PS2.png b/assets/logos/PS2.png
new file mode 100644
index 0000000..37608a2
Binary files /dev/null and b/assets/logos/PS2.png differ
diff --git a/assets/logos/PS3.png b/assets/logos/PS3.png
new file mode 100644
index 0000000..31c7640
Binary files /dev/null and b/assets/logos/PS3.png differ
diff --git a/assets/logos/PSP.png b/assets/logos/PSP.png
new file mode 100644
index 0000000..d58dce3
Binary files /dev/null and b/assets/logos/PSP.png differ
diff --git a/assets/logos/PSP2.png b/assets/logos/PSP2.png
new file mode 100644
index 0000000..1929347
Binary files /dev/null and b/assets/logos/PSP2.png differ
diff --git a/assets/logos/PSPMINIS.png b/assets/logos/PSPMINIS.png
new file mode 100644
index 0000000..cd2b819
Binary files /dev/null and b/assets/logos/PSPMINIS.png differ
diff --git a/assets/logos/PSVITA.png b/assets/logos/PSVITA.png
new file mode 100644
index 0000000..7c3a68b
Binary files /dev/null and b/assets/logos/PSVITA.png differ
diff --git a/assets/logos/PSX.png b/assets/logos/PSX.png
new file mode 100644
index 0000000..fe9f77b
Binary files /dev/null and b/assets/logos/PSX.png differ
diff --git a/assets/logos/PSXMINI.png b/assets/logos/PSXMINI.png
new file mode 100644
index 0000000..bd5e29c
Binary files /dev/null and b/assets/logos/PSXMINI.png differ
diff --git a/assets/logos/PV1000.png b/assets/logos/PV1000.png
new file mode 100644
index 0000000..28c8ba7
Binary files /dev/null and b/assets/logos/PV1000.png differ
diff --git a/assets/logos/PYGAME.png b/assets/logos/PYGAME.png
new file mode 100644
index 0000000..a8f5bf6
Binary files /dev/null and b/assets/logos/PYGAME.png differ
diff --git a/assets/logos/QUAKE.png b/assets/logos/QUAKE.png
new file mode 100644
index 0000000..fbac44a
Binary files /dev/null and b/assets/logos/QUAKE.png differ
diff --git a/assets/logos/RAMPAGE.png b/assets/logos/RAMPAGE.png
new file mode 100644
index 0000000..c062d88
Binary files /dev/null and b/assets/logos/RAMPAGE.png differ
diff --git a/assets/logos/RAZE.png b/assets/logos/RAZE.png
new file mode 100644
index 0000000..1ef537a
Binary files /dev/null and b/assets/logos/RAZE.png differ
diff --git a/assets/logos/RESIDUALVM.png b/assets/logos/RESIDUALVM.png
new file mode 100644
index 0000000..42e8d84
Binary files /dev/null and b/assets/logos/RESIDUALVM.png differ
diff --git a/assets/logos/RETROBAT.png b/assets/logos/RETROBAT.png
new file mode 100644
index 0000000..f1a60c0
Binary files /dev/null and b/assets/logos/RETROBAT.png differ
diff --git a/assets/logos/ROCKSTAR.png b/assets/logos/ROCKSTAR.png
new file mode 100644
index 0000000..88f3a72
Binary files /dev/null and b/assets/logos/ROCKSTAR.png differ
diff --git a/assets/logos/SAMCOUPE.png b/assets/logos/SAMCOUPE.png
new file mode 100644
index 0000000..8c4720b
Binary files /dev/null and b/assets/logos/SAMCOUPE.png differ
diff --git a/assets/logos/SATELLAVIEW.png b/assets/logos/SATELLAVIEW.png
new file mode 100644
index 0000000..b2107fe
Binary files /dev/null and b/assets/logos/SATELLAVIEW.png differ
diff --git a/assets/logos/SATURN.png b/assets/logos/SATURN.png
new file mode 100644
index 0000000..a48c8fa
Binary files /dev/null and b/assets/logos/SATURN.png differ
diff --git a/assets/logos/SC-3000.png b/assets/logos/SC-3000.png
new file mode 100644
index 0000000..45d9ba1
Binary files /dev/null and b/assets/logos/SC-3000.png differ
diff --git a/assets/logos/SCUMMVM.png b/assets/logos/SCUMMVM.png
new file mode 100644
index 0000000..c73d661
Binary files /dev/null and b/assets/logos/SCUMMVM.png differ
diff --git a/assets/logos/SCV.png b/assets/logos/SCV.png
new file mode 100644
index 0000000..77c0384
Binary files /dev/null and b/assets/logos/SCV.png differ
diff --git a/assets/logos/SDLPOP.png b/assets/logos/SDLPOP.png
new file mode 100644
index 0000000..b14165c
Binary files /dev/null and b/assets/logos/SDLPOP.png differ
diff --git a/assets/logos/SEGA PICO.png b/assets/logos/SEGA PICO.png
new file mode 100644
index 0000000..bd5b922
Binary files /dev/null and b/assets/logos/SEGA PICO.png differ
diff --git a/assets/logos/SEGA.png b/assets/logos/SEGA.png
new file mode 100644
index 0000000..053b903
Binary files /dev/null and b/assets/logos/SEGA.png differ
diff --git a/assets/logos/SEGA32X.png b/assets/logos/SEGA32X.png
new file mode 100644
index 0000000..21e2004
Binary files /dev/null and b/assets/logos/SEGA32X.png differ
diff --git a/assets/logos/SEGACD.png b/assets/logos/SEGACD.png
new file mode 100644
index 0000000..4293271
Binary files /dev/null and b/assets/logos/SEGACD.png differ
diff --git a/assets/logos/SEGASTV.png b/assets/logos/SEGASTV.png
new file mode 100644
index 0000000..a1668f5
Binary files /dev/null and b/assets/logos/SEGASTV.png differ
diff --git a/assets/logos/SETUP.png b/assets/logos/SETUP.png
new file mode 100644
index 0000000..cfb23a0
Binary files /dev/null and b/assets/logos/SETUP.png differ
diff --git a/assets/logos/SFC.png b/assets/logos/SFC.png
new file mode 100644
index 0000000..a02d7fc
Binary files /dev/null and b/assets/logos/SFC.png differ
diff --git a/assets/logos/SFCMSU.png b/assets/logos/SFCMSU.png
new file mode 100644
index 0000000..a02d7fc
Binary files /dev/null and b/assets/logos/SFCMSU.png differ
diff --git a/assets/logos/SFX.png b/assets/logos/SFX.png
new file mode 100644
index 0000000..71f9571
Binary files /dev/null and b/assets/logos/SFX.png differ
diff --git a/assets/logos/SG-1000.png b/assets/logos/SG-1000.png
new file mode 100644
index 0000000..002a80b
Binary files /dev/null and b/assets/logos/SG-1000.png differ
diff --git a/assets/logos/SG1000.png b/assets/logos/SG1000.png
new file mode 100644
index 0000000..4fc91ea
Binary files /dev/null and b/assets/logos/SG1000.png differ
diff --git a/assets/logos/SGB.png b/assets/logos/SGB.png
new file mode 100644
index 0000000..61b1758
Binary files /dev/null and b/assets/logos/SGB.png differ
diff --git a/assets/logos/SNES-MSU.png b/assets/logos/SNES-MSU.png
new file mode 100644
index 0000000..899f218
Binary files /dev/null and b/assets/logos/SNES-MSU.png differ
diff --git a/assets/logos/SNES-MSU1.png b/assets/logos/SNES-MSU1.png
new file mode 100644
index 0000000..05f3a6e
Binary files /dev/null and b/assets/logos/SNES-MSU1.png differ
diff --git a/assets/logos/SNES.png b/assets/logos/SNES.png
new file mode 100644
index 0000000..a02d7fc
Binary files /dev/null and b/assets/logos/SNES.png differ
diff --git a/assets/logos/SNESCD.png b/assets/logos/SNESCD.png
new file mode 100644
index 0000000..9e02ae2
Binary files /dev/null and b/assets/logos/SNESCD.png differ
diff --git a/assets/logos/SNESH.png b/assets/logos/SNESH.png
new file mode 100644
index 0000000..e365a16
Binary files /dev/null and b/assets/logos/SNESH.png differ
diff --git a/assets/logos/SNESMINI.png b/assets/logos/SNESMINI.png
new file mode 100644
index 0000000..d04c37a
Binary files /dev/null and b/assets/logos/SNESMINI.png differ
diff --git a/assets/logos/SNESMSU1.png b/assets/logos/SNESMSU1.png
new file mode 100644
index 0000000..899f218
Binary files /dev/null and b/assets/logos/SNESMSU1.png differ
diff --git a/assets/logos/SNK.png b/assets/logos/SNK.png
new file mode 100644
index 0000000..6260212
Binary files /dev/null and b/assets/logos/SNK.png differ
diff --git a/assets/logos/SOCRATES.png b/assets/logos/SOCRATES.png
new file mode 100644
index 0000000..e6ff7a8
Binary files /dev/null and b/assets/logos/SOCRATES.png differ
diff --git a/assets/logos/SOLARUS.png b/assets/logos/SOLARUS.png
new file mode 100644
index 0000000..af8696c
Binary files /dev/null and b/assets/logos/SOLARUS.png differ
diff --git a/assets/logos/SONICRETRO.png b/assets/logos/SONICRETRO.png
new file mode 100644
index 0000000..efafbac
Binary files /dev/null and b/assets/logos/SONICRETRO.png differ
diff --git a/assets/logos/SPECTRAVIDEO.png b/assets/logos/SPECTRAVIDEO.png
new file mode 100644
index 0000000..012b8cc
Binary files /dev/null and b/assets/logos/SPECTRAVIDEO.png differ
diff --git a/assets/logos/STEAM.png b/assets/logos/STEAM.png
new file mode 100644
index 0000000..f2b6f5d
Binary files /dev/null and b/assets/logos/STEAM.png differ
diff --git a/assets/logos/SUFAMI.png b/assets/logos/SUFAMI.png
new file mode 100644
index 0000000..b6eee84
Binary files /dev/null and b/assets/logos/SUFAMI.png differ
diff --git a/assets/logos/SUPERGRAFX.png b/assets/logos/SUPERGRAFX.png
new file mode 100644
index 0000000..71f9571
Binary files /dev/null and b/assets/logos/SUPERGRAFX.png differ
diff --git a/assets/logos/SUPERVISION.png b/assets/logos/SUPERVISION.png
new file mode 100644
index 0000000..611e2e2
Binary files /dev/null and b/assets/logos/SUPERVISION.png differ
diff --git a/assets/logos/SUPRACAN.png b/assets/logos/SUPRACAN.png
new file mode 100644
index 0000000..9dc5199
Binary files /dev/null and b/assets/logos/SUPRACAN.png differ
diff --git a/assets/logos/SWITCH.png b/assets/logos/SWITCH.png
new file mode 100644
index 0000000..8d4cfe4
Binary files /dev/null and b/assets/logos/SWITCH.png differ
diff --git a/assets/logos/TAITO.png b/assets/logos/TAITO.png
new file mode 100644
index 0000000..2bf34c6
Binary files /dev/null and b/assets/logos/TAITO.png differ
diff --git a/assets/logos/TANDY1K.png b/assets/logos/TANDY1K.png
new file mode 100644
index 0000000..c63e873
Binary files /dev/null and b/assets/logos/TANDY1K.png differ
diff --git a/assets/logos/TEKNOPARROT.png b/assets/logos/TEKNOPARROT.png
new file mode 100644
index 0000000..4f75624
Binary files /dev/null and b/assets/logos/TEKNOPARROT.png differ
diff --git a/assets/logos/TG-CD.png b/assets/logos/TG-CD.png
new file mode 100644
index 0000000..804c4a8
Binary files /dev/null and b/assets/logos/TG-CD.png differ
diff --git a/assets/logos/TG16.png b/assets/logos/TG16.png
new file mode 100644
index 0000000..79de11a
Binary files /dev/null and b/assets/logos/TG16.png differ
diff --git a/assets/logos/THOMSON.png b/assets/logos/THOMSON.png
new file mode 100644
index 0000000..04d1056
Binary files /dev/null and b/assets/logos/THOMSON.png differ
diff --git a/assets/logos/TI83.png b/assets/logos/TI83.png
new file mode 100644
index 0000000..7faafe2
Binary files /dev/null and b/assets/logos/TI83.png differ
diff --git a/assets/logos/TI99.png b/assets/logos/TI99.png
new file mode 100644
index 0000000..e0dfb18
Binary files /dev/null and b/assets/logos/TI99.png differ
diff --git a/assets/logos/TIC.png b/assets/logos/TIC.png
new file mode 100644
index 0000000..d2d11a9
Binary files /dev/null and b/assets/logos/TIC.png differ
diff --git a/assets/logos/TIC80.png b/assets/logos/TIC80.png
new file mode 100644
index 0000000..d2d11a9
Binary files /dev/null and b/assets/logos/TIC80.png differ
diff --git a/assets/logos/TO8.png b/assets/logos/TO8.png
new file mode 100644
index 0000000..0a266fd
Binary files /dev/null and b/assets/logos/TO8.png differ
diff --git a/assets/logos/TOAPLAN.png b/assets/logos/TOAPLAN.png
new file mode 100644
index 0000000..9a94dcb
Binary files /dev/null and b/assets/logos/TOAPLAN.png differ
diff --git a/assets/logos/TRIFORCE.png b/assets/logos/TRIFORCE.png
new file mode 100644
index 0000000..b86af0d
Binary files /dev/null and b/assets/logos/TRIFORCE.png differ
diff --git a/assets/logos/TUTOR.png b/assets/logos/TUTOR.png
new file mode 100644
index 0000000..e08529f
Binary files /dev/null and b/assets/logos/TUTOR.png differ
diff --git a/assets/logos/TVGAMES.png b/assets/logos/TVGAMES.png
new file mode 100644
index 0000000..892ea28
Binary files /dev/null and b/assets/logos/TVGAMES.png differ
diff --git a/assets/logos/TYPEX.png b/assets/logos/TYPEX.png
new file mode 100644
index 0000000..9828c7a
Binary files /dev/null and b/assets/logos/TYPEX.png differ
diff --git a/assets/logos/TYPEX2.png b/assets/logos/TYPEX2.png
new file mode 100644
index 0000000..c2f2ce3
Binary files /dev/null and b/assets/logos/TYPEX2.png differ
diff --git a/assets/logos/TYRQUAKE.png b/assets/logos/TYRQUAKE.png
new file mode 100644
index 0000000..8d92d97
Binary files /dev/null and b/assets/logos/TYRQUAKE.png differ
diff --git a/assets/logos/ULTIMATE.png b/assets/logos/ULTIMATE.png
new file mode 100644
index 0000000..85e9405
Binary files /dev/null and b/assets/logos/ULTIMATE.png differ
diff --git a/assets/logos/UZEBOX.png b/assets/logos/UZEBOX.png
new file mode 100644
index 0000000..b0e341c
Binary files /dev/null and b/assets/logos/UZEBOX.png differ
diff --git a/assets/logos/VB.png b/assets/logos/VB.png
new file mode 100644
index 0000000..06e7e8f
Binary files /dev/null and b/assets/logos/VB.png differ
diff --git a/assets/logos/VECTREX.png b/assets/logos/VECTREX.png
new file mode 100644
index 0000000..98580ed
Binary files /dev/null and b/assets/logos/VECTREX.png differ
diff --git a/assets/logos/VEMULATOR.png b/assets/logos/VEMULATOR.png
new file mode 100644
index 0000000..63f0b46
Binary files /dev/null and b/assets/logos/VEMULATOR.png differ
diff --git a/assets/logos/VGMPLAY.png b/assets/logos/VGMPLAY.png
new file mode 100644
index 0000000..1b82f7d
Binary files /dev/null and b/assets/logos/VGMPLAY.png differ
diff --git a/assets/logos/VIC20.png b/assets/logos/VIC20.png
new file mode 100644
index 0000000..aae6efe
Binary files /dev/null and b/assets/logos/VIC20.png differ
diff --git a/assets/logos/VIDEOPAC.png b/assets/logos/VIDEOPAC.png
new file mode 100644
index 0000000..89330d4
Binary files /dev/null and b/assets/logos/VIDEOPAC.png differ
diff --git a/assets/logos/VIDEOPACPLUS.png b/assets/logos/VIDEOPACPLUS.png
new file mode 100644
index 0000000..89330d4
Binary files /dev/null and b/assets/logos/VIDEOPACPLUS.png differ
diff --git a/assets/logos/VIDEOS.png b/assets/logos/VIDEOS.png
new file mode 100644
index 0000000..d4c620a
Binary files /dev/null and b/assets/logos/VIDEOS.png differ
diff --git a/assets/logos/VIDEOTON.png b/assets/logos/VIDEOTON.png
new file mode 100644
index 0000000..c76541b
Binary files /dev/null and b/assets/logos/VIDEOTON.png differ
diff --git a/assets/logos/VISUALPINBALL.png b/assets/logos/VISUALPINBALL.png
new file mode 100644
index 0000000..0337e6b
Binary files /dev/null and b/assets/logos/VISUALPINBALL.png differ
diff --git a/assets/logos/VITAQUAKE2.png b/assets/logos/VITAQUAKE2.png
new file mode 100644
index 0000000..b64313e
Binary files /dev/null and b/assets/logos/VITAQUAKE2.png differ
diff --git a/assets/logos/VMAC.png b/assets/logos/VMAC.png
new file mode 100644
index 0000000..35df394
Binary files /dev/null and b/assets/logos/VMAC.png differ
diff --git a/assets/logos/VPINBALL.png b/assets/logos/VPINBALL.png
new file mode 100644
index 0000000..0337e6b
Binary files /dev/null and b/assets/logos/VPINBALL.png differ
diff --git a/assets/logos/VSMILE.png b/assets/logos/VSMILE.png
new file mode 100644
index 0000000..fbb53eb
Binary files /dev/null and b/assets/logos/VSMILE.png differ
diff --git a/assets/logos/WII.png b/assets/logos/WII.png
new file mode 100644
index 0000000..31fbded
Binary files /dev/null and b/assets/logos/WII.png differ
diff --git a/assets/logos/WIIU.png b/assets/logos/WIIU.png
new file mode 100644
index 0000000..e60c916
Binary files /dev/null and b/assets/logos/WIIU.png differ
diff --git a/assets/logos/WONDERSWAN.png b/assets/logos/WONDERSWAN.png
new file mode 100644
index 0000000..a9627a1
Binary files /dev/null and b/assets/logos/WONDERSWAN.png differ
diff --git a/assets/logos/WONDERSWANCOLOR.png b/assets/logos/WONDERSWANCOLOR.png
new file mode 100644
index 0000000..32da74c
Binary files /dev/null and b/assets/logos/WONDERSWANCOLOR.png differ
diff --git a/assets/logos/WS.png b/assets/logos/WS.png
new file mode 100644
index 0000000..a9627a1
Binary files /dev/null and b/assets/logos/WS.png differ
diff --git a/assets/logos/WSC.png b/assets/logos/WSC.png
new file mode 100644
index 0000000..32da74c
Binary files /dev/null and b/assets/logos/WSC.png differ
diff --git a/assets/logos/X1.png b/assets/logos/X1.png
new file mode 100644
index 0000000..627c01a
Binary files /dev/null and b/assets/logos/X1.png differ
diff --git a/assets/logos/X68000.png b/assets/logos/X68000.png
new file mode 100644
index 0000000..4b2e83d
Binary files /dev/null and b/assets/logos/X68000.png differ
diff --git a/assets/logos/XASH3D_FWGS.png b/assets/logos/XASH3D_FWGS.png
new file mode 100644
index 0000000..8d7eaf4
Binary files /dev/null and b/assets/logos/XASH3D_FWGS.png differ
diff --git a/assets/logos/XBOX.png b/assets/logos/XBOX.png
new file mode 100644
index 0000000..13b859e
Binary files /dev/null and b/assets/logos/XBOX.png differ
diff --git a/assets/logos/XBOX360.png b/assets/logos/XBOX360.png
new file mode 100644
index 0000000..b5ebf40
Binary files /dev/null and b/assets/logos/XBOX360.png differ
diff --git a/assets/logos/XEGS.png b/assets/logos/XEGS.png
new file mode 100644
index 0000000..d56f617
Binary files /dev/null and b/assets/logos/XEGS.png differ
diff --git a/assets/logos/XRICK.png b/assets/logos/XRICK.png
new file mode 100644
index 0000000..01fc923
Binary files /dev/null and b/assets/logos/XRICK.png differ
diff --git a/assets/logos/ZC210.png b/assets/logos/ZC210.png
new file mode 100644
index 0000000..6c020b1
Binary files /dev/null and b/assets/logos/ZC210.png differ
diff --git a/assets/logos/ZELDA.png b/assets/logos/ZELDA.png
new file mode 100644
index 0000000..0d5f631
Binary files /dev/null and b/assets/logos/ZELDA.png differ
diff --git a/assets/logos/ZELDAC.png b/assets/logos/ZELDAC.png
new file mode 100644
index 0000000..8321ec8
Binary files /dev/null and b/assets/logos/ZELDAC.png differ
diff --git a/assets/logos/ZX81.png b/assets/logos/ZX81.png
new file mode 100644
index 0000000..f4d7a9d
Binary files /dev/null and b/assets/logos/ZX81.png differ
diff --git a/assets/logos/ZXS.png b/assets/logos/ZXS.png
new file mode 100644
index 0000000..fdd8260
Binary files /dev/null and b/assets/logos/ZXS.png differ
diff --git a/assets/logos/ZXSPECTRUM.png b/assets/logos/ZXSPECTRUM.png
new file mode 100644
index 0000000..b39a58d
Binary files /dev/null and b/assets/logos/ZXSPECTRUM.png differ
diff --git a/assets/ui_controls_1280_720.bmp b/assets/ui_controls_1280_720.bmp
new file mode 100644
index 0000000..7a5c7e3
Binary files /dev/null and b/assets/ui_controls_1280_720.bmp differ
diff --git a/config.json b/config.json
new file mode 100644
index 0000000..f475f9b
--- /dev/null
+++ b/config.json
@@ -0,0 +1,636 @@
+{
+ "roms": "/mnt/sdcard/ROMS",
+ "logos": "assets/logos",
+ "screenscraper": {
+ "username": "",
+ "password": "",
+ "devid": "cmVhdmVu",
+ "devpassword": "MDZXZUY5bTBldWs=",
+ "threads": 3,
+ "media": {
+ "type": "box-3D",
+ "width": 400,
+ "height": 580,
+ "regions": [
+ "br",
+ "us",
+ "ame",
+ "wor"
+ ]
+ },
+ "systems": [
+ {
+ "dir": "ADVMAME",
+ "id": "75",
+ "name": "Mame",
+ "art": "/mnt/mmc/MUOS/info/catalogue/ADVMAME/"
+ },
+ {
+ "dir": "AMIGA",
+ "id": "64",
+ "name": "Commodore Amiga",
+ "art": "/mnt/mmc/MUOS/info/catalogue/AMIGA/"
+ },
+ {
+ "dir": "AMIGACD",
+ "id": "134",
+ "name": "Commodore Amiga CD",
+ "art": "/mnt/mmc/MUOS/info/catalogue/AMIGACD/"
+ },
+ {
+ "dir": "AMIGACDTV",
+ "id": "129",
+ "name": "Commodore Amiga CD",
+ "art": "/mnt/mmc/MUOS/info/catalogue/AMIGACDTV/"
+ },
+ {
+ "dir": "ARCADE",
+ "id": "75",
+ "name": "Mame",
+ "art": "/mnt/mmc/MUOS/info/catalogue/ARCADE/"
+ },
+ {
+ "dir": "ARDUBOY",
+ "id": "263",
+ "name": "Arduboy",
+ "art": "/mnt/mmc/MUOS/info/catalogue/ARDUBOY/"
+ },
+ {
+ "dir": "ATARI2600",
+ "id": "26",
+ "name": "Atari 2600",
+ "art": "/mnt/mmc/MUOS/info/catalogue/ATARI2600/"
+ },
+ {
+ "dir": "ATARIST",
+ "id": "42",
+ "name": "Atari ST",
+ "art": "/mnt/mmc/MUOS/info/catalogue/ATARIST/"
+ },
+ {
+ "dir": "ATOMISWAVE",
+ "id": "53",
+ "name": "Atari ST",
+ "art": "/mnt/mmc/MUOS/info/catalogue/ATOMISWAVE/"
+ },
+ {
+ "dir": "COLECO",
+ "id": "183",
+ "name": "Coleco",
+ "art": "/mnt/mmc/MUOS/info/catalogue/COLECO/"
+ },
+ {
+ "dir": "COLSGM",
+ "id": "183",
+ "name": "Coleco",
+ "art": "/mnt/mmc/MUOS/info/catalogue/COLSGM/"
+ },
+ {
+ "dir": "C64",
+ "id": "66",
+ "name": "Commodore 64",
+ "art": "/mnt/mmc/MUOS/info/catalogue/C64/"
+ },
+ {
+ "dir": "CPC",
+ "id": "65",
+ "name": "Amstrad CPC",
+ "art": "/mnt/mmc/MUOS/info/catalogue/CPC/"
+ },
+ {
+ "dir": "CPET",
+ "id": "240",
+ "name": "Commodore PET",
+ "art": "/mnt/mmc/MUOS/info/catalogue/CPET/"
+ },
+ {
+ "dir": "CPLUS4",
+ "id": "99",
+ "name": "Commodore Plus 4",
+ "art": "/mnt/mmc/MUOS/info/catalogue/CPLUS4/"
+ },
+ {
+ "dir": "CPS1",
+ "id": "6",
+ "name": "Capcom Play System",
+ "art": "/mnt/mmc/MUOS/info/catalogue/CPS1/"
+ },
+ {
+ "dir": "CPS2",
+ "id": "7",
+ "name": "Capcom Play System 2",
+ "art": "/mnt/mmc/MUOS/info/catalogue/CPS2/"
+ },
+ {
+ "dir": "CPS3",
+ "id": "8",
+ "name": "Capcom Play System 3",
+ "art": "/mnt/mmc/MUOS/info/catalogue/CPS3/"
+ },
+ {
+ "dir": "DAPHNE",
+ "id": "49",
+ "name": "Daphne",
+ "art": "/mnt/mmc/MUOS/info/catalogue/DAPHNE/"
+ },
+ {
+ "dir": "DC",
+ "id": "23",
+ "name": "dreamcast",
+ "art": "/mnt/mmc/MUOS/info/catalogue/DC/"
+ },
+ {
+ "dir": "DOS",
+ "id": "135",
+ "name": "DOS",
+ "art": "/mnt/mmc/MUOS/info/catalogue/DOS/"
+ },
+ {
+ "dir": "EASYRPG",
+ "id": "231",
+ "name": "EasyRPG",
+ "art": "/mnt/mmc/MUOS/info/catalogue/EASYRPG/"
+ },
+ {
+ "dir": "EBK",
+ "id": "93",
+ "name": "EBK",
+ "art": "/mnt/mmc/MUOS/info/catalogue/EBK/"
+ },
+ {
+ "dir": "ATARI800",
+ "id": "43",
+ "name": "Atari 800",
+ "art": "/mnt/mmc/MUOS/info/catalogue/ATARI800/"
+ },
+ {
+ "dir": "CHANNELF",
+ "id": "80",
+ "name": "Fairchild Channel F",
+ "art": "/mnt/mmc/MUOS/info/catalogue/CHANNELF/"
+ },
+ {
+ "dir": "FBA2012",
+ "id": "75",
+ "name": "FBA2012",
+ "art": "/mnt/mmc/MUOS/info/catalogue/FBA2012/"
+ },
+ {
+ "dir": "FBALPHA",
+ "id": "75",
+ "name": "FBAlpha",
+ "art": "/mnt/mmc/MUOS/info/catalogue/FBALPHA/"
+ },
+ {
+ "dir": "FBNEO",
+ "id": "",
+ "name": "FBNeo (Empty)",
+ "art": "/mnt/mmc/MUOS/info/catalogue/FBNEO/"
+ },
+ {
+ "dir": "FC",
+ "id": "3",
+ "name": "NES (Famicom)",
+ "art": "/mnt/mmc/MUOS/info/catalogue/FC/"
+ },
+ {
+ "dir": "FDS",
+ "id": "106",
+ "name": "Famicom Disk System",
+ "art": "/mnt/mmc/MUOS/info/catalogue/FDS/"
+ },
+ {
+ "dir": "ATARI5200",
+ "id": "40",
+ "name": "Atari 5200",
+ "art": "/mnt/mmc/MUOS/info/catalogue/ATARI5200/"
+ },
+ {
+ "dir": "GB",
+ "id": "9",
+ "name": "Game Boy",
+ "art": "/mnt/mmc/MUOS/info/catalogue/GB/"
+ },
+ {
+ "dir": "GBA",
+ "id": "12",
+ "name": "Game Boy Advance",
+ "art": "/mnt/mmc/MUOS/info/catalogue/GBA/"
+ },
+ {
+ "dir": "GBC",
+ "id": "10",
+ "name": "Game Boy Color",
+ "art": "/mnt/mmc/MUOS/info/catalogue/GBC/"
+ },
+ {
+ "dir": "GG",
+ "id": "21",
+ "name": "Sega Game Gear",
+ "art": "/mnt/mmc/MUOS/info/catalogue/GG/"
+ },
+ {
+ "dir": "GW",
+ "id": "52",
+ "name": "Nintendo Game & Watch",
+ "art": "/mnt/mmc/MUOS/info/catalogue/GW/"
+ },
+ {
+ "dir": "INTELLIVISION",
+ "id": "115",
+ "name": "Intellivision",
+ "art": "/mnt/mmc/MUOS/info/catalogue/INTELLIVISION/"
+ },
+ {
+ "dir": "JAGUAR",
+ "id": "27",
+ "name": "Atari Jaguar",
+ "art": "/mnt/mmc/MUOS/info/catalogue/JAGUAR/"
+ },
+ {
+ "dir": "LOWRESNX",
+ "id": "244",
+ "name": "LowRes NX",
+ "art": "/mnt/mmc/MUOS/info/catalogue/LOWRESNX/"
+ },
+ {
+ "dir": "LUTRO",
+ "id": "206",
+ "name": "Lutro",
+ "art": "/mnt/mmc/MUOS/info/catalogue/LUTRO/"
+ },
+ {
+ "dir": "LYNX",
+ "id": "28",
+ "name": "Atari Lynx",
+ "art": "/mnt/mmc/MUOS/info/catalogue/LYNX/"
+ },
+ {
+ "dir": "MAME",
+ "id": "75",
+ "name": "Mame 2000",
+ "art": "/mnt/mmc/MUOS/info/catalogue/MAME/"
+ },
+ {
+ "dir": "MAME2003PLUS",
+ "id": "75",
+ "name": "Mame 2003",
+ "art": "/mnt/mmc/MUOS/info/catalogue/MAME2003PLUS/"
+ },
+ {
+ "dir": "MAME2010",
+ "id": "75",
+ "name": "Mame 2003",
+ "art": "/mnt/mmc/MUOS/info/catalogue/MAME2010/"
+ },
+ {
+ "dir": "MBA",
+ "id": "75",
+ "name": "MBA",
+ "art": "/mnt/mmc/MUOS/info/catalogue/MBA/"
+ },
+ {
+ "dir": "MD",
+ "id": "1",
+ "name": "Sega Genesis (Mega Drive)",
+ "art": "/mnt/mmc/MUOS/info/catalogue/MD/"
+ },
+ {
+ "dir": "MDMSU",
+ "id": "1",
+ "name": "Sega Genesis (Mega Drive) Hacks",
+ "art": "/mnt/mmc/MUOS/info/catalogue/MDMSU/"
+ },
+ {
+ "dir": "MEGADUCK",
+ "id": "90",
+ "name": "Megaduck",
+ "art": "/mnt/mmc/MUOS/info/catalogue/MEGADUCK/"
+ },
+ {
+ "dir": "MS",
+ "id": "2",
+ "name": "Sega Master System",
+ "art": "/mnt/mmc/MUOS/info/catalogue/MS/"
+ },
+ {
+ "dir": "MSX",
+ "id": "113",
+ "name": "MSX",
+ "art": "/mnt/mmc/MUOS/info/catalogue/MSX/"
+ },
+ {
+ "dir": "MSX2",
+ "id": "116",
+ "name": "MSX",
+ "art": "/mnt/mmc/MUOS/info/catalogue/MSX2/"
+ },
+ {
+ "dir": "N64",
+ "id": "14",
+ "name": "Nintendo 64",
+ "art": "/mnt/mmc/MUOS/info/catalogue/N64/"
+ },
+ {
+ "dir": "N64DD",
+ "id": "122",
+ "name": "Nintendo 64DD",
+ "art": "/mnt/mmc/MUOS/info/catalogue/N64DD/"
+ },
+ {
+ "dir": "NAOMI",
+ "id": "56",
+ "name": "Sega Naomi",
+ "art": "/mnt/mmc/MUOS/info/catalogue/NAOMI/"
+ },
+ {
+ "dir": "NDS",
+ "id": "15",
+ "name": "NDS",
+ "art": "/mnt/mmc/MUOS/info/catalogue/NDS/"
+ },
+ {
+ "dir": "NEOCD",
+ "id": "70",
+ "name": "Neo Geo CD",
+ "art": "/mnt/mmc/MUOS/info/catalogue/NEOCD/"
+ },
+ {
+ "dir": "NEOGEO",
+ "id": "142",
+ "name": "Neo Geo AES",
+ "art": "/mnt/mmc/MUOS/info/catalogue/NEOGEO/"
+ },
+ {
+ "dir": "NGP",
+ "id": "25",
+ "name": "Neo Geo Pocket",
+ "art": "/mnt/mmc/MUOS/info/catalogue/NGP/"
+ },
+ {
+ "dir": "NGC",
+ "id": "82",
+ "name": "Neo-geo Pocket Color",
+ "art": "/mnt/mmc/MUOS/info/catalogue/NGC/"
+ },
+ {
+ "dir": "ODYSSEY",
+ "id": "104",
+ "name": "Videopac / Magnavox Odyssey 2",
+ "art": "/mnt/mmc/MUOS/info/catalogue/ODYSSEY/"
+ },
+ {
+ "dir": "OPENBOR",
+ "id": "214",
+ "name": "OpenBOR",
+ "art": "/mnt/mmc/MUOS/info/catalogue/OPENBOR/"
+ },
+ {
+ "dir": "PALMOS",
+ "id": "219",
+ "name": "Palm",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PALMOS/"
+ },
+ {
+ "dir": "PANASONIC",
+ "id": "29",
+ "name": "3DO",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PANASONIC/"
+ },
+ {
+ "dir": "PCE",
+ "id": "31",
+ "name": "NEC TurboGrafx-16 / PC Engine",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PCE/"
+ },
+ {
+ "dir": "PCECD",
+ "id": "114",
+ "name": "NEC TurboGrafx-CD",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PCECD/"
+ },
+ {
+ "dir": "PC88",
+ "id": "221",
+ "name": "NEC PC-8000 & PC-8800 series / NEC PC-8801",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PC88/"
+ },
+ {
+ "dir": "PCFX",
+ "id": "72",
+ "name": "NEC PC-FX",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PCFX/"
+ },
+ {
+ "dir": "PC98",
+ "id": "208",
+ "name": "NEC PC-98 / NEC PC-9801",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PC98/"
+ },
+ {
+ "dir": "PICO",
+ "id": "234",
+ "name": "PICO",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PICO/"
+ },
+ {
+ "dir": "POKEMINI",
+ "id": "211",
+ "name": "PokeMini",
+ "art": "/mnt/mmc/MUOS/info/catalogue/POKEMINI/"
+ },
+ {
+ "dir": "PORTS",
+ "id": "137",
+ "name": "PC Win9X",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PORTS/"
+ },
+ {
+ "dir": "PS",
+ "id": "57",
+ "name": "Sony Playstation",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PS/"
+ },
+ {
+ "dir": "PSP",
+ "id": "61",
+ "name": "Sony PSP",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PSP/"
+ },
+ {
+ "dir": "PSPMINIS",
+ "id": "172",
+ "name": "Sony PSP Minis",
+ "art": "/mnt/mmc/MUOS/info/catalogue/PSPMINIS/"
+ },
+ {
+ "dir": "SATURN",
+ "id": "22",
+ "name": "Sony PSP Minis",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SATURN/"
+ },
+ {
+ "dir": "SATELLAVIEW",
+ "id": "107",
+ "name": "Satellaview",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SATELLAVIEW/"
+ },
+ {
+ "dir": "SCUMMVM",
+ "id": "123",
+ "name": "ScummVM",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SCUMMVM/"
+ },
+ {
+ "dir": "SEGACD",
+ "id": "20",
+ "name": "Sega CD",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SEGACD/"
+ },
+ {
+ "dir": "SG1000",
+ "id": "109",
+ "name": "Sega SG-1000",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SG1000/"
+ },
+ {
+ "dir": "ATARI7800",
+ "id": "41",
+ "name": "Atari 7800",
+ "art": "/mnt/mmc/MUOS/info/catalogue/ATARI7800/"
+ },
+ {
+ "dir": "SFC",
+ "id": "4",
+ "name": "Super Nintendo (SNES)",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SFC/"
+ },
+ {
+ "dir": "SFCMSU",
+ "id": "4",
+ "name": "Super Nintendo (SNES) hacks",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SFCMSU/"
+ },
+ {
+ "dir": "SGB",
+ "id": "127",
+ "name": "Super Game Boy",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SGB/"
+ },
+ {
+ "dir": "SFX",
+ "id": "105",
+ "name": "NEC PC Engine SuperGrafx",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SFX/"
+ },
+ {
+ "dir": "SUFAMI",
+ "id": "108",
+ "name": "Sufami Turbo",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SUFAMI/"
+ },
+ {
+ "dir": "WS",
+ "id": "207",
+ "name": "Watara Supervision",
+ "art": "/mnt/mmc/MUOS/info/catalogue/WS/"
+ },
+ {
+ "dir": "WSC",
+ "id": "207",
+ "name": "Watara Supervision",
+ "art": "/mnt/mmc/MUOS/info/catalogue/WSC/"
+ },
+ {
+ "dir": "SEGA32X",
+ "id": "19",
+ "name": "Sega 32X",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SEGA32X/"
+ },
+ {
+ "dir": "SFX",
+ "id": "19",
+ "name": "Sega 32X",
+ "art": "/mnt/mmc/MUOS/info/catalogue/SFX/"
+ },
+ {
+ "dir": "THOMSON",
+ "id": "141",
+ "name": "Thomson",
+ "art": "/mnt/mmc/MUOS/info/catalogue/THOMSON/"
+ },
+ {
+ "dir": "TIC",
+ "id": "222",
+ "name": "TIC-80",
+ "art": "/mnt/mmc/MUOS/info/catalogue/TIC/"
+ },
+ {
+ "dir": "UZEBOX",
+ "id": "216",
+ "name": "Uzebox",
+ "art": "/mnt/mmc/MUOS/info/catalogue/UZEBOX/"
+ },
+ {
+ "dir": "VB",
+ "id": "11",
+ "name": "Virtual Boy",
+ "art": "/mnt/mmc/MUOS/info/catalogue/VB/"
+ },
+ {
+ "dir": "VECTREX",
+ "id": "102",
+ "name": "Vectrex",
+ "art": "roms/vectrex/art"
+ },
+ {
+ "dir": "VIC20",
+ "id": "73",
+ "name": "Commodore VIC-20",
+ "art": "roms/vic20/art"
+ },
+ {
+ "dir": "VIDEOPAC",
+ "id": "104",
+ "name": "Videopac",
+ "art": "roms/videopac/art"
+ },
+ {
+ "dir": "VMU",
+ "id": "23",
+ "name": "Dreamcast VMU (useless)",
+ "art": "roms/vmu/art"
+ },
+ {
+ "dir": "WS",
+ "id": "45",
+ "name": "Bandai WonderSwan & Color",
+ "art": "roms/ws/art"
+ },
+ {
+ "dir": "X68000",
+ "id": "79",
+ "name": "Sharp X68000",
+ "art": "roms/x68000/art"
+ },
+ {
+ "dir": "X1",
+ "id": "220",
+ "name": "Sharp X1",
+ "art": "roms/x1/art"
+ },
+ {
+ "dir": "ZXEIGHTYONE",
+ "id": "77",
+ "name": "Sinclair ZX-81",
+ "art": "roms/zxeightyone/art"
+ },
+ {
+ "dir": "ZXS",
+ "id": "76",
+ "name": "Sinclair ZX Spectrum",
+ "art": "roms/zxs/art"
+ }
+ ]
+ }
+}
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..fb38e6b
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+requests==2.32.3
+Pillow==10.4.0
diff --git a/src/app.py b/src/app.py
new file mode 100644
index 0000000..9695996
--- /dev/null
+++ b/src/app.py
@@ -0,0 +1,408 @@
+import contextlib
+import json
+import os
+import sys
+import time
+from pathlib import Path
+from typing import List, Optional
+
+import graphic as gr
+import input
+from PIL import Image
+from scraper import (
+ check_destination,
+ download_media,
+ find_game,
+ get_image_files_without_extension,
+)
+
+selected_position = 0
+roms_selected_position = 0
+selected_system = ""
+current_window = "console"
+max_elem = 11
+skip_input_check = False
+scraping = False
+
+
+class Rom:
+ def __init__(self, name, filename):
+ self.name = name
+ self.filename = filename
+
+
+class App:
+ def __init__(self):
+ self.config = {}
+ self.systems_mapping = {}
+ self.roms_path = ""
+ self.systems_logo_path = ""
+ self.media = {}
+ self.threads = 1
+ self.username = ""
+ self.password = ""
+
+ def load_config(self, config_file):
+ with open(config_file, "r") as file:
+ file_contents = file.read()
+
+ self.config = json.loads(file_contents)
+ self.roms_path = self.config.get("roms")
+ self.systems_logo_path = self.config.get("logos")
+ self.dev_id = self.config.get("screenscraper").get("devid")
+ self.dev_password = self.config.get("screenscraper").get("devpassword")
+ self.username = self.config.get("screenscraper").get("username")
+ self.password = self.config.get("screenscraper").get("password")
+ self.media = self.config.get("screenscraper").get("media")
+ self.threads = self.config.get("threads")
+ for system in self.config["screenscraper"]["systems"]:
+ self.systems_mapping[system["dir"]] = system
+
+ def start(self, config_file: str) -> None:
+ print("Starting Artie...")
+ self.load_config(config_file)
+ self.load_ui()
+
+ def update(self) -> None:
+ global current_window, selected_position, skip_input_check
+
+ if skip_input_check:
+ input.reset_input()
+ skip_input_check = False
+ else:
+ input.check()
+
+ if input.key("MENUF"):
+ gr.draw_end()
+ print("Exiting Artie...")
+ sys.exit()
+
+ if current_window == "console":
+ self.load_ui()
+ elif current_window == "roms":
+ self.load_roms()
+ else:
+ self.load_ui()
+
+ def get_available_systems(self) -> list[str]:
+ all_systems = list(self.systems_mapping.keys())
+ available_systems = [
+ d.upper()
+ for d in os.listdir(self.roms_path)
+ if os.path.isdir(os.path.join(self.roms_path, d))
+ ]
+ filtered_systems = [
+ system for system in available_systems if system in all_systems
+ ]
+ print(all_systems)
+ print("----------------")
+ print(available_systems)
+ print("----------------")
+ print(filtered_systems)
+ return filtered_systems
+
+ def get_roms(self, system: str) -> list[Rom]:
+ roms = []
+ system_path = Path(self.roms_path) / system
+
+ for file in os.listdir(system_path):
+ file_path = Path(system_path) / file
+ if file.startswith("."):
+ continue
+ if file_path.is_file() and self.is_valid_rom(file):
+ name = file_path.stem
+ rom = Rom(filename=file, name=name)
+ roms.append(rom)
+
+ return roms
+
+ def load_ui(self) -> None:
+ global selected_position, selected_system, current_window, skip_input_check
+
+ available_systems = self.get_available_systems()
+
+ if available_systems:
+ if input.key("DY"):
+ if input.value == 1:
+ if selected_position < len(available_systems) - 1:
+ selected_position += 1
+ elif input.value == -1:
+ if selected_position > 0:
+ selected_position -= 1
+ elif input.key("A"):
+ selected_system = available_systems[selected_position]
+ current_window = "roms"
+ gr.draw_log(
+ "Checking existing media...",
+ fill=gr.COLOR_BLUE,
+ outline=gr.COLOR_BLUE_D1,
+ )
+ gr.draw_paint()
+ skip_input_check = True
+ return
+
+ gr.draw_clear()
+
+ gr.draw_rectangle_r([10, 40, 630, 440], 15, fill=gr.COLOR_GRAY_D2, outline=None)
+ gr.draw_text((320, 20), "Artie", anchor="mm")
+
+ if len(available_systems) > 1:
+ start_idx = int(selected_position / max_elem) * max_elem
+ end_idx = start_idx + max_elem
+ for i, system in enumerate(available_systems[start_idx:end_idx]):
+ logo = f"{self.systems_logo_path}/{system}.png"
+ self.row_list(
+ system,
+ (20, 50 + (i * 35)),
+ 600,
+ i == (selected_position % max_elem),
+ Path(logo),
+ )
+ self.button_circle((30, 450), "A", "Select")
+ else:
+ gr.draw_text((320, 240), f"No roms found in {self.roms_path}", anchor="mm")
+
+ self.button_circle((133, 450), "M", "Exit")
+
+ gr.draw_paint()
+
+ def is_valid_rom(self, rom):
+ invalid_extensions = {
+ ".cue",
+ ".m3u",
+ ".jpg",
+ ".png",
+ ".img",
+ ".sub",
+ ".db",
+ ".xml",
+ ".txt",
+ ".dat",
+ }
+ return os.path.splitext(rom)[1] not in invalid_extensions
+
+ def save_to_disk(self, rom, scraped_media, art_folder):
+ img_path: Path = art_folder / f"{rom.name}.png"
+ check_destination(img_path)
+ img_path.write_bytes(scraped_media)
+ gr.draw_log("Scraping completed!", fill=gr.COLOR_BLUE, outline=gr.COLOR_BLUE_D1)
+ return True
+ print(f"Done scraping {rom.name}. Saved file to {img_path}")
+
+ def scrape(self, rom, system_path, system_id):
+ game = find_game(
+ system_id,
+ system_path / rom.filename,
+ self.dev_id,
+ self.dev_password,
+ self.username,
+ self.password,
+ )
+ if game:
+ medias = game["response"]["jeu"]["medias"]
+ media = download_media(medias, self.media)
+ if media:
+ return media
+
+ def load_roms(self) -> None:
+ global selected_position, current_window, roms_selected_position, skip_input_check, selected_system
+
+ exit_menu = False
+ roms_list = self.get_roms(selected_system)
+ system_path = Path(self.roms_path) / selected_system
+ system = self.systems_mapping.get(selected_system)
+ if not system:
+ gr.draw_log(
+ "No roms missing media found...",
+ fill=gr.COLOR_BLUE,
+ outline=gr.COLOR_BLUE_D1,
+ )
+ gr.draw_paint()
+ time.sleep(2)
+ gr.draw_clear()
+ exit_menu = True
+
+ art_folder = Path(system["art"])
+ system_id = system["id"]
+
+ if not art_folder.exists():
+ art_folder.mkdir()
+ imgs_files: List[str] = []
+ else:
+ imgs_files = get_image_files_without_extension(art_folder)
+
+ roms_without_image = [rom for rom in roms_list if rom.name not in imgs_files]
+
+ if len(roms_without_image) < 1:
+ current_window = "console"
+ selected_system = ""
+ gr.draw_log(
+ "No roms missing media found...",
+ fill=gr.COLOR_BLUE,
+ outline=gr.COLOR_BLUE_D1,
+ )
+ gr.draw_paint()
+ time.sleep(2)
+ gr.draw_clear()
+ exit_menu = True
+
+ if input.key("B"):
+ exit_menu = True
+ elif input.key("A"):
+ gr.draw_log("Scraping...", fill=gr.COLOR_BLUE, outline=gr.COLOR_BLUE_D1)
+ gr.draw_paint()
+ rom = roms_without_image[roms_selected_position]
+ scraped_media = self.scrape(rom, system_path, system_id)
+ if scraped_media:
+ self.save_to_disk(rom, scraped_media, art_folder)
+ else:
+ gr.draw_log(
+ "Scraping failed!", fill=gr.COLOR_BLUE, outline=gr.COLOR_BLUE_D1
+ )
+ print(f"Failed to get screenshot for {rom.name}")
+ gr.draw_paint()
+ time.sleep(3)
+ exit_menu = True
+ elif input.key("START"):
+ progress: int = 0
+ success: int = 0
+ failure: int = 0
+ gr.draw_log(
+ f"Scraping {progress} of {len(roms_without_image)}",
+ fill=gr.COLOR_BLUE,
+ outline=gr.COLOR_BLUE_D1,
+ )
+ gr.draw_paint()
+ for rom in roms_without_image:
+ if rom.name not in imgs_files:
+ scraped_media = self.scrape(rom, system_path, system_id)
+ if scraped_media:
+ self.save_to_disk(rom, scraped_media, art_folder)
+ else:
+ gr.draw_log(
+ "Scraping failed!",
+ fill=gr.COLOR_BLUE,
+ outline=gr.COLOR_BLUE_D1,
+ )
+ print(f"Failed to get screenshot for {rom.name}")
+ failure += 1
+ progress += 1
+ gr.draw_log(
+ f"Scraping {progress} of {len(roms_without_image)}",
+ fill=gr.COLOR_BLUE,
+ outline=gr.COLOR_BLUE_D1,
+ )
+ gr.draw_paint()
+ gr.draw_log(
+ f"Scraping completed! Success: {success} Errors: {failure}",
+ fill=gr.COLOR_BLUE,
+ outline=gr.COLOR_BLUE_D1,
+ width=800,
+ )
+ gr.draw_paint()
+ time.sleep(4)
+ exit_menu = True
+ elif input.key("DY"):
+ if input.value == 1:
+ if roms_selected_position < len(roms_list) - 1:
+ roms_selected_position += 1
+ elif input.value == -1:
+ if roms_selected_position > 0:
+ roms_selected_position -= 1
+ elif input.key("L1"):
+ if roms_selected_position > 0:
+ roms_selected_position = max(0, roms_selected_position - max_elem)
+ elif input.key("R1"):
+ if roms_selected_position < len(roms_list) - 1:
+ roms_selected_position = min(
+ len(roms_list) - 1, roms_selected_position + max_elem
+ )
+ elif input.key("L2"):
+ if roms_selected_position > 0:
+ roms_selected_position = max(0, roms_selected_position - 100)
+ elif input.key("R2"):
+ if roms_selected_position < len(roms_list) - 1:
+ roms_selected_position = min(
+ len(roms_list) - 1, roms_selected_position + 100
+ )
+
+ if exit_menu:
+ current_window = "console"
+ selected_system = ""
+ gr.draw_clear()
+ roms_selected_position = 0
+ skip_input_check = True
+ return
+
+ gr.draw_clear()
+
+ gr.draw_rectangle_r([10, 40, 630, 440], 15, fill=gr.COLOR_GRAY_D2, outline=None)
+ gr.draw_text(
+ (320, 10),
+ f"{selected_system} - Roms: {len(roms_list)} Missing media: {len(roms_without_image)}",
+ anchor="mm",
+ )
+
+ start_idx = int(roms_selected_position / max_elem) * max_elem
+ end_idx = start_idx + max_elem
+ for i, rom in enumerate(roms_without_image[start_idx:end_idx]):
+ self.row_list(
+ rom.name[:48] + "..." if len(rom.name) > 50 else rom.name,
+ (20, 50 + (i * 35)),
+ 600,
+ i == (roms_selected_position % max_elem),
+ )
+
+ self.button_rectangle((30, 450), "Start", "All")
+ self.button_circle((170, 450), "A", "Download")
+ self.button_circle((300, 450), "B", "Back")
+ self.button_circle((480, 450), "M", "Exit")
+
+ gr.draw_paint()
+
+ def row_list(
+ self,
+ text: str,
+ pos: tuple[int, int],
+ width: int,
+ selected: bool,
+ image_path: str = None,
+ ) -> None:
+ gr.draw_rectangle_r(
+ [pos[0], pos[1], pos[0] + width, pos[1] + 32],
+ 5,
+ fill=(gr.COLOR_BLUE if selected else gr.COLOR_GRAY_L1),
+ )
+
+ text_offset_x = pos[0] + 5
+ if image_path:
+ try:
+ image = Image.open(image_path)
+ image_width, image_height = image.size
+ gr.draw_image((pos[0] + 5, pos[1] + (32 - image_height) // 2), image)
+ text_offset_x += image_width + 5
+ except Exception as e:
+ print(f"Error loading image from {image_path}: {e}")
+
+ # Draw the text
+ gr.draw_text((text_offset_x, pos[1] + 5), text)
+
+ def button_circle(self, pos: tuple[int, int], button: str, text: str) -> None:
+ gr.draw_circle(pos, 25, fill=gr.COLOR_BLUE_D1)
+ gr.draw_text((pos[0] + 12, pos[1] + 12), button, anchor="mm")
+ gr.draw_text((pos[0] + 30, pos[1] + 12), text, font=13, anchor="lm")
+
+ def button_rectangle(self, pos: tuple[int, int], button: str, text: str) -> None:
+ gr.draw_rectangle_r(
+ (pos[0], pos[1], pos[0] + 60, pos[1] + 25), 5, fill=gr.COLOR_GRAY_L1
+ )
+ gr.draw_text((pos[0] + 30, pos[1] + 12), button, anchor="mm")
+ gr.draw_text((pos[0] + 65, pos[1] + 12), text, font=13, anchor="lm")
+
+
+if __name__ == "__main__":
+ app = App()
+ app.start(f"{os.getcwd()}/config.json")
+
+ while True:
+ app.update()
diff --git a/src/graphic.py b/src/graphic.py
new file mode 100644
index 0000000..400f633
--- /dev/null
+++ b/src/graphic.py
@@ -0,0 +1,235 @@
+from fcntl import ioctl
+from PIL import Image, ImageDraw, ImageFont
+import mmap
+import os
+
+fb: int
+mm: mmap.mmap
+screen_width = 640
+screen_height = 480
+bytes_per_pixel = 4
+screen_size = screen_width * screen_height * bytes_per_pixel
+
+fontFile = {}
+fontFile[15] = ImageFont.truetype("assets/Roboto-Condensed.ttf", 15)
+fontFile[13] = ImageFont.truetype("assets/Roboto-Condensed.ttf", 13)
+fontFile[11] = ImageFont.truetype("assets/Roboto-Condensed.ttf", 11)
+
+COLOR_BLUE = "#bb7200"
+COLOR_BLUE_D1 = "#7f4f00"
+COLOR_GRAY = "#292929"
+COLOR_GRAY_L1 = "#383838"
+COLOR_GRAY_D2 = "#141414"
+
+activeImage: Image.Image
+activeDraw: ImageDraw.ImageDraw
+
+
+def screen_reset():
+ ioctl(
+ fb,
+ 0x4601,
+ b"\x80\x02\x00\x00\xe0\x01\x00\x00\x80\x02\x00\x00\xc0\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00^\x00\x00\x00\x96\x00\x00\x00\x00\x00\x00\x00\xc2\xa2\x00\x00\x1a\x00\x00\x00T\x00\x00\x00\x0c\x00\x00\x00\x1e\x00\x00\x00\x14\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ )
+ ioctl(fb, 0x4611, 0)
+
+
+def draw_start():
+ global fb, mm
+ fb = os.open("/dev/fb0", os.O_RDWR)
+ mm = mmap.mmap(fb, screen_size)
+
+
+def draw_end():
+ global fb, mm
+ mm.close()
+ os.close(fb)
+
+
+def crate_image():
+ image = Image.new("RGBA", (screen_width, screen_height), color="black")
+ return image
+
+
+def draw_active(image):
+ global activeImage, activeDraw
+ activeImage = image
+ activeDraw = ImageDraw.Draw(activeImage)
+
+
+def draw_paint():
+ global activeImage, mm
+ mm.seek(0)
+ mm.write(activeImage.tobytes())
+
+
+def draw_clear():
+ global activeDraw
+ activeDraw.rectangle((0, 0, screen_width, screen_height), fill="black")
+
+
+def draw_text(position, text, font=15, color="white", **kwargs):
+ global activeDraw
+ activeDraw.text(position, text, font=fontFile[font], fill=color, **kwargs)
+
+
+def draw_rectangle(position, fill=None, outline=None, width=1):
+ global activeDraw
+ activeDraw.rectangle(position, fill=fill, outline=outline, width=width)
+
+
+def draw_rectangle_r(position, radius, fill=None, outline=None):
+ global activeDraw
+ activeDraw.rounded_rectangle(position, radius, fill=fill, outline=outline)
+
+
+def draw_circle(position, radius, fill=None, outline="white"):
+ global activeDraw
+ activeDraw.ellipse(
+ [position[0], position[1], position[0] + radius, position[1] + radius],
+ fill=fill,
+ outline=outline,
+ )
+
+
+def draw_log(text, fill="Black", outline="black", width=500):
+ # Center the rectangle horizontally
+ x = (screen_width - width) / 2
+ # Center the rectangle vertically
+ y = (screen_height - 80) / 2 # 80 is the height of the rectangle
+ draw_rectangle_r([x, y, x + width, y + 80], 5, fill=fill, outline=outline)
+
+ # Center the text within the rectangle
+ text_x = x + width / 2
+ text_y = y + 40 # Vertically center within the 80px height
+ draw_text((text_x, text_y), text, anchor="mm") # Use middle-middle anchor
+
+
+draw_start()
+screen_reset()
+
+imgMain = crate_image()
+draw_active(imgMain)
+
+
+# from PIL import Image, ImageDraw, ImageFont
+# import os
+
+# screen_width = 640
+# screen_height = 480
+# bytes_per_pixel = 4
+# screen_size = screen_width * screen_height * bytes_per_pixel
+
+# fontFile = {}
+# fontFile[15] = ImageFont.truetype("assets/Roboto-Condensed.ttf", 15)
+# fontFile[13] = ImageFont.truetype("assets/Roboto-Condensed.ttf", 13)
+# fontFile[11] = ImageFont.truetype("assets/Roboto-Condensed.ttf", 11)
+
+# COLOR_BLUE = "#bb7200"
+# COLOR_BLUE_D1 = "#7f4f00"
+# COLOR_GRAY = "#292929"
+# COLOR_GRAY_L1 = "#383838"
+# COLOR_GRAY_D2 = "#141414"
+
+# activeImage: Image.Image
+# activeDraw: ImageDraw.ImageDraw
+
+
+# def screen_reset():
+# print("Screen reset is not applicable on macOS.")
+
+
+# def draw_start():
+# global activeImage, activeDraw
+# activeImage = Image.new("RGBA", (screen_width, screen_height), color="black")
+# activeDraw = ImageDraw.Draw(activeImage)
+
+
+# def draw_end():
+# print("Draw end is not applicable on macOS.")
+
+
+# # Initialize the main image
+
+# from PIL import Image
+
+
+# def draw_image(one, two):
+# global activeImage
+# activeImage.show()
+
+
+# def create_image():
+# bg_image_path = "assets/bg.bmp"
+# overlay_image_path = "assets/bg_overlay.bmp"
+
+# try:
+# bg_image = Image.open(bg_image_path)
+# overlay_image = Image.open(overlay_image_path)
+# overlay_image = overlay_image.resize(bg_image.size, Image.LANCZOS)
+# bg_image.paste(overlay_image, (0, 0), overlay_image)
+
+# return bg_image
+# except IOError as e:
+# print(f"Error: Unable to load image: {e}")
+# return None
+
+
+# def draw_active(image):
+# global activeImage, activeDraw
+# activeImage = image
+# activeDraw = ImageDraw.Draw(activeImage)
+
+
+# def draw_paint():
+# global activeImage
+# activeImage.show() # Display the image for debugging purposes
+
+
+# def draw_clear():
+# global activeDraw
+# activeDraw.rectangle((0, 0, screen_width, screen_height), fill="black")
+
+
+# def draw_text(position, text, font=15, color="white", **kwargs):
+# global activeDraw
+# activeDraw.text(position, text, font=fontFile[font], fill=color, **kwargs)
+
+
+# def draw_rectangle(position, fill=None, outline=None, width=1):
+# global activeDraw
+# activeDraw.rectangle(position, fill=fill, outline=outline, width=width)
+
+
+# def draw_rectangle_r(position, radius, fill=None, outline=None):
+# global activeDraw
+# activeDraw.rounded_rectangle(position, radius, fill=fill, outline=outline)
+
+
+# def draw_circle(position, radius, fill=None, outline="white"):
+# global activeDraw
+# activeDraw.ellipse(
+# [position[0], position[1], position[0] + radius, position[1] + radius],
+# fill=fill,
+# outline=outline,
+# )
+
+
+# def draw_log(text, fill="Black", outline="black", width=500):
+# # Center the rectangle horizontally
+# x = (screen_width - width) / 2
+# # Center the rectangle vertically
+# y = (screen_height - 80) / 2 # 80 is the height of the rectangle
+# draw_rectangle_r([x, y, x + width, y + 80], 5, fill=fill, outline=outline)
+
+# # Center the text within the rectangle
+# text_x = x + width / 2
+# text_y = y + 40 # Vertically center within the 80px height
+# draw_text((text_x, text_y), text, anchor="mm") # Use middle-middle anchor
+
+
+# draw_start()
+# screen_reset()
+
+# imgMain = create_image()
+# draw_active(imgMain)
diff --git a/src/input.py b/src/input.py
new file mode 100644
index 0000000..e9b7347
--- /dev/null
+++ b/src/input.py
@@ -0,0 +1,55 @@
+import struct
+import time
+
+code = 0
+codeName = ""
+value = 0
+
+mapping = {
+ 304: "A",
+ 305: "B",
+ 306: "Y",
+ 307: "X",
+ 308: "L1",
+ 309: "R1",
+ 314: "L2",
+ 315: "R2",
+ 17: "DY",
+ 16: "DX",
+ 310: "SELECT",
+ 311: "START",
+ 312: "MENUF",
+ 114: "V+",
+ 115: "V-",
+}
+
+
+def check():
+ global type, code, codeName, codeDown, value, valueDown
+ with open("/dev/input/event1", "rb") as f:
+ while True:
+ event = f.read(24)
+
+ if event:
+ (tv_sec, tv_usec, type, kcode, kvalue) = struct.unpack("llHHI", event)
+ if kvalue != 0:
+ if kvalue != 1:
+ kvalue = -1
+ code = kcode
+ codeName = mapping.get(code, str(code))
+ value = kvalue
+ return
+
+
+def key(keyCodeName, keyValue=99):
+ global code, codeName, value
+ if codeName == keyCodeName:
+ if keyValue != 99:
+ return value == keyValue
+ return True
+
+
+def reset_input():
+ global codeName, value
+ codeName = ""
+ value = 0
diff --git a/src/scraper.py b/src/scraper.py
new file mode 100644
index 0000000..5238f39
--- /dev/null
+++ b/src/scraper.py
@@ -0,0 +1,187 @@
+import base64
+import hashlib
+import json
+import os
+import re
+from contextlib import contextmanager
+from pathlib import Path
+from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
+
+import requests
+
+BASE_URL = "https://www.screenscraper.fr/api2/jeuInfos.php"
+MAX_FILE_SIZE_BYTES = 104857600 # 100MB
+
+
+class ScraperError(Exception):
+ pass
+
+
+class UnreadableBodyError(ScraperError):
+ pass
+
+
+class EmptyBodyError(ScraperError):
+ pass
+
+
+class GameNotFoundError(ScraperError):
+ pass
+
+
+class APIClosedError(ScraperError):
+ pass
+
+
+class HTTPRequestError(ScraperError):
+ pass
+
+
+class UnknownMediaTypeError(ScraperError):
+ pass
+
+
+def get_image_files_without_extension(folder):
+ image_extensions = (".jpg", ".jpeg", ".png")
+ return [f.stem for f in folder.glob("*") if f.suffix.lower() in image_extensions]
+
+
+def sha1sum(file_path):
+ if os.path.getsize(file_path) > MAX_FILE_SIZE_BYTES:
+ return ""
+
+ hash_sha1 = hashlib.sha1()
+ with open(file_path, "rb") as f:
+ for chunk in iter(lambda: f.read(4096), b""):
+ hash_sha1.update(chunk)
+ return hash_sha1.hexdigest()
+
+
+def clean_rom_name(file_path):
+ file_name = os.path.basename(file_path)
+ cleaned_name = re.sub(
+ r"(\.nkit|!|&|Disc |Rev |-|\s*\([^()]*\)|\s*\[[^\[\]]*\])",
+ " ",
+ os.path.splitext(file_name)[0],
+ )
+ return re.sub(r"\s+", " ", cleaned_name).strip()
+
+
+def file_size(file_path):
+ return os.path.getsize(file_path)
+
+
+def parse_find_game_url(system_id, rom_path, dev_id, dev_password, username, password):
+ params = {
+ "devid": base64.b64decode(dev_id).decode(),
+ "devpassword": base64.b64decode(dev_password).decode(),
+ "softname": "crossmix",
+ "output": "json",
+ "ssid": username,
+ "sspassword": password,
+ "sha1": sha1sum(rom_path),
+ "systemeid": system_id,
+ "romtype": "rom",
+ "romnom": clean_rom_name(rom_path) + ".zip",
+ "romtaille": str(file_size(rom_path)),
+ }
+
+ url_parts = list(urlparse(BASE_URL))
+ query = urlencode(params)
+ url_parts[4] = query
+ return urlunparse(url_parts)
+
+
+def find_media_url_by_region(medias, media_type, regions):
+ for region in regions:
+ for media in medias:
+ if media["type"] == media_type and media["region"] == region:
+ return media["url"]
+
+ raise ScraperError(f"Media not found for regions: {regions}")
+
+
+def add_wh_to_media_url(media_url, width, height):
+ parsed_url = urlparse(media_url)
+ query = parse_qs(parsed_url.query)
+ query["maxwidth"] = [str(width)]
+ query["maxheight"] = [str(height)]
+ new_query = urlencode(query, doseq=True)
+ return urlunparse(parsed_url._replace(query=new_query))
+
+
+def check_media_type(media_type):
+ if media_type not in [
+ "box-2D",
+ "box-3D",
+ "mixrbv1",
+ "mixrbv2",
+ ]:
+ raise UnknownMediaTypeError("Unknown media type")
+
+
+def check_destination(dest):
+ if os.path.exists(dest):
+ raise ScraperError(f"Destination file already exists: {dest}")
+ dest_dir = os.path.dirname(dest)
+ os.makedirs(dest_dir, exist_ok=True)
+
+
+def get(url):
+ try:
+ response = requests.get(url, timeout=10)
+ response.raise_for_status()
+ except requests.RequestException as e:
+ if isinstance(e, requests.Timeout):
+ raise HTTPRequestError("Request aborted")
+ raise HTTPRequestError("Error making HTTP request")
+
+ body = response.content
+ return body
+
+
+# def save_to_disk(dest, file_content):
+# check_destination(dest)
+# with open(dest, "wb") as f:
+# f.write(file_content)
+
+
+def find_game(system_id, rom_path, dev_id, dev_password, username, password):
+ result = {}
+ game_url = parse_find_game_url(
+ system_id, rom_path, dev_id, dev_password, username, password
+ )
+
+ body = get(game_url)
+ body_str = body.decode("utf-8")
+
+ if "API closed" in body_str:
+ raise APIClosedError()
+ if "Erreur" in body_str:
+ raise GameNotFoundError()
+ if not body:
+ raise EmptyBodyError()
+ try:
+
+ result = json.loads(body_str)
+ except json.JSONDecodeError:
+ raise UnreadableBodyError()
+
+ return result
+
+
+def download_media(medias, config_media):
+ media_type = config_media["type"]
+ regions = config_media["regions"]
+ width = config_media["width"]
+ height = config_media["height"]
+ check_media_type(media_type)
+
+ try:
+ media_url = find_media_url_by_region(medias, media_type, regions)
+ media_url = add_wh_to_media_url(media_url, width, height)
+ res = get(media_url)
+ except ScraperError as e:
+ raise e
+
+ return res