Initial commit
This commit is contained in:
commit
e43e43bf3a
8
.idea/.gitignore
generated
vendored
Executable file
8
.idea/.gitignore
generated
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
1
.idea/.name
generated
Executable file
1
.idea/.name
generated
Executable file
@ -0,0 +1 @@
|
|||||||
|
athnos
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Executable file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||||
|
</state>
|
||||||
|
</component>
|
26
.idea/dataSources.xml
generated
Executable file
26
.idea/dataSources.xml
generated
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="MariaDB - clipbase@localhost" uuid="b00c2254-51bc-43f0-a615-07b7e45401d8">
|
||||||
|
<driver-ref>mariadb</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.mariadb.jdbc.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:mariadb://localhost:3306/clipbase</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="athnos.sqlite3" uuid="670a72d3-6b02-4c42-ad20-feb8cbd9644f">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/athnos.sqlite3</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="test.sqlite3" uuid="fd482fc2-e22e-4a9a-b240-33bb720b7c73">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/test.sqlite3</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
7
.idea/discord.xml
generated
Executable file
7
.idea/discord.xml
generated
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DiscordProjectSettings">
|
||||||
|
<option name="show" value="PROJECT_FILES" />
|
||||||
|
<option name="description" value="A tag based (video) clip UI" />
|
||||||
|
</component>
|
||||||
|
</project>
|
7
.idea/inspectionProfiles/profiles_settings.xml
generated
Executable file
7
.idea/inspectionProfiles/profiles_settings.xml
generated
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="PROJECT_PROFILE" value="Default" />
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
4
.idea/misc.xml
generated
Executable file
4
.idea/misc.xml
generated
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
8
.idea/modules.xml
generated
Executable file
8
.idea/modules.xml
generated
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/../athnos/.idea/athnos.iml" filepath="$PROJECT_DIR$/../athnos/.idea/athnos.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/sqldialects.xml
generated
Executable file
6
.idea/sqldialects.xml
generated
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="SqlDialectMappings">
|
||||||
|
<file url="file://$PROJECT_DIR$/resources/clipbase.sql" dialect="MariaDB" />
|
||||||
|
</component>
|
||||||
|
</project>
|
14
.idea/webResources.xml
generated
Executable file
14
.idea/webResources.xml
generated
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="WebResourcesPaths">
|
||||||
|
<contentEntries>
|
||||||
|
<entry url="file://$PROJECT_DIR$">
|
||||||
|
<entryData>
|
||||||
|
<resourceRoots>
|
||||||
|
<path value="file://$PROJECT_DIR$/resources" />
|
||||||
|
</resourceRoots>
|
||||||
|
</entryData>
|
||||||
|
</entry>
|
||||||
|
</contentEntries>
|
||||||
|
</component>
|
||||||
|
</project>
|
675
LICENSE
Executable file
675
LICENSE
Executable file
@ -0,0 +1,675 @@
|
|||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
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.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
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
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
180
README.md
Executable file
180
README.md
Executable file
@ -0,0 +1,180 @@
|
|||||||
|
# ⚠️ UNFINISHED PROJECT ⚠️
|
||||||
|
|
||||||
|
> This project were not finsihed because pyqt5 development was a huge pain and I didn't saw the need for such a software anymore. Nevertheless, it runs and works partly.
|
||||||
|
|
||||||
|
# Athnos
|
||||||
|
|
||||||
|
With **Athnos** you can store media files like videos, audios or images
|
||||||
|
(called `clip`) structured / sorted.
|
||||||
|
|
||||||
|
Every clip has a link or file path to the (media) file, a name, description and can have several tags.
|
||||||
|
Additionally, a clip can have a `source`. For example, if the clip is a 10-second clip from a movie, the movie can be set as the source
|
||||||
|
and each time you select the clip, you can see where it came from.
|
||||||
|
|
||||||
|
This makes **Athnos** the perfect tool for video creators who often use many and different clips/scenes, audio, images, etc.
|
||||||
|
in their videos and currently have dozens of different folders and cryptic-looking file names to somehow bring order to the pile of files.
|
||||||
|
But it's also useful for 'normal' people, like you and me, who just want to store their images or videos centrally.
|
||||||
|
|
||||||
|
Download the latest executables:
|
||||||
|
- Linux
|
||||||
|
- [Linux x64 standalone / portable]()
|
||||||
|
- [Linux x64 installer (.deb)]()
|
||||||
|
|
||||||
|
- Windows
|
||||||
|
- [Windows 10 x64 standalone / portable]()
|
||||||
|
- [Windows 10 x64 installer]()
|
||||||
|
|
||||||
|
The installation and other stuff (besides [Todo](#todo) and [License](#licence)) below are just for the people, who want to
|
||||||
|
compile the code themselves and doesn't use the executables linked above.
|
||||||
|
|
||||||
|
If you only have a 32 bit, arm, etc. processor, window 8 or another reason why you can't use the already compiled versions linked above,
|
||||||
|
you have to download the source code and execute / compile it yourself. The instructions are below.
|
||||||
|
|
||||||
|
## Known issues
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
- `FileNotFoundError: [Errno 2] No such file or directory 'objcopy'` when [compiling](#compile) the code with pyinstaller
|
||||||
|
|
||||||
|
Cause: PyInstaller doesn't find the `objcopy` command
|
||||||
|
|
||||||
|
Solution: Run `apt install binutils`, which installs `objcopy`
|
||||||
|
|
||||||
|
- `staticx: Couldn't find 'patchelf'. Is 'patchelf' installed?` when 're-building' the pyinstaller executable with staticx
|
||||||
|
|
||||||
|
Cause: staticx doesn't find the `patchelf` module
|
||||||
|
|
||||||
|
Solution: Run `apt install patchelf`, which installs `patchelf`
|
||||||
|
|
||||||
|
- ```...dlopen: /lib/x86_64-linux-gnu/libc.so.6: version ``GLIBC_2.x' not found...``` when try to run
|
||||||
|
|
||||||
|
Cause: This means that the file was compiled with a newer `glibc` version, than the one on your system.
|
||||||
|
Usually happens if you compile the file on your computer and try to execute it on another one with an older `glibc` version.
|
||||||
|
|
||||||
|
Solution: If you compiled the file yourself, re-compile it and after that follow the instructions [here](#create-real-independent-file).
|
||||||
|
If you downloaded the file from here, download it again ([latest version]()) and if the is still there when running the new file,
|
||||||
|
open a new [issue]()
|
||||||
|
|
||||||
|
- `[12345] Cannot open self /tmp/staticx-*/main or archive /tmp/staticx-*/main.pkg` when try to run
|
||||||
|
|
||||||
|
Cause: When a pyinstaller executable was 're-built' with [staticx](#create-real-independent-file).
|
||||||
|
Usually happens if pyinstaller creates a executable, which can't be 're-build' correctly with staticx
|
||||||
|
|
||||||
|
Solution: If you compiled the file yourself, use pyinstaller version 4.0, instead of the newest version an then [compile it again](#compile-linux)
|
||||||
|
If you downloaded the file from here, download it again ([latest version]()) and if the is still there when running the new file,
|
||||||
|
open a new [issue]()
|
||||||
|
|
||||||
|
## Installation🎰
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
1. Install the required apt packages. **Note: The python3 version must be 3.6 or higher!**
|
||||||
|
```bash
|
||||||
|
apt install git
|
||||||
|
apt install python3
|
||||||
|
apt install python3-pip
|
||||||
|
apt install python3-pyqt5
|
||||||
|
apt install python3-pyqt5.qtsql
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Then clone the repository and install its requirements
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ByteDream/athnos.git
|
||||||
|
cd athnos/
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
1. Download the latest python version from [here](https://www.python.org/downloads/) (at least version 3.6 or higher) and install it.
|
||||||
|
|
||||||
|
2. Download the [repository](https://github.com/ByteDream/athnos/archive/master.zip) and unzip it (e.g. with [7zip](https://www.7-zip.org/)).
|
||||||
|
|
||||||
|
3. Open the unzipped folder in the [cmd](https://www.minitool.com/news/how-to-open-a-file-folder-cmd.html).
|
||||||
|
|
||||||
|
4. Install PyQt5 and the requirements
|
||||||
|
```cmd
|
||||||
|
pip install pyqt5
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run🚀
|
||||||
|
|
||||||
|
After the [setup](#installation) is done, you can run **athnos** via
|
||||||
|
|
||||||
|
- `python3 main.py` on **Linux**
|
||||||
|
- `python main.py` on **Windows** (or just double click `main.py`)
|
||||||
|
|
||||||
|
|
||||||
|
## Compile🔨
|
||||||
|
|
||||||
|
If you want to compile independent executables, the [installation](#installation) has to be done first.
|
||||||
|
|
||||||
|
<h3 id="compile-linux">Linux</h3>
|
||||||
|
|
||||||
|
1. Go into the `athnos` folder and execute the following commands
|
||||||
|
```bash
|
||||||
|
pip3 install pyinstaller
|
||||||
|
pyinstaller --noconsole --onefile main.py
|
||||||
|
```
|
||||||
|
The path of the generated executable is `dist/main`.
|
||||||
|
|
||||||
|
Note that if you share the file with other systems,
|
||||||
|
the other systems `glibc` version must be equal or higher than the one on your system, because some python libraries
|
||||||
|
packed in the `main` file rely on them. If you want to make the file 'real' independent, see the next paragraph
|
||||||
|
|
||||||
|
##### Create real independent file
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
If you want to share the executable file with another systems which has a lower `glibc` version
|
||||||
|
(can be obtained if you run the `ldd --version` command), you need to 'rebuild' the generated `main` file.
|
||||||
|
The following method currently **only works on 64-bit machines / with 64-bit executables** and has some disadvantages:
|
||||||
|
It takes longer to startup and causes higher cpu load on startup. An alternate method is, to re-run the steps above on the oldest
|
||||||
|
system you can find / with the oldest `glibc` version.
|
||||||
|
To build the real independent file, you have to execute the following commands
|
||||||
|
```bash
|
||||||
|
apt install patchelf
|
||||||
|
pip3 install staticx
|
||||||
|
staticx dist/main dist/static_main
|
||||||
|
```
|
||||||
|
The now generated `dist/static_main` file is the independent file.
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
1. Open the [cmd](https://www.minitool.com/news/how-to-open-a-file-folder-cmd.html) in the `athnos` folder and execute the following commands
|
||||||
|
```cmd
|
||||||
|
pip install pyinstaller
|
||||||
|
pyinstaller --noconsole --onefile main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
2. The generated executable `main.exe` is in the new created `dist` folder
|
||||||
|
|
||||||
|
|
||||||
|
**Note: If a new major python3 version has been released lately, and you've installed this version,
|
||||||
|
PyInstaller may not work. See [here](#https://pypi.org/project/pyinstaller/#main-advantages) for all supported python3 version of PyInstaller**
|
||||||
|
|
||||||
|
|
||||||
|
If there is any issue while compiling or when you try to launch the compiled file, look at the [known issues](#known-issues).
|
||||||
|
When your issue isn't listed there or the given solution not works, feel free to open a new [issue]()
|
||||||
|
|
||||||
|
|
||||||
|
Successfully compiled (staticx and non-staticx executables) on
|
||||||
|
- Pop!_OS 20.10 with `python3.8.6`, `pyqt 5.15.0`, `pyinstaller 4.0`, `staticx 0.12.0`, `glibc 2.32`
|
||||||
|
- Ubuntu 20.04 with `python3.8.5`, `pyqt 5.14.1`, `pyinstaller 4.0`, `staticx 0.12.0`, `glibc 2.31`
|
||||||
|
- Manjaro 20.2 with `python3.8.6`, `pyqt 5.15.2`, `pyinstaller 4.0`, `staticx 0.12.0`, `glibc 2.32`
|
||||||
|
|
||||||
|
|
||||||
|
## Additional components
|
||||||
|
|
||||||
|
|
||||||
|
## Todo
|
||||||
|
|
||||||
|
- [ ] Tags for the source
|
||||||
|
- [ ] Colored tags
|
||||||
|
- [ ] Clip column hide
|
||||||
|
- [ ] Database driver download options
|
||||||
|
- [ ] Server software
|
||||||
|
- [ ] Custom style
|
||||||
|
- [ ] Optional plugins (e.g. direct download a youtube video by its link)
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
This project is licensed under the GNU General Public License v3.0 (GPL-3.0) - see the [LICENSE](LICENSE) file for more details
|
BIN
athnos.sqlite3
Executable file
BIN
athnos.sqlite3
Executable file
Binary file not shown.
8
athnos/__init__.py
Executable file
8
athnos/__init__.py
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
from .utils import Config as _Config, get_logger as _get_logger
|
||||||
|
|
||||||
|
|
||||||
|
# creates a global config
|
||||||
|
config = _Config()
|
||||||
|
|
||||||
|
# creates a global logger
|
||||||
|
logger = _get_logger()
|
0
athnos/cli/__init__.py
Executable file
0
athnos/cli/__init__.py
Executable file
223
athnos/cli/main.py
Executable file
223
athnos/cli/main.py
Executable file
@ -0,0 +1,223 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from dreamutils.file import recursive_directory_data
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import filetype
|
||||||
|
from typing import Dict, Union, Text
|
||||||
|
from json import dump
|
||||||
|
from ..database import Type
|
||||||
|
from zipfile import ZipFile, ZIP_DEFLATED
|
||||||
|
|
||||||
|
|
||||||
|
# creating the logger
|
||||||
|
logger = logging.getLogger('athnos cli')
|
||||||
|
# the logger format
|
||||||
|
formatter = logging.Formatter('%(levelname)s: %(message)s')
|
||||||
|
# creates and configures the loggers console output handler
|
||||||
|
console_handler = logging.StreamHandler()
|
||||||
|
console_handler.setFormatter(formatter)
|
||||||
|
# adding the console handler to the logger
|
||||||
|
logger.addHandler(console_handler)
|
||||||
|
# the logger level
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
|
class _AthnosHelpFormatter(argparse.RawDescriptionHelpFormatter):
|
||||||
|
"""A better format / formatter for the help message"""
|
||||||
|
|
||||||
|
def __init__(self, prog: Text):
|
||||||
|
super().__init__(prog)
|
||||||
|
|
||||||
|
def _format_action_invocation(self, action):
|
||||||
|
# see https://stackoverflow.com/questions/23936145/python-argparse-help-message-disable-metavar-for-short-options
|
||||||
|
if not action.option_strings:
|
||||||
|
metavar, = self._metavar_formatter(action, action.dest)(1)
|
||||||
|
return metavar
|
||||||
|
else:
|
||||||
|
parts = []
|
||||||
|
# if the Optional doesn't take a value, format is:
|
||||||
|
# -s, --long
|
||||||
|
if action.nargs == 0:
|
||||||
|
parts.extend(action.option_strings)
|
||||||
|
|
||||||
|
# if the Optional takes a value, format is:
|
||||||
|
# -s ARGS, --long ARGS
|
||||||
|
# change to
|
||||||
|
# -s, --long ARGS
|
||||||
|
else:
|
||||||
|
default = action.dest.upper()
|
||||||
|
args_string = self._format_args(action, default)
|
||||||
|
for option_string in action.option_strings:
|
||||||
|
# parts.append('%s %s' % (option_string, args_string))
|
||||||
|
parts.append('%s' % option_string)
|
||||||
|
parts[-1] += ' %s' % args_string
|
||||||
|
return ', '.join(parts)
|
||||||
|
|
||||||
|
def _format_action(self, action: argparse.Action):
|
||||||
|
# sets the position of the strings in the help message
|
||||||
|
help_position = min(self._action_max_length + 2, self._max_help_position)
|
||||||
|
self._max_help_position = self._width - help_position
|
||||||
|
return super()._format_action(action)
|
||||||
|
|
||||||
|
def _format_usage(self, usage, actions, groups, prefix=None):
|
||||||
|
# this is the help message. maybe there is a better way to do this, but I haven't found it (yet)
|
||||||
|
return f'Usage: {self._prog} [-h] [OPTIONS] path\n\n'
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Creates a \'.json\' file, containing all files from a given path '
|
||||||
|
'to simplify importing a huge number of files', formatter_class=_AthnosHelpFormatter)
|
||||||
|
|
||||||
|
option = parser.add_argument_group('OPTIONS')
|
||||||
|
option.add_argument('-d', '--description', action='store', default='',
|
||||||
|
help='The description for every clip')
|
||||||
|
option.add_argument('-o', '--out', action='store', default='clips.json',
|
||||||
|
help='The file to write all information in. Default is \'clips.json\'')
|
||||||
|
option.add_argument('-t', '--type', type=str, choices=['audio', 'video', 'image', 'other', 'ignore'], default='ignore',
|
||||||
|
help='Normally the command execution would stop and display an error if the file type can\'t figured out (ending is not specified or not supported) '
|
||||||
|
'but if this flag is specified all files which can\'t be assigned will be from the given type. '
|
||||||
|
'If the value is `ignore`, all not specified files will be ignored')
|
||||||
|
option.add_argument('-b', '--build', action='store_true',
|
||||||
|
help='If given a \'clips.zip\' will be created, containing all from the given path. '
|
||||||
|
'Be careful this flag, it might cause a very huge file!')
|
||||||
|
option.add_argument('-r', '--recursive', action='store_true',
|
||||||
|
help='If given and the given path is a directory, all files will be selected recursively')
|
||||||
|
option.add_argument('-q', '--quiet', action='store_true',
|
||||||
|
help='No output message besides errors will be displayed')
|
||||||
|
option.add_argument('-v', '--verbose', action='store_true',
|
||||||
|
help='Shows even more infos')
|
||||||
|
option.add_argument('--overwrite', action='store_true',
|
||||||
|
help='If given and the output file (default \'clips.json\' or specified with the `-o` flag) exists, it will be overwritten')
|
||||||
|
# parser.add_argument('-src', '--source', action='store_const')
|
||||||
|
parser.add_argument('path', action='store', help='Path of the directory to add the files')
|
||||||
|
|
||||||
|
parsed = parser.parse_args()
|
||||||
|
|
||||||
|
clips = {'move': False, 'copy': False, 'root_dir': os.path.realpath(parsed.path), 'clips': []}
|
||||||
|
|
||||||
|
if parsed.quiet:
|
||||||
|
logger.setLevel(logging.CRITICAL)
|
||||||
|
if parsed.verbose:
|
||||||
|
if logger.level == logging.CRITICAL:
|
||||||
|
logger.critical('Cannot use \'--quiet\' and \'--verbose\' at the same time')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
if parsed.build:
|
||||||
|
archive = ZipFile('clips.zip', 'w', compression=ZIP_DEFLATED)
|
||||||
|
logger.debug('Building zipfile is enabled')
|
||||||
|
else:
|
||||||
|
archive = None
|
||||||
|
|
||||||
|
if os.path.exists(parsed.path):
|
||||||
|
# if the file from the '--out' flag already exists in this directory and if the '--overwrite' flag is not given
|
||||||
|
if os.path.isfile(parsed.out) and not parsed.overwrite:
|
||||||
|
logger.critical(f'Cannot write the clips into \'{parsed.out}\': The file already exists. Use the `--overwrite` flag to overwrite the file')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
files_to_skip = [os.path.realpath(parsed.out)]
|
||||||
|
|
||||||
|
# set the default audio type
|
||||||
|
default_clip_type = Type.Clip.from_name(parsed.type)
|
||||||
|
if not default_clip_type:
|
||||||
|
default_clip_type = Type.Clip.OTHER
|
||||||
|
logger.debug(f'The default clip type is \'{parsed.type}\'')
|
||||||
|
|
||||||
|
# get the real / full path of the given path
|
||||||
|
full_path = os.path.realpath(parsed.path)
|
||||||
|
logger.debug(f'Real path: {full_path}')
|
||||||
|
if os.path.isfile(full_path):
|
||||||
|
logger.debug('Path is a file')
|
||||||
|
# creating a athnos json object out of the file(path)
|
||||||
|
clip = _json_object(full_path, parsed.description, default_clip_type)
|
||||||
|
# if the file cannot be ready or something like this
|
||||||
|
if clip == OSError:
|
||||||
|
logger.critical(f'Cannot process the file: {clip.strerror}')
|
||||||
|
return
|
||||||
|
# appending the new clip json object to `clips`
|
||||||
|
else:
|
||||||
|
clips['clips'].append(clip)
|
||||||
|
elif os.path.isdir(full_path):
|
||||||
|
logger.debug('Path is a directory')
|
||||||
|
if parsed.recursive:
|
||||||
|
logger.debug('Getting files recursively')
|
||||||
|
files = recursive_directory_data(full_path, only_files=True)
|
||||||
|
else:
|
||||||
|
logger.debug('Getting directory files')
|
||||||
|
files = [os.path.join(full_path, file) for file in os.listdir(full_path) if os.path.isfile(file)]
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
# checks first if the file in `files_to_skip`
|
||||||
|
if file in files_to_skip:
|
||||||
|
logger.warning(f'Skipping file {file}')
|
||||||
|
else:
|
||||||
|
# creating a athnos json object out of the file(path)
|
||||||
|
clip = _json_object(file, parsed.description, default_clip_type)
|
||||||
|
if clip != OSError:
|
||||||
|
logger.debug(f'Adding file {file}')
|
||||||
|
clips['clips'].append(clip)
|
||||||
|
# if `archive` is True and the file is not 'clips.zip', it will be written in the clips.zip file.
|
||||||
|
# if clips.zip tried to write itself into itself, a infinite recursion would be created.
|
||||||
|
# i recognized that, when the file already was around 26GB big...
|
||||||
|
if archive and file != os.path.realpath('clips.zip'):
|
||||||
|
logger.info(f'Adding {file} to archive')
|
||||||
|
try:
|
||||||
|
archive.write(file, arcname=f'clips/{file[len(full_path):]}')
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.info('Aborting process, removing clips.zip...')
|
||||||
|
archive.close()
|
||||||
|
os.remove('clips.zip')
|
||||||
|
logger.debug('Removed clips.zip')
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
logger.critical('Given path does not exist')
|
||||||
|
return
|
||||||
|
|
||||||
|
if not clips:
|
||||||
|
logger.critical('Could not proceed any file')
|
||||||
|
if archive:
|
||||||
|
logger.critical('Archive has no file, removing clips.zip...')
|
||||||
|
archive.close()
|
||||||
|
os.remove('clips.zip')
|
||||||
|
logger.debug('Removed clips.zip')
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
# dumping the the clips json object into a file
|
||||||
|
dump(clips, open(parsed.out, 'w+'), indent=4)
|
||||||
|
logger.debug(f'Dumped all clips into \'{parsed.out}\'')
|
||||||
|
|
||||||
|
if archive:
|
||||||
|
archive.close()
|
||||||
|
logger.info('Wrote archive')
|
||||||
|
|
||||||
|
|
||||||
|
def _json_object(file: str, description: str, default: Type.Clip = None) -> Union[Dict[str, Union[str, int, Dict[str, Union[str, int]]]], OSError, None]:
|
||||||
|
try:
|
||||||
|
if filetype.is_audio(file):
|
||||||
|
type_ = Type.Clip.AUDIO
|
||||||
|
elif filetype.is_video(file):
|
||||||
|
type_ = Type.Clip.VIDEO
|
||||||
|
elif filetype.is_image(file):
|
||||||
|
type_ = Type.Clip.IMAGE
|
||||||
|
elif default is not None:
|
||||||
|
type_ = default
|
||||||
|
else:
|
||||||
|
logger.critical(f'{file} is not a supported file type (audio, video, image). '
|
||||||
|
f'Maybe the file has an incorrect file ending?\n'
|
||||||
|
f'See https://github.com/h2non/filetype.py#supported-types for all supported file endings (only audio, video and image) '
|
||||||
|
f'or use the `-t` flag to specify what should happen with not correctly recognized files (use `-h` to get help)\n')
|
||||||
|
exit(0)
|
||||||
|
return
|
||||||
|
|
||||||
|
return {'source': {'type': '', 'path': '', 'name': '', 'description': '', 'season': '', 'episode': ''},
|
||||||
|
'path': file,
|
||||||
|
'type': type_.value,
|
||||||
|
'name': os.path.splitext(os.path.basename(file))[0],
|
||||||
|
'description': description}
|
||||||
|
# this gets caused if, for example, the given file is a socket file in linux
|
||||||
|
except OSError as e:
|
||||||
|
return e
|
824
athnos/database.py
Executable file
824
athnos/database.py
Executable file
@ -0,0 +1,824 @@
|
|||||||
|
from PyQt5 import QtSql
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Any, Dict, Union, List, Tuple
|
||||||
|
from . import logger
|
||||||
|
|
||||||
|
|
||||||
|
default_databases = [{'title': 'SQLite3', 'driver': 'QSQLITE', 'name': 'athnos.sqlite3', 'user': None, 'password': None, 'ip': None, 'port': None},
|
||||||
|
{'title': 'MariaDB', 'driver': 'QMARIADB', 'name': 'athnos', 'user': 'root', 'password': '', 'ip': '127.0.0.1', 'port': 3306},
|
||||||
|
{'title': 'MySQL', 'driver': 'QMYSQL', 'name': 'athnos', 'user': 'root', 'password': '', 'ip': '127.0.0.1', 'port': 3306},
|
||||||
|
{'title': 'PostgreSQL', 'driver': 'QPSQL', 'name': 'athnos', 'user': 'postgres', 'password': '', 'ip': '127.0.0.1', 'port': 5432},
|
||||||
|
{'title': 'ODBC', 'driver': 'QODBC', 'name': 'athnos', 'user': 'postgres', 'password': '', 'ip': '127.0.0.1', 'port': 1433},
|
||||||
|
{'title': 'IBM DB2', 'driver': 'QDB2', 'name': 'athnos', 'user': 'db2admin', 'password': 'db2admin', 'ip': '127.0.0.1', 'port': 50000},
|
||||||
|
{'title': 'Borland InterBase', 'driver': 'QIBASE', 'name': 'athnos', 'user': '', 'password': '', 'ip': '127.0.0.1', 'port': 3050}]
|
||||||
|
|
||||||
|
|
||||||
|
class _Table:
|
||||||
|
"""Base class of every table in `Database`"""
|
||||||
|
|
||||||
|
def __init__(self, database, table_name: str, zero_id_value=None):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
database (Database): Database of the table
|
||||||
|
table_name: Name of the table
|
||||||
|
"""
|
||||||
|
self.database = database
|
||||||
|
self.table_name = table_name
|
||||||
|
self.zero_id_value = zero_id_value
|
||||||
|
|
||||||
|
# checks if the table exists
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT 1 FROM {self.table_name}')
|
||||||
|
|
||||||
|
if query.lastError().isValid():
|
||||||
|
# raises an IOError if the table doesn't exist
|
||||||
|
raise IOError(query.lastError().text())
|
||||||
|
else:
|
||||||
|
# adds all table columns to a list
|
||||||
|
self.columns = []
|
||||||
|
column_record = self.database.record(table_name)
|
||||||
|
for column in range(column_record.count()):
|
||||||
|
# » reads the column names and adds it
|
||||||
|
self.columns.append(column_record.field(column).name())
|
||||||
|
|
||||||
|
# sets `self.item` and `self.rows`.
|
||||||
|
# `self.item` is a child class of `_Row`, `self.rows` is a child class of `self._Rows`
|
||||||
|
if issubclass(self.__class__, Database._Clip):
|
||||||
|
self.item = Clip
|
||||||
|
self.rows = ClipRows
|
||||||
|
elif issubclass(self.__class__, Database._Item):
|
||||||
|
self.item = Item
|
||||||
|
self.rows = ItemRows
|
||||||
|
elif issubclass(self.__class__, Database._Source):
|
||||||
|
self.item = Source
|
||||||
|
self.rows = SourceRows
|
||||||
|
else:
|
||||||
|
self.item = Tag
|
||||||
|
self.rows = TagRows
|
||||||
|
|
||||||
|
def delete(self, id: int) -> None:
|
||||||
|
"""
|
||||||
|
Deletes the entry with the corresponding id from the database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: ID of the entry to delete
|
||||||
|
"""
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'DELETE FROM {self.table_name} WHERE id={id}')
|
||||||
|
if query.lastError().isValid():
|
||||||
|
logger.warning(f'Error while deleting {id} from {self.table_name}: {query.lastError().text()}')
|
||||||
|
|
||||||
|
def edit(self, id: int, **kwargs) -> None:
|
||||||
|
"""
|
||||||
|
Edits the entry with the corresponding id from the database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: ID of the entry to edit
|
||||||
|
**kwargs: New values for specific columns
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: if one of the `**kwargs` is not in `self.columns` or is ``id``
|
||||||
|
"""
|
||||||
|
self.make_sql_valid(kwargs)
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'UPDATE {self.table_name} SET {", ".join([f"{column}={value}" for column, value in kwargs.items()])} WHERE id={id}')
|
||||||
|
if query.lastError().isValid():
|
||||||
|
logger.warning(f'Error while updating {id} in {self.table_name}: {query.lastError().text()}')
|
||||||
|
|
||||||
|
def get(self, id: int):
|
||||||
|
"""
|
||||||
|
Get a database object by it's id
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: The id of the object you want to get
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
[Clip, Item, Source, Tag]: The database object
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
QtSql.QSqlError: If the sql query wasn't executed correct
|
||||||
|
"""
|
||||||
|
if id == 0:
|
||||||
|
# returns a special value if `id` is 0 and `self.zero_id_value` is not None
|
||||||
|
if self.zero_id_value:
|
||||||
|
return self.zero_id_value
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT * FROM {self.table_name} WHERE id={id}')
|
||||||
|
self.validate_query(query, True)
|
||||||
|
return self.item(self.database, query)
|
||||||
|
|
||||||
|
def get_all(self):
|
||||||
|
"""
|
||||||
|
Get all infos in the table
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
_Rows: The infos stored in a child row from ``_Rows``
|
||||||
|
"""
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT * FROM {self.table_name}')
|
||||||
|
self.validate_query(query, True)
|
||||||
|
return self.rows(self.database, query=query)
|
||||||
|
|
||||||
|
def get_all_by(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Get items by its values
|
||||||
|
|
||||||
|
Args:
|
||||||
|
**kwargs: The values from the items you want to get
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The information stored in a child class of ``_Rows``
|
||||||
|
"""
|
||||||
|
self.make_sql_valid(kwargs)
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT * FROM {self.table_name} WHERE {" AND ".join(f"{column_name}={value}" for column_name, value in kwargs.items())}')
|
||||||
|
self.validate_query(query, True)
|
||||||
|
return self.rows(self.database, query=query)
|
||||||
|
|
||||||
|
def get_by(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Get a item by its values
|
||||||
|
|
||||||
|
Args:
|
||||||
|
**kwargs: The values from the item you want to get
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The information stored in a child class of ``_Row``
|
||||||
|
"""
|
||||||
|
self.make_sql_valid(kwargs)
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT * FROM {self.table_name} WHERE {" AND ".join(f"{column_name}={value}" for column_name, value in kwargs.items())}')
|
||||||
|
self.validate_query(query, True)
|
||||||
|
return self.item(self.database, query=query)
|
||||||
|
|
||||||
|
def has(self, **kwargs) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if the table has a entry, corresponding with the `**kwargs`
|
||||||
|
|
||||||
|
Args:
|
||||||
|
include_missing: Includes all column names (besides `id`), which weren't specified in `**kwargs` and set their value to None / NULL
|
||||||
|
**kwargs: Table keys and their values to check if they exists in the table
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
If the `**kwargs` are in the table
|
||||||
|
"""
|
||||||
|
self.make_sql_valid(kwargs)
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT 1 FROM {self.table_name} WHERE ({" AND ".join(f"{key}={value}" for key, value in kwargs.items())})')
|
||||||
|
self.validate_query(query, True)
|
||||||
|
if query.isValid():
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def has_id(self, id: int) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if the table has a given id
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: ID to check if its in the table
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
If the id is in the table
|
||||||
|
"""
|
||||||
|
return self.has(id=id)
|
||||||
|
|
||||||
|
def highest_id(self) -> int:
|
||||||
|
"""
|
||||||
|
Selects the highest / max id from the given `self.table_name`
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The highest id
|
||||||
|
|
||||||
|
"""
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT MAX(id) FROM {self.table_name}')
|
||||||
|
query.next()
|
||||||
|
|
||||||
|
# the highest id
|
||||||
|
highest_id = query.value(0)
|
||||||
|
|
||||||
|
if highest_id:
|
||||||
|
return highest_id
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def new_query(self) -> QtSql.QSqlQuery:
|
||||||
|
"""
|
||||||
|
Get a new sql query
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The sql query
|
||||||
|
|
||||||
|
"""
|
||||||
|
return QtSql.QSqlQuery(self.database)
|
||||||
|
|
||||||
|
def make_sql_valid(self, to_correct: Union[Dict[Any, Any], List[Any]]) -> Union[Dict[Any, Any], List[Any]]:
|
||||||
|
"""
|
||||||
|
Makes all items in a dictionary or list valid to use in a sql query
|
||||||
|
|
||||||
|
Args:
|
||||||
|
to_correct: The dict or list to make valid
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The corrected dict or list
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If one of the items in not str, int or bool
|
||||||
|
"""
|
||||||
|
if isinstance(to_correct, dict):
|
||||||
|
for key, value in to_correct.items():
|
||||||
|
if isinstance(value, str):
|
||||||
|
to_correct[key] = f'"{value}"'
|
||||||
|
elif isinstance(value, int):
|
||||||
|
to_correct[key] = str(value)
|
||||||
|
elif not isinstance(value, bool):
|
||||||
|
raise ValueError(f'The value {value} of key {key} must be type str, int or bool')
|
||||||
|
elif isinstance(to_correct, list):
|
||||||
|
for i, item in enumerate(to_correct):
|
||||||
|
if isinstance(item, str):
|
||||||
|
to_correct[i] = f'"{item}"'
|
||||||
|
elif isinstance(item, int):
|
||||||
|
to_correct[i] = str(item)
|
||||||
|
elif not isinstance(item, bool):
|
||||||
|
raise ValueError(f'{item} must be type str, int or bool')
|
||||||
|
|
||||||
|
return to_correct
|
||||||
|
|
||||||
|
def validate_query(self, query: QtSql.QSqlQuery, error=False) -> bool:
|
||||||
|
"""
|
||||||
|
Checks if the given query has errors and if it has, a log output will be generated
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: Query to check
|
||||||
|
error: If given, instead of the log output, a error will be raised
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
If the query has errors or not
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
IOError: If the query has errors and `error` is True
|
||||||
|
"""
|
||||||
|
if query.lastError().isValid():
|
||||||
|
message = f'Error while executing query \'{query.lastQuery()}\': {query.lastError().text()}'
|
||||||
|
if error:
|
||||||
|
raise IOError(message)
|
||||||
|
else:
|
||||||
|
logger.warning(message)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class Type:
|
||||||
|
"""Enum for clip / source types"""
|
||||||
|
class Clip(Enum):
|
||||||
|
OTHER = 0
|
||||||
|
AUDIO = 1
|
||||||
|
IMAGE = 2
|
||||||
|
VIDEO = 3
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_name(name: str):
|
||||||
|
"""
|
||||||
|
Returns a `Type.Clip` by its name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Name of the value
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Type.Clip: The corresponding type
|
||||||
|
"""
|
||||||
|
for type in Type.Clip:
|
||||||
|
if type.name.lower() == name.lower():
|
||||||
|
return type
|
||||||
|
|
||||||
|
class Source(Enum):
|
||||||
|
OTHER = 0
|
||||||
|
AUDIO = 1
|
||||||
|
MOVIE = 2
|
||||||
|
SERIES = 3
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_name(name: str):
|
||||||
|
"""
|
||||||
|
Returns a `Type.Source` by its name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Name of the value
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Type.Source: The corresponding type
|
||||||
|
"""
|
||||||
|
for type in Type.Source:
|
||||||
|
if type.name.lower() == name.lower():
|
||||||
|
return type
|
||||||
|
|
||||||
|
|
||||||
|
class Database(QtSql.QSqlDatabase):
|
||||||
|
|
||||||
|
def __init__(self, database: QtSql.QSqlDatabase, auto_table=True):
|
||||||
|
super().__init__(database)
|
||||||
|
|
||||||
|
self._auto_table = auto_table
|
||||||
|
|
||||||
|
# if `auto_table` is True it will be checked if every table exists and if not
|
||||||
|
# it will be created
|
||||||
|
if auto_table:
|
||||||
|
tables = self.tables()
|
||||||
|
if 'clip' not in tables:
|
||||||
|
self.new_query().exec('CREATE TABLE clip (id int(10) DEFAULT NULL,'
|
||||||
|
'source_id int(10) DEFAULT NULL,'
|
||||||
|
'path text DEFAULT NULL,'
|
||||||
|
'type smallint(1) DEFAULT NULL,'
|
||||||
|
'name text DEFAULT NULL,'
|
||||||
|
'description text DEFAULT NULL)')
|
||||||
|
logger.debug('Created clip table')
|
||||||
|
if 'item' not in tables:
|
||||||
|
self.new_query().exec('CREATE TABLE item (id int(10) DEFAULT NULL,'
|
||||||
|
'clip_id int(10) DEFAULT NULL,'
|
||||||
|
'tag_id int(10) DEFAULT NULL)')
|
||||||
|
logger.debug('Created item table')
|
||||||
|
if 'source' not in tables:
|
||||||
|
self.new_query().exec('CREATE TABLE source (id int(10) DEFAULT NULL,'
|
||||||
|
'path text DEFAULT NULL,'
|
||||||
|
'type smallint(1) DEFAULT NULL,'
|
||||||
|
'name text DEFAULT NULL,'
|
||||||
|
'season text DEFAULT NULL,'
|
||||||
|
'episode text DEFAULt NULL,'
|
||||||
|
'description text DEFAULT NULL)')
|
||||||
|
logger.debug('Created source table')
|
||||||
|
if 'tag' not in tables:
|
||||||
|
self.new_query().exec('CREATE TABLE tag (id int(10) DEFAULT NULL,'
|
||||||
|
'name text DEFAULT NULL,'
|
||||||
|
'color char(7) DEFAULT "#c8c8c8")') # <- will be needed in a future update
|
||||||
|
logger.debug('Created tag table')
|
||||||
|
|
||||||
|
# initializes the table classes and makes it public available
|
||||||
|
self.Clip = self._Clip(self)
|
||||||
|
self.Item = self._Item(self)
|
||||||
|
self.Source = self._Source(self)
|
||||||
|
self.Tag = self._Tag(self)
|
||||||
|
|
||||||
|
class _Clip(_Table):
|
||||||
|
"""Class for the 'clip' table"""
|
||||||
|
|
||||||
|
table_name = 'clip'
|
||||||
|
|
||||||
|
def __init__(self, database):
|
||||||
|
super().__init__(database, Database._Clip.table_name, Clip(database, None, 0, 0, "", Type.Clip.OTHER.value, "", ""))
|
||||||
|
|
||||||
|
def add_clip(self, path: str, source_id: int = None, type: Union[Type.Clip, int] = Type.Clip.OTHER, name: str = None, description: str = None):
|
||||||
|
"""
|
||||||
|
Adds a new clip to the database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: Path of the clip
|
||||||
|
source_id: Id of the clips source
|
||||||
|
type: Type of the clip to add
|
||||||
|
name: Name of the clip
|
||||||
|
description: Description of the clip
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Clip: The new created clip
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
TypeError: If `type_` is int and ``Type.Clip`` has no value like `type_`
|
||||||
|
"""
|
||||||
|
|
||||||
|
if isinstance(type, int):
|
||||||
|
type = Type.Clip(type)
|
||||||
|
|
||||||
|
clip_id = self.highest_id() + 1
|
||||||
|
|
||||||
|
if source_id is None:
|
||||||
|
source_id = 0
|
||||||
|
|
||||||
|
# adds the new clip to the table
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'INSERT INTO {self.table_name} (id, source_id, path, type, name, description)'
|
||||||
|
f'VALUES ({clip_id}, {source_id}, "{path}", {type.value}, "{name}", "{description}")')
|
||||||
|
|
||||||
|
if self.validate_query(query):
|
||||||
|
return Clip(self.database, None, clip_id, source_id, path, type.value, name, description)
|
||||||
|
else:
|
||||||
|
return Clip(self.database)
|
||||||
|
|
||||||
|
def add_clips(self, clips: List[Dict[str, Union[str, int, Type.Clip]]]):
|
||||||
|
"""
|
||||||
|
Adds a new clip to the database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
clips: The clips to add. See `self.add_clip(...)` for more information about the elements
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Clip]: A list of the new created clips
|
||||||
|
|
||||||
|
"""
|
||||||
|
keys = ['path', 'source_id', 'type', 'name', 'description']
|
||||||
|
|
||||||
|
new_clips = []
|
||||||
|
highest_id = self.highest_id()
|
||||||
|
|
||||||
|
for i, clip in enumerate(clips):
|
||||||
|
clip['id'] = highest_id + i + 1
|
||||||
|
for key in keys:
|
||||||
|
# adds the non existing key to the dict
|
||||||
|
if key not in clip:
|
||||||
|
if key == 'path':
|
||||||
|
raise IOError(f'path must be specified in {clip}')
|
||||||
|
elif key in ('name', 'description'):
|
||||||
|
clip[key] = ''
|
||||||
|
elif key == 'source_id':
|
||||||
|
clip[key] = 0
|
||||||
|
elif key == 'type':
|
||||||
|
clip[key] = Type.Clip.OTHER
|
||||||
|
if key == 'type' and not isinstance(key, int):
|
||||||
|
clip[key] = Type.Clip(clip[key])
|
||||||
|
new_clips.append(Clip(self.database, None, clip))
|
||||||
|
|
||||||
|
query = self.new_query()
|
||||||
|
# adds the new clips to the table
|
||||||
|
query.exec(f'INSERT INTO {self.table_name} (id, source_id, path, type, name, description) VALUES '
|
||||||
|
f'({"), (".join([", ".join(self.make_sql_valid(clip["id"], [clip["source_id"], clip["path"], clip["type"].value, clip["name"], clip["description"]])) for clip in clips])})')
|
||||||
|
self.validate_query(query, True)
|
||||||
|
|
||||||
|
|
||||||
|
class _Item(_Table):
|
||||||
|
"""Class for the 'item' table"""
|
||||||
|
|
||||||
|
table_name = 'item'
|
||||||
|
|
||||||
|
def __init__(self, database):
|
||||||
|
super().__init__(database, Database._Item.table_name, Item(database, None, 0, 0, 0))
|
||||||
|
|
||||||
|
def add_item(self, clip_id, tag_id):
|
||||||
|
"""
|
||||||
|
Adds a new item to the database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tag_id: Id of the tag
|
||||||
|
clip_id: Id of the clip
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Item_ The new created item
|
||||||
|
|
||||||
|
"""
|
||||||
|
item_id = self.highest_id() + 1
|
||||||
|
|
||||||
|
# adds the new item to the table
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'INSERT INTO {self.table_name} (id, clip_id, tag_id)'
|
||||||
|
f'VALUES ({item_id}, {clip_id}, {tag_id})')
|
||||||
|
|
||||||
|
if self.validate_query(query):
|
||||||
|
return Item(self.database, None, item_id, clip_id, tag_id)
|
||||||
|
else:
|
||||||
|
return Item(self.database)
|
||||||
|
|
||||||
|
class _Source(_Table):
|
||||||
|
"""Class for the 'source' table"""
|
||||||
|
|
||||||
|
table_name = 'source'
|
||||||
|
|
||||||
|
def __init__(self, database):
|
||||||
|
super().__init__(database, Database._Source.table_name, Source(database, None, 0, "", Type.Source.OTHER.value, "", "", "", ""))
|
||||||
|
|
||||||
|
def add_source(self, path_or_url: str, type: Union[Type.Source, int], name: str, description: str = None, season: str = None, episode: str = None):
|
||||||
|
"""
|
||||||
|
Adds a new source to the database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path_or_url: Path or url to the source
|
||||||
|
type: Type of the source to add
|
||||||
|
name: Name of the source
|
||||||
|
description: Description of the source
|
||||||
|
season: Season of the source. Is only used if type_ is `Type.Source.SERIES`
|
||||||
|
episode: Episode of the source. Is only used if type_ is `Type.Source.SERIES`
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Source: The new created source
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
TypeError: If `type_` is int and ``Type.Source`` has no value like `type_`
|
||||||
|
"""
|
||||||
|
if isinstance(type, int):
|
||||||
|
type = Type.Source(type)
|
||||||
|
if type is not Type.Source.SERIES:
|
||||||
|
season = None
|
||||||
|
episode = None
|
||||||
|
|
||||||
|
source_id = self.highest_id() + 1
|
||||||
|
|
||||||
|
# adds the new source to the table
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'INSERT INTO {self.table_name} (id, path, type, name, description, season, episode)'
|
||||||
|
f'VALUES ({source_id}, "{path_or_url}", {type.value}, "{name}", "{description}", "{season}", "{episode}")')
|
||||||
|
|
||||||
|
if self.validate_query(query):
|
||||||
|
return source_id
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
class _Tag(_Table):
|
||||||
|
"""Class for the 'tag' table"""
|
||||||
|
|
||||||
|
table_name = 'tag'
|
||||||
|
|
||||||
|
def __init__(self, database):
|
||||||
|
super().__init__(database, Database._Tag.table_name, Tag(database, None, 0, ""))
|
||||||
|
|
||||||
|
def add_tag(self, tag_name: str):
|
||||||
|
"""
|
||||||
|
Adds a new tag to the database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tag_name: Name of the new tag
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tag: The new created tag
|
||||||
|
"""
|
||||||
|
tag_id = self.highest_id() + 1
|
||||||
|
|
||||||
|
# adds the new tag to the database
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'INSERT INTO {self.table_name} (id, name)'
|
||||||
|
f'VALUES ({tag_id}, "{tag_name}")')
|
||||||
|
|
||||||
|
if self.validate_query(query):
|
||||||
|
return Tag(self.database, None, tag_id, tag_name)
|
||||||
|
else:
|
||||||
|
return Tag(self.database)
|
||||||
|
|
||||||
|
def get_tags_by_clip_id(self, clip_id: int):
|
||||||
|
"""
|
||||||
|
Receive all tags for a specific clip
|
||||||
|
|
||||||
|
Args:
|
||||||
|
clip_id: Id of the clip
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
ClipRows: All tags from the given clip ids
|
||||||
|
|
||||||
|
"""
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT tag_id FROM {Item.table_name} WHERE clip_id={clip_id}')
|
||||||
|
if self.validate_query(query):
|
||||||
|
ids = []
|
||||||
|
while query.next():
|
||||||
|
ids.append(str(query.value(0)))
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT * FROM {Tag.table_name} WHERE id IN ({", ".join(ids)})')
|
||||||
|
if self.validate_query(query):
|
||||||
|
return TagRows(self.database, query=query)
|
||||||
|
return TagRows(self.database)
|
||||||
|
|
||||||
|
def new_query(self) -> QtSql.QSqlQuery:
|
||||||
|
return QtSql.QSqlQuery(self)
|
||||||
|
|
||||||
|
|
||||||
|
class _Row:
|
||||||
|
"""Class where all information about a row in a table is stored"""
|
||||||
|
|
||||||
|
def __init__(self, database: Database, query: QtSql.QSqlQuery = None, *args):
|
||||||
|
self._database = database
|
||||||
|
self.query = query
|
||||||
|
|
||||||
|
# makes the id better available
|
||||||
|
if args:
|
||||||
|
self.id = args[0]
|
||||||
|
else:
|
||||||
|
self.query.next()
|
||||||
|
self.id = query.value(0)
|
||||||
|
|
||||||
|
|
||||||
|
class Clip(_Row):
|
||||||
|
"""Class where all information about a row in the 'clip' table is stored"""
|
||||||
|
|
||||||
|
table_name = 'clip'
|
||||||
|
|
||||||
|
def __init__(self, database: Database, query: QtSql.QSqlQuery = None, *args):
|
||||||
|
super().__init__(database, query, *args)
|
||||||
|
|
||||||
|
if args:
|
||||||
|
self.source_id: int = args[1]
|
||||||
|
self.path: str = args[2]
|
||||||
|
self.type = Type.Clip(args[3])
|
||||||
|
self.name: str = args[4]
|
||||||
|
self.description: str = args[5]
|
||||||
|
else:
|
||||||
|
self.source_id: int = self.query.value(1)
|
||||||
|
self.path: str = self.query.value(2)
|
||||||
|
self.type = Type.Clip(self.query.value(3))
|
||||||
|
self.name: str = self.query.value(4)
|
||||||
|
self.description: str = self.query.value(5)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.source_id, self.path, self.type, self.name, self.description))
|
||||||
|
|
||||||
|
def get_source(self):
|
||||||
|
"""
|
||||||
|
Get the clip's source
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Source: The clip's source
|
||||||
|
"""
|
||||||
|
return self._database.Source.get(self.source_id)
|
||||||
|
|
||||||
|
def get_tags(self):
|
||||||
|
"""
|
||||||
|
Get all tags with which the clip is tagged
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
TagRows: All tags from the clip
|
||||||
|
"""
|
||||||
|
return self._database.Tag.get_tags_by_clip_id(self.id)
|
||||||
|
|
||||||
|
def remove_tag(self, tag_id: int) -> None:
|
||||||
|
"""
|
||||||
|
Removes a tag from the clip
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tag_id: Id of the tag to remove
|
||||||
|
"""
|
||||||
|
self._database.Item.delete(self._database.Item.get_by(clip_id=self.id, tag_id=tag_id).id)
|
||||||
|
|
||||||
|
|
||||||
|
class Item(_Row):
|
||||||
|
"""Class where all information about a row in the 'item' table is stored"""
|
||||||
|
|
||||||
|
table_name = 'item'
|
||||||
|
|
||||||
|
def __init__(self, database: Database, query: QtSql.QSqlQuery = None, *args):
|
||||||
|
super().__init__(database, query, *args)
|
||||||
|
|
||||||
|
if args:
|
||||||
|
self.clip_id: int = args[1]
|
||||||
|
self.tag_id: int = args[2]
|
||||||
|
else:
|
||||||
|
self.clip_id: int = self.query.value(1)
|
||||||
|
self.tag_id: int = self.query.value(2)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.clip_id, self.tag_id))
|
||||||
|
|
||||||
|
|
||||||
|
class Source(_Row):
|
||||||
|
"""Class where all information about a row in the 'source' table is stored"""
|
||||||
|
|
||||||
|
table_name = 'source'
|
||||||
|
|
||||||
|
def __init__(self, database: Database, query: QtSql.QSqlQuery = None, *args):
|
||||||
|
super().__init__(database, query, *args)
|
||||||
|
|
||||||
|
if args:
|
||||||
|
self.path: str = args[1]
|
||||||
|
self.type = Type.Source(args[2])
|
||||||
|
self.name: str = args[3]
|
||||||
|
self.season: str = args[4]
|
||||||
|
self.episode: str = args[5]
|
||||||
|
self.description: str = args[6]
|
||||||
|
else:
|
||||||
|
self.path: str = self.query.value(1)
|
||||||
|
self.type = Type.Source(self.query.value(2))
|
||||||
|
self.name: str = self.query.value(3)
|
||||||
|
self.season: str = self.query.value(4)
|
||||||
|
self.episode: str = self.query.value(5)
|
||||||
|
self.description: str = self.query.value(6)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.path, self.type, self.name, self.season, self.episode, self.description))
|
||||||
|
|
||||||
|
def get_all_clips(self):
|
||||||
|
"""
|
||||||
|
Get all clips using this source
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
ClipRows: All clips using this source
|
||||||
|
"""
|
||||||
|
return self._database.Clip.get_all_by(source_id=self.id)
|
||||||
|
|
||||||
|
|
||||||
|
class Tag(_Row):
|
||||||
|
"""Class where all information about a row in the 'tag' table is stored"""
|
||||||
|
|
||||||
|
table_name = 'tag'
|
||||||
|
|
||||||
|
def __init__(self, database: Database, query: QtSql.QSqlQuery = None, *args):
|
||||||
|
super().__init__(database, query, *args)
|
||||||
|
|
||||||
|
if args:
|
||||||
|
self.name: str = args[1]
|
||||||
|
else:
|
||||||
|
self.name: str = self.query.value(1)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.name,))
|
||||||
|
|
||||||
|
|
||||||
|
class _Rows(list):
|
||||||
|
"""Class where all information about multiple rows in a table are stored in"""
|
||||||
|
|
||||||
|
def __init__(self, database: Database, row_type: _Row.__class__, rows: List[_Row.__class__] = None, query: QtSql.QSqlQuery = None):
|
||||||
|
super().__init__()
|
||||||
|
self._database = database
|
||||||
|
self.query = query
|
||||||
|
|
||||||
|
if rows:
|
||||||
|
self.extend(rows)
|
||||||
|
else:
|
||||||
|
if query:
|
||||||
|
columns = query.record().count()
|
||||||
|
# iterate through the query to get all values
|
||||||
|
while query.next():
|
||||||
|
self.append(row_type(database, *[query.value(count) for count in range(-1, columns)]))
|
||||||
|
else:
|
||||||
|
raise ValueError('rows and query cannot be None at the same time')
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((hash(item) for item in self))
|
||||||
|
|
||||||
|
def new_query(self) -> QtSql.QSqlQuery:
|
||||||
|
"""
|
||||||
|
Get a new sql query
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The sql query
|
||||||
|
"""
|
||||||
|
return QtSql.QSqlQuery(self._database)
|
||||||
|
|
||||||
|
|
||||||
|
class ClipRows(_Rows):
|
||||||
|
"""Class where all information about multiple rows in the 'clip' table are stored in"""
|
||||||
|
|
||||||
|
table_name = Clip.table_name
|
||||||
|
|
||||||
|
def __init__(self, database: Database, rows: List[Clip] = None, query: QtSql.QSqlQuery = None):
|
||||||
|
super().__init__(database, Clip, rows, query)
|
||||||
|
|
||||||
|
self.table_name = Database._Clip.table_name
|
||||||
|
|
||||||
|
|
||||||
|
class ItemRows(_Rows):
|
||||||
|
"""Class where all information about multiple rows in the 'item' table are stored in"""
|
||||||
|
|
||||||
|
table_name = Item.table_name
|
||||||
|
|
||||||
|
def __init__(self, database: Database, rows: List[Item] = None, query: QtSql.QSqlQuery = None):
|
||||||
|
super().__init__(database, Item, rows, query)
|
||||||
|
|
||||||
|
self.table_name = Database._Item.table_name
|
||||||
|
|
||||||
|
def get_clips(self) -> ClipRows:
|
||||||
|
"""
|
||||||
|
Get all clips which have one of the here saved clip_ids as a id
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
All corresponding clips
|
||||||
|
"""
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT * FROM {Database._Clip.table_name} WHERE id IN ({", ".join(item.tag_id for item in self)})')
|
||||||
|
return ClipRows(self._database, query=query)
|
||||||
|
|
||||||
|
|
||||||
|
class SourceRows(_Rows):
|
||||||
|
"""Class where all information about multiple rows in the 'source' table are stored in"""
|
||||||
|
|
||||||
|
table_name = Source.table_name
|
||||||
|
|
||||||
|
def __init__(self, database: Database, rows: List[Source] = None, query: QtSql.QSqlQuery = None):
|
||||||
|
super().__init__(database, Source, rows, query)
|
||||||
|
|
||||||
|
self.table_name = Database._Source.table_name
|
||||||
|
|
||||||
|
def get_tags(self):
|
||||||
|
"""
|
||||||
|
Get all tags which have one of the here saved sources as source
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
TagRows: All corresponding tags
|
||||||
|
"""
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT * FROM {Tag.table_name} WHERE source_id IN ({", ".join(str(item.id) for item in self)})')
|
||||||
|
return TagRows(self._database, query=query)
|
||||||
|
|
||||||
|
|
||||||
|
class TagRows(_Rows):
|
||||||
|
"""Class where all information about multiple rows in the 'tag' table are stored in"""
|
||||||
|
|
||||||
|
table_name = Tag.table_name
|
||||||
|
|
||||||
|
def __init__(self, database: Database, rows: List[Tag] = None, query: QtSql.QSqlQuery = None):
|
||||||
|
super().__init__(database, Tag, rows, query)
|
||||||
|
|
||||||
|
self.table_name = Database._Tag.table_name
|
||||||
|
|
||||||
|
def get_items(self) -> ItemRows:
|
||||||
|
"""
|
||||||
|
Get all clips which have one of the here saved tags as a tag
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
All corresponding clips
|
||||||
|
"""
|
||||||
|
query = self.new_query()
|
||||||
|
query.exec(f'SELECT clip_id FROM {Database._Item.table_name} WHERE tag_id IN ({", ".join(item.id for item in self)})')
|
||||||
|
return ItemRows(self._database, query=query)
|
190
athnos/utils.py
Executable file
190
athnos/utils.py
Executable file
@ -0,0 +1,190 @@
|
|||||||
|
from dreamutils.os import platform, Platform
|
||||||
|
from PyQt5.QtWidgets import QApplication
|
||||||
|
from typing import Any, Dict, Union, Mapping, overload, Iterable, Tuple
|
||||||
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import urllib.error, urllib.request
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class AthnosPath:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def athnos_path() -> Path:
|
||||||
|
"""Returns the path where all athnos stuff like clips or configurations are stored"""
|
||||||
|
if platform() == Platform.WINDOWS:
|
||||||
|
clip_path = Path.home().joinpath('AppData\\Roaming\\athnos')
|
||||||
|
else:
|
||||||
|
clip_path = Path.home().joinpath('.athnos/')
|
||||||
|
|
||||||
|
return clip_path
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clips_path(cls) -> Path:
|
||||||
|
"""Returns the path where the clips should be stored"""
|
||||||
|
return cls.athnos_path().joinpath('clips')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def config_path(cls) -> Path:
|
||||||
|
"""Path to the config file"""
|
||||||
|
return cls.athnos_path().joinpath('config.json')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def logging_path(cls) -> Path:
|
||||||
|
"""Path to the log file"""
|
||||||
|
return cls.athnos_path().joinpath('athnos.log')
|
||||||
|
|
||||||
|
|
||||||
|
class Config(dict):
|
||||||
|
"""Class to read / edit the configuration"""
|
||||||
|
|
||||||
|
config_path = AthnosPath.config_path()
|
||||||
|
|
||||||
|
def __init__(self, auto_write=True):
|
||||||
|
self.auto_write = auto_write
|
||||||
|
# creates the file if it doesn't exits
|
||||||
|
if not self.config_path.is_file():
|
||||||
|
super().__init__()
|
||||||
|
self.config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
self.set_default()
|
||||||
|
|
||||||
|
# loads the config file
|
||||||
|
file = self.config_path.open('r')
|
||||||
|
super().__init__(json.load(file))
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
super().__setitem__(key, value)
|
||||||
|
if self.auto_write:
|
||||||
|
self.write()
|
||||||
|
|
||||||
|
def set_default(self) -> None:
|
||||||
|
"""Sets the default parameter of the file"""
|
||||||
|
json.dump({'check_for_updates': True,
|
||||||
|
'update-notification': 'minor',
|
||||||
|
'updates_ignore': [],
|
||||||
|
'style': QApplication.style().objectName(),
|
||||||
|
'database': {'title': 'SQLite3', 'driver': 'QSQLITE', 'name': 'athnos.sqlite3', 'user': None, 'password': None, 'ip': None, 'port': None}},
|
||||||
|
open(self.config_path, 'w'), indent=4)
|
||||||
|
|
||||||
|
def write(self) -> None:
|
||||||
|
"""Writes the config file"""
|
||||||
|
json.dump(self, open(self.config_path, 'w'), indent=4)
|
||||||
|
|
||||||
|
|
||||||
|
def check_version(current_version: str) -> Union[Dict[str, Any], None]:
|
||||||
|
"""Checks if a new version was released"""
|
||||||
|
from . import config, logger
|
||||||
|
|
||||||
|
update_notification = config['update-notification']
|
||||||
|
# checks if '-' is in `current-version`.
|
||||||
|
# might be possible if version is x.y.z-beta or something else
|
||||||
|
if '-' in current_version:
|
||||||
|
internal_version, internal_pre_release = current_version.split('-')
|
||||||
|
internal_version = internal_version.split('.')
|
||||||
|
else:
|
||||||
|
internal_version = current_version.split('.')
|
||||||
|
|
||||||
|
if update_notification is not None:
|
||||||
|
try:
|
||||||
|
# fetch all release versions
|
||||||
|
latest = urllib.request.urlopen('https://api.github.com/repos/ByteDream/athnos/tags')
|
||||||
|
data = json.loads(latest.read().decode())
|
||||||
|
|
||||||
|
notification = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
notification_level = {'major': 0, 'minor': 1, 'patch': 2, 'all': 3}[update_notification]
|
||||||
|
full_break = False
|
||||||
|
|
||||||
|
for release in data:
|
||||||
|
# searches the version number and the eventual pre release
|
||||||
|
release_regex = re.search(r'^v(?P<version>(?:\d*\.){,2}\d*)-?(?P<pre_release>.*$)', release['name'])
|
||||||
|
version = release_regex.group('version').split('.')
|
||||||
|
|
||||||
|
if release['name'] in config['updates_ignore']:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# if the version is not x.y.z
|
||||||
|
if len(version) == 2:
|
||||||
|
version.append('0')
|
||||||
|
|
||||||
|
if version > internal_version:
|
||||||
|
for i in range(0, len(version)):
|
||||||
|
if version[i] > internal_version[i]:
|
||||||
|
if notification_level >= i:
|
||||||
|
notification = True
|
||||||
|
elif version[i] < internal_version[i]:
|
||||||
|
full_break = True
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if full_break or notification_level:
|
||||||
|
break
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if notification:
|
||||||
|
return release
|
||||||
|
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
logger.warning(f'Could not get releases (Status: {e.getcode()}): {e.read().decode()}')
|
||||||
|
except urllib.error.URLError as e:
|
||||||
|
logger.warning(f'Could not get releases: {e.reason}. '
|
||||||
|
f'This error often occurs when a computer has no internet connection')
|
||||||
|
|
||||||
|
|
||||||
|
def get_logger(file_output=True, console_output=True, level=logging.DEBUG) -> logging.Logger:
|
||||||
|
"""
|
||||||
|
Creates a new logger
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_output: If the logger should log to file or not
|
||||||
|
console_output: If the logger should log to the console or not
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The new created logger
|
||||||
|
"""
|
||||||
|
logger = logging.getLogger('athnos')
|
||||||
|
if logger.hasHandlers():
|
||||||
|
return logger
|
||||||
|
|
||||||
|
# sets the logger output format
|
||||||
|
formatter = logging.Formatter('[%(asctime)s] - %(levelname)s: %(message)s', '%H:%M:%S')
|
||||||
|
# creates the logger handlers
|
||||||
|
|
||||||
|
# configuring the logger
|
||||||
|
logger.setLevel(level)
|
||||||
|
|
||||||
|
if console_output:
|
||||||
|
console_handler = logging.StreamHandler()
|
||||||
|
console_handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(console_handler)
|
||||||
|
if file_output:
|
||||||
|
file_handler = logging.FileHandler(AthnosPath.logging_path())
|
||||||
|
file_handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
|
return logger
|
||||||
|
|
||||||
|
|
||||||
|
def remove_prefix(string: str, prefix: str) -> str:
|
||||||
|
"""
|
||||||
|
Removes the given prefix from the given string
|
||||||
|
|
||||||
|
Args:
|
||||||
|
string: string to cut the prefix off
|
||||||
|
prefix: Prefix to cut off
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The string without the prefix
|
||||||
|
"""
|
||||||
|
# uses the internal `removeprefix` method if the python version is higher or equal then 3.9
|
||||||
|
if sys.version_info >= (3, 9):
|
||||||
|
return string.removeprefix(prefix)
|
||||||
|
elif string.startswith(prefix):
|
||||||
|
return string[len(prefix):]
|
||||||
|
# returns the string, if its not starting with the prefix
|
||||||
|
else:
|
||||||
|
return string
|
428
athnos/window/QCustomObject.py
Executable file
428
athnos/window/QCustomObject.py
Executable file
@ -0,0 +1,428 @@
|
|||||||
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
|
from typing import Any, Dict, List, Union
|
||||||
|
from . import resources
|
||||||
|
|
||||||
|
|
||||||
|
# https://github.com/baoboa/pyqt5/blob/master/examples/layouts/flowlayout.py
|
||||||
|
class QFlowLayout(QtWidgets.QLayout):
|
||||||
|
def __init__(self, parent=None, margin=0, spacing=-1):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
if parent is not None:
|
||||||
|
self.setContentsMargins(margin, margin, margin, margin)
|
||||||
|
|
||||||
|
self.setSpacing(spacing)
|
||||||
|
|
||||||
|
self._items = []
|
||||||
|
self.__pending_positions = {}
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
item = self.takeAt(0)
|
||||||
|
while item:
|
||||||
|
item = self.takeAt(0)
|
||||||
|
|
||||||
|
def addItem(self, a0: QtWidgets.QLayoutItem) -> None:
|
||||||
|
try:
|
||||||
|
position = self.__pending_positions[a0.widget()]
|
||||||
|
self._items.insert(position, a0)
|
||||||
|
del self.__pending_positions[a0.widget()]
|
||||||
|
except KeyError:
|
||||||
|
self._items.append(a0)
|
||||||
|
|
||||||
|
def addWidget(self, w: QtWidgets.QWidget, position: int = None) -> None:
|
||||||
|
if position:
|
||||||
|
self.__pending_positions[w] = position
|
||||||
|
super().addWidget(w)
|
||||||
|
|
||||||
|
def count(self):
|
||||||
|
return len(self._items)
|
||||||
|
|
||||||
|
def expandingDirections(self):
|
||||||
|
return QtCore.Qt.Orientations(QtCore.Qt.Orientation(0))
|
||||||
|
|
||||||
|
def itemAt(self, index: int) -> QtWidgets.QLayoutItem:
|
||||||
|
if 0 <= index < len(self._items):
|
||||||
|
return self._items[index]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def hasHeightForWidth(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def heightForWidth(self, width):
|
||||||
|
height = self._doLayout(QtCore.QRect(0, 0, width, 0), True)
|
||||||
|
return height
|
||||||
|
|
||||||
|
def minimumSize(self):
|
||||||
|
size = QtCore.QSize()
|
||||||
|
|
||||||
|
for item in self._items:
|
||||||
|
size = size.expandedTo(item.minimumSize())
|
||||||
|
|
||||||
|
margin, _, _, _ = self.getContentsMargins()
|
||||||
|
|
||||||
|
size += QtCore.QSize(2 * margin, 2 * margin)
|
||||||
|
return size
|
||||||
|
|
||||||
|
def removeItem(self, a0: QtWidgets.QLayoutItem) -> None:
|
||||||
|
a0.widget().deleteLater()
|
||||||
|
|
||||||
|
def removeWidget(self, w: QtWidgets.QWidget) -> None:
|
||||||
|
w.deleteLater()
|
||||||
|
|
||||||
|
def setGeometry(self, rect):
|
||||||
|
super().setGeometry(rect)
|
||||||
|
self._doLayout(rect, False)
|
||||||
|
|
||||||
|
def sizeHint(self):
|
||||||
|
return self.minimumSize()
|
||||||
|
|
||||||
|
def takeAt(self, index: int) -> QtWidgets.QLayoutItem:
|
||||||
|
if 0 <= index < len(self._items):
|
||||||
|
return self._items.pop(index)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _doLayout(self, rect, testOnly):
|
||||||
|
"""This does the layout. Dont ask me how. Source: https://github.com/baoboa/pyqt5/blob/master/examples/layouts/flowlayout.py"""
|
||||||
|
x = rect.x()
|
||||||
|
y = rect.y()
|
||||||
|
line_height = 0
|
||||||
|
|
||||||
|
for item in self._items:
|
||||||
|
wid = item.widget()
|
||||||
|
space_x = self.spacing() + wid.style().layoutSpacing(
|
||||||
|
QtWidgets.QSizePolicy.PushButton,
|
||||||
|
QtWidgets.QSizePolicy.PushButton,
|
||||||
|
QtCore.Qt.Horizontal)
|
||||||
|
space_y = self.spacing() + wid.style().layoutSpacing(
|
||||||
|
QtWidgets.QSizePolicy.PushButton,
|
||||||
|
QtWidgets.QSizePolicy.PushButton,
|
||||||
|
QtCore.Qt.Vertical)
|
||||||
|
next_x = x + item.sizeHint().width() + space_x
|
||||||
|
if next_x - space_x > rect.right() and line_height > 0:
|
||||||
|
x = rect.x()
|
||||||
|
y = y + line_height + space_y
|
||||||
|
next_x = x + item.sizeHint().width() + space_x
|
||||||
|
line_height = 0
|
||||||
|
|
||||||
|
if not testOnly:
|
||||||
|
item.setGeometry(QtCore.QRect(QtCore.QPoint(x, y), item.sizeHint()))
|
||||||
|
|
||||||
|
x = next_x
|
||||||
|
line_height = max(line_height, item.sizeHint().height())
|
||||||
|
|
||||||
|
return y + line_height - rect.y()
|
||||||
|
|
||||||
|
|
||||||
|
class QTagEdit(QtWidgets.QScrollArea):
|
||||||
|
"""A tag based edit"""
|
||||||
|
|
||||||
|
def __init__(self, parent: QtWidgets = None, tag_suggestions: List[str] = []):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
# setup the ui stuff
|
||||||
|
self.setWidgetResizable(True)
|
||||||
|
|
||||||
|
self._main_widget = QtWidgets.QWidget()
|
||||||
|
self._layout = QFlowLayout(self._main_widget)
|
||||||
|
|
||||||
|
self._tag_input = QtWidgets.QLineEdit()
|
||||||
|
# self._tag_input.setPlaceholderText('Type in a new tag and hit enter...')
|
||||||
|
self._tag_input.setFixedWidth(10)
|
||||||
|
self._tag_input.setStyleSheet('border: 0px')
|
||||||
|
self._tag_input.setContentsMargins(0, 5, 0, 0)
|
||||||
|
self._tag_input.keyReleaseEvent = self.__tag_input_key_release_event
|
||||||
|
|
||||||
|
self._layout.addWidget(self._tag_input)
|
||||||
|
|
||||||
|
self._tag_input.palette().color(QtGui.QPalette.Background)
|
||||||
|
tag_input_color = self._tag_input.palette().color(QtGui.QPalette.Background)
|
||||||
|
self.setStyleSheet(f'background-color: rgb({tag_input_color.red()}, {tag_input_color.green()}, {tag_input_color.blue()})')
|
||||||
|
|
||||||
|
self.setWidget(self._main_widget)
|
||||||
|
|
||||||
|
# setup all other things
|
||||||
|
self.__font_calculator = QtGui.QFontMetrics(QtWidgets.QApplication.font())
|
||||||
|
self.__tags = []
|
||||||
|
self.__tag_suggestions = tag_suggestions
|
||||||
|
self._tag_suggestions = False
|
||||||
|
self._check_for_doubles = True
|
||||||
|
|
||||||
|
def focusInEvent(self, a0: QtGui.QFocusEvent) -> None:
|
||||||
|
"""Sets the focus always to `self._tag_input`"""
|
||||||
|
self._tag_input.setFocus()
|
||||||
|
|
||||||
|
def addTag(self, text: str) -> bool:
|
||||||
|
"""
|
||||||
|
Adds a new tag
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: The text of the new tag
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
If the tag was added successfully
|
||||||
|
"""
|
||||||
|
# if `self._check_for_doubles` is True, it checks if the tag already exists
|
||||||
|
if self._check_for_doubles and text.lower() in (tag.lower() for tag in self.__tags):
|
||||||
|
self.onDoubledTag(text)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# a new tag
|
||||||
|
tag = self.__QTagFrame(self, text)
|
||||||
|
# tag.setStyleSheet('border: 0px; margin: 0px; padding: 0px')
|
||||||
|
|
||||||
|
self.__tags.append(text)
|
||||||
|
for tag_name in self.__tag_suggestions:
|
||||||
|
# if the tag is in `self.__tag_suggestions` it will be removed from there
|
||||||
|
if tag_name.lower() == text:
|
||||||
|
self.__tag_suggestions.remove(tag_name)
|
||||||
|
self.enableTagSuggestions(self._tag_suggestions)
|
||||||
|
break
|
||||||
|
# insert the tag before the line edit
|
||||||
|
self._layout.addWidget(tag, -1)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def clear(self, input=True) -> None:
|
||||||
|
"""
|
||||||
|
Clears all tags
|
||||||
|
|
||||||
|
Args:
|
||||||
|
input: If True, the current text in the line edit will be cleared as well
|
||||||
|
"""
|
||||||
|
for i in range(self._layout.count()):
|
||||||
|
widget = self._layout.itemAt(i).widget()
|
||||||
|
if type(widget) == QtWidgets.QLineEdit and input:
|
||||||
|
widget.clear()
|
||||||
|
else:
|
||||||
|
self.removeTag(widget)
|
||||||
|
|
||||||
|
def enableCheckForDoubles(self, check_for_doubles) -> None:
|
||||||
|
"""
|
||||||
|
Enables if a new tag, when its going to be added, should be checked if it already exists
|
||||||
|
|
||||||
|
Args:
|
||||||
|
check_for_doubles: True if double checking should be active, False if not
|
||||||
|
"""
|
||||||
|
self._check_for_doubles = check_for_doubles
|
||||||
|
|
||||||
|
def enableTagSuggestions(self, tag_suggestions: bool) -> None:
|
||||||
|
"""
|
||||||
|
Enables whenever a new tag is typed in that suggestions from `self.__tag_suggestions(...)` should be showing or not.
|
||||||
|
They can be added on the class initialization or via `setTagSuggestions`
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tag_suggestions: If tag suggestions should be active or not
|
||||||
|
"""
|
||||||
|
if tag_suggestions:
|
||||||
|
# sets the completer for the line edit
|
||||||
|
completer = QtWidgets.QCompleter(self.__tag_suggestions, self)
|
||||||
|
completer.setCaseSensitivity(QtCore.Qt.CaseSensitive)
|
||||||
|
self._tag_input.setCompleter(completer)
|
||||||
|
else:
|
||||||
|
self._tag_input.setCompleter(None)
|
||||||
|
|
||||||
|
def onDoubledTag(self, text: str) -> None:
|
||||||
|
"""
|
||||||
|
This method gets called if `self._check_for_doubles` is True (can be set via `enableCheckForDoubles(...)`)
|
||||||
|
and a new tag which already exists are going to be added.
|
||||||
|
This method is actually there to display an error message
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: The text of the new tag
|
||||||
|
"""
|
||||||
|
button = QtWidgets.QMessageBox()
|
||||||
|
|
||||||
|
# if `self.tag_input.keyReleaseEvent`is not overridden, it would trigger itself when the enter key is pressed
|
||||||
|
# to close the popup and open it again. idk why
|
||||||
|
def reset(a0: QtGui.QKeyEvent):
|
||||||
|
if a0.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
|
||||||
|
button.destroy()
|
||||||
|
self._tag_input.keyReleaseEvent = self.__tag_input_key_release_event
|
||||||
|
|
||||||
|
self._tag_input.keyReleaseEvent = reset
|
||||||
|
|
||||||
|
# shows the warning
|
||||||
|
button.warning(self, 'Tag already exists', f'The tag {text} already exists')
|
||||||
|
|
||||||
|
def removeTag(self, tag) -> None:
|
||||||
|
"""
|
||||||
|
Removes a tag
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tag (QTagEdit.__QTagFrame): The tag to remove
|
||||||
|
"""
|
||||||
|
self.__tags.remove(tag.text())
|
||||||
|
self._layout.removeWidget(tag)
|
||||||
|
|
||||||
|
def setTags(self, tags: List[str]) -> None:
|
||||||
|
"""
|
||||||
|
Replaces all current tags with tag from the `tags` argument
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tags: The new tags to be set
|
||||||
|
"""
|
||||||
|
self.clear()
|
||||||
|
for tag in tags:
|
||||||
|
self.addTag(tag)
|
||||||
|
|
||||||
|
def setTagSuggestions(self, suggenstions: List[str]) -> None:
|
||||||
|
"""
|
||||||
|
Sets the tag suggestions. They will be used if `self._tag_suggestions` is True (can be set via `enableTagSuggestions(...)`)
|
||||||
|
and will be shown if a new tag is typed in
|
||||||
|
|
||||||
|
Args:
|
||||||
|
suggenstions: The new tag suggestions
|
||||||
|
"""
|
||||||
|
self.__tag_suggestions = suggenstions
|
||||||
|
self.enableTagSuggestions(self._tag_suggestions)
|
||||||
|
|
||||||
|
def tags(self) -> Union[List[str], List]:
|
||||||
|
"""
|
||||||
|
Returns all tag names
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
All tag names
|
||||||
|
"""
|
||||||
|
return self.__tags
|
||||||
|
|
||||||
|
def __tag_input_key_release_event(self, a0: QtGui.QKeyEvent) -> None:
|
||||||
|
"""
|
||||||
|
The `keyReleaseEvent(...)` of the line edit. Whenever return / enter is pressed, the current text in the line edit
|
||||||
|
will be added as new tag. It also expands the width of the line edit if the text in it is over an specific limit
|
||||||
|
"""
|
||||||
|
if a0.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
|
||||||
|
# adds the tag
|
||||||
|
if self.addTag(self._tag_input.text()):
|
||||||
|
self._tag_input.clear()
|
||||||
|
self._tag_input.setFixedWidth(10)
|
||||||
|
return
|
||||||
|
elif a0.key() in (QtCore.Qt.Key_Backspace, QtCore.Qt.Key_Delete):
|
||||||
|
# calculates the current line edit text width
|
||||||
|
width = self.__font_calculator.width(self._tag_input.text())
|
||||||
|
if width + 10 < self._tag_input.width():
|
||||||
|
self._tag_input.setFixedWidth(width + 10)
|
||||||
|
else:
|
||||||
|
# calculates the current line edit text width
|
||||||
|
width = self.__font_calculator.width(self._tag_input.text())
|
||||||
|
# this resizes the tag input if the text in it will be longer than it's width.
|
||||||
|
# not the best way, but it does what it does
|
||||||
|
if width + 20 > self._tag_input.width():
|
||||||
|
self._tag_input.setFixedWidth(width + 20)
|
||||||
|
|
||||||
|
class __QTagFrame(QtWidgets.QFrame):
|
||||||
|
"""The tag class for the QTagEdit tags"""
|
||||||
|
|
||||||
|
def __init__(self, parent, text: str):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
# setup the ui stuff
|
||||||
|
self.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed))
|
||||||
|
self.setLayout(QtWidgets.QHBoxLayout())
|
||||||
|
self.setContentsMargins(3, 0, 3, 0)
|
||||||
|
|
||||||
|
# the tag name label
|
||||||
|
self._name = QtWidgets.QLabel()
|
||||||
|
self._name.setText(text)
|
||||||
|
self._name.setStyleSheet('background: transparent')
|
||||||
|
|
||||||
|
# the tag delete button
|
||||||
|
self._delete_button = QtWidgets.QPushButton()
|
||||||
|
self._delete_button.setStyleSheet('QPushButton{background: transparent; image: url(:/tags/delete); border: 0px}'
|
||||||
|
'QPushButton:hover {image: url(:/tags/delete_hover)}')
|
||||||
|
self._delete_button.clicked.connect(self.onDeleteButtonClick)
|
||||||
|
|
||||||
|
self.layout().addWidget(self._name)
|
||||||
|
self.layout().addWidget(self._delete_button)
|
||||||
|
|
||||||
|
# setup all other things
|
||||||
|
self.__parent = parent
|
||||||
|
self._text = text
|
||||||
|
|
||||||
|
def onDeleteButtonClick(self) -> None:
|
||||||
|
"""This will get triggered if the delete button on a tag is pressed"""
|
||||||
|
self.__parent.removeTag(self)
|
||||||
|
self.__parent._tag_input.setFocus()
|
||||||
|
|
||||||
|
def paintEvent(self, a0: QtGui.QPaintEvent) -> None:
|
||||||
|
"""Styles the tag"""
|
||||||
|
painter = QtGui.QPainter(self)
|
||||||
|
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||||
|
painter.setPen(QtGui.QPen(QtGui.QColor(200, 200, 200, 255), 1, QtCore.Qt.SolidLine))
|
||||||
|
painter.setBrush(QtGui.QBrush(QtGui.QColor(200, 200, 200, 255), QtCore.Qt.SolidPattern))
|
||||||
|
|
||||||
|
# draws the tag 'filling'
|
||||||
|
painter.drawRoundedRect(0, 0, self.width() - 5, self.height(), self.height() / 2, self.height() / 2)
|
||||||
|
|
||||||
|
def text(self) -> str:
|
||||||
|
"""
|
||||||
|
Returns the current tag text
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The tag text
|
||||||
|
|
||||||
|
"""
|
||||||
|
return self._text
|
||||||
|
|
||||||
|
|
||||||
|
class QTableSortFilterProxyModel(QtCore.QSortFilterProxyModel):
|
||||||
|
"""The normal `QtCore.QSortFilterProxyModel` class but with table / multiple column support"""
|
||||||
|
|
||||||
|
def __init__(self, overwrite_filters=False):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.overwrite_filters = overwrite_filters
|
||||||
|
|
||||||
|
# all filters
|
||||||
|
self.filters: Dict[int, QtCore.QRegExp] = {}
|
||||||
|
|
||||||
|
def clearFilter(self) -> None:
|
||||||
|
"""Removes all filter"""
|
||||||
|
self.filters = {}
|
||||||
|
|
||||||
|
# https://stackoverflow.com/questions/60425164/adding-a-checkbox-column-to-a-custom-qsortfilterproxymodel
|
||||||
|
#def data(self, index, role: int = 0):
|
||||||
|
# return QtCore.Qt.Checked
|
||||||
|
|
||||||
|
def setRegExpFilter(self, column: int, regExp: QtCore.QRegExp) -> None:
|
||||||
|
"""
|
||||||
|
Adds a new regex filter to a specific column
|
||||||
|
|
||||||
|
Args:
|
||||||
|
column: The column to add the filter to
|
||||||
|
regExp: The regex filter
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
KeyError: If the column has already a filter
|
||||||
|
"""
|
||||||
|
if column in self.filters and not self.overwrite_filters:
|
||||||
|
raise KeyError('The column already has a filter')
|
||||||
|
self.filters[column] = regExp
|
||||||
|
|
||||||
|
def removeRegExpFilter(self, column: int) -> None:
|
||||||
|
"""
|
||||||
|
Removes the regex filter for a specific column
|
||||||
|
|
||||||
|
Args:
|
||||||
|
column: The column to remove the regex filter from
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
KeyError: If the column has no filter
|
||||||
|
"""
|
||||||
|
if column not in self.filters:
|
||||||
|
raise KeyError('The column has no filter')
|
||||||
|
del self.filters[column]
|
||||||
|
|
||||||
|
def filterAcceptsRow(self, source_row: int, source_parent: QtCore.QModelIndex) -> bool:
|
||||||
|
# if one or more filters are set
|
||||||
|
if self.filters:
|
||||||
|
model = self.sourceModel()
|
||||||
|
# loops through the given source model and checks if a regex filter is installed for one column
|
||||||
|
for i in range(model.columnCount()):
|
||||||
|
# if the current column has a filter and it matches with the index data / text
|
||||||
|
if i in self.filters and self.filters[i].indexIn(str(model.data(model.index(source_row, i)))) != -1:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# if there are no filters, the normal `filterAcceptsRow(...)` gets called
|
||||||
|
return super().filterAcceptsRow(source_row, source_parent)
|
49
athnos/window/__init__.py
Executable file
49
athnos/window/__init__.py
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
from ..database import Database
|
||||||
|
from PyQt5.QtWidgets import QWidget
|
||||||
|
|
||||||
|
|
||||||
|
class _Window(QWidget):
|
||||||
|
"""The base class for every qt specific window"""
|
||||||
|
|
||||||
|
def __init__(self, window):
|
||||||
|
super().__init__()
|
||||||
|
self.window = window
|
||||||
|
self.setupUi(self.window)
|
||||||
|
self.after_setup_ui()
|
||||||
|
|
||||||
|
def setupUi(self, window) -> None:
|
||||||
|
"""setupUi method which creates the basic window, generated from a .ui file with the pyuic5 command line tool"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def after_setup_ui(self) -> None:
|
||||||
|
"""
|
||||||
|
Here should stay every ui specific code which should be executed before opening the window and after calling `self.setupUi`.
|
||||||
|
This is to prevent to overload the `self.__init__` method
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def show(self) -> None:
|
||||||
|
"""Show / executes the window"""
|
||||||
|
try:
|
||||||
|
self.window.exec()
|
||||||
|
except AttributeError:
|
||||||
|
self.window.show()
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
"""Closes the window"""
|
||||||
|
self.window.close()
|
||||||
|
|
||||||
|
|
||||||
|
class _DatabaseWindow(_Window):
|
||||||
|
"""Base class for every window besides `window.Window` which want to use the database"""
|
||||||
|
|
||||||
|
def __init__(self, window):
|
||||||
|
# the import is here, because if it would be imported above, a circular import would be created
|
||||||
|
from .window import _database
|
||||||
|
|
||||||
|
if not _database:
|
||||||
|
raise IOError('Database or main window is not initialized')
|
||||||
|
else:
|
||||||
|
self.database: Database = _database
|
||||||
|
|
||||||
|
super().__init__(window)
|
543
athnos/window/add.py
Executable file
543
athnos/window/add.py
Executable file
@ -0,0 +1,543 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
from . import _DatabaseWindow
|
||||||
|
import filetype
|
||||||
|
from ..database import Type
|
||||||
|
from .. import logger
|
||||||
|
from .QCustomObject import QTagEdit
|
||||||
|
|
||||||
|
|
||||||
|
class _Add(_DatabaseWindow):
|
||||||
|
"""Base class for every add window"""
|
||||||
|
|
||||||
|
def __init__(self, window):
|
||||||
|
super().__init__(window)
|
||||||
|
|
||||||
|
old_key_press_event = self.window.keyPressEvent
|
||||||
|
|
||||||
|
def new_key_press_event(a0: QtGui.QKeyEvent):
|
||||||
|
if a0.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter) and not self.file_or_url_edit.hasFocus():
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
old_key_press_event(a0)
|
||||||
|
|
||||||
|
# the normal key press event would open the file choose dialog / press the file_chooser button
|
||||||
|
# everytime enter his when a ``QLineEdit`` is focused
|
||||||
|
self.window.keyPressEvent = new_key_press_event
|
||||||
|
|
||||||
|
def after_setup_ui(self) -> None:
|
||||||
|
# file chooser
|
||||||
|
self.file_or_url_edit.textChanged.connect(self.on_text_changed)
|
||||||
|
self.file_chooser.clicked.connect(self.on_choose_file)
|
||||||
|
|
||||||
|
# save / new buttons
|
||||||
|
self.save_button.clicked.connect(self.on_save)
|
||||||
|
self.new_button.clicked.connect(self.on_new)
|
||||||
|
|
||||||
|
def on_text_changed(self, value: str) -> None:
|
||||||
|
"""This will get called if the file or url line edit text is changing"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_choose_file(self) -> None:
|
||||||
|
"""Opens a file choose dialog"""
|
||||||
|
# all unique media file types
|
||||||
|
all_preferred_types = [extension.extension for clip_type in [filetype.audio_matchers, filetype.image_matchers, filetype.video_matchers] for extension in clip_type]
|
||||||
|
file = QtWidgets.QFileDialog.getOpenFileName(self.window, directory=str(Path().home()),
|
||||||
|
filter=f'Preferred media file(*.{" *.".join(all_preferred_types)});;All files(*)')[0]
|
||||||
|
if file:
|
||||||
|
# checks the file type and sets the index if the type box after the type
|
||||||
|
match = filetype.guess(file)
|
||||||
|
if match in filetype.audio_matchers:
|
||||||
|
self.type_box.setCurrentIndex(0)
|
||||||
|
elif match in filetype.image_matchers:
|
||||||
|
self.type_box.setCurrentIndex(1)
|
||||||
|
elif match in filetype.video_matchers:
|
||||||
|
self.type_box.setCurrentIndex(2)
|
||||||
|
else:
|
||||||
|
self.type_box.setCurrentIndex(3)
|
||||||
|
# changes the file or url text edit text
|
||||||
|
self.file_or_url_edit.setText(file)
|
||||||
|
|
||||||
|
def on_save(self) -> None:
|
||||||
|
"""This will get called if the 'Save' button is clicked"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_new(self) -> None:
|
||||||
|
"""This will get called if the 'New' button is clicked"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AddClip(_Add):
|
||||||
|
|
||||||
|
def __init__(self, window):
|
||||||
|
super().__init__(window)
|
||||||
|
|
||||||
|
# all tags which are currently in the database
|
||||||
|
self._all_tags = [tag.name for tag in self.database.Tag.get_all()]
|
||||||
|
self._source_id = 0
|
||||||
|
|
||||||
|
def setupUi(self, Form):
|
||||||
|
Form.setObjectName("Form")
|
||||||
|
Form.resize(400, 469)
|
||||||
|
self.verticalLayout_2 = QtWidgets.QVBoxLayout(Form)
|
||||||
|
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||||
|
self.add_clip = QtWidgets.QLabel(Form)
|
||||||
|
self.add_clip.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.add_clip.setObjectName("add_clip")
|
||||||
|
self.verticalLayout_2.addWidget(self.add_clip)
|
||||||
|
self.name_description_frame = QtWidgets.QFrame(Form)
|
||||||
|
self.name_description_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||||
|
self.name_description_frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||||
|
self.name_description_frame.setObjectName("name_description_frame")
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(self.name_description_frame)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.file_or_url_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.file_or_url_hlayout.setObjectName("file_or_url_hlayout")
|
||||||
|
self.file_or_url_edit = QtWidgets.QLineEdit(self.name_description_frame)
|
||||||
|
self.file_or_url_edit.setText("")
|
||||||
|
self.file_or_url_edit.setClearButtonEnabled(False)
|
||||||
|
self.file_or_url_edit.setObjectName("file_or_url_edit")
|
||||||
|
self.file_or_url_hlayout.addWidget(self.file_or_url_edit)
|
||||||
|
self.file_chooser = QtWidgets.QPushButton(self.name_description_frame)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.file_chooser.sizePolicy().hasHeightForWidth())
|
||||||
|
self.file_chooser.setSizePolicy(sizePolicy)
|
||||||
|
self.file_chooser.setSizeIncrement(QtCore.QSize(0, 0))
|
||||||
|
self.file_chooser.setCheckable(False)
|
||||||
|
self.file_chooser.setObjectName("file_chooser")
|
||||||
|
self.file_or_url_hlayout.addWidget(self.file_chooser)
|
||||||
|
self.verticalLayout.addLayout(self.file_or_url_hlayout)
|
||||||
|
self.line = QtWidgets.QFrame(self.name_description_frame)
|
||||||
|
self.line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||||
|
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
|
self.line.setObjectName("line")
|
||||||
|
self.verticalLayout.addWidget(self.line)
|
||||||
|
self.name_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.name_hlayout.setObjectName("name_hlayout")
|
||||||
|
self.name_label = QtWidgets.QLabel(self.name_description_frame)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.name_label.sizePolicy().hasHeightForWidth())
|
||||||
|
self.name_label.setSizePolicy(sizePolicy)
|
||||||
|
self.name_label.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
|
self.name_label.setBaseSize(QtCore.QSize(0, 0))
|
||||||
|
self.name_label.setObjectName("name_label")
|
||||||
|
self.name_hlayout.addWidget(self.name_label)
|
||||||
|
self.name_edit = QtWidgets.QLineEdit(self.name_description_frame)
|
||||||
|
self.name_edit.setStyleSheet("")
|
||||||
|
self.name_edit.setReadOnly(True)
|
||||||
|
self.name_edit.setClearButtonEnabled(False)
|
||||||
|
self.name_edit.setObjectName("name_edit")
|
||||||
|
self.name_hlayout.addWidget(self.name_edit)
|
||||||
|
self.verticalLayout.addLayout(self.name_hlayout)
|
||||||
|
self.description_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.description_hlayout.setObjectName("description_hlayout")
|
||||||
|
self.description_label = QtWidgets.QLabel(self.name_description_frame)
|
||||||
|
self.description_label.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
|
self.description_label.setBaseSize(QtCore.QSize(0, 0))
|
||||||
|
self.description_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
|
||||||
|
self.description_label.setObjectName("description_label")
|
||||||
|
self.description_hlayout.addWidget(self.description_label)
|
||||||
|
self.description_edit = QtWidgets.QTextEdit(self.name_description_frame)
|
||||||
|
self.description_edit.setEnabled(True)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.description_edit.sizePolicy().hasHeightForWidth())
|
||||||
|
self.description_edit.setSizePolicy(sizePolicy)
|
||||||
|
self.description_edit.setReadOnly(True)
|
||||||
|
self.description_edit.setObjectName("description_edit")
|
||||||
|
self.description_hlayout.addWidget(self.description_edit)
|
||||||
|
self.verticalLayout.addLayout(self.description_hlayout)
|
||||||
|
self.type_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.type_hlayout.setObjectName("type_hlayout")
|
||||||
|
self.type_label = QtWidgets.QLabel(self.name_description_frame)
|
||||||
|
self.type_label.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
|
self.type_label.setBaseSize(QtCore.QSize(0, 0))
|
||||||
|
self.type_label.setObjectName("type_label")
|
||||||
|
self.type_hlayout.addWidget(self.type_label)
|
||||||
|
self.type_box = QtWidgets.QComboBox(self.name_description_frame)
|
||||||
|
self.type_box.setEnabled(False)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.type_box.sizePolicy().hasHeightForWidth())
|
||||||
|
self.type_box.setSizePolicy(sizePolicy)
|
||||||
|
self.type_box.setFocusPolicy(QtCore.Qt.WheelFocus)
|
||||||
|
self.type_box.setObjectName("type_box")
|
||||||
|
self.type_box.addItem("")
|
||||||
|
self.type_box.addItem("")
|
||||||
|
self.type_box.addItem("")
|
||||||
|
self.type_box.addItem("")
|
||||||
|
self.type_hlayout.addWidget(self.type_box)
|
||||||
|
self.verticalLayout.addLayout(self.type_hlayout)
|
||||||
|
self.line_3 = QtWidgets.QFrame(self.name_description_frame)
|
||||||
|
self.line_3.setFrameShape(QtWidgets.QFrame.HLine)
|
||||||
|
self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
|
self.line_3.setObjectName("line_3")
|
||||||
|
self.verticalLayout.addWidget(self.line_3)
|
||||||
|
self.tags_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.tags_hlayout.setObjectName("tags_hlayout")
|
||||||
|
self.tags_label = QtWidgets.QLabel(self.name_description_frame)
|
||||||
|
self.tags_label.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
|
self.tags_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
|
||||||
|
self.tags_label.setObjectName("tags_label")
|
||||||
|
self.tags_hlayout.addWidget(self.tags_label)
|
||||||
|
self.tags_edit = QtWidgets.QScrollArea(self.name_description_frame)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.tags_edit.sizePolicy().hasHeightForWidth())
|
||||||
|
self.tags_edit.setSizePolicy(sizePolicy)
|
||||||
|
self.tags_edit.setWidgetResizable(True)
|
||||||
|
self.tags_edit.setObjectName("tags_edit")
|
||||||
|
self.scrollAreaWidgetContents = QtWidgets.QWidget()
|
||||||
|
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 290, 83))
|
||||||
|
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
|
||||||
|
self.tags_edit.setWidget(self.scrollAreaWidgetContents)
|
||||||
|
self.tags_hlayout.addWidget(self.tags_edit)
|
||||||
|
self.verticalLayout.addLayout(self.tags_hlayout)
|
||||||
|
self.line_2 = QtWidgets.QFrame(self.name_description_frame)
|
||||||
|
self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
|
||||||
|
self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
|
self.line_2.setObjectName("line_2")
|
||||||
|
self.verticalLayout.addWidget(self.line_2)
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.choose_source_button = QtWidgets.QPushButton(self.name_description_frame)
|
||||||
|
self.choose_source_button.setEnabled(False)
|
||||||
|
self.choose_source_button.setMaximumSize(QtCore.QSize(100, 16777215))
|
||||||
|
self.choose_source_button.setObjectName("choose_source_button")
|
||||||
|
self.horizontalLayout.addWidget(self.choose_source_button)
|
||||||
|
self.choose_source_label = QtWidgets.QLabel(self.name_description_frame)
|
||||||
|
self.choose_source_label.setEnabled(False)
|
||||||
|
self.choose_source_label.setObjectName("choose_source_label")
|
||||||
|
self.horizontalLayout.addWidget(self.choose_source_label)
|
||||||
|
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||||
|
self.verticalLayout_2.addWidget(self.name_description_frame)
|
||||||
|
self.save_new_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.save_new_hlayout.setObjectName("save_new_hlayout")
|
||||||
|
self.save_button = QtWidgets.QPushButton(Form)
|
||||||
|
self.save_button.setEnabled(False)
|
||||||
|
self.save_button.setFlat(False)
|
||||||
|
self.save_button.setObjectName("save_button")
|
||||||
|
self.save_new_hlayout.addWidget(self.save_button)
|
||||||
|
self.new_button = QtWidgets.QPushButton(Form)
|
||||||
|
self.new_button.setCheckable(False)
|
||||||
|
self.new_button.setChecked(False)
|
||||||
|
self.new_button.setAutoRepeat(False)
|
||||||
|
self.new_button.setAutoExclusive(False)
|
||||||
|
self.new_button.setObjectName("new_button")
|
||||||
|
self.save_new_hlayout.addWidget(self.new_button)
|
||||||
|
self.verticalLayout_2.addLayout(self.save_new_hlayout)
|
||||||
|
|
||||||
|
self.retranslateUi(Form)
|
||||||
|
self.type_box.setCurrentIndex(3)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||||
|
|
||||||
|
def retranslateUi(self, Form):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
Form.setWindowTitle(_translate("Form", "Form"))
|
||||||
|
self.add_clip.setText(_translate("Form", "Add clip"))
|
||||||
|
self.file_or_url_edit.setPlaceholderText(_translate("Form", "File or url..."))
|
||||||
|
self.file_chooser.setText(_translate("Form", "Choose file"))
|
||||||
|
self.name_label.setText(_translate("Form", "Name"))
|
||||||
|
self.description_label.setText(_translate("Form", "Description"))
|
||||||
|
self.type_label.setText(_translate("Form", "Type"))
|
||||||
|
self.type_box.setItemText(0, _translate("Form", "Audio"))
|
||||||
|
self.type_box.setItemText(1, _translate("Form", "Image"))
|
||||||
|
self.type_box.setItemText(2, _translate("Form", "Video"))
|
||||||
|
self.type_box.setItemText(3, _translate("Form", "Other"))
|
||||||
|
self.tags_label.setText(_translate("Form", "Tags"))
|
||||||
|
self.choose_source_button.setText(_translate("Form", "Select source"))
|
||||||
|
self.choose_source_label.setText(_translate("Form", "No source selected"))
|
||||||
|
self.save_button.setText(_translate("Form", "Save"))
|
||||||
|
self.save_button.setShortcut(_translate("Form", "Ctrl+S"))
|
||||||
|
self.new_button.setText(_translate("Form", "New"))
|
||||||
|
|
||||||
|
def after_setup_ui(self) -> None:
|
||||||
|
super().after_setup_ui()
|
||||||
|
|
||||||
|
# replaces the `self.tags_edit` scroll area with an `QCustomObject.QTagEdit`
|
||||||
|
self.tags_edit.deleteLater()
|
||||||
|
self.tags_edit.hide()
|
||||||
|
self.tags_edit = QTagEdit()
|
||||||
|
# configures the tage edit
|
||||||
|
self.tags_edit.setEnabled(False)
|
||||||
|
self.tags_edit.enableTagSuggestions(True)
|
||||||
|
self.tags_edit.setTagSuggestions([tag.name for tag in self.database.Tag.get_all()])
|
||||||
|
self.tags_hlayout.addWidget(self.tags_edit)
|
||||||
|
|
||||||
|
self.choose_source_button.clicked.connect(self.on_select_source)
|
||||||
|
|
||||||
|
def on_text_changed(self, text: str) -> None:
|
||||||
|
if text.strip() == '':
|
||||||
|
is_value = False
|
||||||
|
else:
|
||||||
|
is_value = True
|
||||||
|
|
||||||
|
self.name_edit.setReadOnly(not is_value)
|
||||||
|
self.description_edit.setReadOnly(not is_value)
|
||||||
|
self.type_box.setEnabled(is_value)
|
||||||
|
self.tags_edit.setEnabled(is_value)
|
||||||
|
self.choose_source_button.setEnabled(is_value)
|
||||||
|
self.choose_source_label.setEnabled(is_value)
|
||||||
|
self.save_button.setEnabled(is_value)
|
||||||
|
|
||||||
|
def on_select_source(self) -> None:
|
||||||
|
"""Opens a new `source.ShowSource` window to select the clips source"""
|
||||||
|
|
||||||
|
# this is imported here, because it would cause a circular import if it's imported above
|
||||||
|
from .source import ShowSource
|
||||||
|
|
||||||
|
source = self.database.Source.get(ShowSource(QtWidgets.QDialog(self.window, QtCore.Qt.WindowSystemMenuHint)).select())
|
||||||
|
self._source_id = source.id
|
||||||
|
self.choose_source_label.setText(source.name)
|
||||||
|
|
||||||
|
def on_save(self) -> None:
|
||||||
|
if not self._source_id:
|
||||||
|
reply = QtWidgets.QMessageBox.question(self.window,
|
||||||
|
'No source is given', 'No source for the clip is given. Are you sure to proceed?',
|
||||||
|
buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||||
|
if reply == QtWidgets.QMessageBox.No:
|
||||||
|
return
|
||||||
|
|
||||||
|
type = Type.Clip.from_name(self.type_box.currentText().lower())
|
||||||
|
if not type:
|
||||||
|
return
|
||||||
|
|
||||||
|
id = self.database.Clip.add_clip(self.file_or_url_edit.text(), self._source_id, type.value, self.name_edit.text(), self.description_edit.toPlainText()).id
|
||||||
|
for tag in self.tags_edit.tags():
|
||||||
|
if tag in self._all_tags:
|
||||||
|
self.database.Item.add_item(id, self.database.Tag.get_by(name=tag).id)
|
||||||
|
else:
|
||||||
|
self.database.Item.add_item(id, self.database.Tag.add_tag(tag).id)
|
||||||
|
logger.debug(f'Added new tag - Name: {tag}')
|
||||||
|
|
||||||
|
logger.debug(f'Added new clip - file / url: "{self.file_or_url_edit.text()}", source id: "{self._source_id}", type: "{type.value}", '
|
||||||
|
f'name: "{self.name_edit.text()}", description: "{self.description_edit.toPlainText()}", tags: {", ".join(self.tags_edit.tags())}')
|
||||||
|
|
||||||
|
self.on_new()
|
||||||
|
|
||||||
|
def on_new(self) -> None:
|
||||||
|
self.file_or_url_edit.setText('')
|
||||||
|
self.name_edit.setText('')
|
||||||
|
self.on_text_changed('')
|
||||||
|
self.type_box.setCurrentIndex(3)
|
||||||
|
self.tags_edit.clear()
|
||||||
|
|
||||||
|
|
||||||
|
class AddSource(_Add):
|
||||||
|
|
||||||
|
def setupUi(self, Form):
|
||||||
|
Form.setObjectName("Form")
|
||||||
|
Form.resize(452, 400)
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.add_source_label = QtWidgets.QLabel(Form)
|
||||||
|
self.add_source_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.add_source_label.setObjectName("add_source_label")
|
||||||
|
self.verticalLayout.addWidget(self.add_source_label)
|
||||||
|
self.frame = QtWidgets.QFrame(Form)
|
||||||
|
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||||
|
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||||
|
self.frame.setObjectName("frame")
|
||||||
|
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame)
|
||||||
|
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||||
|
self.file_or_url_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.file_or_url_hlayout.setObjectName("file_or_url_hlayout")
|
||||||
|
self.file_or_url_edit = QtWidgets.QLineEdit(self.frame)
|
||||||
|
self.file_or_url_edit.setText("")
|
||||||
|
self.file_or_url_edit.setObjectName("file_or_url_edit")
|
||||||
|
self.file_or_url_hlayout.addWidget(self.file_or_url_edit)
|
||||||
|
self.file_chooser = QtWidgets.QPushButton(self.frame)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.file_chooser.sizePolicy().hasHeightForWidth())
|
||||||
|
self.file_chooser.setSizePolicy(sizePolicy)
|
||||||
|
self.file_chooser.setSizeIncrement(QtCore.QSize(0, 0))
|
||||||
|
self.file_chooser.setObjectName("file_chooser")
|
||||||
|
self.file_or_url_hlayout.addWidget(self.file_chooser)
|
||||||
|
self.verticalLayout_2.addLayout(self.file_or_url_hlayout)
|
||||||
|
self.line_3 = QtWidgets.QFrame(self.frame)
|
||||||
|
self.line_3.setFrameShape(QtWidgets.QFrame.HLine)
|
||||||
|
self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
|
self.line_3.setObjectName("line_3")
|
||||||
|
self.verticalLayout_2.addWidget(self.line_3)
|
||||||
|
self.type_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.type_hlayout.setObjectName("type_hlayout")
|
||||||
|
self.type_label = QtWidgets.QLabel(self.frame)
|
||||||
|
self.type_label.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
|
self.type_label.setObjectName("type_label")
|
||||||
|
self.type_hlayout.addWidget(self.type_label)
|
||||||
|
self.type_box = QtWidgets.QComboBox(self.frame)
|
||||||
|
self.type_box.setEnabled(False)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.type_box.sizePolicy().hasHeightForWidth())
|
||||||
|
self.type_box.setSizePolicy(sizePolicy)
|
||||||
|
self.type_box.setObjectName("type_box")
|
||||||
|
self.type_box.addItem("")
|
||||||
|
self.type_box.addItem("")
|
||||||
|
self.type_box.addItem("")
|
||||||
|
self.type_box.addItem("")
|
||||||
|
self.type_hlayout.addWidget(self.type_box)
|
||||||
|
self.verticalLayout_2.addLayout(self.type_hlayout)
|
||||||
|
self.from_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.from_hlayout.setObjectName("from_hlayout")
|
||||||
|
self.name_label = QtWidgets.QLabel(self.frame)
|
||||||
|
self.name_label.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
|
self.name_label.setObjectName("name_label")
|
||||||
|
self.from_hlayout.addWidget(self.name_label)
|
||||||
|
self.name_edit = QtWidgets.QLineEdit(self.frame)
|
||||||
|
self.name_edit.setReadOnly(True)
|
||||||
|
self.name_edit.setObjectName("name_edit")
|
||||||
|
self.from_hlayout.addWidget(self.name_edit)
|
||||||
|
self.season_label = QtWidgets.QLabel(self.frame)
|
||||||
|
self.season_label.setObjectName("season_label")
|
||||||
|
self.from_hlayout.addWidget(self.season_label)
|
||||||
|
self.season_edit = QtWidgets.QLineEdit(self.frame)
|
||||||
|
self.season_edit.setMaximumSize(QtCore.QSize(50, 16777215))
|
||||||
|
self.season_edit.setReadOnly(True)
|
||||||
|
self.season_edit.setObjectName("season_edit")
|
||||||
|
self.from_hlayout.addWidget(self.season_edit)
|
||||||
|
self.episode_label = QtWidgets.QLabel(self.frame)
|
||||||
|
self.episode_label.setObjectName("episode_label")
|
||||||
|
self.from_hlayout.addWidget(self.episode_label)
|
||||||
|
self.episode_edit = QtWidgets.QLineEdit(self.frame)
|
||||||
|
self.episode_edit.setMaximumSize(QtCore.QSize(50, 16777215))
|
||||||
|
self.episode_edit.setReadOnly(True)
|
||||||
|
self.episode_edit.setObjectName("episode_edit")
|
||||||
|
self.from_hlayout.addWidget(self.episode_edit)
|
||||||
|
self.verticalLayout_2.addLayout(self.from_hlayout)
|
||||||
|
self.description_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.description_hlayout.setObjectName("description_hlayout")
|
||||||
|
self.description_label = QtWidgets.QLabel(self.frame)
|
||||||
|
self.description_label.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
|
self.description_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
|
||||||
|
self.description_label.setObjectName("description_label")
|
||||||
|
self.description_hlayout.addWidget(self.description_label)
|
||||||
|
self.description_edit = QtWidgets.QTextEdit(self.frame)
|
||||||
|
self.description_edit.setReadOnly(True)
|
||||||
|
self.description_edit.setObjectName("description_edit")
|
||||||
|
self.description_hlayout.addWidget(self.description_edit)
|
||||||
|
self.verticalLayout_2.addLayout(self.description_hlayout)
|
||||||
|
self.verticalLayout.addWidget(self.frame)
|
||||||
|
self.save_new_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.save_new_hlayout.setObjectName("save_new_hlayout")
|
||||||
|
self.save_button = QtWidgets.QPushButton(Form)
|
||||||
|
self.save_button.setEnabled(False)
|
||||||
|
self.save_button.setObjectName("save_button")
|
||||||
|
self.save_new_hlayout.addWidget(self.save_button)
|
||||||
|
self.new_button = QtWidgets.QPushButton(Form)
|
||||||
|
self.new_button.setObjectName("new_button")
|
||||||
|
self.save_new_hlayout.addWidget(self.new_button)
|
||||||
|
self.verticalLayout.addLayout(self.save_new_hlayout)
|
||||||
|
|
||||||
|
self.retranslateUi(Form)
|
||||||
|
self.type_box.setCurrentIndex(2)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||||
|
|
||||||
|
def retranslateUi(self, Form):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
Form.setWindowTitle(_translate("Form", "Form"))
|
||||||
|
self.add_source_label.setText(_translate("Form", "Add source"))
|
||||||
|
self.file_or_url_edit.setPlaceholderText(_translate("Form", "File or url..."))
|
||||||
|
self.file_chooser.setText(_translate("Form", "Choose file"))
|
||||||
|
self.file_chooser.setShortcut(_translate("Form", "Ctrl+O"))
|
||||||
|
self.type_label.setText(_translate("Form", "Type"))
|
||||||
|
self.type_box.setItemText(0, _translate("Form", "Audio"))
|
||||||
|
self.type_box.setItemText(1, _translate("Form", "Movie"))
|
||||||
|
self.type_box.setItemText(2, _translate("Form", "Series"))
|
||||||
|
self.type_box.setItemText(3, _translate("Form", "Other"))
|
||||||
|
self.name_label.setText(_translate("Form", "From"))
|
||||||
|
self.season_label.setText(_translate("Form", "Season"))
|
||||||
|
self.episode_label.setText(_translate("Form", "Episode"))
|
||||||
|
self.description_label.setText(_translate("Form", "Description"))
|
||||||
|
self.save_button.setText(_translate("Form", "Save"))
|
||||||
|
self.save_button.setShortcut(_translate("Form", "Ctrl+S"))
|
||||||
|
self.new_button.setText(_translate("Form", "New"))
|
||||||
|
self.new_button.setShortcut(_translate("Form", "Ctrl+N"))
|
||||||
|
|
||||||
|
def after_setup_ui(self) -> None:
|
||||||
|
super().after_setup_ui()
|
||||||
|
|
||||||
|
self.type_box.currentIndexChanged.connect(self.on_type_changed)
|
||||||
|
|
||||||
|
def on_text_changed(self, text: str):
|
||||||
|
if text.strip() == '':
|
||||||
|
is_value = False
|
||||||
|
else:
|
||||||
|
is_value = True
|
||||||
|
|
||||||
|
self.name_edit.setReadOnly(not is_value)
|
||||||
|
self.season_edit.setReadOnly(not is_value)
|
||||||
|
self.episode_edit.setReadOnly(not is_value)
|
||||||
|
self.description_edit.setReadOnly(not is_value)
|
||||||
|
self.type_box.setEnabled(is_value)
|
||||||
|
self.save_button.setEnabled(is_value)
|
||||||
|
|
||||||
|
def on_type_changed(self, index: int) -> None:
|
||||||
|
"""Modifies the name / from, season and episode line edits, based on the `index`"""
|
||||||
|
if index in [0, 1, 3]: # audio / movie
|
||||||
|
# hides the season and episode label / line edit and sets the text of the name / from label to 'Name'
|
||||||
|
self.name_label.setText('Name')
|
||||||
|
self.season_label.hide()
|
||||||
|
self.season_edit.hide()
|
||||||
|
self.episode_label.hide()
|
||||||
|
self.episode_edit.hide()
|
||||||
|
elif index == 2: # series
|
||||||
|
# shows the season and episode label / line edit and sets the text of the name / from label to 'From'
|
||||||
|
self.name_label.setText('From')
|
||||||
|
self.season_label.show()
|
||||||
|
self.season_edit.show()
|
||||||
|
self.episode_label.show()
|
||||||
|
self.episode_edit.show()
|
||||||
|
|
||||||
|
def on_save(self) -> None:
|
||||||
|
type = Type.Source.from_name(self.type_box.currentText().lower())
|
||||||
|
if not type:
|
||||||
|
return
|
||||||
|
|
||||||
|
file_or_url = self.file_or_url_edit.text()
|
||||||
|
name = self.name_edit.text()
|
||||||
|
description = self.description_edit.toPlainText()
|
||||||
|
season = self.season_edit.text()
|
||||||
|
episode = self.episode_edit.text()
|
||||||
|
|
||||||
|
# it checks if some of the data is already in the database
|
||||||
|
if type == Type.Source.SERIES and self.database.Source.has(type=type.value, name=name, season=season, episode=episode):
|
||||||
|
has_same = True
|
||||||
|
elif type != Type.Source.SERIES and self.database.Source.has(name=name):
|
||||||
|
has_same = True
|
||||||
|
else:
|
||||||
|
has_same = False
|
||||||
|
|
||||||
|
if has_same:
|
||||||
|
# if some of the data were in the database it checks if the exact same data is in the database
|
||||||
|
if self.database.Source.has(path=file_or_url, type=type.value, name=name, description=description, season=season, episode=episode):
|
||||||
|
QtWidgets.QMessageBox.warning(self.window, 'The source already exist', 'A source with the exact same data (name, description, type, etc.) already exist')
|
||||||
|
return
|
||||||
|
elif type == Type.Source.SERIES:
|
||||||
|
proceed = QtWidgets.QMessageBox.question(self.window, 'The source may already exist', 'A source with some same data (name, season and episode at least) already exist. '
|
||||||
|
'Do you want to proceed?', QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||||
|
if not proceed:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.database.Source.add_source(self.file_or_url_edit.text(), type.value, self.name_edit.text(), self.description_edit.toPlainText(), self.season_edit.text(), self.episode_edit.text())
|
||||||
|
logger.debug(f'Added new source - file / url: "{self.file_or_url_edit.text()}", name: "{self.name_edit.text()}", description: "{self.description_edit.toPlainText()}", '
|
||||||
|
f'season: "{self.season_edit.text()}", episode: "{self.episode_edit.text()}"')
|
||||||
|
self.on_new()
|
||||||
|
|
||||||
|
def on_new(self) -> None:
|
||||||
|
self.file_or_url_edit.setText('')
|
||||||
|
self.type_box.setCurrentIndex(2)
|
||||||
|
self.name_edit.setText('')
|
||||||
|
self.season_edit.setText('')
|
||||||
|
self.episode_edit.setText('')
|
||||||
|
self.description_edit.setText('')
|
426
athnos/window/connect.py
Executable file
426
athnos/window/connect.py
Executable file
@ -0,0 +1,426 @@
|
|||||||
|
from . import _DatabaseWindow
|
||||||
|
from .. import config
|
||||||
|
from ..database import default_databases, Database
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets, QtSql
|
||||||
|
import os
|
||||||
|
from copy import copy
|
||||||
|
from . import style
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
class Connect(_DatabaseWindow):
|
||||||
|
"""Class to connect to another database"""
|
||||||
|
|
||||||
|
def __init__(self, window):
|
||||||
|
self.file = ''
|
||||||
|
self.database = None
|
||||||
|
self.current_index = -1
|
||||||
|
self.is_database_file_new = False
|
||||||
|
|
||||||
|
super().__init__(window)
|
||||||
|
|
||||||
|
self.on_database_index_change(self.database_type.currentIndex())
|
||||||
|
|
||||||
|
def setupUi(self, Form):
|
||||||
|
Form.setObjectName("Form")
|
||||||
|
Form.resize(400, 490)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth())
|
||||||
|
Form.setSizePolicy(sizePolicy)
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
|
||||||
|
self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.database_type_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.database_type_hlayout.setObjectName("database_type_hlayout")
|
||||||
|
self.database_label = QtWidgets.QLabel(Form)
|
||||||
|
self.database_label.setObjectName("database_label")
|
||||||
|
self.database_type_hlayout.addWidget(self.database_label)
|
||||||
|
spacerItem = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
self.database_type_hlayout.addItem(spacerItem)
|
||||||
|
self.database_type = QtWidgets.QComboBox(Form)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.database_type.sizePolicy().hasHeightForWidth())
|
||||||
|
self.database_type.setSizePolicy(sizePolicy)
|
||||||
|
self.database_type.setObjectName("database_type")
|
||||||
|
self.database_type_hlayout.addWidget(self.database_type)
|
||||||
|
self.verticalLayout.addLayout(self.database_type_hlayout)
|
||||||
|
self.line = QtWidgets.QFrame(Form)
|
||||||
|
self.line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||||
|
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
|
self.line.setObjectName("line")
|
||||||
|
self.verticalLayout.addWidget(self.line)
|
||||||
|
self.database_file_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.database_file_hlayout.setObjectName("database_file_hlayout")
|
||||||
|
self.database_file = QtWidgets.QPushButton(Form)
|
||||||
|
self.database_file.setMinimumSize(QtCore.QSize(118, 0))
|
||||||
|
self.database_file.setMaximumSize(QtCore.QSize(130, 16777215))
|
||||||
|
self.database_file.setObjectName("database_file")
|
||||||
|
self.database_file_hlayout.addWidget(self.database_file)
|
||||||
|
self.file_name_label = QtWidgets.QLabel(Form)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.file_name_label.sizePolicy().hasHeightForWidth())
|
||||||
|
self.file_name_label.setSizePolicy(sizePolicy)
|
||||||
|
self.file_name_label.setObjectName("file_name_label")
|
||||||
|
self.database_file_hlayout.addWidget(self.file_name_label)
|
||||||
|
self.file_utils_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.file_utils_hlayout.setSpacing(0)
|
||||||
|
self.file_utils_hlayout.setObjectName("file_utils_hlayout")
|
||||||
|
self.line_2 = QtWidgets.QFrame(Form)
|
||||||
|
self.line_2.setFrameShape(QtWidgets.QFrame.VLine)
|
||||||
|
self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
|
self.line_2.setObjectName("line_2")
|
||||||
|
self.file_utils_hlayout.addWidget(self.line_2)
|
||||||
|
self.delete_file_button = QtWidgets.QPushButton(Form)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.delete_file_button.sizePolicy().hasHeightForWidth())
|
||||||
|
self.delete_file_button.setSizePolicy(sizePolicy)
|
||||||
|
self.delete_file_button.setStyleSheet("")
|
||||||
|
self.delete_file_button.setText("")
|
||||||
|
icon = QtGui.QIcon()
|
||||||
|
icon.addPixmap(QtGui.QPixmap(":/file_url/trash"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.delete_file_button.setIcon(icon)
|
||||||
|
self.delete_file_button.setIconSize(QtCore.QSize(18, 18))
|
||||||
|
self.delete_file_button.setAutoDefault(False)
|
||||||
|
self.delete_file_button.setDefault(False)
|
||||||
|
self.delete_file_button.setFlat(True)
|
||||||
|
self.delete_file_button.setObjectName("delete_file_button")
|
||||||
|
self.file_utils_hlayout.addWidget(self.delete_file_button)
|
||||||
|
self.add_file_button = QtWidgets.QPushButton(Form)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.add_file_button.sizePolicy().hasHeightForWidth())
|
||||||
|
self.add_file_button.setSizePolicy(sizePolicy)
|
||||||
|
self.add_file_button.setStyleSheet("")
|
||||||
|
self.add_file_button.setText("")
|
||||||
|
icon1 = QtGui.QIcon()
|
||||||
|
icon1.addPixmap(QtGui.QPixmap(":/file_url/add_file"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.add_file_button.setIcon(icon1)
|
||||||
|
self.add_file_button.setIconSize(QtCore.QSize(18, 18))
|
||||||
|
self.add_file_button.setFlat(True)
|
||||||
|
self.add_file_button.setObjectName("add_file_button")
|
||||||
|
self.file_utils_hlayout.addWidget(self.add_file_button)
|
||||||
|
self.database_file_hlayout.addLayout(self.file_utils_hlayout)
|
||||||
|
self.verticalLayout.addLayout(self.database_file_hlayout)
|
||||||
|
self.database_settings_frame = QtWidgets.QFrame(Form)
|
||||||
|
self.database_settings_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||||
|
self.database_settings_frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||||
|
self.database_settings_frame.setObjectName("database_settings_frame")
|
||||||
|
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.database_settings_frame)
|
||||||
|
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||||
|
self.database_ip_layout = QtWidgets.QHBoxLayout()
|
||||||
|
self.database_ip_layout.setObjectName("database_ip_layout")
|
||||||
|
self.database_ip_label = QtWidgets.QLabel(self.database_settings_frame)
|
||||||
|
self.database_ip_label.setMinimumSize(QtCore.QSize(100, 0))
|
||||||
|
self.database_ip_label.setObjectName("database_ip_label")
|
||||||
|
self.database_ip_layout.addWidget(self.database_ip_label)
|
||||||
|
self.database_ip_edit = QtWidgets.QLineEdit(self.database_settings_frame)
|
||||||
|
self.database_ip_edit.setObjectName("database_ip_edit")
|
||||||
|
self.database_ip_layout.addWidget(self.database_ip_edit)
|
||||||
|
self.verticalLayout_2.addLayout(self.database_ip_layout)
|
||||||
|
self.user_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.user_hlayout.setObjectName("user_hlayout")
|
||||||
|
self.user_label = QtWidgets.QLabel(self.database_settings_frame)
|
||||||
|
self.user_label.setMinimumSize(QtCore.QSize(100, 0))
|
||||||
|
self.user_label.setObjectName("user_label")
|
||||||
|
self.user_hlayout.addWidget(self.user_label)
|
||||||
|
self.user_edit = QtWidgets.QLineEdit(self.database_settings_frame)
|
||||||
|
self.user_edit.setObjectName("user_edit")
|
||||||
|
self.user_hlayout.addWidget(self.user_edit)
|
||||||
|
self.verticalLayout_2.addLayout(self.user_hlayout)
|
||||||
|
self.password_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.password_hlayout.setObjectName("password_hlayout")
|
||||||
|
self.password_label = QtWidgets.QLabel(self.database_settings_frame)
|
||||||
|
self.password_label.setMinimumSize(QtCore.QSize(100, 0))
|
||||||
|
self.password_label.setObjectName("password_label")
|
||||||
|
self.password_hlayout.addWidget(self.password_label)
|
||||||
|
self.password_edit = QtWidgets.QLineEdit(self.database_settings_frame)
|
||||||
|
self.password_edit.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText|QtCore.Qt.ImhSensitiveData)
|
||||||
|
self.password_edit.setEchoMode(QtWidgets.QLineEdit.Password)
|
||||||
|
self.password_edit.setObjectName("password_edit")
|
||||||
|
self.password_hlayout.addWidget(self.password_edit)
|
||||||
|
self.verticalLayout_2.addLayout(self.password_hlayout)
|
||||||
|
self.port_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.port_hlayout.setObjectName("port_hlayout")
|
||||||
|
self.port_label = QtWidgets.QLabel(self.database_settings_frame)
|
||||||
|
self.port_label.setMinimumSize(QtCore.QSize(100, 0))
|
||||||
|
self.port_label.setObjectName("port_label")
|
||||||
|
self.port_hlayout.addWidget(self.port_label)
|
||||||
|
self.port_edit = QtWidgets.QLineEdit(self.database_settings_frame)
|
||||||
|
self.port_edit.setFrame(True)
|
||||||
|
self.port_edit.setClearButtonEnabled(False)
|
||||||
|
self.port_edit.setObjectName("port_edit")
|
||||||
|
self.port_hlayout.addWidget(self.port_edit)
|
||||||
|
self.verticalLayout_2.addLayout(self.port_hlayout)
|
||||||
|
self.database_name_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.database_name_hlayout.setObjectName("database_name_hlayout")
|
||||||
|
self.database_name_label = QtWidgets.QLabel(self.database_settings_frame)
|
||||||
|
self.database_name_label.setMinimumSize(QtCore.QSize(100, 0))
|
||||||
|
self.database_name_label.setObjectName("database_name_label")
|
||||||
|
self.database_name_hlayout.addWidget(self.database_name_label)
|
||||||
|
self.database_name_edit = QtWidgets.QLineEdit(self.database_settings_frame)
|
||||||
|
self.database_name_edit.setPlaceholderText("")
|
||||||
|
self.database_name_edit.setObjectName("database_name_edit")
|
||||||
|
self.database_name_hlayout.addWidget(self.database_name_edit)
|
||||||
|
self.verticalLayout_2.addLayout(self.database_name_hlayout)
|
||||||
|
self.show_databases_button = QtWidgets.QPushButton(self.database_settings_frame)
|
||||||
|
self.show_databases_button.setObjectName("show_databases_button")
|
||||||
|
self.verticalLayout_2.addWidget(self.show_databases_button)
|
||||||
|
self.databases_view = QtWidgets.QListView(self.database_settings_frame)
|
||||||
|
self.databases_view.setInputMethodHints(QtCore.Qt.ImhNone)
|
||||||
|
self.databases_view.setObjectName("databases_view")
|
||||||
|
self.verticalLayout_2.addWidget(self.databases_view)
|
||||||
|
self.verticalLayout.addWidget(self.database_settings_frame)
|
||||||
|
self.test_save_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.test_save_hlayout.setObjectName("test_save_hlayout")
|
||||||
|
self.test_connection_button = QtWidgets.QPushButton(Form)
|
||||||
|
self.test_connection_button.setToolTip("")
|
||||||
|
self.test_connection_button.setStatusTip("")
|
||||||
|
self.test_connection_button.setWhatsThis("")
|
||||||
|
self.test_connection_button.setObjectName("test_connection_button")
|
||||||
|
self.test_save_hlayout.addWidget(self.test_connection_button)
|
||||||
|
self.save_button = QtWidgets.QPushButton(Form)
|
||||||
|
self.save_button.setObjectName("save_button")
|
||||||
|
self.test_save_hlayout.addWidget(self.save_button)
|
||||||
|
self.verticalLayout.addLayout(self.test_save_hlayout)
|
||||||
|
|
||||||
|
self.retranslateUi(Form)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||||
|
|
||||||
|
def retranslateUi(self, Form):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
Form.setWindowTitle(_translate("Form", "Connect to database"))
|
||||||
|
self.database_label.setText(_translate("Form", "Database"))
|
||||||
|
self.database_file.setText(_translate("Form", "Database file"))
|
||||||
|
self.file_name_label.setText(_translate("Form", "No file selected"))
|
||||||
|
self.database_ip_label.setText(_translate("Form", "Database IP"))
|
||||||
|
self.database_ip_edit.setText(_translate("Form", "127.0.0.1"))
|
||||||
|
self.user_label.setText(_translate("Form", "User"))
|
||||||
|
self.user_edit.setText(_translate("Form", "root"))
|
||||||
|
self.password_label.setText(_translate("Form", "Password"))
|
||||||
|
self.port_label.setText(_translate("Form", "Port"))
|
||||||
|
self.port_edit.setText(_translate("Form", "3306"))
|
||||||
|
self.database_name_label.setText(_translate("Form", "Database name"))
|
||||||
|
self.database_name_edit.setText(_translate("Form", "athnos"))
|
||||||
|
self.show_databases_button.setText(_translate("Form", "Show available names"))
|
||||||
|
self.test_connection_button.setText(_translate("Form", "Test connection"))
|
||||||
|
self.save_button.setText(_translate("Form", "Save"))
|
||||||
|
|
||||||
|
def after_setup_ui(self) -> None:
|
||||||
|
item_model = QtGui.QStandardItemModel()
|
||||||
|
# loads all sql driver to the database combobox
|
||||||
|
for i, driver in enumerate(default_databases):
|
||||||
|
item = QtGui.QStandardItem(driver['title'])
|
||||||
|
# if the driver is not available, the index gets disabled
|
||||||
|
if not QtSql.QSqlDatabase.isDriverAvailable(driver['driver']):
|
||||||
|
item.setEnabled(False)
|
||||||
|
item_model.setItem(i, 0, item)
|
||||||
|
|
||||||
|
# sets the item model to the database type combobox
|
||||||
|
self.database_type.setModel(item_model)
|
||||||
|
|
||||||
|
# gets called if another database driver is chosen
|
||||||
|
self.database_type.currentIndexChanged.connect(self.on_database_index_change)
|
||||||
|
|
||||||
|
# database file specific
|
||||||
|
self.database_file.clicked.connect(self.on_choose_database_file)
|
||||||
|
self.delete_file_button.clicked.connect(self.on_remove_database_file)
|
||||||
|
self.add_file_button.clicked.connect(self.on_new_database_file)
|
||||||
|
|
||||||
|
# database settings
|
||||||
|
self.port_edit.setValidator(QtGui.QIntValidator(0, 65535))
|
||||||
|
|
||||||
|
self.show_databases_button.clicked.connect(self.on_show_databases)
|
||||||
|
self.database_name_proxy_model = QtCore.QSortFilterProxyModel()
|
||||||
|
self.database_name_edit.textChanged.connect(lambda: self.database_name_proxy_model.setFilterRegExp(QtCore.QRegExp(f'^{self.database_name_edit.text()}')) if not self.databases_view.isHidden() else None)
|
||||||
|
self.databases_view.doubleClicked.connect(lambda a0: self.database_name_edit.setText(a0.data(QtCore.Qt.DisplayRole)))
|
||||||
|
|
||||||
|
# test connection / save buttons
|
||||||
|
self.test_connection_button.clicked.connect(self.on_test_connection)
|
||||||
|
self.save_button.clicked.connect(self.on_save)
|
||||||
|
|
||||||
|
# chooses the default database
|
||||||
|
self.on_database_index_change(-1 if len(default_databases) == 0 else 0)
|
||||||
|
|
||||||
|
def on_database_index_change(self, index: int) -> None:
|
||||||
|
"""Changes the text edit etc. settings, depending on the `index`"""
|
||||||
|
if index == -1:
|
||||||
|
self.database_settings_frame.setEnabled(False)
|
||||||
|
self.database_ip_edit.setText('')
|
||||||
|
self.database_name_edit.setText('')
|
||||||
|
self.user_edit.setText('')
|
||||||
|
self.password_edit.setText('')
|
||||||
|
self.port_edit.setText('')
|
||||||
|
return
|
||||||
|
|
||||||
|
self.current_index = index
|
||||||
|
database = default_databases[index]
|
||||||
|
|
||||||
|
# sets the content of `self.database_file_hlayout` enabled or disabled, according to if database['file'] is True or False
|
||||||
|
for i in range(self.database_file_hlayout.count()):
|
||||||
|
item = self.database_file_hlayout.itemAt(i)
|
||||||
|
try:
|
||||||
|
item.widget().setEnabled(database['ip'] is None)
|
||||||
|
except AttributeError:
|
||||||
|
for j in range(item.layout().count()):
|
||||||
|
item.layout().itemAt(j).widget().setEnabled(database['ip'] is None)
|
||||||
|
|
||||||
|
self.databases_view.setModel(None)
|
||||||
|
|
||||||
|
# currently only sqlite3
|
||||||
|
if database['ip'] is None:
|
||||||
|
self.file_name_label.setText('No file selected')
|
||||||
|
self.database_settings_frame.setEnabled(False)
|
||||||
|
self.database_ip_edit.setText('')
|
||||||
|
self.database_name_edit.setText('')
|
||||||
|
self.user_edit.setText('')
|
||||||
|
self.password_edit.setText('')
|
||||||
|
self.port_edit.setText('')
|
||||||
|
else:
|
||||||
|
self.file_name_label.setText('No file selected')
|
||||||
|
self.database_settings_frame.setEnabled(True)
|
||||||
|
self.database_ip_edit.setText('127.0.0.1')
|
||||||
|
self.database_name_edit.setText('athnos')
|
||||||
|
self.user_edit.setText(database['user'])
|
||||||
|
self.password_edit.setText(database['password'])
|
||||||
|
self.port_edit.setText(str(database['port']))
|
||||||
|
|
||||||
|
def on_choose_database_file(self) -> None:
|
||||||
|
"""Opens a file choose dialog"""
|
||||||
|
if default_databases[self.current_index]['driver'] == 'QSQLITE':
|
||||||
|
file_name = 'SQLite3 database'
|
||||||
|
file_endings = ['sqlite', 'sqlite3']
|
||||||
|
else:
|
||||||
|
file_endings = ['*']
|
||||||
|
file_name = 'Database file'
|
||||||
|
|
||||||
|
file = QtWidgets.QFileDialog.getOpenFileName(self.window, filter=f'{file_name}({" *.".join(file_endings)});;All files(*.*)')[0]
|
||||||
|
if file:
|
||||||
|
self.file = file
|
||||||
|
self.file_name_label.setText(file)
|
||||||
|
|
||||||
|
def on_new_database_file(self) -> None:
|
||||||
|
"""Opens a create file dialog for a database file"""
|
||||||
|
if default_databases[self.current_index]['driver'] == 'QSQLITE':
|
||||||
|
file_name = 'SQLite3 database'
|
||||||
|
file_endings = ['sqlite', 'sqlite3']
|
||||||
|
else:
|
||||||
|
file_endings = ['*']
|
||||||
|
file_name = 'Database file'
|
||||||
|
|
||||||
|
file = QtWidgets.QFileDialog.getSaveFileName(self.window, filter=f'{file_name}({" *.".join(file_endings)});;All files(*.*)')[0]
|
||||||
|
if file:
|
||||||
|
self.file = file
|
||||||
|
self.file_name_label.setText(file)
|
||||||
|
self.is_database_file_new = True
|
||||||
|
|
||||||
|
def on_remove_database_file(self) -> None:
|
||||||
|
"""Removes the database file (internal)"""
|
||||||
|
self.file = None
|
||||||
|
self.file_name_label.setText('No file selected')
|
||||||
|
|
||||||
|
def on_show_databases(self) -> None:
|
||||||
|
"""Shows all available databases (names)"""
|
||||||
|
if self.database_type.currentText().lower() in ('mariadb', 'mysql', 'postgresql'):
|
||||||
|
result = QtWidgets.QMessageBox.question(self.window, 'Connect to database',
|
||||||
|
'To show all databases / database names, I have to connect with the ip. '
|
||||||
|
'Proceed?')
|
||||||
|
if result == QtWidgets.QMessageBox.Yes:
|
||||||
|
databases_model = QtGui.QStandardItemModel()
|
||||||
|
db = self.on_test_connection(True, False)
|
||||||
|
if db:
|
||||||
|
if self.database_type.currentText().lower() == 'postgresql':
|
||||||
|
databases = db.exec('SELECT datname FROM pg_database')
|
||||||
|
else:
|
||||||
|
databases = db.exec('SHOW DATABASES')
|
||||||
|
i = 0
|
||||||
|
while databases.next():
|
||||||
|
databases_model.setItem(i, 0, QtGui.QStandardItem(databases.value(0)))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
self.database_name_proxy_model.setSourceModel(databases_model)
|
||||||
|
self.databases_view.setModel(self.database_name_proxy_model)
|
||||||
|
self.database_name_edit.setText('')
|
||||||
|
else:
|
||||||
|
QtWidgets.QMessageBox.warning(self.window, 'Not supported', 'Currently database / name detection is only available for '
|
||||||
|
'MariaDB, MySQL and PostgreSQL')
|
||||||
|
|
||||||
|
def on_test_connection(self, return_db=False, specify_database=True) -> Union[QtSql.QSqlDatabase, None]:
|
||||||
|
"""Test the connection to the database with the current settings"""
|
||||||
|
database = default_databases[self.current_index]
|
||||||
|
|
||||||
|
db = QtSql.QSqlDatabase(database['driver'])
|
||||||
|
|
||||||
|
# only sqlite3 which uses files to store the data in it has no ip
|
||||||
|
if not database['ip']:
|
||||||
|
if self.file:
|
||||||
|
if os.path.isfile(self.file) or self.is_database_file_new:
|
||||||
|
db.setDatabaseName(self.file)
|
||||||
|
message = None
|
||||||
|
else:
|
||||||
|
message = f'The file {self.file} does not exist'
|
||||||
|
else:
|
||||||
|
message = 'No file is selected'
|
||||||
|
|
||||||
|
if message:
|
||||||
|
# the connection would be successful, even if the file does not exist
|
||||||
|
QtWidgets.QMessageBox.warning(self.window, 'Connection failed', f'Could not connect to the database: {message}',
|
||||||
|
QtWidgets.QMessageBox.Ok)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if specify_database:
|
||||||
|
db.setDatabaseName(self.database_name_edit.text())
|
||||||
|
|
||||||
|
db.setHostName(self.database_ip_edit.text())
|
||||||
|
db.setUserName(self.user_edit.text())
|
||||||
|
db.setPassword(self.password_edit.text())
|
||||||
|
db.setPort(int(self.port_edit.text()))
|
||||||
|
|
||||||
|
if db.open():
|
||||||
|
if specify_database:
|
||||||
|
is_table = 'test' in db.tables()
|
||||||
|
# creates a test table to check if the database integrity
|
||||||
|
db.exec('CREATE TABLE IF NOT EXISTS test (test varchar(1))')
|
||||||
|
if not db.lastError().isValid():
|
||||||
|
if specify_database and not is_table:
|
||||||
|
db.exec('DROP TABLE test')
|
||||||
|
if return_db:
|
||||||
|
return db
|
||||||
|
else:
|
||||||
|
QtWidgets.QMessageBox.information(self.window, 'Connection successful', 'Connected successful to the database', QtWidgets.QMessageBox.Ok)
|
||||||
|
db.close()
|
||||||
|
return
|
||||||
|
QtWidgets.QMessageBox.warning(self.window, 'Connection failed', f'Could not connect to the database: {db.lastError().text()}', QtWidgets.QMessageBox.Ok)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def on_save(self) -> None:
|
||||||
|
"""Saves the connection"""
|
||||||
|
# the connection gets tested first
|
||||||
|
db = self.on_test_connection(True)
|
||||||
|
if db:
|
||||||
|
self.database = Database(db, self.database._auto_table)
|
||||||
|
# writes the connection in the config
|
||||||
|
for item in default_databases:
|
||||||
|
if item['driver'] == db.driverName():
|
||||||
|
item = copy(item)
|
||||||
|
if self.file:
|
||||||
|
item['name'] = self.file
|
||||||
|
else:
|
||||||
|
item['name'] = self.database_ip_edit.text()
|
||||||
|
config['database'] = item
|
||||||
|
break
|
||||||
|
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def show(self) -> Union[QtSql.QSqlDatabase, None]:
|
||||||
|
super().show()
|
||||||
|
return self.database
|
125
athnos/window/importexport.py
Executable file
125
athnos/window/importexport.py
Executable file
@ -0,0 +1,125 @@
|
|||||||
|
from PyQt5 import QtWidgets, QtSql, QtCore, QtGui
|
||||||
|
from .window import Window
|
||||||
|
from ..database import Database
|
||||||
|
from .. import logger
|
||||||
|
|
||||||
|
|
||||||
|
class _ImportExport:
|
||||||
|
|
||||||
|
def __init__(self, main_window: Window, database_file: str):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
main_window Window: The instance of the main window
|
||||||
|
"""
|
||||||
|
self.main_window = main_window
|
||||||
|
|
||||||
|
self.old_database = self.main_window.database
|
||||||
|
self.old_model = self.main_window.model
|
||||||
|
|
||||||
|
db = QtSql.QSqlDatabase('QSQLITE')
|
||||||
|
db.setDatabaseName(database_file)
|
||||||
|
|
||||||
|
# tries to open a database connection
|
||||||
|
if not db.open():
|
||||||
|
raise IOError(db.lastError().text())
|
||||||
|
|
||||||
|
self.main_window.window.setWindowTitle(f'Athnos [{self.__class__.__name__}]')
|
||||||
|
self.main_window.window.setStyleSheet('#main_splitter {border: 1px solid #08F7FE;}')
|
||||||
|
|
||||||
|
self.main_window.database = Database(db, False)
|
||||||
|
self.main_window.load_model()
|
||||||
|
|
||||||
|
self.extra_button_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.cancel_button = QtWidgets.QPushButton('Cancel')
|
||||||
|
self.cancel_button.clicked.connect(lambda: self.on_cancel())
|
||||||
|
|
||||||
|
self.extra_button_hlayout.addWidget(self.cancel_button)
|
||||||
|
|
||||||
|
self.main_window.verticalLayout.addLayout(self.extra_button_hlayout)
|
||||||
|
|
||||||
|
def on_cancel(self) -> None:
|
||||||
|
"""Gets called if the cancel button is pressed"""
|
||||||
|
result = QtWidgets.QMessageBox.warning(self.main_window.window, 'Cancel', 'Do you really want to cancel? All changes <strong>won\'t<strong> be saved!',
|
||||||
|
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
||||||
|
if result == QtWidgets.QMessageBox.Ok:
|
||||||
|
self.reset()
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
def reset(self) -> None:
|
||||||
|
"""Resets the modified main window"""
|
||||||
|
# deletes all widgets in the added layout
|
||||||
|
for i in range(self.extra_button_hlayout.count()):
|
||||||
|
self.extra_button_hlayout.itemAt(i).widget().deleteLater()
|
||||||
|
|
||||||
|
# removes the added layout from the main window
|
||||||
|
for i in range(self.main_window.verticalLayout.count()):
|
||||||
|
item = self.main_window.verticalLayout.itemAt(i)
|
||||||
|
if item.layout() == self.extra_button_hlayout:
|
||||||
|
self.main_window.verticalLayout.removeItem(item)
|
||||||
|
break
|
||||||
|
|
||||||
|
self.main_window.window.setStyleSheet('')
|
||||||
|
self.main_window.window.setWindowTitle('Athnos')
|
||||||
|
self.main_window.database = self.old_database
|
||||||
|
self.main_window.load_model()
|
||||||
|
|
||||||
|
|
||||||
|
class Import(_ImportExport):
|
||||||
|
|
||||||
|
def __init__(self, main_window: Window):
|
||||||
|
file = QtWidgets.QFileDialog.getOpenFileName(filter='sqlite3 database (*.sqlite3 *.sqlite);;zip file (*.zip);;All files (*.*)')[0]
|
||||||
|
if not file:
|
||||||
|
self.main_window.close()
|
||||||
|
return
|
||||||
|
super().__init__(main_window, file)
|
||||||
|
|
||||||
|
self.import_button = QtWidgets.QPushButton('Import')
|
||||||
|
self.import_button.clicked.connect(self.on_import)
|
||||||
|
|
||||||
|
self.extra_button_hlayout.insertWidget(0, self.import_button)
|
||||||
|
|
||||||
|
def on_import(self) -> None:
|
||||||
|
"""Imports all database entries from the database to import into the current database"""
|
||||||
|
# creates dicts for every table with the hash of the item as key and the item itself as value
|
||||||
|
clips = {hash(clip):clip for clip in self.main_window.database.Clip.get_all()}
|
||||||
|
items = {hash(item):item for item in self.main_window.database.Item.get_all()}
|
||||||
|
sources = {hash(source):source for source in self.main_window.database.Source.get_all()}
|
||||||
|
tags = {hash(tag):tag for tag in self.main_window.database.Tag.get_all()}
|
||||||
|
|
||||||
|
for old_table, new_table in {self.old_database.Clip.get_all(): clips,
|
||||||
|
self.old_database.Item.get_all(): items,
|
||||||
|
self.old_database.Source.get_all(): sources,
|
||||||
|
self.old_database.Tag.get_all(): tags}.items():
|
||||||
|
for item in old_table:
|
||||||
|
# every item is hashed and checked if it (the hash) already exists
|
||||||
|
item_hash = hash(item)
|
||||||
|
if item_hash in new_table:
|
||||||
|
# if the item already exists, it's will be deleted
|
||||||
|
logger.warning(f'Skipping {item.table_name} with id {item.id} - already exists in the database to be imported')
|
||||||
|
del new_table[item_hash]
|
||||||
|
|
||||||
|
if clips:
|
||||||
|
query = self.old_database.Clip.new_query()
|
||||||
|
query.exec(f'INSERT INTO {self.old_database.Clip.table_name} (source_id, path, type, name, description) VALUES '
|
||||||
|
f'({"), (".join([", ".join(self.old_database.Item.make_sql_valid([clip.source_id, clip.path, clip.type.value, clip.name, clip.description])) for clip in clips.values()])})')
|
||||||
|
self.old_database.Clip.validate_query(query)
|
||||||
|
if items:
|
||||||
|
query = self.old_database.Item.new_query()
|
||||||
|
query.exec(f'INSERT INTO {self.old_database.Item.table_name} (clip_id, tag_id) VALUES '
|
||||||
|
f'({"), (".join([", ".join(self.old_database.Item.make_sql_valid([item.clip_id, item.tag_id])) for item in items.values()])})')
|
||||||
|
self.old_database.Item.validate_query(query)
|
||||||
|
if sources:
|
||||||
|
query = self.old_database.Source.new_query()
|
||||||
|
query.exec(f'INSERT INTO {self.old_database.Source.table_name} (path, type, name, season, episode, description) VALUES '
|
||||||
|
f'({"), (".join([", ".join(self.old_database.Source.make_sql_valid([source.path, source.type.value, source.name, source.season, source.episode, source.description])) for source in sources.values()])})')
|
||||||
|
self.old_database.Source.validate_query(query)
|
||||||
|
if tags:
|
||||||
|
query = self.old_database.Tag.new_query()
|
||||||
|
query.exec(f'INSERT INTO {self.old_database.Tag.table_name} (name) VALUES '
|
||||||
|
f'({"), (".join([", ".join(self.old_database.Tag.make_sql_valid([tag.name])) for tag in tags.values()])})')
|
||||||
|
self.old_database.Tag.validate_query(query)
|
||||||
|
|
||||||
|
logger.debug(f'Imported {len(clips)} clips, {len(items)} items, {len(sources)} sources, {len(tags)} tags to the database')
|
||||||
|
|
||||||
|
self.reset()
|
669
athnos/window/resources.py
Executable file
669
athnos/window/resources.py
Executable file
@ -0,0 +1,669 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Resource object code
|
||||||
|
#
|
||||||
|
# Created by: The Resource Compiler for PyQt5 (Qt v5.14.2)
|
||||||
|
#
|
||||||
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
|
qt_resource_data = b"\
|
||||||
|
\x00\x00\x0d\x92\
|
||||||
|
\x3c\
|
||||||
|
\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
|
||||||
|
\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
|
||||||
|
\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
|
||||||
|
\x6e\x6f\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\
|
||||||
|
\x6c\x6e\x73\x3a\x64\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\
|
||||||
|
\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\
|
||||||
|
\x6e\x74\x73\x2f\x31\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\
|
||||||
|
\x6e\x73\x3a\x63\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\
|
||||||
|
\x65\x61\x74\x69\x76\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\
|
||||||
|
\x67\x2f\x6e\x73\x23\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\
|
||||||
|
\x72\x64\x66\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
|
||||||
|
\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\
|
||||||
|
\x32\x2d\x72\x64\x66\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\
|
||||||
|
\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\
|
||||||
|
\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
|
||||||
|
\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\
|
||||||
|
\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\
|
||||||
|
\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\
|
||||||
|
\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\
|
||||||
|
\x6f\x64\x69\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\
|
||||||
|
\x70\x6f\x64\x69\x2e\x73\x6f\x75\x72\x63\x65\x66\x6f\x72\x67\x65\
|
||||||
|
\x2e\x6e\x65\x74\x2f\x44\x54\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\
|
||||||
|
\x69\x2d\x30\x2e\x64\x74\x64\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\
|
||||||
|
\x73\x3a\x69\x6e\x6b\x73\x63\x61\x70\x65\x3d\x22\x68\x74\x74\x70\
|
||||||
|
\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\
|
||||||
|
\x6f\x72\x67\x2f\x6e\x61\x6d\x65\x73\x70\x61\x63\x65\x73\x2f\x69\
|
||||||
|
\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x76\x65\x72\x73\
|
||||||
|
\x69\x6f\x6e\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x77\x69\x64\
|
||||||
|
\x74\x68\x3d\x22\x39\x30\x2e\x30\x30\x30\x30\x30\x30\x70\x74\x22\
|
||||||
|
\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x39\x30\x2e\x30\
|
||||||
|
\x30\x30\x30\x30\x30\x70\x74\x22\x0a\x20\x20\x20\x76\x69\x65\x77\
|
||||||
|
\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x39\x30\x2e\x30\x30\x30\x30\
|
||||||
|
\x30\x30\x20\x39\x30\x2e\x30\x30\x30\x30\x30\x30\x22\x0a\x20\x20\
|
||||||
|
\x20\x70\x72\x65\x73\x65\x72\x76\x65\x41\x73\x70\x65\x63\x74\x52\
|
||||||
|
\x61\x74\x69\x6f\x3d\x22\x78\x4d\x69\x64\x59\x4d\x69\x64\x20\x6d\
|
||||||
|
\x65\x65\x74\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x36\
|
||||||
|
\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\
|
||||||
|
\x63\x6e\x61\x6d\x65\x3d\x22\x68\x6f\x76\x65\x72\x2e\x73\x76\x67\
|
||||||
|
\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\
|
||||||
|
\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x30\x2e\x31\x20\x28\x31\x2e\
|
||||||
|
\x30\x2e\x31\x2b\x72\x37\x34\x29\x22\x3e\x0a\x20\x20\x3c\x6d\x65\
|
||||||
|
\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\
|
||||||
|
\x6d\x65\x74\x61\x64\x61\x74\x61\x31\x32\x22\x3e\x0a\x20\x20\x20\
|
||||||
|
\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x20\x20\x20\
|
||||||
|
\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\x0a\x20\x20\x20\x20\x20\x20\
|
||||||
|
\x20\x20\x20\x72\x64\x66\x3a\x61\x62\x6f\x75\x74\x3d\x22\x22\x3e\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x66\x6f\x72\
|
||||||
|
\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\x2f\x73\x76\x67\x2b\x78\x6d\
|
||||||
|
\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x0a\x20\x20\
|
||||||
|
\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x79\x70\x65\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x72\x65\
|
||||||
|
\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\
|
||||||
|
\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x64\x63\x6d\x69\x74\
|
||||||
|
\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\x49\x6d\x61\x67\x65\x22\x20\
|
||||||
|
\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\
|
||||||
|
\x69\x74\x6c\x65\x3e\x3c\x2f\x64\x63\x3a\x74\x69\x74\x6c\x65\x3e\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\
|
||||||
|
\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\
|
||||||
|
\x0a\x20\x20\x3c\x2f\x6d\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\
|
||||||
|
\x20\x3c\x64\x65\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\
|
||||||
|
\x64\x65\x66\x73\x31\x30\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x73\x6f\
|
||||||
|
\x64\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\
|
||||||
|
\x22\x23\x66\x66\x66\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\
|
||||||
|
\x6f\x72\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\
|
||||||
|
\x36\x36\x36\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\
|
||||||
|
\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\
|
||||||
|
\x20\x6f\x62\x6a\x65\x63\x74\x74\x6f\x6c\x65\x72\x61\x6e\x63\x65\
|
||||||
|
\x3d\x22\x31\x30\x22\x0a\x20\x20\x20\x20\x20\x67\x72\x69\x64\x74\
|
||||||
|
\x6f\x6c\x65\x72\x61\x6e\x63\x65\x3d\x22\x31\x30\x22\x0a\x20\x20\
|
||||||
|
\x20\x20\x20\x67\x75\x69\x64\x65\x74\x6f\x6c\x65\x72\x61\x6e\x63\
|
||||||
|
\x65\x3d\x22\x31\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
|
||||||
|
\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\
|
||||||
|
\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
|
||||||
|
\x70\x65\x3a\x70\x61\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\
|
||||||
|
\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
|
||||||
|
\x77\x69\x6e\x64\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x39\
|
||||||
|
\x32\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
|
||||||
|
\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\
|
||||||
|
\x22\x31\x30\x31\x35\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\
|
||||||
|
\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x38\x22\x0a\x20\x20\x20\x20\
|
||||||
|
\x20\x73\x68\x6f\x77\x67\x72\x69\x64\x3d\x22\x66\x61\x6c\x73\x65\
|
||||||
|
\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
|
||||||
|
\x7a\x6f\x6f\x6d\x3d\x22\x31\x2e\x30\x35\x33\x32\x39\x34\x35\x22\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\
|
||||||
|
\x78\x3d\x22\x35\x30\x33\x2e\x38\x30\x36\x30\x33\x22\x0a\x20\x20\
|
||||||
|
\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\
|
||||||
|
\x37\x33\x2e\x33\x38\x31\x38\x31\x37\x22\x0a\x20\x20\x20\x20\x20\
|
||||||
|
\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\
|
||||||
|
\x78\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\
|
||||||
|
\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x79\x3d\x22\x30\x22\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\
|
||||||
|
\x69\x6e\x64\x6f\x77\x2d\x6d\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\
|
||||||
|
\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
|
||||||
|
\x65\x3a\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\
|
||||||
|
\x22\x73\x76\x67\x36\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
|
||||||
|
\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2d\x72\x6f\
|
||||||
|
\x74\x61\x74\x69\x6f\x6e\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\
|
||||||
|
\x3c\x67\x0a\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\
|
||||||
|
\x6d\x3d\x22\x74\x72\x61\x6e\x73\x6c\x61\x74\x65\x28\x30\x2e\x30\
|
||||||
|
\x30\x30\x30\x30\x30\x2c\x39\x30\x2e\x30\x30\x30\x30\x30\x30\x29\
|
||||||
|
\x20\x73\x63\x61\x6c\x65\x28\x30\x2e\x31\x30\x30\x30\x30\x30\x2c\
|
||||||
|
\x2d\x30\x2e\x31\x30\x30\x30\x30\x30\x29\x22\x0a\x20\x20\x20\x20\
|
||||||
|
\x20\x66\x69\x6c\x6c\x3d\x22\x23\x65\x37\x34\x63\x33\x63\x22\x0a\
|
||||||
|
\x20\x20\x20\x20\x20\x73\x74\x72\x6f\x6b\x65\x3d\x22\x6e\x6f\x6e\
|
||||||
|
\x65\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x67\x34\x22\x0a\
|
||||||
|
\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\x6c\
|
||||||
|
\x3a\x23\x66\x66\x30\x30\x30\x30\x22\x3e\x0a\x20\x20\x20\x20\x3c\
|
||||||
|
\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\
|
||||||
|
\x33\x38\x31\x20\x38\x30\x30\x20\x63\x2d\x31\x34\x34\x20\x2d\x33\
|
||||||
|
\x30\x20\x2d\x32\x35\x34\x20\x2d\x31\x34\x35\x20\x2d\x32\x38\x32\
|
||||||
|
\x20\x2d\x32\x39\x33\x20\x2d\x34\x32\x20\x2d\x32\x33\x32\x20\x31\
|
||||||
|
\x37\x36\x20\x2d\x34\x35\x30\x20\x34\x30\x38\x20\x2d\x34\x30\x38\
|
||||||
|
\x20\x32\x33\x30\x20\x34\x33\x20\x33\x36\x31\x20\x32\x38\x31\x20\
|
||||||
|
\x32\x37\x30\x20\x34\x39\x33\x20\x2d\x36\x34\x20\x31\x34\x38\x20\
|
||||||
|
\x2d\x32\x33\x38\x20\x32\x34\x30\x20\x2d\x33\x39\x36\x20\x32\x30\
|
||||||
|
\x38\x7a\x20\x6d\x31\x36\x20\x2d\x32\x35\x32\x20\x6c\x35\x33\x20\
|
||||||
|
\x2d\x35\x32\x20\x35\x34\x20\x35\x33\x20\x63\x35\x35\x20\x35\x34\
|
||||||
|
\x20\x38\x37\x20\x36\x34\x20\x39\x34\x20\x32\x37\x20\x33\x20\x2d\
|
||||||
|
\x31\x32\x20\x2d\x31\x35\x20\x2d\x33\x38\x20\x2d\x34\x39\x20\x2d\
|
||||||
|
\x37\x32\x20\x6c\x2d\x35\x33\x20\x2d\x35\x34\x20\x35\x33\x20\x2d\
|
||||||
|
\x35\x34\x20\x63\x35\x34\x20\x2d\x35\x35\x20\x36\x34\x20\x2d\x38\
|
||||||
|
\x37\x20\x32\x37\x20\x2d\x39\x34\x20\x2d\x31\x32\x20\x2d\x33\x20\
|
||||||
|
\x2d\x33\x38\x20\x31\x35\x20\x2d\x37\x32\x20\x34\x39\x20\x6c\x2d\
|
||||||
|
\x35\x34\x20\x35\x33\x20\x2d\x35\x34\x20\x2d\x35\x33\x20\x63\x2d\
|
||||||
|
\x33\x34\x20\x2d\x33\x34\x20\x2d\x36\x30\x20\x2d\x35\x32\x20\x2d\
|
||||||
|
\x37\x32\x20\x2d\x34\x39\x20\x2d\x33\x37\x20\x37\x20\x2d\x32\x37\
|
||||||
|
\x20\x33\x39\x20\x32\x37\x20\x39\x34\x20\x6c\x35\x33\x20\x35\x34\
|
||||||
|
\x20\x2d\x35\x32\x20\x35\x33\x20\x63\x2d\x34\x39\x20\x34\x39\x20\
|
||||||
|
\x2d\x36\x31\x20\x37\x34\x20\x2d\x34\x35\x20\x39\x30\x20\x31\x36\
|
||||||
|
\x20\x31\x36\x20\x34\x31\x20\x34\x20\x39\x30\x20\x2d\x34\x35\x7a\
|
||||||
|
\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\
|
||||||
|
\x68\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\
|
||||||
|
\x3d\x22\x66\x69\x6c\x6c\x3a\x23\x66\x66\x30\x30\x30\x30\x22\x20\
|
||||||
|
\x2f\x3e\x0a\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\x3c\x70\x61\x74\
|
||||||
|
\x68\x0a\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\
|
||||||
|
\x6c\x6c\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x72\x6f\x6b\
|
||||||
|
\x65\x2d\x77\x69\x64\x74\x68\x3a\x30\x2e\x31\x31\x38\x36\x37\x35\
|
||||||
|
\x22\x0a\x20\x20\x20\x20\x20\x64\x3d\x22\x6d\x20\x34\x32\x2e\x36\
|
||||||
|
\x32\x32\x36\x31\x2c\x37\x39\x2e\x35\x34\x31\x38\x39\x33\x20\x63\
|
||||||
|
\x20\x2d\x33\x2e\x31\x31\x36\x31\x36\x35\x2c\x2d\x31\x2e\x30\x32\
|
||||||
|
\x39\x36\x31\x32\x20\x2d\x33\x2e\x30\x35\x38\x38\x2c\x2d\x33\x2e\
|
||||||
|
\x33\x36\x36\x38\x30\x38\x20\x30\x2e\x31\x38\x38\x32\x35\x34\x2c\
|
||||||
|
\x2d\x37\x2e\x36\x36\x39\x39\x38\x39\x20\x31\x2e\x33\x39\x36\x34\
|
||||||
|
\x36\x39\x2c\x2d\x31\x2e\x38\x35\x30\x36\x38\x32\x20\x32\x2e\x37\
|
||||||
|
\x31\x36\x37\x39\x39\x2c\x2d\x33\x2e\x32\x38\x37\x33\x38\x37\x20\
|
||||||
|
\x37\x2e\x32\x38\x31\x38\x35\x33\x2c\x2d\x37\x2e\x39\x32\x33\x36\
|
||||||
|
\x38\x36\x20\x6c\x20\x33\x2e\x38\x38\x34\x39\x33\x33\x2c\x2d\x33\
|
||||||
|
\x2e\x39\x34\x35\x35\x36\x32\x20\x2d\x34\x2e\x35\x36\x34\x32\x34\
|
||||||
|
\x31\x2c\x2d\x34\x2e\x36\x35\x38\x33\x39\x34\x20\x63\x20\x2d\x36\
|
||||||
|
\x2e\x30\x38\x35\x35\x35\x2c\x2d\x36\x2e\x32\x31\x31\x30\x38\x35\
|
||||||
|
\x20\x2d\x37\x2e\x34\x33\x39\x37\x30\x39\x2c\x2d\x37\x2e\x37\x37\
|
||||||
|
\x35\x39\x33\x31\x20\x2d\x38\x2e\x35\x31\x32\x35\x35\x39\x2c\x2d\
|
||||||
|
\x39\x2e\x38\x33\x36\x39\x38\x36\x20\x2d\x31\x2e\x31\x31\x34\x30\
|
||||||
|
\x39\x31\x2c\x2d\x32\x2e\x31\x34\x30\x32\x38\x32\x20\x2d\x31\x2e\
|
||||||
|
\x30\x33\x35\x30\x35\x33\x2c\x2d\x33\x2e\x35\x35\x33\x39\x36\x34\
|
||||||
|
\x20\x30\x2e\x32\x36\x30\x37\x30\x38\x2c\x2d\x34\x2e\x36\x36\x33\
|
||||||
|
\x30\x38\x38\x20\x30\x2e\x37\x30\x38\x37\x38\x34\x2c\x2d\x30\x2e\
|
||||||
|
\x36\x30\x36\x36\x39\x32\x20\x31\x2e\x35\x38\x35\x35\x37\x34\x2c\
|
||||||
|
\x2d\x30\x2e\x38\x34\x37\x31\x20\x32\x2e\x34\x35\x33\x36\x34\x37\
|
||||||
|
\x2c\x2d\x30\x2e\x36\x37\x32\x37\x36\x36\x20\x31\x2e\x32\x38\x32\
|
||||||
|
\x35\x34\x32\x2c\x30\x2e\x32\x35\x37\x35\x37\x32\x20\x32\x2e\x38\
|
||||||
|
\x39\x33\x39\x38\x39\x2c\x31\x2e\x31\x37\x37\x35\x34\x36\x20\x34\
|
||||||
|
\x2e\x38\x36\x39\x36\x32\x31\x2c\x32\x2e\x37\x38\x30\x30\x36\x35\
|
||||||
|
\x20\x31\x2e\x34\x32\x38\x36\x35\x32\x2c\x31\x2e\x31\x35\x38\x38\
|
||||||
|
\x34\x20\x31\x2e\x37\x35\x38\x39\x37\x34\x2c\x31\x2e\x34\x36\x39\
|
||||||
|
\x39\x39\x39\x20\x36\x2e\x39\x32\x34\x37\x30\x31\x2c\x36\x2e\x35\
|
||||||
|
\x32\x32\x39\x38\x32\x20\x6c\x20\x34\x2e\x35\x39\x38\x33\x32\x33\
|
||||||
|
\x2c\x34\x2e\x34\x39\x37\x39\x36\x34\x20\x33\x2e\x39\x34\x36\x32\
|
||||||
|
\x39\x36\x2c\x2d\x33\x2e\x38\x38\x35\x36\x35\x35\x20\x63\x20\x35\
|
||||||
|
\x2e\x36\x38\x37\x34\x38\x38\x2c\x2d\x35\x2e\x36\x30\x30\x30\x39\
|
||||||
|
\x20\x37\x2e\x35\x30\x35\x32\x36\x2c\x2d\x37\x2e\x31\x38\x38\x37\
|
||||||
|
\x36\x31\x20\x39\x2e\x38\x33\x34\x37\x30\x31\x2c\x2d\x38\x2e\x35\
|
||||||
|
\x39\x35\x31\x39\x37\x20\x30\x2e\x39\x39\x35\x37\x32\x37\x2c\x2d\
|
||||||
|
\x30\x2e\x36\x30\x31\x31\x38\x35\x20\x32\x2e\x35\x36\x34\x37\x37\
|
||||||
|
\x35\x2c\x2d\x31\x2e\x31\x39\x30\x33\x38\x32\x20\x33\x2e\x31\x36\
|
||||||
|
\x36\x37\x30\x39\x2c\x2d\x31\x2e\x31\x38\x39\x31\x33\x38\x20\x31\
|
||||||
|
\x2e\x33\x32\x39\x35\x38\x39\x2c\x30\x2e\x30\x30\x32\x37\x20\x32\
|
||||||
|
\x2e\x32\x35\x38\x34\x37\x31\x2c\x30\x2e\x39\x32\x38\x31\x32\x36\
|
||||||
|
\x20\x32\x2e\x36\x33\x36\x30\x30\x38\x2c\x32\x2e\x36\x32\x36\x30\
|
||||||
|
\x36\x33\x20\x30\x2e\x31\x38\x34\x34\x32\x34\x2c\x30\x2e\x38\x32\
|
||||||
|
\x39\x34\x33\x34\x20\x30\x2e\x31\x31\x30\x32\x39\x2c\x31\x2e\x32\
|
||||||
|
\x34\x30\x37\x37\x36\x20\x2d\x30\x2e\x34\x32\x34\x38\x38\x36\x2c\
|
||||||
|
\x32\x2e\x33\x35\x37\x34\x39\x39\x20\x2d\x31\x2e\x31\x30\x34\x36\
|
||||||
|
\x39\x2c\x32\x2e\x33\x30\x35\x31\x20\x2d\x32\x2e\x38\x35\x31\x38\
|
||||||
|
\x31\x34\x2c\x34\x2e\x33\x30\x32\x35\x34\x34\x20\x2d\x31\x30\x2e\
|
||||||
|
\x36\x36\x35\x38\x37\x36\x2c\x31\x32\x2e\x31\x39\x34\x30\x33\x33\
|
||||||
|
\x20\x6c\x20\x2d\x32\x2e\x34\x39\x37\x31\x31\x38\x2c\x32\x2e\x35\
|
||||||
|
\x32\x31\x38\x36\x31\x20\x32\x2e\x35\x35\x36\x32\x37\x36\x2c\x32\
|
||||||
|
\x2e\x35\x38\x31\x31\x37\x35\x20\x63\x20\x37\x2e\x34\x37\x38\x39\
|
||||||
|
\x35\x2c\x37\x2e\x35\x35\x31\x37\x39\x39\x20\x39\x2e\x31\x38\x30\
|
||||||
|
\x34\x34\x37\x2c\x39\x2e\x35\x33\x33\x37\x30\x39\x20\x31\x30\x2e\
|
||||||
|
\x34\x34\x32\x30\x32\x36\x2c\x31\x32\x2e\x31\x36\x32\x39\x31\x32\
|
||||||
|
\x20\x31\x2e\x31\x31\x38\x30\x38\x33\x2c\x32\x2e\x33\x33\x30\x31\
|
||||||
|
\x34\x37\x20\x30\x2e\x38\x32\x34\x33\x34\x33\x2c\x33\x2e\x37\x33\
|
||||||
|
\x32\x36\x33\x31\x20\x2d\x30\x2e\x39\x34\x38\x33\x39\x35\x2c\x34\
|
||||||
|
\x2e\x35\x32\x38\x31\x39\x20\x2d\x31\x2e\x34\x36\x38\x33\x31\x37\
|
||||||
|
\x2c\x30\x2e\x36\x35\x38\x39\x34\x31\x20\x2d\x32\x2e\x34\x36\x33\
|
||||||
|
\x37\x33\x2c\x30\x2e\x35\x31\x37\x39\x35\x38\x20\x2d\x34\x2e\x32\
|
||||||
|
\x34\x36\x37\x39\x31\x2c\x2d\x30\x2e\x36\x30\x31\x34\x38\x32\x20\
|
||||||
|
\x2d\x32\x2e\x32\x33\x30\x38\x34\x33\x2c\x2d\x31\x2e\x34\x30\x30\
|
||||||
|
\x35\x36\x36\x20\x2d\x33\x2e\x31\x39\x35\x34\x35\x2c\x2d\x32\x2e\
|
||||||
|
\x32\x35\x33\x34\x37\x20\x2d\x39\x2e\x32\x30\x30\x36\x38\x33\x2c\
|
||||||
|
\x2d\x38\x2e\x31\x33\x35\x32\x32\x34\x20\x6c\x20\x2d\x34\x2e\x35\
|
||||||
|
\x39\x39\x37\x35\x33\x2c\x2d\x34\x2e\x35\x30\x35\x31\x37\x33\x20\
|
||||||
|
\x2d\x34\x2e\x35\x33\x38\x32\x34\x33\x2c\x34\x2e\x34\x33\x37\x39\
|
||||||
|
\x32\x31\x20\x63\x20\x2d\x35\x2e\x31\x32\x35\x35\x30\x39\x2c\x35\
|
||||||
|
\x2e\x30\x31\x32\x32\x30\x35\x20\x2d\x35\x2e\x34\x33\x36\x38\x35\
|
||||||
|
\x34\x2c\x35\x2e\x33\x30\x35\x31\x37\x31\x20\x2d\x36\x2e\x38\x39\
|
||||||
|
\x36\x37\x33\x32\x2c\x36\x2e\x34\x38\x39\x36\x31\x39\x20\x2d\x32\
|
||||||
|
\x2e\x37\x39\x33\x39\x38\x2c\x32\x2e\x32\x36\x36\x38\x35\x32\x20\
|
||||||
|
\x2d\x34\x2e\x35\x36\x39\x38\x35\x35\x2c\x33\x2e\x30\x33\x37\x36\
|
||||||
|
\x36\x37\x20\x2d\x35\x2e\x39\x34\x38\x37\x37\x39\x2c\x32\x2e\x35\
|
||||||
|
\x38\x32\x30\x35\x36\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\x69\x64\
|
||||||
|
\x3d\x22\x70\x61\x74\x68\x31\x36\x22\x0a\x20\x20\x20\x20\x20\x74\
|
||||||
|
\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x73\x63\x61\x6c\x65\x28\
|
||||||
|
\x30\x2e\x37\x35\x29\x22\x20\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\
|
||||||
|
\x0a\
|
||||||
|
\x00\x00\x0d\x4d\
|
||||||
|
\x3c\
|
||||||
|
\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
|
||||||
|
\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
|
||||||
|
\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
|
||||||
|
\x6e\x6f\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\
|
||||||
|
\x6c\x6e\x73\x3a\x64\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\
|
||||||
|
\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\
|
||||||
|
\x6e\x74\x73\x2f\x31\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\
|
||||||
|
\x6e\x73\x3a\x63\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\
|
||||||
|
\x65\x61\x74\x69\x76\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\
|
||||||
|
\x67\x2f\x6e\x73\x23\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\
|
||||||
|
\x72\x64\x66\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
|
||||||
|
\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\
|
||||||
|
\x32\x2d\x72\x64\x66\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\
|
||||||
|
\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\
|
||||||
|
\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
|
||||||
|
\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\
|
||||||
|
\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\
|
||||||
|
\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\
|
||||||
|
\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\
|
||||||
|
\x6f\x64\x69\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\
|
||||||
|
\x70\x6f\x64\x69\x2e\x73\x6f\x75\x72\x63\x65\x66\x6f\x72\x67\x65\
|
||||||
|
\x2e\x6e\x65\x74\x2f\x44\x54\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\
|
||||||
|
\x69\x2d\x30\x2e\x64\x74\x64\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\
|
||||||
|
\x73\x3a\x69\x6e\x6b\x73\x63\x61\x70\x65\x3d\x22\x68\x74\x74\x70\
|
||||||
|
\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\
|
||||||
|
\x6f\x72\x67\x2f\x6e\x61\x6d\x65\x73\x70\x61\x63\x65\x73\x2f\x69\
|
||||||
|
\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x76\x65\x72\x73\
|
||||||
|
\x69\x6f\x6e\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x77\x69\x64\
|
||||||
|
\x74\x68\x3d\x22\x39\x30\x2e\x30\x30\x30\x30\x30\x30\x70\x74\x22\
|
||||||
|
\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x39\x30\x2e\x30\
|
||||||
|
\x30\x30\x30\x30\x30\x70\x74\x22\x0a\x20\x20\x20\x76\x69\x65\x77\
|
||||||
|
\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x39\x30\x2e\x30\x30\x30\x30\
|
||||||
|
\x30\x30\x20\x39\x30\x2e\x30\x30\x30\x30\x30\x30\x22\x0a\x20\x20\
|
||||||
|
\x20\x70\x72\x65\x73\x65\x72\x76\x65\x41\x73\x70\x65\x63\x74\x52\
|
||||||
|
\x61\x74\x69\x6f\x3d\x22\x78\x4d\x69\x64\x59\x4d\x69\x64\x20\x6d\
|
||||||
|
\x65\x65\x74\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x36\
|
||||||
|
\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\
|
||||||
|
\x63\x6e\x61\x6d\x65\x3d\x22\x69\x63\x6f\x6e\x73\x38\x2d\x6d\x61\
|
||||||
|
\x63\x6f\x73\x2d\x73\x63\x68\x6c\x69\x65\xc3\x9f\x65\x6e\x2d\x39\
|
||||||
|
\x30\x5f\x31\x5f\x2e\x73\x76\x67\x22\x0a\x20\x20\x20\x69\x6e\x6b\
|
||||||
|
\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\
|
||||||
|
\x2e\x30\x2e\x31\x20\x28\x31\x2e\x30\x2e\x31\x2b\x72\x37\x34\x29\
|
||||||
|
\x22\x3e\x0a\x20\x20\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x69\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\x61\
|
||||||
|
\x31\x32\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\
|
||||||
|
\x46\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\
|
||||||
|
\x6b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\
|
||||||
|
\x62\x6f\x75\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\
|
||||||
|
\x20\x3c\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\
|
||||||
|
\x65\x2f\x73\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\
|
||||||
|
\x72\x6d\x61\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\
|
||||||
|
\x63\x3a\x74\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\
|
||||||
|
\x20\x20\x72\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\
|
||||||
|
\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\
|
||||||
|
\x64\x63\x2f\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\
|
||||||
|
\x6c\x49\x6d\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\
|
||||||
|
\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\x20\
|
||||||
|
\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\x6d\
|
||||||
|
\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\x73\x31\x30\
|
||||||
|
\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\
|
||||||
|
\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\
|
||||||
|
\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\x66\
|
||||||
|
\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x63\
|
||||||
|
\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\x36\x36\x36\x22\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\x61\x63\x69\x74\
|
||||||
|
\x79\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x6f\x62\x6a\x65\x63\
|
||||||
|
\x74\x74\x6f\x6c\x65\x72\x61\x6e\x63\x65\x3d\x22\x31\x30\x22\x0a\
|
||||||
|
\x20\x20\x20\x20\x20\x67\x72\x69\x64\x74\x6f\x6c\x65\x72\x61\x6e\
|
||||||
|
\x63\x65\x3d\x22\x31\x30\x22\x0a\x20\x20\x20\x20\x20\x67\x75\x69\
|
||||||
|
\x64\x65\x74\x6f\x6c\x65\x72\x61\x6e\x63\x65\x3d\x22\x31\x30\x22\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\
|
||||||
|
\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x22\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\
|
||||||
|
\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\x20\
|
||||||
|
\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\
|
||||||
|
\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x39\x32\x30\x22\x0a\x20\x20\
|
||||||
|
\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\
|
||||||
|
\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x31\x30\x31\x35\x22\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6e\x61\x6d\x65\x64\x76\
|
||||||
|
\x69\x65\x77\x38\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\x77\x67\
|
||||||
|
\x72\x69\x64\x3d\x22\x66\x61\x6c\x73\x65\x22\x0a\x20\x20\x20\x20\
|
||||||
|
\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\
|
||||||
|
\x35\x2e\x39\x35\x38\x33\x33\x33\x33\x22\x0a\x20\x20\x20\x20\x20\
|
||||||
|
\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\x22\x35\x31\x2e\
|
||||||
|
\x35\x32\x39\x39\x35\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
|
||||||
|
\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\x35\x33\x2e\x31\x36\x38\x33\
|
||||||
|
\x32\x38\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
|
||||||
|
\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\
|
||||||
|
\x64\x6f\x77\x2d\x79\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\
|
||||||
|
\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\
|
||||||
|
\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x0a\x20\x20\x20\
|
||||||
|
\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\x72\x65\
|
||||||
|
\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x73\x76\x67\x36\x22\x20\
|
||||||
|
\x2f\x3e\x0a\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x74\x72\x61\
|
||||||
|
\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x74\x72\x61\x6e\x73\x6c\x61\x74\
|
||||||
|
\x65\x28\x30\x2e\x30\x30\x30\x30\x30\x30\x2c\x39\x30\x2e\x30\x30\
|
||||||
|
\x30\x30\x30\x30\x29\x20\x73\x63\x61\x6c\x65\x28\x30\x2e\x31\x30\
|
||||||
|
\x30\x30\x30\x30\x2c\x2d\x30\x2e\x31\x30\x30\x30\x30\x30\x29\x22\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x66\x69\x6c\x6c\x3d\x22\x23\x65\x37\x34\
|
||||||
|
\x63\x33\x63\x22\x0a\x20\x20\x20\x20\x20\x73\x74\x72\x6f\x6b\x65\
|
||||||
|
\x3d\x22\x6e\x6f\x6e\x65\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\
|
||||||
|
\x22\x67\x34\x22\x3e\x0a\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\
|
||||||
|
\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x33\x38\x31\x20\x38\
|
||||||
|
\x30\x30\x20\x63\x2d\x31\x34\x34\x20\x2d\x33\x30\x20\x2d\x32\x35\
|
||||||
|
\x34\x20\x2d\x31\x34\x35\x20\x2d\x32\x38\x32\x20\x2d\x32\x39\x33\
|
||||||
|
\x20\x2d\x34\x32\x20\x2d\x32\x33\x32\x20\x31\x37\x36\x20\x2d\x34\
|
||||||
|
\x35\x30\x20\x34\x30\x38\x20\x2d\x34\x30\x38\x20\x32\x33\x30\x20\
|
||||||
|
\x34\x33\x20\x33\x36\x31\x20\x32\x38\x31\x20\x32\x37\x30\x20\x34\
|
||||||
|
\x39\x33\x20\x2d\x36\x34\x20\x31\x34\x38\x20\x2d\x32\x33\x38\x20\
|
||||||
|
\x32\x34\x30\x20\x2d\x33\x39\x36\x20\x32\x30\x38\x7a\x20\x6d\x31\
|
||||||
|
\x36\x20\x2d\x32\x35\x32\x20\x6c\x35\x33\x20\x2d\x35\x32\x20\x35\
|
||||||
|
\x34\x20\x35\x33\x20\x63\x35\x35\x20\x35\x34\x20\x38\x37\x20\x36\
|
||||||
|
\x34\x20\x39\x34\x20\x32\x37\x20\x33\x20\x2d\x31\x32\x20\x2d\x31\
|
||||||
|
\x35\x20\x2d\x33\x38\x20\x2d\x34\x39\x20\x2d\x37\x32\x20\x6c\x2d\
|
||||||
|
\x35\x33\x20\x2d\x35\x34\x20\x35\x33\x20\x2d\x35\x34\x20\x63\x35\
|
||||||
|
\x34\x20\x2d\x35\x35\x20\x36\x34\x20\x2d\x38\x37\x20\x32\x37\x20\
|
||||||
|
\x2d\x39\x34\x20\x2d\x31\x32\x20\x2d\x33\x20\x2d\x33\x38\x20\x31\
|
||||||
|
\x35\x20\x2d\x37\x32\x20\x34\x39\x20\x6c\x2d\x35\x34\x20\x35\x33\
|
||||||
|
\x20\x2d\x35\x34\x20\x2d\x35\x33\x20\x63\x2d\x33\x34\x20\x2d\x33\
|
||||||
|
\x34\x20\x2d\x36\x30\x20\x2d\x35\x32\x20\x2d\x37\x32\x20\x2d\x34\
|
||||||
|
\x39\x20\x2d\x33\x37\x20\x37\x20\x2d\x32\x37\x20\x33\x39\x20\x32\
|
||||||
|
\x37\x20\x39\x34\x20\x6c\x35\x33\x20\x35\x34\x20\x2d\x35\x32\x20\
|
||||||
|
\x35\x33\x20\x63\x2d\x34\x39\x20\x34\x39\x20\x2d\x36\x31\x20\x37\
|
||||||
|
\x34\x20\x2d\x34\x35\x20\x39\x30\x20\x31\x36\x20\x31\x36\x20\x34\
|
||||||
|
\x31\x20\x34\x20\x39\x30\x20\x2d\x34\x35\x7a\x22\x0a\x20\x20\x20\
|
||||||
|
\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x32\x22\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\
|
||||||
|
\x6c\x3a\x23\x66\x66\x66\x66\x66\x66\x22\x20\x2f\x3e\x0a\x20\x20\
|
||||||
|
\x3c\x2f\x67\x3e\x0a\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\
|
||||||
|
\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\x6c\x3a\x23\x38\
|
||||||
|
\x30\x38\x30\x38\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\
|
||||||
|
\x74\x68\x3a\x30\x2e\x31\x31\x38\x36\x37\x35\x22\x0a\x20\x20\x20\
|
||||||
|
\x20\x20\x64\x3d\x22\x6d\x20\x34\x32\x2e\x36\x32\x32\x36\x31\x2c\
|
||||||
|
\x37\x39\x2e\x35\x34\x31\x38\x39\x33\x20\x63\x20\x2d\x33\x2e\x31\
|
||||||
|
\x31\x36\x31\x36\x35\x2c\x2d\x31\x2e\x30\x32\x39\x36\x31\x32\x20\
|
||||||
|
\x2d\x33\x2e\x30\x35\x38\x38\x2c\x2d\x33\x2e\x33\x36\x36\x38\x30\
|
||||||
|
\x38\x20\x30\x2e\x31\x38\x38\x32\x35\x34\x2c\x2d\x37\x2e\x36\x36\
|
||||||
|
\x39\x39\x38\x39\x20\x31\x2e\x33\x39\x36\x34\x36\x39\x2c\x2d\x31\
|
||||||
|
\x2e\x38\x35\x30\x36\x38\x32\x20\x32\x2e\x37\x31\x36\x37\x39\x39\
|
||||||
|
\x2c\x2d\x33\x2e\x32\x38\x37\x33\x38\x37\x20\x37\x2e\x32\x38\x31\
|
||||||
|
\x38\x35\x33\x2c\x2d\x37\x2e\x39\x32\x33\x36\x38\x36\x20\x6c\x20\
|
||||||
|
\x33\x2e\x38\x38\x34\x39\x33\x33\x2c\x2d\x33\x2e\x39\x34\x35\x35\
|
||||||
|
\x36\x32\x20\x2d\x34\x2e\x35\x36\x34\x32\x34\x31\x2c\x2d\x34\x2e\
|
||||||
|
\x36\x35\x38\x33\x39\x34\x20\x63\x20\x2d\x36\x2e\x30\x38\x35\x35\
|
||||||
|
\x35\x2c\x2d\x36\x2e\x32\x31\x31\x30\x38\x35\x20\x2d\x37\x2e\x34\
|
||||||
|
\x33\x39\x37\x30\x39\x2c\x2d\x37\x2e\x37\x37\x35\x39\x33\x31\x20\
|
||||||
|
\x2d\x38\x2e\x35\x31\x32\x35\x35\x39\x2c\x2d\x39\x2e\x38\x33\x36\
|
||||||
|
\x39\x38\x36\x20\x2d\x31\x2e\x31\x31\x34\x30\x39\x31\x2c\x2d\x32\
|
||||||
|
\x2e\x31\x34\x30\x32\x38\x32\x20\x2d\x31\x2e\x30\x33\x35\x30\x35\
|
||||||
|
\x33\x2c\x2d\x33\x2e\x35\x35\x33\x39\x36\x34\x20\x30\x2e\x32\x36\
|
||||||
|
\x30\x37\x30\x38\x2c\x2d\x34\x2e\x36\x36\x33\x30\x38\x38\x20\x30\
|
||||||
|
\x2e\x37\x30\x38\x37\x38\x34\x2c\x2d\x30\x2e\x36\x30\x36\x36\x39\
|
||||||
|
\x32\x20\x31\x2e\x35\x38\x35\x35\x37\x34\x2c\x2d\x30\x2e\x38\x34\
|
||||||
|
\x37\x31\x20\x32\x2e\x34\x35\x33\x36\x34\x37\x2c\x2d\x30\x2e\x36\
|
||||||
|
\x37\x32\x37\x36\x36\x20\x31\x2e\x32\x38\x32\x35\x34\x32\x2c\x30\
|
||||||
|
\x2e\x32\x35\x37\x35\x37\x32\x20\x32\x2e\x38\x39\x33\x39\x38\x39\
|
||||||
|
\x2c\x31\x2e\x31\x37\x37\x35\x34\x36\x20\x34\x2e\x38\x36\x39\x36\
|
||||||
|
\x32\x31\x2c\x32\x2e\x37\x38\x30\x30\x36\x35\x20\x31\x2e\x34\x32\
|
||||||
|
\x38\x36\x35\x32\x2c\x31\x2e\x31\x35\x38\x38\x34\x20\x31\x2e\x37\
|
||||||
|
\x35\x38\x39\x37\x34\x2c\x31\x2e\x34\x36\x39\x39\x39\x39\x20\x36\
|
||||||
|
\x2e\x39\x32\x34\x37\x30\x31\x2c\x36\x2e\x35\x32\x32\x39\x38\x32\
|
||||||
|
\x20\x6c\x20\x34\x2e\x35\x39\x38\x33\x32\x33\x2c\x34\x2e\x34\x39\
|
||||||
|
\x37\x39\x36\x34\x20\x33\x2e\x39\x34\x36\x32\x39\x36\x2c\x2d\x33\
|
||||||
|
\x2e\x38\x38\x35\x36\x35\x35\x20\x63\x20\x35\x2e\x36\x38\x37\x34\
|
||||||
|
\x38\x38\x2c\x2d\x35\x2e\x36\x30\x30\x30\x39\x20\x37\x2e\x35\x30\
|
||||||
|
\x35\x32\x36\x2c\x2d\x37\x2e\x31\x38\x38\x37\x36\x31\x20\x39\x2e\
|
||||||
|
\x38\x33\x34\x37\x30\x31\x2c\x2d\x38\x2e\x35\x39\x35\x31\x39\x37\
|
||||||
|
\x20\x30\x2e\x39\x39\x35\x37\x32\x37\x2c\x2d\x30\x2e\x36\x30\x31\
|
||||||
|
\x31\x38\x35\x20\x32\x2e\x35\x36\x34\x37\x37\x35\x2c\x2d\x31\x2e\
|
||||||
|
\x31\x39\x30\x33\x38\x32\x20\x33\x2e\x31\x36\x36\x37\x30\x39\x2c\
|
||||||
|
\x2d\x31\x2e\x31\x38\x39\x31\x33\x38\x20\x31\x2e\x33\x32\x39\x35\
|
||||||
|
\x38\x39\x2c\x30\x2e\x30\x30\x32\x37\x20\x32\x2e\x32\x35\x38\x34\
|
||||||
|
\x37\x31\x2c\x30\x2e\x39\x32\x38\x31\x32\x36\x20\x32\x2e\x36\x33\
|
||||||
|
\x36\x30\x30\x38\x2c\x32\x2e\x36\x32\x36\x30\x36\x33\x20\x30\x2e\
|
||||||
|
\x31\x38\x34\x34\x32\x34\x2c\x30\x2e\x38\x32\x39\x34\x33\x34\x20\
|
||||||
|
\x30\x2e\x31\x31\x30\x32\x39\x2c\x31\x2e\x32\x34\x30\x37\x37\x36\
|
||||||
|
\x20\x2d\x30\x2e\x34\x32\x34\x38\x38\x36\x2c\x32\x2e\x33\x35\x37\
|
||||||
|
\x34\x39\x39\x20\x2d\x31\x2e\x31\x30\x34\x36\x39\x2c\x32\x2e\x33\
|
||||||
|
\x30\x35\x31\x20\x2d\x32\x2e\x38\x35\x31\x38\x31\x34\x2c\x34\x2e\
|
||||||
|
\x33\x30\x32\x35\x34\x34\x20\x2d\x31\x30\x2e\x36\x36\x35\x38\x37\
|
||||||
|
\x36\x2c\x31\x32\x2e\x31\x39\x34\x30\x33\x33\x20\x6c\x20\x2d\x32\
|
||||||
|
\x2e\x34\x39\x37\x31\x31\x38\x2c\x32\x2e\x35\x32\x31\x38\x36\x31\
|
||||||
|
\x20\x32\x2e\x35\x35\x36\x32\x37\x36\x2c\x32\x2e\x35\x38\x31\x31\
|
||||||
|
\x37\x35\x20\x63\x20\x37\x2e\x34\x37\x38\x39\x35\x2c\x37\x2e\x35\
|
||||||
|
\x35\x31\x37\x39\x39\x20\x39\x2e\x31\x38\x30\x34\x34\x37\x2c\x39\
|
||||||
|
\x2e\x35\x33\x33\x37\x30\x39\x20\x31\x30\x2e\x34\x34\x32\x30\x32\
|
||||||
|
\x36\x2c\x31\x32\x2e\x31\x36\x32\x39\x31\x32\x20\x31\x2e\x31\x31\
|
||||||
|
\x38\x30\x38\x33\x2c\x32\x2e\x33\x33\x30\x31\x34\x37\x20\x30\x2e\
|
||||||
|
\x38\x32\x34\x33\x34\x33\x2c\x33\x2e\x37\x33\x32\x36\x33\x31\x20\
|
||||||
|
\x2d\x30\x2e\x39\x34\x38\x33\x39\x35\x2c\x34\x2e\x35\x32\x38\x31\
|
||||||
|
\x39\x20\x2d\x31\x2e\x34\x36\x38\x33\x31\x37\x2c\x30\x2e\x36\x35\
|
||||||
|
\x38\x39\x34\x31\x20\x2d\x32\x2e\x34\x36\x33\x37\x33\x2c\x30\x2e\
|
||||||
|
\x35\x31\x37\x39\x35\x38\x20\x2d\x34\x2e\x32\x34\x36\x37\x39\x31\
|
||||||
|
\x2c\x2d\x30\x2e\x36\x30\x31\x34\x38\x32\x20\x2d\x32\x2e\x32\x33\
|
||||||
|
\x30\x38\x34\x33\x2c\x2d\x31\x2e\x34\x30\x30\x35\x36\x36\x20\x2d\
|
||||||
|
\x33\x2e\x31\x39\x35\x34\x35\x2c\x2d\x32\x2e\x32\x35\x33\x34\x37\
|
||||||
|
\x20\x2d\x39\x2e\x32\x30\x30\x36\x38\x33\x2c\x2d\x38\x2e\x31\x33\
|
||||||
|
\x35\x32\x32\x34\x20\x6c\x20\x2d\x34\x2e\x35\x39\x39\x37\x35\x33\
|
||||||
|
\x2c\x2d\x34\x2e\x35\x30\x35\x31\x37\x33\x20\x2d\x34\x2e\x35\x33\
|
||||||
|
\x38\x32\x34\x33\x2c\x34\x2e\x34\x33\x37\x39\x32\x31\x20\x63\x20\
|
||||||
|
\x2d\x35\x2e\x31\x32\x35\x35\x30\x39\x2c\x35\x2e\x30\x31\x32\x32\
|
||||||
|
\x30\x35\x20\x2d\x35\x2e\x34\x33\x36\x38\x35\x34\x2c\x35\x2e\x33\
|
||||||
|
\x30\x35\x31\x37\x31\x20\x2d\x36\x2e\x38\x39\x36\x37\x33\x32\x2c\
|
||||||
|
\x36\x2e\x34\x38\x39\x36\x31\x39\x20\x2d\x32\x2e\x37\x39\x33\x39\
|
||||||
|
\x38\x2c\x32\x2e\x32\x36\x36\x38\x35\x32\x20\x2d\x34\x2e\x35\x36\
|
||||||
|
\x39\x38\x35\x35\x2c\x33\x2e\x30\x33\x37\x36\x36\x37\x20\x2d\x35\
|
||||||
|
\x2e\x39\x34\x38\x37\x37\x39\x2c\x32\x2e\x35\x38\x32\x30\x35\x36\
|
||||||
|
\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\
|
||||||
|
\x68\x31\x36\x22\x0a\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\x66\
|
||||||
|
\x6f\x72\x6d\x3d\x22\x73\x63\x61\x6c\x65\x28\x30\x2e\x37\x35\x29\
|
||||||
|
\x22\x20\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
|
||||||
|
\x00\x00\x09\xc1\
|
||||||
|
\x3c\
|
||||||
|
\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
|
||||||
|
\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x69\x73\x6f\
|
||||||
|
\x2d\x38\x38\x35\x39\x2d\x31\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\
|
||||||
|
\x20\x47\x65\x6e\x65\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\
|
||||||
|
\x65\x20\x49\x6c\x6c\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x39\
|
||||||
|
\x2e\x30\x2e\x30\x2c\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\
|
||||||
|
\x20\x50\x6c\x75\x67\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\
|
||||||
|
\x65\x72\x73\x69\x6f\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\
|
||||||
|
\x6c\x64\x20\x30\x29\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x73\x76\x67\
|
||||||
|
\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\
|
||||||
|
\x64\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\
|
||||||
|
\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\
|
||||||
|
\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\
|
||||||
|
\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\
|
||||||
|
\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\
|
||||||
|
\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\
|
||||||
|
\x22\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x76\x69\x65\
|
||||||
|
\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
|
||||||
|
\x32\x22\x20\x73\x74\x79\x6c\x65\x3d\x22\x65\x6e\x61\x62\x6c\x65\
|
||||||
|
\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x6e\x65\x77\x20\
|
||||||
|
\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x3b\x22\x20\x78\x6d\
|
||||||
|
\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\
|
||||||
|
\x65\x22\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x09\x3c\x67\x3e\x0d\x0a\
|
||||||
|
\x09\x09\x3c\x67\x3e\x0d\x0a\x09\x09\x09\x3c\x70\x61\x74\x68\x20\
|
||||||
|
\x64\x3d\x22\x4d\x34\x37\x32\x2e\x31\x37\x38\x2c\x33\x34\x2e\x36\
|
||||||
|
\x32\x48\x33\x39\x2e\x38\x32\x32\x43\x31\x37\x2e\x38\x36\x34\x2c\
|
||||||
|
\x33\x34\x2e\x36\x32\x2c\x30\x2c\x35\x32\x2e\x34\x38\x34\x2c\x30\
|
||||||
|
\x2c\x37\x34\x2e\x34\x34\x32\x63\x30\x2c\x31\x37\x2e\x39\x35\x35\
|
||||||
|
\x2c\x30\x2c\x33\x34\x35\x2e\x32\x33\x34\x2c\x30\x2c\x33\x36\x33\
|
||||||
|
\x2e\x31\x31\x36\x0d\x0a\x09\x09\x09\x09\x63\x30\x2c\x32\x31\x2e\
|
||||||
|
\x39\x35\x38\x2c\x31\x37\x2e\x38\x36\x34\x2c\x33\x39\x2e\x38\x32\
|
||||||
|
\x32\x2c\x33\x39\x2e\x38\x32\x32\x2c\x33\x39\x2e\x38\x32\x32\x68\
|
||||||
|
\x34\x33\x32\x2e\x33\x35\x36\x63\x32\x31\x2e\x39\x35\x38\x2c\x30\
|
||||||
|
\x2c\x33\x39\x2e\x38\x32\x32\x2d\x31\x37\x2e\x38\x36\x34\x2c\x33\
|
||||||
|
\x39\x2e\x38\x32\x32\x2d\x33\x39\x2e\x38\x32\x32\x63\x30\x2d\x31\
|
||||||
|
\x37\x2e\x38\x39\x2c\x30\x2d\x33\x34\x35\x2e\x31\x36\x37\x2c\x30\
|
||||||
|
\x2d\x33\x36\x33\x2e\x31\x31\x36\x0d\x0a\x09\x09\x09\x09\x43\x35\
|
||||||
|
\x31\x32\x2c\x35\x32\x2e\x34\x38\x34\x2c\x34\x39\x34\x2e\x31\x33\
|
||||||
|
\x36\x2c\x33\x34\x2e\x36\x32\x2c\x34\x37\x32\x2e\x31\x37\x38\x2c\
|
||||||
|
\x33\x34\x2e\x36\x32\x7a\x20\x4d\x34\x37\x37\x2e\x38\x36\x37\x2c\
|
||||||
|
\x34\x33\x37\x2e\x35\x35\x37\x63\x30\x2c\x33\x2e\x31\x33\x37\x2d\
|
||||||
|
\x32\x2e\x35\x35\x32\x2c\x35\x2e\x36\x38\x39\x2d\x35\x2e\x36\x38\
|
||||||
|
\x39\x2c\x35\x2e\x36\x38\x39\x48\x33\x39\x2e\x38\x32\x32\x0d\x0a\
|
||||||
|
\x09\x09\x09\x09\x63\x2d\x33\x2e\x31\x33\x37\x2c\x30\x2d\x35\x2e\
|
||||||
|
\x36\x38\x39\x2d\x32\x2e\x35\x35\x32\x2d\x35\x2e\x36\x38\x39\x2d\
|
||||||
|
\x35\x2e\x36\x38\x39\x56\x31\x35\x33\x2e\x38\x33\x38\x68\x34\x34\
|
||||||
|
\x33\x2e\x37\x33\x33\x56\x34\x33\x37\x2e\x35\x35\x37\x7a\x20\x4d\
|
||||||
|
\x34\x37\x37\x2e\x38\x36\x37\x2c\x31\x31\x39\x2e\x37\x30\x35\x48\
|
||||||
|
\x33\x34\x2e\x31\x33\x33\x56\x37\x34\x2e\x34\x34\x32\x63\x30\x2d\
|
||||||
|
\x33\x2e\x31\x33\x37\x2c\x32\x2e\x35\x35\x32\x2d\x35\x2e\x36\x38\
|
||||||
|
\x39\x2c\x35\x2e\x36\x38\x39\x2d\x35\x2e\x36\x38\x39\x0d\x0a\x09\
|
||||||
|
\x09\x09\x09\x68\x34\x33\x32\x2e\x33\x35\x36\x63\x33\x2e\x31\x33\
|
||||||
|
\x37\x2c\x30\x2c\x35\x2e\x36\x38\x39\x2c\x32\x2e\x35\x35\x32\x2c\
|
||||||
|
\x35\x2e\x36\x38\x39\x2c\x35\x2e\x36\x38\x39\x56\x31\x31\x39\x2e\
|
||||||
|
\x37\x30\x35\x7a\x22\x2f\x3e\x0d\x0a\x09\x09\x09\x3c\x63\x69\x72\
|
||||||
|
\x63\x6c\x65\x20\x63\x78\x3d\x22\x37\x31\x2e\x38\x30\x35\x22\x20\
|
||||||
|
\x63\x79\x3d\x22\x39\x34\x2e\x32\x33\x22\x20\x72\x3d\x22\x31\x32\
|
||||||
|
\x2e\x38\x33\x36\x22\x2f\x3e\x0d\x0a\x09\x09\x09\x3c\x63\x69\x72\
|
||||||
|
\x63\x6c\x65\x20\x63\x78\x3d\x22\x31\x31\x32\x2e\x39\x35\x39\x22\
|
||||||
|
\x20\x63\x79\x3d\x22\x39\x34\x2e\x32\x33\x22\x20\x72\x3d\x22\x31\
|
||||||
|
\x32\x2e\x38\x33\x36\x22\x2f\x3e\x0d\x0a\x09\x09\x09\x3c\x63\x69\
|
||||||
|
\x72\x63\x6c\x65\x20\x63\x78\x3d\x22\x31\x35\x34\x2e\x31\x31\x32\
|
||||||
|
\x22\x20\x63\x79\x3d\x22\x39\x34\x2e\x32\x33\x22\x20\x72\x3d\x22\
|
||||||
|
\x31\x32\x2e\x38\x33\x36\x22\x2f\x3e\x0d\x0a\x09\x09\x09\x3c\x70\
|
||||||
|
\x61\x74\x68\x20\x64\x3d\x22\x4d\x38\x31\x2e\x35\x38\x31\x2c\x33\
|
||||||
|
\x33\x34\x2e\x34\x34\x32\x63\x34\x2e\x34\x34\x2c\x31\x33\x2e\x37\
|
||||||
|
\x30\x31\x2c\x32\x32\x2e\x38\x37\x32\x2c\x31\x36\x2e\x31\x30\x31\
|
||||||
|
\x2c\x33\x30\x2e\x36\x33\x36\x2c\x33\x2e\x39\x6c\x31\x30\x2e\x34\
|
||||||
|
\x35\x34\x2d\x31\x36\x2e\x34\x33\x32\x6c\x31\x30\x2e\x34\x35\x34\
|
||||||
|
\x2c\x31\x36\x2e\x34\x33\x32\x0d\x0a\x09\x09\x09\x09\x63\x37\x2e\
|
||||||
|
\x37\x34\x34\x2c\x31\x32\x2e\x31\x36\x39\x2c\x32\x36\x2e\x31\x39\
|
||||||
|
\x35\x2c\x39\x2e\x38\x30\x31\x2c\x33\x30\x2e\x36\x33\x36\x2d\x33\
|
||||||
|
\x2e\x39\x6c\x31\x39\x2e\x38\x35\x37\x2d\x36\x31\x2e\x32\x37\x38\
|
||||||
|
\x63\x32\x2e\x39\x30\x36\x2d\x38\x2e\x39\x36\x37\x2d\x32\x2e\x30\
|
||||||
|
\x30\x38\x2d\x31\x38\x2e\x35\x39\x31\x2d\x31\x30\x2e\x39\x37\x35\
|
||||||
|
\x2d\x32\x31\x2e\x34\x39\x37\x0d\x0a\x09\x09\x09\x09\x63\x2d\x38\
|
||||||
|
\x2e\x39\x37\x31\x2d\x32\x2e\x39\x30\x36\x2d\x31\x38\x2e\x35\x39\
|
||||||
|
\x31\x2c\x32\x2e\x30\x30\x39\x2d\x32\x31\x2e\x34\x39\x37\x2c\x31\
|
||||||
|
\x30\x2e\x39\x37\x35\x6c\x2d\x38\x2e\x36\x38\x31\x2c\x32\x36\x2e\
|
||||||
|
\x37\x39\x31\x6c\x2d\x35\x2e\x33\x39\x33\x2d\x38\x2e\x34\x37\x38\
|
||||||
|
\x63\x2d\x36\x2e\x36\x39\x35\x2d\x31\x30\x2e\x35\x32\x2d\x32\x32\
|
||||||
|
\x2e\x30\x39\x34\x2d\x31\x30\x2e\x35\x33\x38\x2d\x32\x38\x2e\x38\
|
||||||
|
\x30\x31\x2c\x30\x6c\x2d\x35\x2e\x33\x39\x32\x2c\x38\x2e\x34\x37\
|
||||||
|
\x38\x0d\x0a\x09\x09\x09\x09\x6c\x2d\x38\x2e\x36\x38\x31\x2d\x32\
|
||||||
|
\x36\x2e\x37\x39\x63\x2d\x32\x2e\x39\x30\x36\x2d\x38\x2e\x39\x36\
|
||||||
|
\x36\x2d\x31\x32\x2e\x35\x32\x36\x2d\x31\x33\x2e\x38\x38\x32\x2d\
|
||||||
|
\x32\x31\x2e\x34\x39\x37\x2d\x31\x30\x2e\x39\x37\x35\x63\x2d\x38\
|
||||||
|
\x2e\x39\x36\x37\x2c\x32\x2e\x39\x30\x36\x2d\x31\x33\x2e\x38\x38\
|
||||||
|
\x2c\x31\x32\x2e\x35\x32\x39\x2d\x31\x30\x2e\x39\x37\x35\x2c\x32\
|
||||||
|
\x31\x2e\x34\x39\x36\x4c\x38\x31\x2e\x35\x38\x31\x2c\x33\x33\x34\
|
||||||
|
\x2e\x34\x34\x32\x7a\x22\x2f\x3e\x0d\x0a\x09\x09\x09\x3c\x70\x61\
|
||||||
|
\x74\x68\x20\x64\x3d\x22\x4d\x32\x31\x34\x2e\x39\x31\x31\x2c\x33\
|
||||||
|
\x33\x34\x2e\x34\x34\x32\x63\x34\x2e\x34\x34\x36\x2c\x31\x33\x2e\
|
||||||
|
\x37\x32\x2c\x32\x32\x2e\x39\x30\x35\x2c\x31\x36\x2e\x30\x35\x32\
|
||||||
|
\x2c\x33\x30\x2e\x36\x33\x36\x2c\x33\x2e\x39\x4c\x32\x35\x36\x2c\
|
||||||
|
\x33\x32\x31\x2e\x39\x31\x31\x6c\x31\x30\x2e\x34\x35\x34\x2c\x31\
|
||||||
|
\x36\x2e\x34\x33\x32\x63\x37\x2e\x37\x36\x32\x2c\x31\x32\x2e\x32\
|
||||||
|
\x2c\x32\x36\x2e\x31\x39\x36\x2c\x39\x2e\x38\x2c\x33\x30\x2e\x36\
|
||||||
|
\x33\x36\x2d\x33\x2e\x39\x0d\x0a\x09\x09\x09\x09\x6c\x31\x39\x2e\
|
||||||
|
\x38\x35\x35\x2d\x36\x31\x2e\x32\x37\x38\x63\x32\x2e\x39\x30\x36\
|
||||||
|
\x2d\x38\x2e\x39\x36\x37\x2d\x32\x2e\x30\x30\x38\x2d\x31\x38\x2e\
|
||||||
|
\x35\x39\x2d\x31\x30\x2e\x39\x37\x35\x2d\x32\x31\x2e\x34\x39\x36\
|
||||||
|
\x63\x2d\x38\x2e\x39\x37\x34\x2d\x32\x2e\x39\x30\x37\x2d\x31\x38\
|
||||||
|
\x2e\x35\x39\x31\x2c\x32\x2e\x30\x30\x38\x2d\x32\x31\x2e\x34\x39\
|
||||||
|
\x37\x2c\x31\x30\x2e\x39\x37\x35\x6c\x2d\x38\x2e\x36\x38\x31\x2c\
|
||||||
|
\x32\x36\x2e\x37\x39\x6c\x2d\x35\x2e\x33\x39\x32\x2d\x38\x2e\x34\
|
||||||
|
\x37\x38\x0d\x0a\x09\x09\x09\x09\x63\x2d\x36\x2e\x36\x39\x35\x2d\
|
||||||
|
\x31\x30\x2e\x35\x32\x2d\x32\x32\x2e\x30\x39\x34\x2d\x31\x30\x2e\
|
||||||
|
\x35\x33\x38\x2d\x32\x38\x2e\x38\x30\x31\x2c\x30\x6c\x2d\x35\x2e\
|
||||||
|
\x33\x39\x32\x2c\x38\x2e\x34\x37\x38\x6c\x2d\x38\x2e\x36\x38\x31\
|
||||||
|
\x2d\x32\x36\x2e\x37\x39\x63\x2d\x32\x2e\x39\x30\x35\x2d\x38\x2e\
|
||||||
|
\x39\x36\x36\x2d\x31\x32\x2e\x35\x32\x37\x2d\x31\x33\x2e\x38\x38\
|
||||||
|
\x32\x2d\x32\x31\x2e\x34\x39\x36\x2d\x31\x30\x2e\x39\x37\x35\x0d\
|
||||||
|
\x0a\x09\x09\x09\x09\x63\x2d\x38\x2e\x39\x36\x37\x2c\x32\x2e\x39\
|
||||||
|
\x30\x36\x2d\x31\x33\x2e\x38\x38\x2c\x31\x32\x2e\x35\x32\x39\x2d\
|
||||||
|
\x31\x30\x2e\x39\x37\x35\x2c\x32\x31\x2e\x34\x39\x36\x4c\x32\x31\
|
||||||
|
\x34\x2e\x39\x31\x31\x2c\x33\x33\x34\x2e\x34\x34\x32\x7a\x22\x2f\
|
||||||
|
\x3e\x0d\x0a\x09\x09\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\
|
||||||
|
\x33\x34\x38\x2e\x32\x34\x31\x2c\x33\x33\x34\x2e\x34\x34\x32\x63\
|
||||||
|
\x34\x2e\x34\x34\x36\x2c\x31\x33\x2e\x37\x32\x2c\x32\x32\x2e\x39\
|
||||||
|
\x30\x35\x2c\x31\x36\x2e\x30\x35\x31\x2c\x33\x30\x2e\x36\x33\x36\
|
||||||
|
\x2c\x33\x2e\x39\x6c\x31\x30\x2e\x34\x35\x34\x2d\x31\x36\x2e\x34\
|
||||||
|
\x33\x32\x6c\x31\x30\x2e\x34\x35\x34\x2c\x31\x36\x2e\x34\x33\x32\
|
||||||
|
\x63\x37\x2e\x37\x36\x32\x2c\x31\x32\x2e\x32\x2c\x32\x36\x2e\x31\
|
||||||
|
\x39\x35\x2c\x39\x2e\x38\x2c\x33\x30\x2e\x36\x33\x36\x2d\x33\x2e\
|
||||||
|
\x39\x0d\x0a\x09\x09\x09\x09\x6c\x31\x39\x2e\x38\x35\x35\x2d\x36\
|
||||||
|
\x31\x2e\x32\x37\x38\x63\x32\x2e\x39\x30\x36\x2d\x38\x2e\x39\x36\
|
||||||
|
\x37\x2d\x32\x2e\x30\x30\x38\x2d\x31\x38\x2e\x35\x39\x2d\x31\x30\
|
||||||
|
\x2e\x39\x37\x35\x2d\x32\x31\x2e\x34\x39\x36\x63\x2d\x38\x2e\x39\
|
||||||
|
\x37\x33\x2d\x32\x2e\x39\x30\x37\x2d\x31\x38\x2e\x35\x39\x31\x2c\
|
||||||
|
\x32\x2e\x30\x30\x38\x2d\x32\x31\x2e\x34\x39\x36\x2c\x31\x30\x2e\
|
||||||
|
\x39\x37\x35\x6c\x2d\x38\x2e\x36\x38\x31\x2c\x32\x36\x2e\x37\x39\
|
||||||
|
\x6c\x2d\x35\x2e\x33\x39\x32\x2d\x38\x2e\x34\x37\x38\x0d\x0a\x09\
|
||||||
|
\x09\x09\x09\x63\x2d\x36\x2e\x36\x39\x35\x2d\x31\x30\x2e\x35\x32\
|
||||||
|
\x2d\x32\x32\x2e\x30\x39\x35\x2d\x31\x30\x2e\x35\x33\x38\x2d\x32\
|
||||||
|
\x38\x2e\x38\x30\x31\x2c\x30\x6c\x2d\x35\x2e\x33\x39\x33\x2c\x38\
|
||||||
|
\x2e\x34\x37\x38\x6c\x2d\x38\x2e\x36\x38\x31\x2d\x32\x36\x2e\x37\
|
||||||
|
\x39\x31\x63\x2d\x32\x2e\x39\x30\x36\x2d\x38\x2e\x39\x36\x36\x2d\
|
||||||
|
\x31\x32\x2e\x35\x33\x31\x2d\x31\x33\x2e\x38\x38\x31\x2d\x32\x31\
|
||||||
|
\x2e\x34\x39\x37\x2d\x31\x30\x2e\x39\x37\x35\x0d\x0a\x09\x09\x09\
|
||||||
|
\x09\x63\x2d\x38\x2e\x39\x36\x37\x2c\x32\x2e\x39\x30\x36\x2d\x31\
|
||||||
|
\x33\x2e\x38\x38\x2c\x31\x32\x2e\x35\x33\x2d\x31\x30\x2e\x39\x37\
|
||||||
|
\x34\x2c\x32\x31\x2e\x34\x39\x37\x4c\x33\x34\x38\x2e\x32\x34\x31\
|
||||||
|
\x2c\x33\x33\x34\x2e\x34\x34\x32\x7a\x22\x2f\x3e\x0d\x0a\x09\x09\
|
||||||
|
\x3c\x2f\x67\x3e\x0d\x0a\x09\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x67\
|
||||||
|
\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\
|
||||||
|
\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\
|
||||||
|
\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\
|
||||||
|
\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\
|
||||||
|
\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\
|
||||||
|
\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\
|
||||||
|
\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\
|
||||||
|
\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\
|
||||||
|
\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\
|
||||||
|
\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\
|
||||||
|
\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
|
||||||
|
\
|
||||||
|
"
|
||||||
|
|
||||||
|
qt_resource_name = b"\
|
||||||
|
\x00\x08\
|
||||||
|
\x00\x2b\x61\x2c\
|
||||||
|
\x00\x66\
|
||||||
|
\x00\x69\x00\x6c\x00\x65\x00\x5f\x00\x75\x00\x72\x00\x6c\
|
||||||
|
\x00\x04\
|
||||||
|
\x00\x07\xa7\xe3\
|
||||||
|
\x00\x74\
|
||||||
|
\x00\x61\x00\x67\x00\x73\
|
||||||
|
\x00\x0c\
|
||||||
|
\x06\x07\x35\x82\
|
||||||
|
\x00\x64\
|
||||||
|
\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x65\x00\x5f\x00\x68\x00\x6f\x00\x76\x00\x65\x00\x72\
|
||||||
|
\x00\x06\
|
||||||
|
\x06\xac\x2c\xa5\
|
||||||
|
\x00\x64\
|
||||||
|
\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x65\
|
||||||
|
\x00\x08\
|
||||||
|
\x05\xac\x9a\xc4\
|
||||||
|
\x00\x69\
|
||||||
|
\x00\x6e\x00\x74\x00\x65\x00\x72\x00\x6e\x00\x65\x00\x74\
|
||||||
|
"
|
||||||
|
|
||||||
|
qt_resource_struct_v1 = b"\
|
||||||
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
|
||||||
|
\x00\x00\x00\x16\x00\x02\x00\x00\x00\x02\x00\x00\x00\x04\
|
||||||
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
|
||||||
|
\x00\x00\x00\x54\x00\x00\x00\x00\x00\x01\x00\x00\x1a\xe7\
|
||||||
|
\x00\x00\x00\x24\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
||||||
|
\x00\x00\x00\x42\x00\x00\x00\x00\x00\x01\x00\x00\x0d\x96\
|
||||||
|
"
|
||||||
|
|
||||||
|
qt_resource_struct_v2 = b"\
|
||||||
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
|
||||||
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
|
\x00\x00\x00\x16\x00\x02\x00\x00\x00\x02\x00\x00\x00\x04\
|
||||||
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
|
||||||
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
|
\x00\x00\x00\x54\x00\x00\x00\x00\x00\x01\x00\x00\x1a\xe7\
|
||||||
|
\x00\x00\x01\x76\xde\x95\xb2\x06\
|
||||||
|
\x00\x00\x00\x24\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
||||||
|
\x00\x00\x01\x76\xd8\xe5\x6d\x99\
|
||||||
|
\x00\x00\x00\x42\x00\x00\x00\x00\x00\x01\x00\x00\x0d\x96\
|
||||||
|
\x00\x00\x01\x76\xd8\xe2\x94\x13\
|
||||||
|
"
|
||||||
|
|
||||||
|
qt_version = [int(v) for v in QtCore.qVersion().split('.')]
|
||||||
|
if qt_version < [5, 8, 0]:
|
||||||
|
rcc_version = 1
|
||||||
|
qt_resource_struct = qt_resource_struct_v1
|
||||||
|
else:
|
||||||
|
rcc_version = 2
|
||||||
|
qt_resource_struct = qt_resource_struct_v2
|
||||||
|
|
||||||
|
def qInitResources():
|
||||||
|
QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
|
||||||
|
|
||||||
|
def qCleanupResources():
|
||||||
|
QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
|
||||||
|
|
||||||
|
qInitResources()
|
267
athnos/window/source.py
Executable file
267
athnos/window/source.py
Executable file
@ -0,0 +1,267 @@
|
|||||||
|
from . import _DatabaseWindow
|
||||||
|
from .. import logger
|
||||||
|
from ..database import Type
|
||||||
|
from .add import AddSource
|
||||||
|
from typing import Union
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets, QtSql
|
||||||
|
|
||||||
|
|
||||||
|
class EditSource(AddSource):
|
||||||
|
"""Manipulates the `add.AddSource` class to create a edit source class"""
|
||||||
|
|
||||||
|
def __init__(self, window):
|
||||||
|
super().__init__(window)
|
||||||
|
|
||||||
|
self.source = None
|
||||||
|
|
||||||
|
def after_setup_ui(self) -> None:
|
||||||
|
super().after_setup_ui()
|
||||||
|
|
||||||
|
self.new_button.hide()
|
||||||
|
|
||||||
|
def on_save(self) -> None:
|
||||||
|
affected_clips = len(self.source.get_all_clips())
|
||||||
|
# if one clip or more is affected
|
||||||
|
if affected_clips > 0:
|
||||||
|
message = QtWidgets.QMessageBox()
|
||||||
|
message.setWindowTitle('Save?')
|
||||||
|
message.setText(f'Are you sure to save the edited source? This will affect {affected_clips} {"clips" if affected_clips > 1 else "clip"}')
|
||||||
|
affected = message.addButton('Show affected clips', QtWidgets.QMessageBox.ActionRole)
|
||||||
|
message.addButton(QtWidgets.QMessageBox.Yes)
|
||||||
|
message.addButton(QtWidgets.QMessageBox.No)
|
||||||
|
|
||||||
|
# shows all affected clips
|
||||||
|
def on_affected() -> None:
|
||||||
|
ShowSource(QtWidgets.QDialog(self.window, QtCore.Qt.WindowSystemMenuHint)).show(self.source.id)
|
||||||
|
|
||||||
|
affected.disconnect()
|
||||||
|
affected.clicked.connect(on_affected)
|
||||||
|
|
||||||
|
# shows the message
|
||||||
|
result = message.exec()
|
||||||
|
if result == QtWidgets.QMessageBox.No:
|
||||||
|
return
|
||||||
|
elif result == QtWidgets.QMessageBox.Yes:
|
||||||
|
type = Type.Source.from_name(self.type_box.currentText()).value
|
||||||
|
# edits the source
|
||||||
|
self.database.Source.edit(self.source.id, path=self.file_or_url_edit.text(), type=type, name=self.name_edit.text(),
|
||||||
|
season=self.season_edit.text(), episode=self.episode_edit.text(), description=self.description_edit.toPlainText())
|
||||||
|
|
||||||
|
logger.debug(f'Edited source {self.source.id} - path: `{self.file_or_url_edit.text()}`, type: `{type}`, '
|
||||||
|
f'season: `{self.season_edit.text()}`, episode: {self.episode_edit.text()}, description: {self.description_edit.toPlainText()}')
|
||||||
|
|
||||||
|
self.window.close()
|
||||||
|
|
||||||
|
def show(self, id: int) -> None:
|
||||||
|
"""
|
||||||
|
Shows the source edit
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: The source id to show the source edit
|
||||||
|
"""
|
||||||
|
# gets the source from the id
|
||||||
|
self.source = self.database.Source.get(id)
|
||||||
|
|
||||||
|
# sets the texts
|
||||||
|
self.file_or_url_edit.setText(self.source.path)
|
||||||
|
if self.source.type == Type.Source.AUDIO:
|
||||||
|
self.type_box.setCurrentIndex(0)
|
||||||
|
elif self.source.type == Type.Source.MOVIE:
|
||||||
|
self.type_box.setCurrentIndex(1)
|
||||||
|
elif self.source.type == Type.Source.SERIES:
|
||||||
|
self.type_box.setCurrentIndex(2)
|
||||||
|
else:
|
||||||
|
self.type_box.setCurrentIndex(3)
|
||||||
|
self.name_edit.setText(self.source.name)
|
||||||
|
self.season_edit.setText(self.source.season)
|
||||||
|
self.episode_edit.setText(self.source.episode)
|
||||||
|
self.description_edit.setText(self.source.description)
|
||||||
|
super().show()
|
||||||
|
|
||||||
|
|
||||||
|
class ShowSource(_DatabaseWindow):
|
||||||
|
"""Class to show all sources"""
|
||||||
|
|
||||||
|
def __init__(self, window):
|
||||||
|
self._all_ids = []
|
||||||
|
self._source_id = None
|
||||||
|
|
||||||
|
super().__init__(window)
|
||||||
|
|
||||||
|
def setupUi(self, Form):
|
||||||
|
Form.setObjectName("Form")
|
||||||
|
Form.resize(814, 447)
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(Form)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.main_splitter = QtWidgets.QSplitter(Form)
|
||||||
|
self.main_splitter.setOrientation(QtCore.Qt.Horizontal)
|
||||||
|
self.main_splitter.setObjectName("main_splitter")
|
||||||
|
self.source_frame = QtWidgets.QFrame(self.main_splitter)
|
||||||
|
self.source_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||||
|
self.source_frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||||
|
self.source_frame.setObjectName("source_frame")
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(self.source_frame)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.source_label = QtWidgets.QLabel(self.source_frame)
|
||||||
|
self.source_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.source_label.setObjectName("source_label")
|
||||||
|
self.verticalLayout.addWidget(self.source_label)
|
||||||
|
self.search_edit = QtWidgets.QLineEdit(self.source_frame)
|
||||||
|
self.search_edit.setObjectName("search_edit")
|
||||||
|
self.verticalLayout.addWidget(self.search_edit)
|
||||||
|
self.source_table_view = QtWidgets.QTableView(self.source_frame)
|
||||||
|
self.source_table_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||||
|
self.source_table_view.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||||
|
self.source_table_view.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||||
|
self.source_table_view.setObjectName("source_table_view")
|
||||||
|
self.verticalLayout.addWidget(self.source_table_view)
|
||||||
|
self.select_source_button = QtWidgets.QPushButton(self.source_frame)
|
||||||
|
self.select_source_button.setAutoDefault(False)
|
||||||
|
self.select_source_button.setDefault(False)
|
||||||
|
self.select_source_button.setFlat(False)
|
||||||
|
self.select_source_button.setObjectName("select_source_button")
|
||||||
|
self.verticalLayout.addWidget(self.select_source_button)
|
||||||
|
self.all_tags_frame = QtWidgets.QFrame(self.main_splitter)
|
||||||
|
self.all_tags_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||||
|
self.all_tags_frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||||
|
self.all_tags_frame.setObjectName("all_tags_frame")
|
||||||
|
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.all_tags_frame)
|
||||||
|
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||||
|
self.all_tags_label = QtWidgets.QLabel(self.all_tags_frame)
|
||||||
|
self.all_tags_label.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||||
|
self.all_tags_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.all_tags_label.setObjectName("all_tags_label")
|
||||||
|
self.verticalLayout_2.addWidget(self.all_tags_label)
|
||||||
|
self.all_tags_table_view = QtWidgets.QTableView(self.all_tags_frame)
|
||||||
|
self.all_tags_table_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||||
|
self.all_tags_table_view.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||||
|
self.all_tags_table_view.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||||
|
self.all_tags_table_view.setObjectName("all_tags_table_view")
|
||||||
|
self.verticalLayout_2.addWidget(self.all_tags_table_view)
|
||||||
|
self.horizontalLayout.addWidget(self.main_splitter)
|
||||||
|
|
||||||
|
self.retranslateUi(Form)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||||
|
|
||||||
|
def retranslateUi(self, Form):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
Form.setWindowTitle(_translate("Form", "Form"))
|
||||||
|
self.source_label.setText(_translate("Form", "Source"))
|
||||||
|
self.search_edit.setPlaceholderText(_translate("Form", "Search for source..."))
|
||||||
|
self.select_source_button.setText(_translate("Form", "Select source"))
|
||||||
|
self.all_tags_label.setText(_translate("Form", "All tags, using this source"))
|
||||||
|
|
||||||
|
def show(self, id: int = None) -> None:
|
||||||
|
"""
|
||||||
|
Shows the window
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id: If given, only the source with this is will be shown
|
||||||
|
"""
|
||||||
|
self.set_query(self.database.Source.get(id).query)
|
||||||
|
|
||||||
|
# hides the 'Select' button
|
||||||
|
self.select_source_button.hide()
|
||||||
|
|
||||||
|
if id:
|
||||||
|
# hides all stuff, which can be used to see other sources than the given
|
||||||
|
self.search_edit.hide()
|
||||||
|
|
||||||
|
# select the entry
|
||||||
|
index = self.source_table_view.model().index(0, 0)
|
||||||
|
self.source_table_view.setCurrentIndex(index)
|
||||||
|
self.on_item_clicked(index)
|
||||||
|
super().show()
|
||||||
|
|
||||||
|
def set_query(self, query: QtSql.QSqlQuery) -> None:
|
||||||
|
"""
|
||||||
|
Sets the source query
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: The source query
|
||||||
|
"""
|
||||||
|
# the sql model
|
||||||
|
model = QtSql.QSqlQueryModel()
|
||||||
|
model.setQuery(query)
|
||||||
|
|
||||||
|
# sets the model to the source table view
|
||||||
|
self.source_table_view.setModel(model)
|
||||||
|
|
||||||
|
for i in range(model.columnCount()):
|
||||||
|
header = str(model.headerData(i, QtCore.Qt.Horizontal)).lower()
|
||||||
|
# hides columns with these headers
|
||||||
|
if header in ['id', 'name', 'season', 'episode']:
|
||||||
|
if header == 'id':
|
||||||
|
for row in range(model.rowCount()):
|
||||||
|
self._all_ids.append(int(model.index(row, i).data()))
|
||||||
|
self.source_table_view.hideColumn(i)
|
||||||
|
else:
|
||||||
|
model.setHeaderData(i, QtCore.Qt.Horizontal, header[0].upper() + header[1:])
|
||||||
|
|
||||||
|
# connect all button click events
|
||||||
|
self.select_source_button.clicked.connect(self.on_select_source)
|
||||||
|
self.source_table_view.clicked.connect(self.on_item_clicked)
|
||||||
|
self.source_table_view.doubleClicked.connect(self.on_select_source)
|
||||||
|
|
||||||
|
def on_item_clicked(self, index: QtCore.QModelIndex):
|
||||||
|
"""
|
||||||
|
Gets called if a source item is clicked
|
||||||
|
|
||||||
|
Args:
|
||||||
|
index: The item which was clicked
|
||||||
|
"""
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
# the source id of the item
|
||||||
|
self._source_id = self._all_ids[row - 1]
|
||||||
|
|
||||||
|
# the model for all tags which are using the selected source
|
||||||
|
model = QtSql.QSqlTableModel()
|
||||||
|
model.setQuery(self.database.Clip.get_all_by(source_id=self._source_id).query)
|
||||||
|
model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
|
||||||
|
|
||||||
|
# sets the model
|
||||||
|
self.all_tags_table_view.setModel(model)
|
||||||
|
self.all_tags_table_view.horizontalHeader().resizeSections(QtWidgets.QHeaderView.Stretch)
|
||||||
|
self.all_tags_table_view.horizontalHeader().setStretchLastSection(True)
|
||||||
|
|
||||||
|
# this sets the header (first letter uppercase, remove id, etc.)
|
||||||
|
for i in range(model.columnCount()):
|
||||||
|
header = str(model.headerData(i, QtCore.Qt.Horizontal)).lower()
|
||||||
|
# » hide the header with the names id or source_id
|
||||||
|
if header in ['id', 'source_id']:
|
||||||
|
if header == 'id':
|
||||||
|
for row in range(model.rowCount()):
|
||||||
|
self._all_ids.append(int(model.index(row, i).data()))
|
||||||
|
self.all_tags_table_view.hideColumn(i)
|
||||||
|
continue
|
||||||
|
elif header == 'type':
|
||||||
|
for row in range(model.rowCount()):
|
||||||
|
index = model.index(row, i)
|
||||||
|
type_name = Type.Clip(model.data(index)).name.lower()
|
||||||
|
model.setData(index, type_name[0].upper() + type_name[1:])
|
||||||
|
model.submit()
|
||||||
|
model.setData(index, QtGui.QColor(100, 100, 100, 1), QtCore.Qt.BackgroundColorRole)
|
||||||
|
model.submit()
|
||||||
|
# » first letter of the header uppercase
|
||||||
|
model.setHeaderData(i, QtCore.Qt.Horizontal, header[0].upper() + header[1:])
|
||||||
|
|
||||||
|
def on_select_source(self):
|
||||||
|
"""Gets called if the 'Select source' button is pressed"""
|
||||||
|
if not self._source_id:
|
||||||
|
proceed = QtWidgets.QMessageBox.question(self.window, 'No source is chosen', 'No source is chosen. Do you want to proceed?',
|
||||||
|
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||||
|
if proceed == QtWidgets.QMessageBox.No:
|
||||||
|
return
|
||||||
|
self.window.close()
|
||||||
|
|
||||||
|
def select(self) -> Union[int, None]:
|
||||||
|
"""
|
||||||
|
Shows the window and enable the user to select a source
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The selected source id
|
||||||
|
"""
|
||||||
|
self.set_query(self.database.Source.get_all().query)
|
||||||
|
self.window.exec()
|
||||||
|
return self._source_id
|
891
athnos/window/style.py
Executable file
891
athnos/window/style.py
Executable file
@ -0,0 +1,891 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Resource object code
|
||||||
|
#
|
||||||
|
# Created by: The Resource Compiler for PyQt5 (Qt v5.14.2)
|
||||||
|
#
|
||||||
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
|
qt_resource_data = b"\
|
||||||
|
\x00\x00\x09\xc1\
|
||||||
|
\x3c\
|
||||||
|
\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
|
||||||
|
\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x69\x73\x6f\
|
||||||
|
\x2d\x38\x38\x35\x39\x2d\x31\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\
|
||||||
|
\x20\x47\x65\x6e\x65\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\
|
||||||
|
\x65\x20\x49\x6c\x6c\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x39\
|
||||||
|
\x2e\x30\x2e\x30\x2c\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\
|
||||||
|
\x20\x50\x6c\x75\x67\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\
|
||||||
|
\x65\x72\x73\x69\x6f\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\
|
||||||
|
\x6c\x64\x20\x30\x29\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x73\x76\x67\
|
||||||
|
\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\
|
||||||
|
\x64\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\
|
||||||
|
\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\
|
||||||
|
\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\
|
||||||
|
\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\
|
||||||
|
\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\
|
||||||
|
\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\
|
||||||
|
\x22\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x76\x69\x65\
|
||||||
|
\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
|
||||||
|
\x32\x22\x20\x73\x74\x79\x6c\x65\x3d\x22\x65\x6e\x61\x62\x6c\x65\
|
||||||
|
\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x6e\x65\x77\x20\
|
||||||
|
\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x3b\x22\x20\x78\x6d\
|
||||||
|
\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\
|
||||||
|
\x65\x22\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x09\x3c\x67\x3e\x0d\x0a\
|
||||||
|
\x09\x09\x3c\x67\x3e\x0d\x0a\x09\x09\x09\x3c\x70\x61\x74\x68\x20\
|
||||||
|
\x64\x3d\x22\x4d\x34\x37\x32\x2e\x31\x37\x38\x2c\x33\x34\x2e\x36\
|
||||||
|
\x32\x48\x33\x39\x2e\x38\x32\x32\x43\x31\x37\x2e\x38\x36\x34\x2c\
|
||||||
|
\x33\x34\x2e\x36\x32\x2c\x30\x2c\x35\x32\x2e\x34\x38\x34\x2c\x30\
|
||||||
|
\x2c\x37\x34\x2e\x34\x34\x32\x63\x30\x2c\x31\x37\x2e\x39\x35\x35\
|
||||||
|
\x2c\x30\x2c\x33\x34\x35\x2e\x32\x33\x34\x2c\x30\x2c\x33\x36\x33\
|
||||||
|
\x2e\x31\x31\x36\x0d\x0a\x09\x09\x09\x09\x63\x30\x2c\x32\x31\x2e\
|
||||||
|
\x39\x35\x38\x2c\x31\x37\x2e\x38\x36\x34\x2c\x33\x39\x2e\x38\x32\
|
||||||
|
\x32\x2c\x33\x39\x2e\x38\x32\x32\x2c\x33\x39\x2e\x38\x32\x32\x68\
|
||||||
|
\x34\x33\x32\x2e\x33\x35\x36\x63\x32\x31\x2e\x39\x35\x38\x2c\x30\
|
||||||
|
\x2c\x33\x39\x2e\x38\x32\x32\x2d\x31\x37\x2e\x38\x36\x34\x2c\x33\
|
||||||
|
\x39\x2e\x38\x32\x32\x2d\x33\x39\x2e\x38\x32\x32\x63\x30\x2d\x31\
|
||||||
|
\x37\x2e\x38\x39\x2c\x30\x2d\x33\x34\x35\x2e\x31\x36\x37\x2c\x30\
|
||||||
|
\x2d\x33\x36\x33\x2e\x31\x31\x36\x0d\x0a\x09\x09\x09\x09\x43\x35\
|
||||||
|
\x31\x32\x2c\x35\x32\x2e\x34\x38\x34\x2c\x34\x39\x34\x2e\x31\x33\
|
||||||
|
\x36\x2c\x33\x34\x2e\x36\x32\x2c\x34\x37\x32\x2e\x31\x37\x38\x2c\
|
||||||
|
\x33\x34\x2e\x36\x32\x7a\x20\x4d\x34\x37\x37\x2e\x38\x36\x37\x2c\
|
||||||
|
\x34\x33\x37\x2e\x35\x35\x37\x63\x30\x2c\x33\x2e\x31\x33\x37\x2d\
|
||||||
|
\x32\x2e\x35\x35\x32\x2c\x35\x2e\x36\x38\x39\x2d\x35\x2e\x36\x38\
|
||||||
|
\x39\x2c\x35\x2e\x36\x38\x39\x48\x33\x39\x2e\x38\x32\x32\x0d\x0a\
|
||||||
|
\x09\x09\x09\x09\x63\x2d\x33\x2e\x31\x33\x37\x2c\x30\x2d\x35\x2e\
|
||||||
|
\x36\x38\x39\x2d\x32\x2e\x35\x35\x32\x2d\x35\x2e\x36\x38\x39\x2d\
|
||||||
|
\x35\x2e\x36\x38\x39\x56\x31\x35\x33\x2e\x38\x33\x38\x68\x34\x34\
|
||||||
|
\x33\x2e\x37\x33\x33\x56\x34\x33\x37\x2e\x35\x35\x37\x7a\x20\x4d\
|
||||||
|
\x34\x37\x37\x2e\x38\x36\x37\x2c\x31\x31\x39\x2e\x37\x30\x35\x48\
|
||||||
|
\x33\x34\x2e\x31\x33\x33\x56\x37\x34\x2e\x34\x34\x32\x63\x30\x2d\
|
||||||
|
\x33\x2e\x31\x33\x37\x2c\x32\x2e\x35\x35\x32\x2d\x35\x2e\x36\x38\
|
||||||
|
\x39\x2c\x35\x2e\x36\x38\x39\x2d\x35\x2e\x36\x38\x39\x0d\x0a\x09\
|
||||||
|
\x09\x09\x09\x68\x34\x33\x32\x2e\x33\x35\x36\x63\x33\x2e\x31\x33\
|
||||||
|
\x37\x2c\x30\x2c\x35\x2e\x36\x38\x39\x2c\x32\x2e\x35\x35\x32\x2c\
|
||||||
|
\x35\x2e\x36\x38\x39\x2c\x35\x2e\x36\x38\x39\x56\x31\x31\x39\x2e\
|
||||||
|
\x37\x30\x35\x7a\x22\x2f\x3e\x0d\x0a\x09\x09\x09\x3c\x63\x69\x72\
|
||||||
|
\x63\x6c\x65\x20\x63\x78\x3d\x22\x37\x31\x2e\x38\x30\x35\x22\x20\
|
||||||
|
\x63\x79\x3d\x22\x39\x34\x2e\x32\x33\x22\x20\x72\x3d\x22\x31\x32\
|
||||||
|
\x2e\x38\x33\x36\x22\x2f\x3e\x0d\x0a\x09\x09\x09\x3c\x63\x69\x72\
|
||||||
|
\x63\x6c\x65\x20\x63\x78\x3d\x22\x31\x31\x32\x2e\x39\x35\x39\x22\
|
||||||
|
\x20\x63\x79\x3d\x22\x39\x34\x2e\x32\x33\x22\x20\x72\x3d\x22\x31\
|
||||||
|
\x32\x2e\x38\x33\x36\x22\x2f\x3e\x0d\x0a\x09\x09\x09\x3c\x63\x69\
|
||||||
|
\x72\x63\x6c\x65\x20\x63\x78\x3d\x22\x31\x35\x34\x2e\x31\x31\x32\
|
||||||
|
\x22\x20\x63\x79\x3d\x22\x39\x34\x2e\x32\x33\x22\x20\x72\x3d\x22\
|
||||||
|
\x31\x32\x2e\x38\x33\x36\x22\x2f\x3e\x0d\x0a\x09\x09\x09\x3c\x70\
|
||||||
|
\x61\x74\x68\x20\x64\x3d\x22\x4d\x38\x31\x2e\x35\x38\x31\x2c\x33\
|
||||||
|
\x33\x34\x2e\x34\x34\x32\x63\x34\x2e\x34\x34\x2c\x31\x33\x2e\x37\
|
||||||
|
\x30\x31\x2c\x32\x32\x2e\x38\x37\x32\x2c\x31\x36\x2e\x31\x30\x31\
|
||||||
|
\x2c\x33\x30\x2e\x36\x33\x36\x2c\x33\x2e\x39\x6c\x31\x30\x2e\x34\
|
||||||
|
\x35\x34\x2d\x31\x36\x2e\x34\x33\x32\x6c\x31\x30\x2e\x34\x35\x34\
|
||||||
|
\x2c\x31\x36\x2e\x34\x33\x32\x0d\x0a\x09\x09\x09\x09\x63\x37\x2e\
|
||||||
|
\x37\x34\x34\x2c\x31\x32\x2e\x31\x36\x39\x2c\x32\x36\x2e\x31\x39\
|
||||||
|
\x35\x2c\x39\x2e\x38\x30\x31\x2c\x33\x30\x2e\x36\x33\x36\x2d\x33\
|
||||||
|
\x2e\x39\x6c\x31\x39\x2e\x38\x35\x37\x2d\x36\x31\x2e\x32\x37\x38\
|
||||||
|
\x63\x32\x2e\x39\x30\x36\x2d\x38\x2e\x39\x36\x37\x2d\x32\x2e\x30\
|
||||||
|
\x30\x38\x2d\x31\x38\x2e\x35\x39\x31\x2d\x31\x30\x2e\x39\x37\x35\
|
||||||
|
\x2d\x32\x31\x2e\x34\x39\x37\x0d\x0a\x09\x09\x09\x09\x63\x2d\x38\
|
||||||
|
\x2e\x39\x37\x31\x2d\x32\x2e\x39\x30\x36\x2d\x31\x38\x2e\x35\x39\
|
||||||
|
\x31\x2c\x32\x2e\x30\x30\x39\x2d\x32\x31\x2e\x34\x39\x37\x2c\x31\
|
||||||
|
\x30\x2e\x39\x37\x35\x6c\x2d\x38\x2e\x36\x38\x31\x2c\x32\x36\x2e\
|
||||||
|
\x37\x39\x31\x6c\x2d\x35\x2e\x33\x39\x33\x2d\x38\x2e\x34\x37\x38\
|
||||||
|
\x63\x2d\x36\x2e\x36\x39\x35\x2d\x31\x30\x2e\x35\x32\x2d\x32\x32\
|
||||||
|
\x2e\x30\x39\x34\x2d\x31\x30\x2e\x35\x33\x38\x2d\x32\x38\x2e\x38\
|
||||||
|
\x30\x31\x2c\x30\x6c\x2d\x35\x2e\x33\x39\x32\x2c\x38\x2e\x34\x37\
|
||||||
|
\x38\x0d\x0a\x09\x09\x09\x09\x6c\x2d\x38\x2e\x36\x38\x31\x2d\x32\
|
||||||
|
\x36\x2e\x37\x39\x63\x2d\x32\x2e\x39\x30\x36\x2d\x38\x2e\x39\x36\
|
||||||
|
\x36\x2d\x31\x32\x2e\x35\x32\x36\x2d\x31\x33\x2e\x38\x38\x32\x2d\
|
||||||
|
\x32\x31\x2e\x34\x39\x37\x2d\x31\x30\x2e\x39\x37\x35\x63\x2d\x38\
|
||||||
|
\x2e\x39\x36\x37\x2c\x32\x2e\x39\x30\x36\x2d\x31\x33\x2e\x38\x38\
|
||||||
|
\x2c\x31\x32\x2e\x35\x32\x39\x2d\x31\x30\x2e\x39\x37\x35\x2c\x32\
|
||||||
|
\x31\x2e\x34\x39\x36\x4c\x38\x31\x2e\x35\x38\x31\x2c\x33\x33\x34\
|
||||||
|
\x2e\x34\x34\x32\x7a\x22\x2f\x3e\x0d\x0a\x09\x09\x09\x3c\x70\x61\
|
||||||
|
\x74\x68\x20\x64\x3d\x22\x4d\x32\x31\x34\x2e\x39\x31\x31\x2c\x33\
|
||||||
|
\x33\x34\x2e\x34\x34\x32\x63\x34\x2e\x34\x34\x36\x2c\x31\x33\x2e\
|
||||||
|
\x37\x32\x2c\x32\x32\x2e\x39\x30\x35\x2c\x31\x36\x2e\x30\x35\x32\
|
||||||
|
\x2c\x33\x30\x2e\x36\x33\x36\x2c\x33\x2e\x39\x4c\x32\x35\x36\x2c\
|
||||||
|
\x33\x32\x31\x2e\x39\x31\x31\x6c\x31\x30\x2e\x34\x35\x34\x2c\x31\
|
||||||
|
\x36\x2e\x34\x33\x32\x63\x37\x2e\x37\x36\x32\x2c\x31\x32\x2e\x32\
|
||||||
|
\x2c\x32\x36\x2e\x31\x39\x36\x2c\x39\x2e\x38\x2c\x33\x30\x2e\x36\
|
||||||
|
\x33\x36\x2d\x33\x2e\x39\x0d\x0a\x09\x09\x09\x09\x6c\x31\x39\x2e\
|
||||||
|
\x38\x35\x35\x2d\x36\x31\x2e\x32\x37\x38\x63\x32\x2e\x39\x30\x36\
|
||||||
|
\x2d\x38\x2e\x39\x36\x37\x2d\x32\x2e\x30\x30\x38\x2d\x31\x38\x2e\
|
||||||
|
\x35\x39\x2d\x31\x30\x2e\x39\x37\x35\x2d\x32\x31\x2e\x34\x39\x36\
|
||||||
|
\x63\x2d\x38\x2e\x39\x37\x34\x2d\x32\x2e\x39\x30\x37\x2d\x31\x38\
|
||||||
|
\x2e\x35\x39\x31\x2c\x32\x2e\x30\x30\x38\x2d\x32\x31\x2e\x34\x39\
|
||||||
|
\x37\x2c\x31\x30\x2e\x39\x37\x35\x6c\x2d\x38\x2e\x36\x38\x31\x2c\
|
||||||
|
\x32\x36\x2e\x37\x39\x6c\x2d\x35\x2e\x33\x39\x32\x2d\x38\x2e\x34\
|
||||||
|
\x37\x38\x0d\x0a\x09\x09\x09\x09\x63\x2d\x36\x2e\x36\x39\x35\x2d\
|
||||||
|
\x31\x30\x2e\x35\x32\x2d\x32\x32\x2e\x30\x39\x34\x2d\x31\x30\x2e\
|
||||||
|
\x35\x33\x38\x2d\x32\x38\x2e\x38\x30\x31\x2c\x30\x6c\x2d\x35\x2e\
|
||||||
|
\x33\x39\x32\x2c\x38\x2e\x34\x37\x38\x6c\x2d\x38\x2e\x36\x38\x31\
|
||||||
|
\x2d\x32\x36\x2e\x37\x39\x63\x2d\x32\x2e\x39\x30\x35\x2d\x38\x2e\
|
||||||
|
\x39\x36\x36\x2d\x31\x32\x2e\x35\x32\x37\x2d\x31\x33\x2e\x38\x38\
|
||||||
|
\x32\x2d\x32\x31\x2e\x34\x39\x36\x2d\x31\x30\x2e\x39\x37\x35\x0d\
|
||||||
|
\x0a\x09\x09\x09\x09\x63\x2d\x38\x2e\x39\x36\x37\x2c\x32\x2e\x39\
|
||||||
|
\x30\x36\x2d\x31\x33\x2e\x38\x38\x2c\x31\x32\x2e\x35\x32\x39\x2d\
|
||||||
|
\x31\x30\x2e\x39\x37\x35\x2c\x32\x31\x2e\x34\x39\x36\x4c\x32\x31\
|
||||||
|
\x34\x2e\x39\x31\x31\x2c\x33\x33\x34\x2e\x34\x34\x32\x7a\x22\x2f\
|
||||||
|
\x3e\x0d\x0a\x09\x09\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\
|
||||||
|
\x33\x34\x38\x2e\x32\x34\x31\x2c\x33\x33\x34\x2e\x34\x34\x32\x63\
|
||||||
|
\x34\x2e\x34\x34\x36\x2c\x31\x33\x2e\x37\x32\x2c\x32\x32\x2e\x39\
|
||||||
|
\x30\x35\x2c\x31\x36\x2e\x30\x35\x31\x2c\x33\x30\x2e\x36\x33\x36\
|
||||||
|
\x2c\x33\x2e\x39\x6c\x31\x30\x2e\x34\x35\x34\x2d\x31\x36\x2e\x34\
|
||||||
|
\x33\x32\x6c\x31\x30\x2e\x34\x35\x34\x2c\x31\x36\x2e\x34\x33\x32\
|
||||||
|
\x63\x37\x2e\x37\x36\x32\x2c\x31\x32\x2e\x32\x2c\x32\x36\x2e\x31\
|
||||||
|
\x39\x35\x2c\x39\x2e\x38\x2c\x33\x30\x2e\x36\x33\x36\x2d\x33\x2e\
|
||||||
|
\x39\x0d\x0a\x09\x09\x09\x09\x6c\x31\x39\x2e\x38\x35\x35\x2d\x36\
|
||||||
|
\x31\x2e\x32\x37\x38\x63\x32\x2e\x39\x30\x36\x2d\x38\x2e\x39\x36\
|
||||||
|
\x37\x2d\x32\x2e\x30\x30\x38\x2d\x31\x38\x2e\x35\x39\x2d\x31\x30\
|
||||||
|
\x2e\x39\x37\x35\x2d\x32\x31\x2e\x34\x39\x36\x63\x2d\x38\x2e\x39\
|
||||||
|
\x37\x33\x2d\x32\x2e\x39\x30\x37\x2d\x31\x38\x2e\x35\x39\x31\x2c\
|
||||||
|
\x32\x2e\x30\x30\x38\x2d\x32\x31\x2e\x34\x39\x36\x2c\x31\x30\x2e\
|
||||||
|
\x39\x37\x35\x6c\x2d\x38\x2e\x36\x38\x31\x2c\x32\x36\x2e\x37\x39\
|
||||||
|
\x6c\x2d\x35\x2e\x33\x39\x32\x2d\x38\x2e\x34\x37\x38\x0d\x0a\x09\
|
||||||
|
\x09\x09\x09\x63\x2d\x36\x2e\x36\x39\x35\x2d\x31\x30\x2e\x35\x32\
|
||||||
|
\x2d\x32\x32\x2e\x30\x39\x35\x2d\x31\x30\x2e\x35\x33\x38\x2d\x32\
|
||||||
|
\x38\x2e\x38\x30\x31\x2c\x30\x6c\x2d\x35\x2e\x33\x39\x33\x2c\x38\
|
||||||
|
\x2e\x34\x37\x38\x6c\x2d\x38\x2e\x36\x38\x31\x2d\x32\x36\x2e\x37\
|
||||||
|
\x39\x31\x63\x2d\x32\x2e\x39\x30\x36\x2d\x38\x2e\x39\x36\x36\x2d\
|
||||||
|
\x31\x32\x2e\x35\x33\x31\x2d\x31\x33\x2e\x38\x38\x31\x2d\x32\x31\
|
||||||
|
\x2e\x34\x39\x37\x2d\x31\x30\x2e\x39\x37\x35\x0d\x0a\x09\x09\x09\
|
||||||
|
\x09\x63\x2d\x38\x2e\x39\x36\x37\x2c\x32\x2e\x39\x30\x36\x2d\x31\
|
||||||
|
\x33\x2e\x38\x38\x2c\x31\x32\x2e\x35\x33\x2d\x31\x30\x2e\x39\x37\
|
||||||
|
\x34\x2c\x32\x31\x2e\x34\x39\x37\x4c\x33\x34\x38\x2e\x32\x34\x31\
|
||||||
|
\x2c\x33\x33\x34\x2e\x34\x34\x32\x7a\x22\x2f\x3e\x0d\x0a\x09\x09\
|
||||||
|
\x3c\x2f\x67\x3e\x0d\x0a\x09\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x67\
|
||||||
|
\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\
|
||||||
|
\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\
|
||||||
|
\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\
|
||||||
|
\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\
|
||||||
|
\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\
|
||||||
|
\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\
|
||||||
|
\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\
|
||||||
|
\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\
|
||||||
|
\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\
|
||||||
|
\x0d\x0a\x3c\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x67\x3e\
|
||||||
|
\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
|
||||||
|
\
|
||||||
|
\x00\x00\x03\xfb\
|
||||||
|
\x3c\
|
||||||
|
\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
|
||||||
|
\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
|
||||||
|
\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
|
||||||
|
\x3d\x22\x34\x34\x38\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x35\
|
||||||
|
\x31\x32\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
|
||||||
|
\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
|
||||||
|
\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\
|
||||||
|
\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
|
||||||
|
\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\x0a\x20\
|
||||||
|
\x3c\x74\x69\x74\x6c\x65\x3e\x74\x72\x61\x73\x68\x2d\x72\x65\x64\
|
||||||
|
\x3c\x2f\x74\x69\x74\x6c\x65\x3e\x0a\x20\x3c\x67\x3e\x0a\x20\x20\
|
||||||
|
\x3c\x74\x69\x74\x6c\x65\x3e\x4c\x61\x79\x65\x72\x20\x31\x3c\x2f\
|
||||||
|
\x74\x69\x74\x6c\x65\x3e\x0a\x20\x20\x3c\x70\x61\x74\x68\x20\x66\
|
||||||
|
\x69\x6c\x6c\x3d\x22\x23\x66\x66\x30\x30\x30\x30\x22\x20\x69\x64\
|
||||||
|
\x3d\x22\x73\x76\x67\x5f\x31\x22\x20\x64\x3d\x22\x6d\x31\x39\x32\
|
||||||
|
\x2c\x31\x38\x38\x6c\x30\x2c\x32\x31\x36\x63\x30\x2c\x36\x2e\x36\
|
||||||
|
\x32\x37\x20\x2d\x35\x2e\x33\x37\x33\x2c\x31\x32\x20\x2d\x31\x32\
|
||||||
|
\x2c\x31\x32\x6c\x2d\x32\x34\x2c\x30\x63\x2d\x36\x2e\x36\x32\x37\
|
||||||
|
\x2c\x30\x20\x2d\x31\x32\x2c\x2d\x35\x2e\x33\x37\x33\x20\x2d\x31\
|
||||||
|
\x32\x2c\x2d\x31\x32\x6c\x30\x2c\x2d\x32\x31\x36\x63\x30\x2c\x2d\
|
||||||
|
\x36\x2e\x36\x32\x37\x20\x35\x2e\x33\x37\x33\x2c\x2d\x31\x32\x20\
|
||||||
|
\x31\x32\x2c\x2d\x31\x32\x6c\x32\x34\x2c\x30\x63\x36\x2e\x36\x32\
|
||||||
|
\x37\x2c\x30\x20\x31\x32\x2c\x35\x2e\x33\x37\x33\x20\x31\x32\x2c\
|
||||||
|
\x31\x32\x7a\x6d\x31\x30\x30\x2c\x2d\x31\x32\x6c\x2d\x32\x34\x2c\
|
||||||
|
\x30\x63\x2d\x36\x2e\x36\x32\x37\x2c\x30\x20\x2d\x31\x32\x2c\x35\
|
||||||
|
\x2e\x33\x37\x33\x20\x2d\x31\x32\x2c\x31\x32\x6c\x30\x2c\x32\x31\
|
||||||
|
\x36\x63\x30\x2c\x36\x2e\x36\x32\x37\x20\x35\x2e\x33\x37\x33\x2c\
|
||||||
|
\x31\x32\x20\x31\x32\x2c\x31\x32\x6c\x32\x34\x2c\x30\x63\x36\x2e\
|
||||||
|
\x36\x32\x37\x2c\x30\x20\x31\x32\x2c\x2d\x35\x2e\x33\x37\x33\x20\
|
||||||
|
\x31\x32\x2c\x2d\x31\x32\x6c\x30\x2c\x2d\x32\x31\x36\x63\x30\x2c\
|
||||||
|
\x2d\x36\x2e\x36\x32\x37\x20\x2d\x35\x2e\x33\x37\x33\x2c\x2d\x31\
|
||||||
|
\x32\x20\x2d\x31\x32\x2c\x2d\x31\x32\x7a\x6d\x31\x33\x32\x2c\x2d\
|
||||||
|
\x39\x36\x63\x31\x33\x2e\x32\x35\x35\x2c\x30\x20\x32\x34\x2c\x31\
|
||||||
|
\x30\x2e\x37\x34\x35\x20\x32\x34\x2c\x32\x34\x6c\x30\x2c\x31\x32\
|
||||||
|
\x63\x30\x2c\x36\x2e\x36\x32\x37\x20\x2d\x35\x2e\x33\x37\x33\x2c\
|
||||||
|
\x31\x32\x20\x2d\x31\x32\x2c\x31\x32\x6c\x2d\x32\x30\x2c\x30\x6c\
|
||||||
|
\x30\x2c\x33\x33\x36\x63\x30\x2c\x32\x36\x2e\x35\x31\x20\x2d\x32\
|
||||||
|
\x31\x2e\x34\x39\x2c\x34\x38\x20\x2d\x34\x38\x2c\x34\x38\x6c\x2d\
|
||||||
|
\x32\x38\x38\x2c\x30\x63\x2d\x32\x36\x2e\x35\x31\x2c\x30\x20\x2d\
|
||||||
|
\x34\x38\x2c\x2d\x32\x31\x2e\x34\x39\x20\x2d\x34\x38\x2c\x2d\x34\
|
||||||
|
\x38\x6c\x30\x2c\x2d\x33\x33\x36\x6c\x2d\x32\x30\x2c\x30\x63\x2d\
|
||||||
|
\x36\x2e\x36\x32\x37\x2c\x30\x20\x2d\x31\x32\x2c\x2d\x35\x2e\x33\
|
||||||
|
\x37\x33\x20\x2d\x31\x32\x2c\x2d\x31\x32\x6c\x30\x2c\x2d\x31\x32\
|
||||||
|
\x63\x30\x2c\x2d\x31\x33\x2e\x32\x35\x35\x20\x31\x30\x2e\x37\x34\
|
||||||
|
\x35\x2c\x2d\x32\x34\x20\x32\x34\x2c\x2d\x32\x34\x6c\x37\x34\x2e\
|
||||||
|
\x34\x31\x31\x2c\x30\x6c\x33\x34\x2e\x30\x31\x38\x2c\x2d\x35\x36\
|
||||||
|
\x2e\x36\x39\x36\x61\x34\x38\x2c\x34\x38\x20\x30\x20\x30\x20\x31\
|
||||||
|
\x20\x34\x31\x2e\x31\x36\x2c\x2d\x32\x33\x2e\x33\x30\x34\x6c\x31\
|
||||||
|
\x30\x30\x2e\x38\x32\x33\x2c\x30\x61\x34\x38\x2c\x34\x38\x20\x30\
|
||||||
|
\x20\x30\x20\x31\x20\x34\x31\x2e\x31\x36\x2c\x32\x33\x2e\x33\x30\
|
||||||
|
\x34\x6c\x33\x34\x2e\x30\x31\x37\x2c\x35\x36\x2e\x36\x39\x36\x6c\
|
||||||
|
\x37\x34\x2e\x34\x31\x31\x2c\x30\x7a\x6d\x2d\x32\x36\x39\x2e\x36\
|
||||||
|
\x31\x31\x2c\x30\x6c\x31\x33\x39\x2e\x32\x32\x33\x2c\x30\x6c\x2d\
|
||||||
|
\x31\x37\x2e\x34\x35\x32\x2c\x2d\x32\x39\x2e\x30\x38\x37\x61\x36\
|
||||||
|
\x2c\x36\x20\x30\x20\x30\x20\x30\x20\x2d\x35\x2e\x31\x34\x35\x2c\
|
||||||
|
\x2d\x32\x2e\x39\x31\x33\x6c\x2d\x39\x34\x2e\x30\x32\x38\x2c\x30\
|
||||||
|
\x61\x36\x2c\x36\x20\x30\x20\x30\x20\x30\x20\x2d\x35\x2e\x31\x34\
|
||||||
|
\x35\x2c\x32\x2e\x39\x31\x33\x6c\x2d\x31\x37\x2e\x34\x35\x33\x2c\
|
||||||
|
\x32\x39\x2e\x30\x38\x37\x7a\x6d\x32\x31\x33\x2e\x36\x31\x31\x2c\
|
||||||
|
\x34\x38\x6c\x2d\x32\x38\x38\x2c\x30\x6c\x30\x2c\x33\x33\x30\x61\
|
||||||
|
\x36\x2c\x36\x20\x30\x20\x30\x20\x30\x20\x36\x2c\x36\x6c\x32\x37\
|
||||||
|
\x36\x2c\x30\x61\x36\x2c\x36\x20\x30\x20\x30\x20\x30\x20\x36\x2c\
|
||||||
|
\x2d\x36\x6c\x30\x2c\x2d\x33\x33\x30\x7a\x22\x2f\x3e\x0a\x20\x3c\
|
||||||
|
\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\
|
||||||
|
\x00\x00\x08\xbd\
|
||||||
|
\x3c\
|
||||||
|
\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x38\x32\x70\
|
||||||
|
\x74\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x2d\x36\x39\x20\
|
||||||
|
\x2d\x32\x31\x20\x36\x38\x32\x20\x36\x38\x32\x2e\x36\x36\x36\x36\
|
||||||
|
\x39\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x36\x38\x32\x70\x74\x22\
|
||||||
|
\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
|
||||||
|
\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\
|
||||||
|
\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x35\x30\
|
||||||
|
\x37\x2e\x38\x38\x36\x37\x31\x39\x20\x34\x36\x39\x2e\x33\x33\x32\
|
||||||
|
\x30\x33\x31\x68\x2d\x31\x35\x38\x2e\x37\x31\x38\x37\x35\x63\x2d\
|
||||||
|
\x35\x2e\x38\x39\x34\x35\x33\x31\x20\x30\x2d\x31\x30\x2e\x36\x36\
|
||||||
|
\x37\x39\x36\x39\x20\x34\x2e\x37\x37\x33\x34\x33\x38\x2d\x31\x30\
|
||||||
|
\x2e\x36\x36\x37\x39\x36\x39\x20\x31\x30\x2e\x36\x36\x37\x39\x36\
|
||||||
|
\x39\x20\x30\x20\x35\x2e\x38\x39\x30\x36\x32\x35\x20\x34\x2e\x37\
|
||||||
|
\x37\x33\x34\x33\x38\x20\x31\x30\x2e\x36\x36\x34\x30\x36\x32\x20\
|
||||||
|
\x31\x30\x2e\x36\x36\x37\x39\x36\x39\x20\x31\x30\x2e\x36\x36\x34\
|
||||||
|
\x30\x36\x32\x68\x31\x35\x38\x2e\x37\x31\x38\x37\x35\x63\x31\x38\
|
||||||
|
\x2e\x31\x33\x36\x37\x31\x39\x2e\x32\x31\x38\x37\x35\x20\x33\x33\
|
||||||
|
\x2e\x30\x32\x37\x33\x34\x33\x2d\x31\x34\x2e\x32\x38\x35\x31\x35\
|
||||||
|
\x36\x20\x33\x33\x2e\x32\x37\x37\x33\x34\x33\x2d\x33\x32\x2e\x34\
|
||||||
|
\x32\x35\x37\x38\x31\x76\x2d\x33\x31\x39\x2e\x34\x36\x38\x37\x35\
|
||||||
|
\x63\x2e\x30\x30\x33\x39\x30\x37\x2d\x32\x2e\x35\x36\x32\x35\x2d\
|
||||||
|
\x2e\x39\x31\x34\x30\x36\x32\x2d\x35\x2e\x30\x34\x32\x39\x36\x39\
|
||||||
|
\x2d\x32\x2e\x35\x38\x39\x38\x34\x33\x2d\x36\x2e\x39\x38\x34\x33\
|
||||||
|
\x37\x35\x6c\x2d\x31\x31\x30\x2e\x37\x32\x32\x36\x35\x37\x2d\x31\
|
||||||
|
\x32\x38\x2e\x30\x39\x37\x36\x35\x36\x63\x2d\x32\x2e\x30\x32\x33\
|
||||||
|
\x34\x33\x37\x2d\x32\x2e\x33\x34\x33\x37\x35\x2d\x34\x2e\x39\x37\
|
||||||
|
\x32\x36\x35\x36\x2d\x33\x2e\x36\x39\x31\x34\x30\x36\x32\x35\x2d\
|
||||||
|
\x38\x2e\x30\x37\x34\x32\x31\x38\x2d\x33\x2e\x36\x38\x33\x35\x39\
|
||||||
|
\x33\x37\x35\x68\x2d\x32\x34\x30\x63\x2d\x31\x38\x2e\x31\x33\x32\
|
||||||
|
\x38\x31\x33\x2d\x2e\x32\x32\x32\x36\x35\x36\x32\x35\x2d\x33\x33\
|
||||||
|
\x2e\x30\x32\x37\x33\x34\x34\x20\x31\x34\x2e\x32\x38\x35\x31\x35\
|
||||||
|
\x35\x37\x35\x2d\x33\x33\x2e\x32\x37\x33\x34\x33\x38\x20\x33\x32\
|
||||||
|
\x2e\x34\x32\x31\x38\x37\x34\x37\x35\x76\x32\x35\x35\x2e\x35\x37\
|
||||||
|
\x34\x32\x31\x39\x63\x30\x20\x35\x2e\x38\x38\x36\x37\x31\x39\x20\
|
||||||
|
\x34\x2e\x37\x37\x33\x34\x33\x38\x20\x31\x30\x2e\x36\x36\x34\x30\
|
||||||
|
\x36\x32\x20\x31\x30\x2e\x36\x36\x30\x31\x35\x36\x20\x31\x30\x2e\
|
||||||
|
\x36\x36\x34\x30\x36\x32\x20\x35\x2e\x38\x39\x34\x35\x33\x32\x20\
|
||||||
|
\x30\x20\x31\x30\x2e\x36\x37\x31\x38\x37\x36\x2d\x34\x2e\x37\x37\
|
||||||
|
\x37\x33\x34\x33\x20\x31\x30\x2e\x36\x37\x31\x38\x37\x36\x2d\x31\
|
||||||
|
\x30\x2e\x36\x36\x34\x30\x36\x32\x76\x2d\x32\x35\x35\x2e\x35\x37\
|
||||||
|
\x34\x32\x31\x39\x63\x2e\x32\x35\x33\x39\x30\x36\x2d\x36\x2e\x33\
|
||||||
|
\x35\x35\x34\x36\x39\x20\x35\x2e\x35\x38\x39\x38\x34\x33\x2d\x31\
|
||||||
|
\x31\x2e\x33\x30\x38\x35\x39\x33\x20\x31\x31\x2e\x39\x34\x31\x34\
|
||||||
|
\x30\x36\x2d\x31\x31\x2e\x30\x38\x39\x38\x34\x33\x68\x32\x32\x31\
|
||||||
|
\x2e\x39\x33\x33\x35\x39\x34\x6c\x2e\x37\x39\x32\x39\x36\x38\x20\
|
||||||
|
\x31\x31\x32\x2e\x31\x37\x35\x37\x38\x31\x63\x2e\x31\x33\x36\x37\
|
||||||
|
\x31\x39\x20\x31\x34\x2e\x36\x34\x34\x35\x33\x31\x20\x31\x32\x2e\
|
||||||
|
\x30\x32\x33\x34\x33\x38\x20\x32\x36\x2e\x34\x34\x35\x33\x31\x32\
|
||||||
|
\x20\x32\x36\x2e\x36\x36\x34\x30\x36\x33\x20\x32\x36\x2e\x34\x38\
|
||||||
|
\x38\x32\x38\x31\x68\x39\x30\x2e\x36\x36\x34\x30\x36\x32\x76\x32\
|
||||||
|
\x39\x38\x2e\x32\x33\x38\x32\x38\x31\x63\x2d\x2e\x32\x35\x33\x39\
|
||||||
|
\x30\x36\x20\x36\x2e\x33\x35\x31\x35\x36\x33\x2d\x35\x2e\x35\x39\
|
||||||
|
\x33\x37\x35\x20\x31\x31\x2e\x33\x30\x38\x35\x39\x34\x2d\x31\x31\
|
||||||
|
\x2e\x39\x34\x35\x33\x31\x32\x20\x31\x31\x2e\x30\x39\x33\x37\x35\
|
||||||
|
\x7a\x6d\x2d\x38\x34\x2e\x30\x35\x30\x37\x38\x31\x2d\x33\x33\x36\
|
||||||
|
\x2d\x2e\x36\x39\x35\x33\x31\x33\x2d\x31\x30\x32\x2e\x35\x34\x36\
|
||||||
|
\x38\x37\x35\x20\x39\x33\x2e\x31\x36\x37\x39\x36\x39\x20\x31\x30\
|
||||||
|
\x37\x2e\x38\x37\x38\x39\x30\x36\x68\x2d\x38\x37\x2e\x31\x34\x30\
|
||||||
|
\x36\x32\x35\x63\x2d\x32\x2e\x39\x34\x35\x33\x31\x33\x20\x30\x2d\
|
||||||
|
\x35\x2e\x33\x33\x32\x30\x33\x31\x2d\x32\x2e\x33\x38\x36\x37\x31\
|
||||||
|
\x38\x2d\x35\x2e\x33\x33\x32\x30\x33\x31\x2d\x35\x2e\x33\x33\x32\
|
||||||
|
\x30\x33\x31\x7a\x6d\x30\x20\x30\x22\x2f\x3e\x3c\x70\x61\x74\x68\
|
||||||
|
\x20\x64\x3d\x22\x6d\x31\x33\x30\x2e\x35\x20\x36\x34\x30\x68\x35\
|
||||||
|
\x33\x2e\x33\x33\x35\x39\x33\x38\x63\x31\x34\x2e\x37\x32\x36\x35\
|
||||||
|
\x36\x32\x20\x30\x20\x32\x36\x2e\x36\x36\x34\x30\x36\x32\x2d\x31\
|
||||||
|
\x31\x2e\x39\x34\x35\x33\x31\x32\x20\x32\x36\x2e\x36\x36\x34\x30\
|
||||||
|
\x36\x32\x2d\x32\x36\x2e\x36\x37\x31\x38\x37\x35\x76\x2d\x37\x39\
|
||||||
|
\x2e\x39\x39\x36\x30\x39\x34\x68\x38\x30\x63\x31\x34\x2e\x37\x32\
|
||||||
|
\x36\x35\x36\x32\x20\x30\x20\x32\x36\x2e\x36\x36\x34\x30\x36\x32\
|
||||||
|
\x2d\x31\x31\x2e\x39\x34\x31\x34\x30\x36\x20\x32\x36\x2e\x36\x36\
|
||||||
|
\x34\x30\x36\x32\x2d\x32\x36\x2e\x36\x36\x37\x39\x36\x39\x76\x2d\
|
||||||
|
\x35\x33\x2e\x33\x33\x32\x30\x33\x31\x63\x30\x2d\x31\x34\x2e\x37\
|
||||||
|
\x32\x36\x35\x36\x32\x2d\x31\x31\x2e\x39\x33\x37\x35\x2d\x32\x36\
|
||||||
|
\x2e\x36\x36\x37\x39\x36\x39\x2d\x32\x36\x2e\x36\x36\x34\x30\x36\
|
||||||
|
\x32\x2d\x32\x36\x2e\x36\x36\x37\x39\x36\x39\x68\x2d\x38\x30\x76\
|
||||||
|
\x2d\x38\x30\x63\x30\x2d\x31\x34\x2e\x37\x32\x32\x36\x35\x36\x2d\
|
||||||
|
\x31\x31\x2e\x39\x33\x37\x35\x2d\x32\x36\x2e\x36\x36\x34\x30\x36\
|
||||||
|
\x32\x2d\x32\x36\x2e\x36\x36\x34\x30\x36\x32\x2d\x32\x36\x2e\x36\
|
||||||
|
\x36\x34\x30\x36\x32\x68\x2d\x35\x33\x2e\x33\x33\x35\x39\x33\x38\
|
||||||
|
\x63\x2d\x31\x34\x2e\x37\x32\x36\x35\x36\x32\x20\x30\x2d\x32\x36\
|
||||||
|
\x2e\x36\x36\x34\x30\x36\x32\x20\x31\x31\x2e\x39\x34\x31\x34\x30\
|
||||||
|
\x36\x2d\x32\x36\x2e\x36\x36\x34\x30\x36\x32\x20\x32\x36\x2e\x36\
|
||||||
|
\x36\x34\x30\x36\x32\x76\x38\x30\x68\x2d\x38\x30\x63\x2d\x31\x34\
|
||||||
|
\x2e\x37\x33\x30\x34\x36\x39\x20\x30\x2d\x32\x36\x2e\x36\x36\x37\
|
||||||
|
\x39\x36\x39\x20\x31\x31\x2e\x39\x34\x31\x34\x30\x37\x2d\x32\x36\
|
||||||
|
\x2e\x36\x36\x37\x39\x36\x39\x20\x32\x36\x2e\x36\x36\x37\x39\x36\
|
||||||
|
\x39\x76\x35\x33\x2e\x33\x33\x32\x30\x33\x31\x63\x30\x20\x31\x34\
|
||||||
|
\x2e\x37\x32\x36\x35\x36\x33\x20\x31\x31\x2e\x39\x33\x37\x35\x20\
|
||||||
|
\x32\x36\x2e\x36\x36\x37\x39\x36\x39\x20\x32\x36\x2e\x36\x36\x37\
|
||||||
|
\x39\x36\x39\x20\x32\x36\x2e\x36\x36\x37\x39\x36\x39\x68\x38\x30\
|
||||||
|
\x76\x37\x39\x2e\x39\x39\x36\x30\x39\x34\x63\x30\x20\x31\x34\x2e\
|
||||||
|
\x37\x32\x36\x35\x36\x33\x20\x31\x31\x2e\x39\x33\x37\x35\x20\x32\
|
||||||
|
\x36\x2e\x36\x37\x31\x38\x37\x35\x20\x32\x36\x2e\x36\x36\x34\x30\
|
||||||
|
\x36\x32\x20\x32\x36\x2e\x36\x37\x31\x38\x37\x35\x7a\x6d\x2d\x31\
|
||||||
|
\x31\x32\x2d\x31\x33\x33\x2e\x33\x33\x35\x39\x33\x38\x76\x2d\x35\
|
||||||
|
\x33\x2e\x33\x33\x32\x30\x33\x31\x63\x30\x2d\x32\x2e\x39\x34\x35\
|
||||||
|
\x33\x31\x32\x20\x32\x2e\x33\x38\x36\x37\x31\x39\x2d\x35\x2e\x33\
|
||||||
|
\x33\x32\x30\x33\x31\x20\x35\x2e\x33\x33\x35\x39\x33\x38\x2d\x35\
|
||||||
|
\x2e\x33\x33\x32\x30\x33\x31\x68\x39\x30\x2e\x36\x36\x34\x30\x36\
|
||||||
|
\x32\x63\x35\x2e\x38\x39\x34\x35\x33\x31\x20\x30\x20\x31\x30\x2e\
|
||||||
|
\x36\x36\x37\x39\x36\x39\x2d\x34\x2e\x37\x37\x37\x33\x34\x34\x20\
|
||||||
|
\x31\x30\x2e\x36\x36\x37\x39\x36\x39\x2d\x31\x30\x2e\x36\x37\x31\
|
||||||
|
\x38\x37\x35\x76\x2d\x39\x30\x2e\x36\x36\x34\x30\x36\x33\x63\x30\
|
||||||
|
\x2d\x32\x2e\x39\x34\x31\x34\x30\x36\x20\x32\x2e\x33\x39\x30\x36\
|
||||||
|
\x32\x35\x2d\x35\x2e\x33\x32\x38\x31\x32\x34\x20\x35\x2e\x33\x33\
|
||||||
|
\x32\x30\x33\x31\x2d\x35\x2e\x33\x32\x38\x31\x32\x34\x68\x35\x33\
|
||||||
|
\x2e\x33\x33\x35\x39\x33\x38\x63\x32\x2e\x39\x34\x35\x33\x31\x32\
|
||||||
|
\x20\x30\x20\x35\x2e\x33\x33\x32\x30\x33\x31\x20\x32\x2e\x33\x38\
|
||||||
|
\x36\x37\x31\x38\x20\x35\x2e\x33\x33\x32\x30\x33\x31\x20\x35\x2e\
|
||||||
|
\x33\x32\x38\x31\x32\x34\x76\x39\x30\x2e\x36\x36\x34\x30\x36\x33\
|
||||||
|
\x63\x30\x20\x35\x2e\x38\x39\x34\x35\x33\x31\x20\x34\x2e\x37\x37\
|
||||||
|
\x33\x34\x33\x37\x20\x31\x30\x2e\x36\x37\x31\x38\x37\x35\x20\x31\
|
||||||
|
\x30\x2e\x36\x36\x34\x30\x36\x32\x20\x31\x30\x2e\x36\x37\x31\x38\
|
||||||
|
\x37\x35\x68\x39\x30\x2e\x36\x36\x37\x39\x36\x39\x63\x32\x2e\x39\
|
||||||
|
\x34\x35\x33\x31\x32\x20\x30\x20\x35\x2e\x33\x33\x32\x30\x33\x31\
|
||||||
|
\x20\x32\x2e\x33\x38\x36\x37\x31\x39\x20\x35\x2e\x33\x33\x32\x30\
|
||||||
|
\x33\x31\x20\x35\x2e\x33\x33\x32\x30\x33\x31\x76\x35\x33\x2e\x33\
|
||||||
|
\x33\x32\x30\x33\x31\x63\x30\x20\x32\x2e\x39\x34\x35\x33\x31\x33\
|
||||||
|
\x2d\x32\x2e\x33\x38\x36\x37\x31\x39\x20\x35\x2e\x33\x33\x32\x30\
|
||||||
|
\x33\x32\x2d\x35\x2e\x33\x33\x32\x30\x33\x31\x20\x35\x2e\x33\x33\
|
||||||
|
\x32\x30\x33\x32\x68\x2d\x39\x30\x2e\x36\x36\x37\x39\x36\x39\x63\
|
||||||
|
\x2d\x35\x2e\x38\x39\x30\x36\x32\x35\x20\x30\x2d\x31\x30\x2e\x36\
|
||||||
|
\x36\x34\x30\x36\x32\x20\x34\x2e\x37\x37\x37\x33\x34\x34\x2d\x31\
|
||||||
|
\x30\x2e\x36\x36\x34\x30\x36\x32\x20\x31\x30\x2e\x36\x37\x31\x38\
|
||||||
|
\x37\x35\x76\x39\x30\x2e\x36\x36\x30\x31\x35\x36\x63\x30\x20\x32\
|
||||||
|
\x2e\x39\x34\x35\x33\x31\x33\x2d\x32\x2e\x33\x38\x36\x37\x31\x39\
|
||||||
|
\x20\x35\x2e\x33\x33\x32\x30\x33\x31\x2d\x35\x2e\x33\x33\x32\x30\
|
||||||
|
\x33\x31\x20\x35\x2e\x33\x33\x32\x30\x33\x31\x68\x2d\x35\x33\x2e\
|
||||||
|
\x33\x33\x35\x39\x33\x38\x63\x2d\x32\x2e\x39\x34\x31\x34\x30\x36\
|
||||||
|
\x20\x30\x2d\x35\x2e\x33\x33\x32\x30\x33\x31\x2d\x32\x2e\x33\x38\
|
||||||
|
\x36\x37\x31\x38\x2d\x35\x2e\x33\x33\x32\x30\x33\x31\x2d\x35\x2e\
|
||||||
|
\x33\x33\x32\x30\x33\x31\x76\x2d\x39\x30\x2e\x36\x36\x30\x31\x35\
|
||||||
|
\x36\x63\x30\x2d\x35\x2e\x38\x39\x34\x35\x33\x31\x2d\x34\x2e\x37\
|
||||||
|
\x37\x33\x34\x33\x38\x2d\x31\x30\x2e\x36\x37\x31\x38\x37\x35\x2d\
|
||||||
|
\x31\x30\x2e\x36\x36\x37\x39\x36\x39\x2d\x31\x30\x2e\x36\x37\x31\
|
||||||
|
\x38\x37\x35\x68\x2d\x39\x30\x2e\x36\x36\x34\x30\x36\x32\x63\x2d\
|
||||||
|
\x32\x2e\x39\x34\x39\x32\x31\x39\x20\x30\x2d\x35\x2e\x33\x33\x35\
|
||||||
|
\x39\x33\x38\x2d\x32\x2e\x33\x38\x36\x37\x31\x39\x2d\x35\x2e\x33\
|
||||||
|
\x33\x35\x39\x33\x38\x2d\x35\x2e\x33\x33\x32\x30\x33\x32\x7a\x6d\
|
||||||
|
\x30\x20\x30\x22\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
|
||||||
|
\x00\x00\x0d\x92\
|
||||||
|
\x3c\
|
||||||
|
\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
|
||||||
|
\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
|
||||||
|
\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
|
||||||
|
\x6e\x6f\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\
|
||||||
|
\x6c\x6e\x73\x3a\x64\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\
|
||||||
|
\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\
|
||||||
|
\x6e\x74\x73\x2f\x31\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\
|
||||||
|
\x6e\x73\x3a\x63\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\
|
||||||
|
\x65\x61\x74\x69\x76\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\
|
||||||
|
\x67\x2f\x6e\x73\x23\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\
|
||||||
|
\x72\x64\x66\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
|
||||||
|
\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\
|
||||||
|
\x32\x2d\x72\x64\x66\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\
|
||||||
|
\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\
|
||||||
|
\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
|
||||||
|
\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\
|
||||||
|
\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\
|
||||||
|
\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\
|
||||||
|
\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\
|
||||||
|
\x6f\x64\x69\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\
|
||||||
|
\x70\x6f\x64\x69\x2e\x73\x6f\x75\x72\x63\x65\x66\x6f\x72\x67\x65\
|
||||||
|
\x2e\x6e\x65\x74\x2f\x44\x54\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\
|
||||||
|
\x69\x2d\x30\x2e\x64\x74\x64\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\
|
||||||
|
\x73\x3a\x69\x6e\x6b\x73\x63\x61\x70\x65\x3d\x22\x68\x74\x74\x70\
|
||||||
|
\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\
|
||||||
|
\x6f\x72\x67\x2f\x6e\x61\x6d\x65\x73\x70\x61\x63\x65\x73\x2f\x69\
|
||||||
|
\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x76\x65\x72\x73\
|
||||||
|
\x69\x6f\x6e\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x77\x69\x64\
|
||||||
|
\x74\x68\x3d\x22\x39\x30\x2e\x30\x30\x30\x30\x30\x30\x70\x74\x22\
|
||||||
|
\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x39\x30\x2e\x30\
|
||||||
|
\x30\x30\x30\x30\x30\x70\x74\x22\x0a\x20\x20\x20\x76\x69\x65\x77\
|
||||||
|
\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x39\x30\x2e\x30\x30\x30\x30\
|
||||||
|
\x30\x30\x20\x39\x30\x2e\x30\x30\x30\x30\x30\x30\x22\x0a\x20\x20\
|
||||||
|
\x20\x70\x72\x65\x73\x65\x72\x76\x65\x41\x73\x70\x65\x63\x74\x52\
|
||||||
|
\x61\x74\x69\x6f\x3d\x22\x78\x4d\x69\x64\x59\x4d\x69\x64\x20\x6d\
|
||||||
|
\x65\x65\x74\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x36\
|
||||||
|
\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\
|
||||||
|
\x63\x6e\x61\x6d\x65\x3d\x22\x68\x6f\x76\x65\x72\x2e\x73\x76\x67\
|
||||||
|
\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\
|
||||||
|
\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x30\x2e\x31\x20\x28\x31\x2e\
|
||||||
|
\x30\x2e\x31\x2b\x72\x37\x34\x29\x22\x3e\x0a\x20\x20\x3c\x6d\x65\
|
||||||
|
\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\
|
||||||
|
\x6d\x65\x74\x61\x64\x61\x74\x61\x31\x32\x22\x3e\x0a\x20\x20\x20\
|
||||||
|
\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x20\x20\x20\
|
||||||
|
\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\x0a\x20\x20\x20\x20\x20\x20\
|
||||||
|
\x20\x20\x20\x72\x64\x66\x3a\x61\x62\x6f\x75\x74\x3d\x22\x22\x3e\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x66\x6f\x72\
|
||||||
|
\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\x2f\x73\x76\x67\x2b\x78\x6d\
|
||||||
|
\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x0a\x20\x20\
|
||||||
|
\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x79\x70\x65\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x72\x65\
|
||||||
|
\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\
|
||||||
|
\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x64\x63\x6d\x69\x74\
|
||||||
|
\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\x49\x6d\x61\x67\x65\x22\x20\
|
||||||
|
\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\
|
||||||
|
\x69\x74\x6c\x65\x3e\x3c\x2f\x64\x63\x3a\x74\x69\x74\x6c\x65\x3e\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\
|
||||||
|
\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\
|
||||||
|
\x0a\x20\x20\x3c\x2f\x6d\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\
|
||||||
|
\x20\x3c\x64\x65\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\
|
||||||
|
\x64\x65\x66\x73\x31\x30\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x73\x6f\
|
||||||
|
\x64\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\
|
||||||
|
\x22\x23\x66\x66\x66\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\
|
||||||
|
\x6f\x72\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\
|
||||||
|
\x36\x36\x36\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\
|
||||||
|
\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\
|
||||||
|
\x20\x6f\x62\x6a\x65\x63\x74\x74\x6f\x6c\x65\x72\x61\x6e\x63\x65\
|
||||||
|
\x3d\x22\x31\x30\x22\x0a\x20\x20\x20\x20\x20\x67\x72\x69\x64\x74\
|
||||||
|
\x6f\x6c\x65\x72\x61\x6e\x63\x65\x3d\x22\x31\x30\x22\x0a\x20\x20\
|
||||||
|
\x20\x20\x20\x67\x75\x69\x64\x65\x74\x6f\x6c\x65\x72\x61\x6e\x63\
|
||||||
|
\x65\x3d\x22\x31\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
|
||||||
|
\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\
|
||||||
|
\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
|
||||||
|
\x70\x65\x3a\x70\x61\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\
|
||||||
|
\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
|
||||||
|
\x77\x69\x6e\x64\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x39\
|
||||||
|
\x32\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
|
||||||
|
\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\
|
||||||
|
\x22\x31\x30\x31\x35\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\
|
||||||
|
\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x38\x22\x0a\x20\x20\x20\x20\
|
||||||
|
\x20\x73\x68\x6f\x77\x67\x72\x69\x64\x3d\x22\x66\x61\x6c\x73\x65\
|
||||||
|
\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
|
||||||
|
\x7a\x6f\x6f\x6d\x3d\x22\x31\x2e\x30\x35\x33\x32\x39\x34\x35\x22\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\
|
||||||
|
\x78\x3d\x22\x35\x30\x33\x2e\x38\x30\x36\x30\x33\x22\x0a\x20\x20\
|
||||||
|
\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\
|
||||||
|
\x37\x33\x2e\x33\x38\x31\x38\x31\x37\x22\x0a\x20\x20\x20\x20\x20\
|
||||||
|
\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\
|
||||||
|
\x78\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\
|
||||||
|
\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x79\x3d\x22\x30\x22\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\
|
||||||
|
\x69\x6e\x64\x6f\x77\x2d\x6d\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\
|
||||||
|
\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
|
||||||
|
\x65\x3a\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\
|
||||||
|
\x22\x73\x76\x67\x36\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
|
||||||
|
\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2d\x72\x6f\
|
||||||
|
\x74\x61\x74\x69\x6f\x6e\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\
|
||||||
|
\x3c\x67\x0a\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\
|
||||||
|
\x6d\x3d\x22\x74\x72\x61\x6e\x73\x6c\x61\x74\x65\x28\x30\x2e\x30\
|
||||||
|
\x30\x30\x30\x30\x30\x2c\x39\x30\x2e\x30\x30\x30\x30\x30\x30\x29\
|
||||||
|
\x20\x73\x63\x61\x6c\x65\x28\x30\x2e\x31\x30\x30\x30\x30\x30\x2c\
|
||||||
|
\x2d\x30\x2e\x31\x30\x30\x30\x30\x30\x29\x22\x0a\x20\x20\x20\x20\
|
||||||
|
\x20\x66\x69\x6c\x6c\x3d\x22\x23\x65\x37\x34\x63\x33\x63\x22\x0a\
|
||||||
|
\x20\x20\x20\x20\x20\x73\x74\x72\x6f\x6b\x65\x3d\x22\x6e\x6f\x6e\
|
||||||
|
\x65\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x67\x34\x22\x0a\
|
||||||
|
\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\x6c\
|
||||||
|
\x3a\x23\x66\x66\x30\x30\x30\x30\x22\x3e\x0a\x20\x20\x20\x20\x3c\
|
||||||
|
\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\
|
||||||
|
\x33\x38\x31\x20\x38\x30\x30\x20\x63\x2d\x31\x34\x34\x20\x2d\x33\
|
||||||
|
\x30\x20\x2d\x32\x35\x34\x20\x2d\x31\x34\x35\x20\x2d\x32\x38\x32\
|
||||||
|
\x20\x2d\x32\x39\x33\x20\x2d\x34\x32\x20\x2d\x32\x33\x32\x20\x31\
|
||||||
|
\x37\x36\x20\x2d\x34\x35\x30\x20\x34\x30\x38\x20\x2d\x34\x30\x38\
|
||||||
|
\x20\x32\x33\x30\x20\x34\x33\x20\x33\x36\x31\x20\x32\x38\x31\x20\
|
||||||
|
\x32\x37\x30\x20\x34\x39\x33\x20\x2d\x36\x34\x20\x31\x34\x38\x20\
|
||||||
|
\x2d\x32\x33\x38\x20\x32\x34\x30\x20\x2d\x33\x39\x36\x20\x32\x30\
|
||||||
|
\x38\x7a\x20\x6d\x31\x36\x20\x2d\x32\x35\x32\x20\x6c\x35\x33\x20\
|
||||||
|
\x2d\x35\x32\x20\x35\x34\x20\x35\x33\x20\x63\x35\x35\x20\x35\x34\
|
||||||
|
\x20\x38\x37\x20\x36\x34\x20\x39\x34\x20\x32\x37\x20\x33\x20\x2d\
|
||||||
|
\x31\x32\x20\x2d\x31\x35\x20\x2d\x33\x38\x20\x2d\x34\x39\x20\x2d\
|
||||||
|
\x37\x32\x20\x6c\x2d\x35\x33\x20\x2d\x35\x34\x20\x35\x33\x20\x2d\
|
||||||
|
\x35\x34\x20\x63\x35\x34\x20\x2d\x35\x35\x20\x36\x34\x20\x2d\x38\
|
||||||
|
\x37\x20\x32\x37\x20\x2d\x39\x34\x20\x2d\x31\x32\x20\x2d\x33\x20\
|
||||||
|
\x2d\x33\x38\x20\x31\x35\x20\x2d\x37\x32\x20\x34\x39\x20\x6c\x2d\
|
||||||
|
\x35\x34\x20\x35\x33\x20\x2d\x35\x34\x20\x2d\x35\x33\x20\x63\x2d\
|
||||||
|
\x33\x34\x20\x2d\x33\x34\x20\x2d\x36\x30\x20\x2d\x35\x32\x20\x2d\
|
||||||
|
\x37\x32\x20\x2d\x34\x39\x20\x2d\x33\x37\x20\x37\x20\x2d\x32\x37\
|
||||||
|
\x20\x33\x39\x20\x32\x37\x20\x39\x34\x20\x6c\x35\x33\x20\x35\x34\
|
||||||
|
\x20\x2d\x35\x32\x20\x35\x33\x20\x63\x2d\x34\x39\x20\x34\x39\x20\
|
||||||
|
\x2d\x36\x31\x20\x37\x34\x20\x2d\x34\x35\x20\x39\x30\x20\x31\x36\
|
||||||
|
\x20\x31\x36\x20\x34\x31\x20\x34\x20\x39\x30\x20\x2d\x34\x35\x7a\
|
||||||
|
\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\
|
||||||
|
\x68\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\
|
||||||
|
\x3d\x22\x66\x69\x6c\x6c\x3a\x23\x66\x66\x30\x30\x30\x30\x22\x20\
|
||||||
|
\x2f\x3e\x0a\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\x3c\x70\x61\x74\
|
||||||
|
\x68\x0a\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\
|
||||||
|
\x6c\x6c\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x72\x6f\x6b\
|
||||||
|
\x65\x2d\x77\x69\x64\x74\x68\x3a\x30\x2e\x31\x31\x38\x36\x37\x35\
|
||||||
|
\x22\x0a\x20\x20\x20\x20\x20\x64\x3d\x22\x6d\x20\x34\x32\x2e\x36\
|
||||||
|
\x32\x32\x36\x31\x2c\x37\x39\x2e\x35\x34\x31\x38\x39\x33\x20\x63\
|
||||||
|
\x20\x2d\x33\x2e\x31\x31\x36\x31\x36\x35\x2c\x2d\x31\x2e\x30\x32\
|
||||||
|
\x39\x36\x31\x32\x20\x2d\x33\x2e\x30\x35\x38\x38\x2c\x2d\x33\x2e\
|
||||||
|
\x33\x36\x36\x38\x30\x38\x20\x30\x2e\x31\x38\x38\x32\x35\x34\x2c\
|
||||||
|
\x2d\x37\x2e\x36\x36\x39\x39\x38\x39\x20\x31\x2e\x33\x39\x36\x34\
|
||||||
|
\x36\x39\x2c\x2d\x31\x2e\x38\x35\x30\x36\x38\x32\x20\x32\x2e\x37\
|
||||||
|
\x31\x36\x37\x39\x39\x2c\x2d\x33\x2e\x32\x38\x37\x33\x38\x37\x20\
|
||||||
|
\x37\x2e\x32\x38\x31\x38\x35\x33\x2c\x2d\x37\x2e\x39\x32\x33\x36\
|
||||||
|
\x38\x36\x20\x6c\x20\x33\x2e\x38\x38\x34\x39\x33\x33\x2c\x2d\x33\
|
||||||
|
\x2e\x39\x34\x35\x35\x36\x32\x20\x2d\x34\x2e\x35\x36\x34\x32\x34\
|
||||||
|
\x31\x2c\x2d\x34\x2e\x36\x35\x38\x33\x39\x34\x20\x63\x20\x2d\x36\
|
||||||
|
\x2e\x30\x38\x35\x35\x35\x2c\x2d\x36\x2e\x32\x31\x31\x30\x38\x35\
|
||||||
|
\x20\x2d\x37\x2e\x34\x33\x39\x37\x30\x39\x2c\x2d\x37\x2e\x37\x37\
|
||||||
|
\x35\x39\x33\x31\x20\x2d\x38\x2e\x35\x31\x32\x35\x35\x39\x2c\x2d\
|
||||||
|
\x39\x2e\x38\x33\x36\x39\x38\x36\x20\x2d\x31\x2e\x31\x31\x34\x30\
|
||||||
|
\x39\x31\x2c\x2d\x32\x2e\x31\x34\x30\x32\x38\x32\x20\x2d\x31\x2e\
|
||||||
|
\x30\x33\x35\x30\x35\x33\x2c\x2d\x33\x2e\x35\x35\x33\x39\x36\x34\
|
||||||
|
\x20\x30\x2e\x32\x36\x30\x37\x30\x38\x2c\x2d\x34\x2e\x36\x36\x33\
|
||||||
|
\x30\x38\x38\x20\x30\x2e\x37\x30\x38\x37\x38\x34\x2c\x2d\x30\x2e\
|
||||||
|
\x36\x30\x36\x36\x39\x32\x20\x31\x2e\x35\x38\x35\x35\x37\x34\x2c\
|
||||||
|
\x2d\x30\x2e\x38\x34\x37\x31\x20\x32\x2e\x34\x35\x33\x36\x34\x37\
|
||||||
|
\x2c\x2d\x30\x2e\x36\x37\x32\x37\x36\x36\x20\x31\x2e\x32\x38\x32\
|
||||||
|
\x35\x34\x32\x2c\x30\x2e\x32\x35\x37\x35\x37\x32\x20\x32\x2e\x38\
|
||||||
|
\x39\x33\x39\x38\x39\x2c\x31\x2e\x31\x37\x37\x35\x34\x36\x20\x34\
|
||||||
|
\x2e\x38\x36\x39\x36\x32\x31\x2c\x32\x2e\x37\x38\x30\x30\x36\x35\
|
||||||
|
\x20\x31\x2e\x34\x32\x38\x36\x35\x32\x2c\x31\x2e\x31\x35\x38\x38\
|
||||||
|
\x34\x20\x31\x2e\x37\x35\x38\x39\x37\x34\x2c\x31\x2e\x34\x36\x39\
|
||||||
|
\x39\x39\x39\x20\x36\x2e\x39\x32\x34\x37\x30\x31\x2c\x36\x2e\x35\
|
||||||
|
\x32\x32\x39\x38\x32\x20\x6c\x20\x34\x2e\x35\x39\x38\x33\x32\x33\
|
||||||
|
\x2c\x34\x2e\x34\x39\x37\x39\x36\x34\x20\x33\x2e\x39\x34\x36\x32\
|
||||||
|
\x39\x36\x2c\x2d\x33\x2e\x38\x38\x35\x36\x35\x35\x20\x63\x20\x35\
|
||||||
|
\x2e\x36\x38\x37\x34\x38\x38\x2c\x2d\x35\x2e\x36\x30\x30\x30\x39\
|
||||||
|
\x20\x37\x2e\x35\x30\x35\x32\x36\x2c\x2d\x37\x2e\x31\x38\x38\x37\
|
||||||
|
\x36\x31\x20\x39\x2e\x38\x33\x34\x37\x30\x31\x2c\x2d\x38\x2e\x35\
|
||||||
|
\x39\x35\x31\x39\x37\x20\x30\x2e\x39\x39\x35\x37\x32\x37\x2c\x2d\
|
||||||
|
\x30\x2e\x36\x30\x31\x31\x38\x35\x20\x32\x2e\x35\x36\x34\x37\x37\
|
||||||
|
\x35\x2c\x2d\x31\x2e\x31\x39\x30\x33\x38\x32\x20\x33\x2e\x31\x36\
|
||||||
|
\x36\x37\x30\x39\x2c\x2d\x31\x2e\x31\x38\x39\x31\x33\x38\x20\x31\
|
||||||
|
\x2e\x33\x32\x39\x35\x38\x39\x2c\x30\x2e\x30\x30\x32\x37\x20\x32\
|
||||||
|
\x2e\x32\x35\x38\x34\x37\x31\x2c\x30\x2e\x39\x32\x38\x31\x32\x36\
|
||||||
|
\x20\x32\x2e\x36\x33\x36\x30\x30\x38\x2c\x32\x2e\x36\x32\x36\x30\
|
||||||
|
\x36\x33\x20\x30\x2e\x31\x38\x34\x34\x32\x34\x2c\x30\x2e\x38\x32\
|
||||||
|
\x39\x34\x33\x34\x20\x30\x2e\x31\x31\x30\x32\x39\x2c\x31\x2e\x32\
|
||||||
|
\x34\x30\x37\x37\x36\x20\x2d\x30\x2e\x34\x32\x34\x38\x38\x36\x2c\
|
||||||
|
\x32\x2e\x33\x35\x37\x34\x39\x39\x20\x2d\x31\x2e\x31\x30\x34\x36\
|
||||||
|
\x39\x2c\x32\x2e\x33\x30\x35\x31\x20\x2d\x32\x2e\x38\x35\x31\x38\
|
||||||
|
\x31\x34\x2c\x34\x2e\x33\x30\x32\x35\x34\x34\x20\x2d\x31\x30\x2e\
|
||||||
|
\x36\x36\x35\x38\x37\x36\x2c\x31\x32\x2e\x31\x39\x34\x30\x33\x33\
|
||||||
|
\x20\x6c\x20\x2d\x32\x2e\x34\x39\x37\x31\x31\x38\x2c\x32\x2e\x35\
|
||||||
|
\x32\x31\x38\x36\x31\x20\x32\x2e\x35\x35\x36\x32\x37\x36\x2c\x32\
|
||||||
|
\x2e\x35\x38\x31\x31\x37\x35\x20\x63\x20\x37\x2e\x34\x37\x38\x39\
|
||||||
|
\x35\x2c\x37\x2e\x35\x35\x31\x37\x39\x39\x20\x39\x2e\x31\x38\x30\
|
||||||
|
\x34\x34\x37\x2c\x39\x2e\x35\x33\x33\x37\x30\x39\x20\x31\x30\x2e\
|
||||||
|
\x34\x34\x32\x30\x32\x36\x2c\x31\x32\x2e\x31\x36\x32\x39\x31\x32\
|
||||||
|
\x20\x31\x2e\x31\x31\x38\x30\x38\x33\x2c\x32\x2e\x33\x33\x30\x31\
|
||||||
|
\x34\x37\x20\x30\x2e\x38\x32\x34\x33\x34\x33\x2c\x33\x2e\x37\x33\
|
||||||
|
\x32\x36\x33\x31\x20\x2d\x30\x2e\x39\x34\x38\x33\x39\x35\x2c\x34\
|
||||||
|
\x2e\x35\x32\x38\x31\x39\x20\x2d\x31\x2e\x34\x36\x38\x33\x31\x37\
|
||||||
|
\x2c\x30\x2e\x36\x35\x38\x39\x34\x31\x20\x2d\x32\x2e\x34\x36\x33\
|
||||||
|
\x37\x33\x2c\x30\x2e\x35\x31\x37\x39\x35\x38\x20\x2d\x34\x2e\x32\
|
||||||
|
\x34\x36\x37\x39\x31\x2c\x2d\x30\x2e\x36\x30\x31\x34\x38\x32\x20\
|
||||||
|
\x2d\x32\x2e\x32\x33\x30\x38\x34\x33\x2c\x2d\x31\x2e\x34\x30\x30\
|
||||||
|
\x35\x36\x36\x20\x2d\x33\x2e\x31\x39\x35\x34\x35\x2c\x2d\x32\x2e\
|
||||||
|
\x32\x35\x33\x34\x37\x20\x2d\x39\x2e\x32\x30\x30\x36\x38\x33\x2c\
|
||||||
|
\x2d\x38\x2e\x31\x33\x35\x32\x32\x34\x20\x6c\x20\x2d\x34\x2e\x35\
|
||||||
|
\x39\x39\x37\x35\x33\x2c\x2d\x34\x2e\x35\x30\x35\x31\x37\x33\x20\
|
||||||
|
\x2d\x34\x2e\x35\x33\x38\x32\x34\x33\x2c\x34\x2e\x34\x33\x37\x39\
|
||||||
|
\x32\x31\x20\x63\x20\x2d\x35\x2e\x31\x32\x35\x35\x30\x39\x2c\x35\
|
||||||
|
\x2e\x30\x31\x32\x32\x30\x35\x20\x2d\x35\x2e\x34\x33\x36\x38\x35\
|
||||||
|
\x34\x2c\x35\x2e\x33\x30\x35\x31\x37\x31\x20\x2d\x36\x2e\x38\x39\
|
||||||
|
\x36\x37\x33\x32\x2c\x36\x2e\x34\x38\x39\x36\x31\x39\x20\x2d\x32\
|
||||||
|
\x2e\x37\x39\x33\x39\x38\x2c\x32\x2e\x32\x36\x36\x38\x35\x32\x20\
|
||||||
|
\x2d\x34\x2e\x35\x36\x39\x38\x35\x35\x2c\x33\x2e\x30\x33\x37\x36\
|
||||||
|
\x36\x37\x20\x2d\x35\x2e\x39\x34\x38\x37\x37\x39\x2c\x32\x2e\x35\
|
||||||
|
\x38\x32\x30\x35\x36\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\x69\x64\
|
||||||
|
\x3d\x22\x70\x61\x74\x68\x31\x36\x22\x0a\x20\x20\x20\x20\x20\x74\
|
||||||
|
\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x73\x63\x61\x6c\x65\x28\
|
||||||
|
\x30\x2e\x37\x35\x29\x22\x20\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\
|
||||||
|
\x0a\
|
||||||
|
\x00\x00\x0d\x4d\
|
||||||
|
\x3c\
|
||||||
|
\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
|
||||||
|
\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
|
||||||
|
\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
|
||||||
|
\x6e\x6f\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\
|
||||||
|
\x6c\x6e\x73\x3a\x64\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\
|
||||||
|
\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\
|
||||||
|
\x6e\x74\x73\x2f\x31\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\
|
||||||
|
\x6e\x73\x3a\x63\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\
|
||||||
|
\x65\x61\x74\x69\x76\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\
|
||||||
|
\x67\x2f\x6e\x73\x23\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\
|
||||||
|
\x72\x64\x66\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
|
||||||
|
\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\
|
||||||
|
\x32\x2d\x72\x64\x66\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\
|
||||||
|
\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\
|
||||||
|
\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
|
||||||
|
\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\
|
||||||
|
\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\
|
||||||
|
\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\
|
||||||
|
\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\
|
||||||
|
\x6f\x64\x69\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\
|
||||||
|
\x70\x6f\x64\x69\x2e\x73\x6f\x75\x72\x63\x65\x66\x6f\x72\x67\x65\
|
||||||
|
\x2e\x6e\x65\x74\x2f\x44\x54\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\
|
||||||
|
\x69\x2d\x30\x2e\x64\x74\x64\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\
|
||||||
|
\x73\x3a\x69\x6e\x6b\x73\x63\x61\x70\x65\x3d\x22\x68\x74\x74\x70\
|
||||||
|
\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\
|
||||||
|
\x6f\x72\x67\x2f\x6e\x61\x6d\x65\x73\x70\x61\x63\x65\x73\x2f\x69\
|
||||||
|
\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x76\x65\x72\x73\
|
||||||
|
\x69\x6f\x6e\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x77\x69\x64\
|
||||||
|
\x74\x68\x3d\x22\x39\x30\x2e\x30\x30\x30\x30\x30\x30\x70\x74\x22\
|
||||||
|
\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x39\x30\x2e\x30\
|
||||||
|
\x30\x30\x30\x30\x30\x70\x74\x22\x0a\x20\x20\x20\x76\x69\x65\x77\
|
||||||
|
\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x39\x30\x2e\x30\x30\x30\x30\
|
||||||
|
\x30\x30\x20\x39\x30\x2e\x30\x30\x30\x30\x30\x30\x22\x0a\x20\x20\
|
||||||
|
\x20\x70\x72\x65\x73\x65\x72\x76\x65\x41\x73\x70\x65\x63\x74\x52\
|
||||||
|
\x61\x74\x69\x6f\x3d\x22\x78\x4d\x69\x64\x59\x4d\x69\x64\x20\x6d\
|
||||||
|
\x65\x65\x74\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x36\
|
||||||
|
\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\
|
||||||
|
\x63\x6e\x61\x6d\x65\x3d\x22\x69\x63\x6f\x6e\x73\x38\x2d\x6d\x61\
|
||||||
|
\x63\x6f\x73\x2d\x73\x63\x68\x6c\x69\x65\xc3\x9f\x65\x6e\x2d\x39\
|
||||||
|
\x30\x5f\x31\x5f\x2e\x73\x76\x67\x22\x0a\x20\x20\x20\x69\x6e\x6b\
|
||||||
|
\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\
|
||||||
|
\x2e\x30\x2e\x31\x20\x28\x31\x2e\x30\x2e\x31\x2b\x72\x37\x34\x29\
|
||||||
|
\x22\x3e\x0a\x20\x20\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x69\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\x61\
|
||||||
|
\x31\x32\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\
|
||||||
|
\x46\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\
|
||||||
|
\x6b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\
|
||||||
|
\x62\x6f\x75\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\
|
||||||
|
\x20\x3c\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\
|
||||||
|
\x65\x2f\x73\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\
|
||||||
|
\x72\x6d\x61\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\
|
||||||
|
\x63\x3a\x74\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\
|
||||||
|
\x20\x20\x72\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\
|
||||||
|
\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\
|
||||||
|
\x64\x63\x2f\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\
|
||||||
|
\x6c\x49\x6d\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\
|
||||||
|
\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\x20\
|
||||||
|
\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\x6d\
|
||||||
|
\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\x73\x31\x30\
|
||||||
|
\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\
|
||||||
|
\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\
|
||||||
|
\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\x66\
|
||||||
|
\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x63\
|
||||||
|
\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\x36\x36\x36\x22\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\x61\x63\x69\x74\
|
||||||
|
\x79\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x6f\x62\x6a\x65\x63\
|
||||||
|
\x74\x74\x6f\x6c\x65\x72\x61\x6e\x63\x65\x3d\x22\x31\x30\x22\x0a\
|
||||||
|
\x20\x20\x20\x20\x20\x67\x72\x69\x64\x74\x6f\x6c\x65\x72\x61\x6e\
|
||||||
|
\x63\x65\x3d\x22\x31\x30\x22\x0a\x20\x20\x20\x20\x20\x67\x75\x69\
|
||||||
|
\x64\x65\x74\x6f\x6c\x65\x72\x61\x6e\x63\x65\x3d\x22\x31\x30\x22\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\
|
||||||
|
\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x22\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\
|
||||||
|
\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\x20\
|
||||||
|
\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\
|
||||||
|
\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x39\x32\x30\x22\x0a\x20\x20\
|
||||||
|
\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\
|
||||||
|
\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x31\x30\x31\x35\x22\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6e\x61\x6d\x65\x64\x76\
|
||||||
|
\x69\x65\x77\x38\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\x77\x67\
|
||||||
|
\x72\x69\x64\x3d\x22\x66\x61\x6c\x73\x65\x22\x0a\x20\x20\x20\x20\
|
||||||
|
\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\
|
||||||
|
\x35\x2e\x39\x35\x38\x33\x33\x33\x33\x22\x0a\x20\x20\x20\x20\x20\
|
||||||
|
\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\x22\x35\x31\x2e\
|
||||||
|
\x35\x32\x39\x39\x35\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
|
||||||
|
\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\x35\x33\x2e\x31\x36\x38\x33\
|
||||||
|
\x32\x38\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
|
||||||
|
\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\
|
||||||
|
\x64\x6f\x77\x2d\x79\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\
|
||||||
|
\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\
|
||||||
|
\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x0a\x20\x20\x20\
|
||||||
|
\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\x72\x65\
|
||||||
|
\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x73\x76\x67\x36\x22\x20\
|
||||||
|
\x2f\x3e\x0a\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x74\x72\x61\
|
||||||
|
\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x74\x72\x61\x6e\x73\x6c\x61\x74\
|
||||||
|
\x65\x28\x30\x2e\x30\x30\x30\x30\x30\x30\x2c\x39\x30\x2e\x30\x30\
|
||||||
|
\x30\x30\x30\x30\x29\x20\x73\x63\x61\x6c\x65\x28\x30\x2e\x31\x30\
|
||||||
|
\x30\x30\x30\x30\x2c\x2d\x30\x2e\x31\x30\x30\x30\x30\x30\x29\x22\
|
||||||
|
\x0a\x20\x20\x20\x20\x20\x66\x69\x6c\x6c\x3d\x22\x23\x65\x37\x34\
|
||||||
|
\x63\x33\x63\x22\x0a\x20\x20\x20\x20\x20\x73\x74\x72\x6f\x6b\x65\
|
||||||
|
\x3d\x22\x6e\x6f\x6e\x65\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\
|
||||||
|
\x22\x67\x34\x22\x3e\x0a\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\
|
||||||
|
\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x33\x38\x31\x20\x38\
|
||||||
|
\x30\x30\x20\x63\x2d\x31\x34\x34\x20\x2d\x33\x30\x20\x2d\x32\x35\
|
||||||
|
\x34\x20\x2d\x31\x34\x35\x20\x2d\x32\x38\x32\x20\x2d\x32\x39\x33\
|
||||||
|
\x20\x2d\x34\x32\x20\x2d\x32\x33\x32\x20\x31\x37\x36\x20\x2d\x34\
|
||||||
|
\x35\x30\x20\x34\x30\x38\x20\x2d\x34\x30\x38\x20\x32\x33\x30\x20\
|
||||||
|
\x34\x33\x20\x33\x36\x31\x20\x32\x38\x31\x20\x32\x37\x30\x20\x34\
|
||||||
|
\x39\x33\x20\x2d\x36\x34\x20\x31\x34\x38\x20\x2d\x32\x33\x38\x20\
|
||||||
|
\x32\x34\x30\x20\x2d\x33\x39\x36\x20\x32\x30\x38\x7a\x20\x6d\x31\
|
||||||
|
\x36\x20\x2d\x32\x35\x32\x20\x6c\x35\x33\x20\x2d\x35\x32\x20\x35\
|
||||||
|
\x34\x20\x35\x33\x20\x63\x35\x35\x20\x35\x34\x20\x38\x37\x20\x36\
|
||||||
|
\x34\x20\x39\x34\x20\x32\x37\x20\x33\x20\x2d\x31\x32\x20\x2d\x31\
|
||||||
|
\x35\x20\x2d\x33\x38\x20\x2d\x34\x39\x20\x2d\x37\x32\x20\x6c\x2d\
|
||||||
|
\x35\x33\x20\x2d\x35\x34\x20\x35\x33\x20\x2d\x35\x34\x20\x63\x35\
|
||||||
|
\x34\x20\x2d\x35\x35\x20\x36\x34\x20\x2d\x38\x37\x20\x32\x37\x20\
|
||||||
|
\x2d\x39\x34\x20\x2d\x31\x32\x20\x2d\x33\x20\x2d\x33\x38\x20\x31\
|
||||||
|
\x35\x20\x2d\x37\x32\x20\x34\x39\x20\x6c\x2d\x35\x34\x20\x35\x33\
|
||||||
|
\x20\x2d\x35\x34\x20\x2d\x35\x33\x20\x63\x2d\x33\x34\x20\x2d\x33\
|
||||||
|
\x34\x20\x2d\x36\x30\x20\x2d\x35\x32\x20\x2d\x37\x32\x20\x2d\x34\
|
||||||
|
\x39\x20\x2d\x33\x37\x20\x37\x20\x2d\x32\x37\x20\x33\x39\x20\x32\
|
||||||
|
\x37\x20\x39\x34\x20\x6c\x35\x33\x20\x35\x34\x20\x2d\x35\x32\x20\
|
||||||
|
\x35\x33\x20\x63\x2d\x34\x39\x20\x34\x39\x20\x2d\x36\x31\x20\x37\
|
||||||
|
\x34\x20\x2d\x34\x35\x20\x39\x30\x20\x31\x36\x20\x31\x36\x20\x34\
|
||||||
|
\x31\x20\x34\x20\x39\x30\x20\x2d\x34\x35\x7a\x22\x0a\x20\x20\x20\
|
||||||
|
\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x32\x22\x0a\x20\
|
||||||
|
\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\
|
||||||
|
\x6c\x3a\x23\x66\x66\x66\x66\x66\x66\x22\x20\x2f\x3e\x0a\x20\x20\
|
||||||
|
\x3c\x2f\x67\x3e\x0a\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\
|
||||||
|
\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\x6c\x3a\x23\x38\
|
||||||
|
\x30\x38\x30\x38\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\
|
||||||
|
\x74\x68\x3a\x30\x2e\x31\x31\x38\x36\x37\x35\x22\x0a\x20\x20\x20\
|
||||||
|
\x20\x20\x64\x3d\x22\x6d\x20\x34\x32\x2e\x36\x32\x32\x36\x31\x2c\
|
||||||
|
\x37\x39\x2e\x35\x34\x31\x38\x39\x33\x20\x63\x20\x2d\x33\x2e\x31\
|
||||||
|
\x31\x36\x31\x36\x35\x2c\x2d\x31\x2e\x30\x32\x39\x36\x31\x32\x20\
|
||||||
|
\x2d\x33\x2e\x30\x35\x38\x38\x2c\x2d\x33\x2e\x33\x36\x36\x38\x30\
|
||||||
|
\x38\x20\x30\x2e\x31\x38\x38\x32\x35\x34\x2c\x2d\x37\x2e\x36\x36\
|
||||||
|
\x39\x39\x38\x39\x20\x31\x2e\x33\x39\x36\x34\x36\x39\x2c\x2d\x31\
|
||||||
|
\x2e\x38\x35\x30\x36\x38\x32\x20\x32\x2e\x37\x31\x36\x37\x39\x39\
|
||||||
|
\x2c\x2d\x33\x2e\x32\x38\x37\x33\x38\x37\x20\x37\x2e\x32\x38\x31\
|
||||||
|
\x38\x35\x33\x2c\x2d\x37\x2e\x39\x32\x33\x36\x38\x36\x20\x6c\x20\
|
||||||
|
\x33\x2e\x38\x38\x34\x39\x33\x33\x2c\x2d\x33\x2e\x39\x34\x35\x35\
|
||||||
|
\x36\x32\x20\x2d\x34\x2e\x35\x36\x34\x32\x34\x31\x2c\x2d\x34\x2e\
|
||||||
|
\x36\x35\x38\x33\x39\x34\x20\x63\x20\x2d\x36\x2e\x30\x38\x35\x35\
|
||||||
|
\x35\x2c\x2d\x36\x2e\x32\x31\x31\x30\x38\x35\x20\x2d\x37\x2e\x34\
|
||||||
|
\x33\x39\x37\x30\x39\x2c\x2d\x37\x2e\x37\x37\x35\x39\x33\x31\x20\
|
||||||
|
\x2d\x38\x2e\x35\x31\x32\x35\x35\x39\x2c\x2d\x39\x2e\x38\x33\x36\
|
||||||
|
\x39\x38\x36\x20\x2d\x31\x2e\x31\x31\x34\x30\x39\x31\x2c\x2d\x32\
|
||||||
|
\x2e\x31\x34\x30\x32\x38\x32\x20\x2d\x31\x2e\x30\x33\x35\x30\x35\
|
||||||
|
\x33\x2c\x2d\x33\x2e\x35\x35\x33\x39\x36\x34\x20\x30\x2e\x32\x36\
|
||||||
|
\x30\x37\x30\x38\x2c\x2d\x34\x2e\x36\x36\x33\x30\x38\x38\x20\x30\
|
||||||
|
\x2e\x37\x30\x38\x37\x38\x34\x2c\x2d\x30\x2e\x36\x30\x36\x36\x39\
|
||||||
|
\x32\x20\x31\x2e\x35\x38\x35\x35\x37\x34\x2c\x2d\x30\x2e\x38\x34\
|
||||||
|
\x37\x31\x20\x32\x2e\x34\x35\x33\x36\x34\x37\x2c\x2d\x30\x2e\x36\
|
||||||
|
\x37\x32\x37\x36\x36\x20\x31\x2e\x32\x38\x32\x35\x34\x32\x2c\x30\
|
||||||
|
\x2e\x32\x35\x37\x35\x37\x32\x20\x32\x2e\x38\x39\x33\x39\x38\x39\
|
||||||
|
\x2c\x31\x2e\x31\x37\x37\x35\x34\x36\x20\x34\x2e\x38\x36\x39\x36\
|
||||||
|
\x32\x31\x2c\x32\x2e\x37\x38\x30\x30\x36\x35\x20\x31\x2e\x34\x32\
|
||||||
|
\x38\x36\x35\x32\x2c\x31\x2e\x31\x35\x38\x38\x34\x20\x31\x2e\x37\
|
||||||
|
\x35\x38\x39\x37\x34\x2c\x31\x2e\x34\x36\x39\x39\x39\x39\x20\x36\
|
||||||
|
\x2e\x39\x32\x34\x37\x30\x31\x2c\x36\x2e\x35\x32\x32\x39\x38\x32\
|
||||||
|
\x20\x6c\x20\x34\x2e\x35\x39\x38\x33\x32\x33\x2c\x34\x2e\x34\x39\
|
||||||
|
\x37\x39\x36\x34\x20\x33\x2e\x39\x34\x36\x32\x39\x36\x2c\x2d\x33\
|
||||||
|
\x2e\x38\x38\x35\x36\x35\x35\x20\x63\x20\x35\x2e\x36\x38\x37\x34\
|
||||||
|
\x38\x38\x2c\x2d\x35\x2e\x36\x30\x30\x30\x39\x20\x37\x2e\x35\x30\
|
||||||
|
\x35\x32\x36\x2c\x2d\x37\x2e\x31\x38\x38\x37\x36\x31\x20\x39\x2e\
|
||||||
|
\x38\x33\x34\x37\x30\x31\x2c\x2d\x38\x2e\x35\x39\x35\x31\x39\x37\
|
||||||
|
\x20\x30\x2e\x39\x39\x35\x37\x32\x37\x2c\x2d\x30\x2e\x36\x30\x31\
|
||||||
|
\x31\x38\x35\x20\x32\x2e\x35\x36\x34\x37\x37\x35\x2c\x2d\x31\x2e\
|
||||||
|
\x31\x39\x30\x33\x38\x32\x20\x33\x2e\x31\x36\x36\x37\x30\x39\x2c\
|
||||||
|
\x2d\x31\x2e\x31\x38\x39\x31\x33\x38\x20\x31\x2e\x33\x32\x39\x35\
|
||||||
|
\x38\x39\x2c\x30\x2e\x30\x30\x32\x37\x20\x32\x2e\x32\x35\x38\x34\
|
||||||
|
\x37\x31\x2c\x30\x2e\x39\x32\x38\x31\x32\x36\x20\x32\x2e\x36\x33\
|
||||||
|
\x36\x30\x30\x38\x2c\x32\x2e\x36\x32\x36\x30\x36\x33\x20\x30\x2e\
|
||||||
|
\x31\x38\x34\x34\x32\x34\x2c\x30\x2e\x38\x32\x39\x34\x33\x34\x20\
|
||||||
|
\x30\x2e\x31\x31\x30\x32\x39\x2c\x31\x2e\x32\x34\x30\x37\x37\x36\
|
||||||
|
\x20\x2d\x30\x2e\x34\x32\x34\x38\x38\x36\x2c\x32\x2e\x33\x35\x37\
|
||||||
|
\x34\x39\x39\x20\x2d\x31\x2e\x31\x30\x34\x36\x39\x2c\x32\x2e\x33\
|
||||||
|
\x30\x35\x31\x20\x2d\x32\x2e\x38\x35\x31\x38\x31\x34\x2c\x34\x2e\
|
||||||
|
\x33\x30\x32\x35\x34\x34\x20\x2d\x31\x30\x2e\x36\x36\x35\x38\x37\
|
||||||
|
\x36\x2c\x31\x32\x2e\x31\x39\x34\x30\x33\x33\x20\x6c\x20\x2d\x32\
|
||||||
|
\x2e\x34\x39\x37\x31\x31\x38\x2c\x32\x2e\x35\x32\x31\x38\x36\x31\
|
||||||
|
\x20\x32\x2e\x35\x35\x36\x32\x37\x36\x2c\x32\x2e\x35\x38\x31\x31\
|
||||||
|
\x37\x35\x20\x63\x20\x37\x2e\x34\x37\x38\x39\x35\x2c\x37\x2e\x35\
|
||||||
|
\x35\x31\x37\x39\x39\x20\x39\x2e\x31\x38\x30\x34\x34\x37\x2c\x39\
|
||||||
|
\x2e\x35\x33\x33\x37\x30\x39\x20\x31\x30\x2e\x34\x34\x32\x30\x32\
|
||||||
|
\x36\x2c\x31\x32\x2e\x31\x36\x32\x39\x31\x32\x20\x31\x2e\x31\x31\
|
||||||
|
\x38\x30\x38\x33\x2c\x32\x2e\x33\x33\x30\x31\x34\x37\x20\x30\x2e\
|
||||||
|
\x38\x32\x34\x33\x34\x33\x2c\x33\x2e\x37\x33\x32\x36\x33\x31\x20\
|
||||||
|
\x2d\x30\x2e\x39\x34\x38\x33\x39\x35\x2c\x34\x2e\x35\x32\x38\x31\
|
||||||
|
\x39\x20\x2d\x31\x2e\x34\x36\x38\x33\x31\x37\x2c\x30\x2e\x36\x35\
|
||||||
|
\x38\x39\x34\x31\x20\x2d\x32\x2e\x34\x36\x33\x37\x33\x2c\x30\x2e\
|
||||||
|
\x35\x31\x37\x39\x35\x38\x20\x2d\x34\x2e\x32\x34\x36\x37\x39\x31\
|
||||||
|
\x2c\x2d\x30\x2e\x36\x30\x31\x34\x38\x32\x20\x2d\x32\x2e\x32\x33\
|
||||||
|
\x30\x38\x34\x33\x2c\x2d\x31\x2e\x34\x30\x30\x35\x36\x36\x20\x2d\
|
||||||
|
\x33\x2e\x31\x39\x35\x34\x35\x2c\x2d\x32\x2e\x32\x35\x33\x34\x37\
|
||||||
|
\x20\x2d\x39\x2e\x32\x30\x30\x36\x38\x33\x2c\x2d\x38\x2e\x31\x33\
|
||||||
|
\x35\x32\x32\x34\x20\x6c\x20\x2d\x34\x2e\x35\x39\x39\x37\x35\x33\
|
||||||
|
\x2c\x2d\x34\x2e\x35\x30\x35\x31\x37\x33\x20\x2d\x34\x2e\x35\x33\
|
||||||
|
\x38\x32\x34\x33\x2c\x34\x2e\x34\x33\x37\x39\x32\x31\x20\x63\x20\
|
||||||
|
\x2d\x35\x2e\x31\x32\x35\x35\x30\x39\x2c\x35\x2e\x30\x31\x32\x32\
|
||||||
|
\x30\x35\x20\x2d\x35\x2e\x34\x33\x36\x38\x35\x34\x2c\x35\x2e\x33\
|
||||||
|
\x30\x35\x31\x37\x31\x20\x2d\x36\x2e\x38\x39\x36\x37\x33\x32\x2c\
|
||||||
|
\x36\x2e\x34\x38\x39\x36\x31\x39\x20\x2d\x32\x2e\x37\x39\x33\x39\
|
||||||
|
\x38\x2c\x32\x2e\x32\x36\x36\x38\x35\x32\x20\x2d\x34\x2e\x35\x36\
|
||||||
|
\x39\x38\x35\x35\x2c\x33\x2e\x30\x33\x37\x36\x36\x37\x20\x2d\x35\
|
||||||
|
\x2e\x39\x34\x38\x37\x37\x39\x2c\x32\x2e\x35\x38\x32\x30\x35\x36\
|
||||||
|
\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\
|
||||||
|
\x68\x31\x36\x22\x0a\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\x66\
|
||||||
|
\x6f\x72\x6d\x3d\x22\x73\x63\x61\x6c\x65\x28\x30\x2e\x37\x35\x29\
|
||||||
|
\x22\x20\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
|
||||||
|
"
|
||||||
|
|
||||||
|
qt_resource_name = b"\
|
||||||
|
\x00\x04\
|
||||||
|
\x00\x07\xa7\xe3\
|
||||||
|
\x00\x74\
|
||||||
|
\x00\x61\x00\x67\x00\x73\
|
||||||
|
\x00\x08\
|
||||||
|
\x00\x2b\x61\x2c\
|
||||||
|
\x00\x66\
|
||||||
|
\x00\x69\x00\x6c\x00\x65\x00\x5f\x00\x75\x00\x72\x00\x6c\
|
||||||
|
\x00\x08\
|
||||||
|
\x05\xac\x9a\xc4\
|
||||||
|
\x00\x69\
|
||||||
|
\x00\x6e\x00\x74\x00\x65\x00\x72\x00\x6e\x00\x65\x00\x74\
|
||||||
|
\x00\x05\
|
||||||
|
\x00\x7b\x88\x98\
|
||||||
|
\x00\x74\
|
||||||
|
\x00\x72\x00\x61\x00\x73\x00\x68\
|
||||||
|
\x00\x08\
|
||||||
|
\x0a\xa5\xc4\xc5\
|
||||||
|
\x00\x61\
|
||||||
|
\x00\x64\x00\x64\x00\x5f\x00\x66\x00\x69\x00\x6c\x00\x65\
|
||||||
|
\x00\x0c\
|
||||||
|
\x06\x07\x35\x82\
|
||||||
|
\x00\x64\
|
||||||
|
\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x65\x00\x5f\x00\x68\x00\x6f\x00\x76\x00\x65\x00\x72\
|
||||||
|
\x00\x06\
|
||||||
|
\x06\xac\x2c\xa5\
|
||||||
|
\x00\x64\
|
||||||
|
\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x65\
|
||||||
|
"
|
||||||
|
|
||||||
|
qt_resource_struct_v1 = b"\
|
||||||
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
|
||||||
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x06\
|
||||||
|
\x00\x00\x00\x0e\x00\x02\x00\x00\x00\x03\x00\x00\x00\x03\
|
||||||
|
\x00\x00\x00\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x09\xc5\
|
||||||
|
\x00\x00\x00\x24\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
||||||
|
\x00\x00\x00\x4a\x00\x00\x00\x00\x00\x01\x00\x00\x0d\xc4\
|
||||||
|
\x00\x00\x00\x60\x00\x00\x00\x00\x00\x01\x00\x00\x16\x85\
|
||||||
|
\x00\x00\x00\x7e\x00\x00\x00\x00\x00\x01\x00\x00\x24\x1b\
|
||||||
|
"
|
||||||
|
|
||||||
|
qt_resource_struct_v2 = b"\
|
||||||
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
|
||||||
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x06\
|
||||||
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
|
\x00\x00\x00\x0e\x00\x02\x00\x00\x00\x03\x00\x00\x00\x03\
|
||||||
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
|
\x00\x00\x00\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x09\xc5\
|
||||||
|
\x00\x00\x01\x76\xa5\x2b\x29\x70\
|
||||||
|
\x00\x00\x00\x24\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
||||||
|
\x00\x00\x01\x76\xde\x95\xb2\x06\
|
||||||
|
\x00\x00\x00\x4a\x00\x00\x00\x00\x00\x01\x00\x00\x0d\xc4\
|
||||||
|
\x00\x00\x01\x76\xf6\x20\x78\x70\
|
||||||
|
\x00\x00\x00\x60\x00\x00\x00\x00\x00\x01\x00\x00\x16\x85\
|
||||||
|
\x00\x00\x01\x76\xd8\xe5\x6d\x99\
|
||||||
|
\x00\x00\x00\x7e\x00\x00\x00\x00\x00\x01\x00\x00\x24\x1b\
|
||||||
|
\x00\x00\x01\x76\xd8\xe2\x94\x13\
|
||||||
|
"
|
||||||
|
|
||||||
|
qt_version = [int(v) for v in QtCore.qVersion().split('.')]
|
||||||
|
if qt_version < [5, 8, 0]:
|
||||||
|
rcc_version = 1
|
||||||
|
qt_resource_struct = qt_resource_struct_v1
|
||||||
|
else:
|
||||||
|
rcc_version = 2
|
||||||
|
qt_resource_struct = qt_resource_struct_v2
|
||||||
|
|
||||||
|
def qInitResources():
|
||||||
|
QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
|
||||||
|
|
||||||
|
def qCleanupResources():
|
||||||
|
QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
|
||||||
|
|
||||||
|
qInitResources()
|
1066
athnos/window/window.py
Executable file
1066
athnos/window/window.py
Executable file
File diff suppressed because it is too large
Load Diff
32
database structure
Executable file
32
database structure
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
- tag
|
||||||
|
- id
|
||||||
|
- name (ignore case)
|
||||||
|
|
||||||
|
- source
|
||||||
|
- id
|
||||||
|
- path
|
||||||
|
- type
|
||||||
|
- audio
|
||||||
|
- series
|
||||||
|
- movie
|
||||||
|
- other
|
||||||
|
- name
|
||||||
|
- description
|
||||||
|
- season
|
||||||
|
- episode
|
||||||
|
|
||||||
|
- clip
|
||||||
|
- id
|
||||||
|
- .source_id
|
||||||
|
- path
|
||||||
|
- type
|
||||||
|
- audio
|
||||||
|
- video
|
||||||
|
- image
|
||||||
|
- name
|
||||||
|
- description
|
||||||
|
|
||||||
|
- item
|
||||||
|
- id
|
||||||
|
- .clip_id
|
||||||
|
- .tag_id
|
43
main.py
Executable file
43
main.py
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
__author = 'ByteDream'
|
||||||
|
__version__ = '1.0.0'
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
|
||||||
|
from athnos.window.window import Window
|
||||||
|
from athnos.utils import check_version
|
||||||
|
from athnos import config, logger
|
||||||
|
|
||||||
|
# sets the window style
|
||||||
|
if config['style'].lower() in (style.lower() for style in QtWidgets.QStyleFactory.keys()):
|
||||||
|
app.setStyle(config['style'])
|
||||||
|
logger.debug(f'Using style {config["style"]}')
|
||||||
|
else:
|
||||||
|
logger.warning(f'Tried to set style {config["style"]} but is not supported. Using {QtWidgets.QApplication.style().objectName()}')
|
||||||
|
|
||||||
|
database = config['database']
|
||||||
|
|
||||||
|
ui = Window(app, driver=database['driver'], name=database['name'], user=database['user'], password=database['password'], ip=database['ip'], port=database['port'])
|
||||||
|
ui.show()
|
||||||
|
|
||||||
|
version = check_version(__version__)
|
||||||
|
if version:
|
||||||
|
message = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Question, 'New release',
|
||||||
|
f'A new version has been released<br>'
|
||||||
|
f'Version: <a href="https://github.com/ByteDream/athnos/releases/tag/{version["name"]}"><strong>{version["name"]}</strong></a><br>')
|
||||||
|
do_not_show_again = QtWidgets.QCheckBox('Do not show again')
|
||||||
|
message.setCheckBox(do_not_show_again)
|
||||||
|
|
||||||
|
result = message.exec()
|
||||||
|
|
||||||
|
if do_not_show_again.isChecked():
|
||||||
|
config['updates_ignore'].append(version['name'])
|
||||||
|
config.write()
|
||||||
|
|
||||||
|
sys.exit(app.exec())
|
3
requirements.txt
Executable file
3
requirements.txt
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
PyQt5>=5.11.2
|
||||||
|
dreamutils>=0.1.1
|
||||||
|
filetype>=1.0.7
|
119
resources/abcd.py
Executable file
119
resources/abcd.py
Executable file
@ -0,0 +1,119 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Form implementation generated from reading ui file 'add_clip.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt5 UI code generator 5.15.1
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_Form(object):
|
||||||
|
def setupUi(self, Form):
|
||||||
|
Form.setObjectName("Form")
|
||||||
|
Form.resize(400, 313)
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.add_clip = QtWidgets.QLabel(Form)
|
||||||
|
self.add_clip.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.add_clip.setObjectName("add_clip")
|
||||||
|
self.verticalLayout.addWidget(self.add_clip)
|
||||||
|
self.line = QtWidgets.QFrame(Form)
|
||||||
|
self.line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||||
|
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
|
self.line.setObjectName("line")
|
||||||
|
self.verticalLayout.addWidget(self.line)
|
||||||
|
self.file_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.file_hlayout.setObjectName("file_hlayout")
|
||||||
|
self.clip_chooser = QtWidgets.QPushButton(Form)
|
||||||
|
self.clip_chooser.setObjectName("clip_chooser")
|
||||||
|
self.file_hlayout.addWidget(self.clip_chooser)
|
||||||
|
self.file_name_label = QtWidgets.QLabel(Form)
|
||||||
|
self.file_name_label.setObjectName("file_name_label")
|
||||||
|
self.file_hlayout.addWidget(self.file_name_label)
|
||||||
|
self.label = QtWidgets.QLabel(Form)
|
||||||
|
self.label.setMaximumSize(QtCore.QSize(16, 18))
|
||||||
|
self.label.setText("")
|
||||||
|
self.label.setPixmap(QtGui.QPixmap("../../trash-red.svg"))
|
||||||
|
self.label.setScaledContents(True)
|
||||||
|
self.label.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.file_hlayout.addWidget(self.label)
|
||||||
|
self.verticalLayout.addLayout(self.file_hlayout)
|
||||||
|
self.name_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.name_hlayout.setObjectName("name_hlayout")
|
||||||
|
self.name_label = QtWidgets.QLabel(Form)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.name_label.sizePolicy().hasHeightForWidth())
|
||||||
|
self.name_label.setSizePolicy(sizePolicy)
|
||||||
|
self.name_label.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
|
self.name_label.setBaseSize(QtCore.QSize(0, 0))
|
||||||
|
self.name_label.setObjectName("name_label")
|
||||||
|
self.name_hlayout.addWidget(self.name_label)
|
||||||
|
self.name_edit = QtWidgets.QLineEdit(Form)
|
||||||
|
self.name_edit.setObjectName("name_edit")
|
||||||
|
self.name_hlayout.addWidget(self.name_edit)
|
||||||
|
self.verticalLayout.addLayout(self.name_hlayout)
|
||||||
|
self.description_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.description_hlayout.setObjectName("description_hlayout")
|
||||||
|
self.description_label = QtWidgets.QLabel(Form)
|
||||||
|
self.description_label.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
|
self.description_label.setBaseSize(QtCore.QSize(0, 0))
|
||||||
|
self.description_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
|
||||||
|
self.description_label.setObjectName("description_label")
|
||||||
|
self.description_hlayout.addWidget(self.description_label)
|
||||||
|
self.description_edit = QtWidgets.QTextEdit(Form)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.description_edit.sizePolicy().hasHeightForWidth())
|
||||||
|
self.description_edit.setSizePolicy(sizePolicy)
|
||||||
|
self.description_edit.setObjectName("description_edit")
|
||||||
|
self.description_hlayout.addWidget(self.description_edit)
|
||||||
|
self.verticalLayout.addLayout(self.description_hlayout)
|
||||||
|
self.type_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.type_hlayout.setObjectName("type_hlayout")
|
||||||
|
self.type_label = QtWidgets.QLabel(Form)
|
||||||
|
self.type_label.setMinimumSize(QtCore.QSize(70, 0))
|
||||||
|
self.type_label.setBaseSize(QtCore.QSize(0, 0))
|
||||||
|
self.type_label.setObjectName("type_label")
|
||||||
|
self.type_hlayout.addWidget(self.type_label)
|
||||||
|
self.type_box = QtWidgets.QComboBox(Form)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.type_box.sizePolicy().hasHeightForWidth())
|
||||||
|
self.type_box.setSizePolicy(sizePolicy)
|
||||||
|
self.type_box.setFocusPolicy(QtCore.Qt.WheelFocus)
|
||||||
|
self.type_box.setObjectName("type_box")
|
||||||
|
self.type_hlayout.addWidget(self.type_box)
|
||||||
|
self.verticalLayout.addLayout(self.type_hlayout)
|
||||||
|
self.save_new_hlayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.save_new_hlayout.setObjectName("save_new_hlayout")
|
||||||
|
self.save_button = QtWidgets.QPushButton(Form)
|
||||||
|
self.save_button.setObjectName("save_button")
|
||||||
|
self.save_new_hlayout.addWidget(self.save_button)
|
||||||
|
self.new_button = QtWidgets.QPushButton(Form)
|
||||||
|
self.new_button.setObjectName("new_button")
|
||||||
|
self.save_new_hlayout.addWidget(self.new_button)
|
||||||
|
self.verticalLayout.addLayout(self.save_new_hlayout)
|
||||||
|
|
||||||
|
self.retranslateUi(Form)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||||
|
|
||||||
|
def retranslateUi(self, Form):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
Form.setWindowTitle(_translate("Form", "Form"))
|
||||||
|
self.add_clip.setText(_translate("Form", "Add clip"))
|
||||||
|
self.clip_chooser.setText(_translate("Form", "Choose file"))
|
||||||
|
self.file_name_label.setText(_translate("Form", "No file selected"))
|
||||||
|
self.name_label.setText(_translate("Form", "Name"))
|
||||||
|
self.description_label.setText(_translate("Form", "Description"))
|
||||||
|
self.type_label.setText(_translate("Form", "Type"))
|
||||||
|
self.save_button.setText(_translate("Form", "Save"))
|
||||||
|
self.new_button.setText(_translate("Form", "New"))
|
361
resources/add_clip.ui
Executable file
361
resources/add_clip.ui
Executable file
@ -0,0 +1,361 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>469</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Add clip</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="add_clip">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add clip</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="name_description_frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="file_or_url_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="file_or_url_edit">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>File or url...</string>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="file_chooser">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="sizeIncrement">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Choose file</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="name_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="name_label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="baseSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="name_edit">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="description_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="description_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="baseSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Description</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="description_edit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="type_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="type_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="baseSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Type</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="type_box">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::WheelFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Audio</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Image</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Video</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Other</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="tags_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="tags_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Tags</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="tags_edit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>290</width>
|
||||||
|
<height>83</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="choose_source_button">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Select source</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="choose_source_label">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>No source selected</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="save_new_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="save_button">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+S</string>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="new_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>New</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="autoRepeat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="autoExclusive">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
257
resources/add_source.ui
Executable file
257
resources/add_source.ui
Executable file
@ -0,0 +1,257 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>452</width>
|
||||||
|
<height>400</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Add source</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="add_source_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add source</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="file_or_url_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="file_or_url_edit">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>File or url...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="file_chooser">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="sizeIncrement">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Choose file</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+O</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="type_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="type_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Type</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="type_box">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Audio</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Movie</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Series</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Other</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="from_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="name_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="name_edit">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="season_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Season</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="season_edit">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="episode_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Episode</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="episode_edit">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="description_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="description_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Description</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="description_edit">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="save_new_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="save_button">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+S</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="new_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>New</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+N</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
125
resources/clipbase.sql
Executable file
125
resources/clipbase.sql
Executable file
@ -0,0 +1,125 @@
|
|||||||
|
-- MariaDB dump 10.18 Distrib 10.5.8-MariaDB, for debian-linux-gnu (x86_64)
|
||||||
|
--
|
||||||
|
-- Host: localhost Database: athnos
|
||||||
|
-- ------------------------------------------------------
|
||||||
|
-- Server version 10.5.8-MariaDB-3
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8mb4 */;
|
||||||
|
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||||
|
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||||
|
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||||
|
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||||
|
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||||
|
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `clip`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `clip`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!40101 SET character_set_client = utf8 */;
|
||||||
|
CREATE TABLE `clip` (
|
||||||
|
`id` int(10) unsigned DEFAULT NULL,
|
||||||
|
`source_id` int(10) unsigned DEFAULT NULL,
|
||||||
|
`path` text DEFAULT NULL,
|
||||||
|
`type` smallint(1) DEFAULT NULL,
|
||||||
|
`name` tinytext DEFAULT NULL,
|
||||||
|
`description` text DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `clip`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `clip` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `clip` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `clip` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `item`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `item`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!40101 SET character_set_client = utf8 */;
|
||||||
|
CREATE TABLE `item` (
|
||||||
|
`id` int(10) unsigned DEFAULT NULL,
|
||||||
|
`clip_id` int(10) unsigned DEFAULT NULL,
|
||||||
|
`tag_id` int(10) unsigned DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `item`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `item` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `item` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `item` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `source`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `source`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!40101 SET character_set_client = utf8 */;
|
||||||
|
CREATE TABLE `source` (
|
||||||
|
`id` int(10) unsigned DEFAULT NULL,
|
||||||
|
`path` text DEFAULT NULL,
|
||||||
|
`type` smallint(1) unsigned DEFAULT NULL,
|
||||||
|
`name` tinytext DEFAULT NULL,
|
||||||
|
`description` text DEFAULT NULL,
|
||||||
|
`season` tinytext DEFAULT NULL,
|
||||||
|
`episode` tinytext DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `source`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `source` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `source` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `source` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `tag`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `tag`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!40101 SET character_set_client = utf8 */;
|
||||||
|
CREATE TABLE `tag` (
|
||||||
|
`id` int(10) unsigned DEFAULT NULL,
|
||||||
|
`name` varchar(255) DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `tag`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `tag` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `tag` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `tag` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||||
|
|
||||||
|
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||||
|
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||||
|
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
|
-- Dump completed on 2020-12-21 20:34:41
|
147
resources/clips.json
Executable file
147
resources/clips.json
Executable file
@ -0,0 +1,147 @@
|
|||||||
|
{
|
||||||
|
"move": false,
|
||||||
|
"copy": false,
|
||||||
|
"root_dir": "/home/bytedream/backup/athnos/resources",
|
||||||
|
"clips": [
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"type": "",
|
||||||
|
"path": "",
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"season": "",
|
||||||
|
"episode": ""
|
||||||
|
},
|
||||||
|
"path": "/home/bytedream/backup/athnos/resources/athnos.qrc",
|
||||||
|
"type": 0,
|
||||||
|
"name": "athnos",
|
||||||
|
"description": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"type": "",
|
||||||
|
"path": "",
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"season": "",
|
||||||
|
"episode": ""
|
||||||
|
},
|
||||||
|
"path": "/home/bytedream/backup/athnos/resources/show_source.ui",
|
||||||
|
"type": 0,
|
||||||
|
"name": "show_source",
|
||||||
|
"description": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"type": "",
|
||||||
|
"path": "",
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"season": "",
|
||||||
|
"episode": ""
|
||||||
|
},
|
||||||
|
"path": "/home/bytedream/backup/athnos/resources/add_clip.ui",
|
||||||
|
"type": 0,
|
||||||
|
"name": "add_clip",
|
||||||
|
"description": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"type": "",
|
||||||
|
"path": "",
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"season": "",
|
||||||
|
"episode": ""
|
||||||
|
},
|
||||||
|
"path": "/home/bytedream/backup/athnos/resources/add_source.ui",
|
||||||
|
"type": 0,
|
||||||
|
"name": "add_source",
|
||||||
|
"description": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"type": "",
|
||||||
|
"path": "",
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"season": "",
|
||||||
|
"episode": ""
|
||||||
|
},
|
||||||
|
"path": "/home/bytedream/backup/athnos/resources/main_window.ui",
|
||||||
|
"type": 0,
|
||||||
|
"name": "main_window",
|
||||||
|
"description": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"type": "",
|
||||||
|
"path": "",
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"season": "",
|
||||||
|
"episode": ""
|
||||||
|
},
|
||||||
|
"path": "/home/bytedream/backup/athnos/resources/connect_to_database.ui",
|
||||||
|
"type": 0,
|
||||||
|
"name": "connect_to_database",
|
||||||
|
"description": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"type": "",
|
||||||
|
"path": "",
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"season": "",
|
||||||
|
"episode": ""
|
||||||
|
},
|
||||||
|
"path": "/home/bytedream/backup/athnos/resources/athnos.sql",
|
||||||
|
"type": 0,
|
||||||
|
"name": "athnos",
|
||||||
|
"description": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"type": "",
|
||||||
|
"path": "",
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"season": "",
|
||||||
|
"episode": ""
|
||||||
|
},
|
||||||
|
"path": "/home/bytedream/backup/athnos/resources/abcd.py",
|
||||||
|
"type": 0,
|
||||||
|
"name": "abcd",
|
||||||
|
"description": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"type": "",
|
||||||
|
"path": "",
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"season": "",
|
||||||
|
"episode": ""
|
||||||
|
},
|
||||||
|
"path": "/home/bytedream/backup/athnos/resources/__pycache__/abcd.cpython-39.pyc",
|
||||||
|
"type": 0,
|
||||||
|
"name": "abcd.cpython-39",
|
||||||
|
"description": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"type": "",
|
||||||
|
"path": "",
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"season": "",
|
||||||
|
"episode": ""
|
||||||
|
},
|
||||||
|
"path": "/home/bytedream/backup/athnos/resources/images/trash-red.svg",
|
||||||
|
"type": 0,
|
||||||
|
"name": "trash-red",
|
||||||
|
"description": "a"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
381
resources/connect_to_database.ui
Executable file
381
resources/connect_to_database.ui
Executable file
@ -0,0 +1,381 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>490</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Connect to database</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetDefaultConstraint</enum>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="database_type_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="database_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Database</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>13</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="database_type">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="database_file_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="database_file">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>118</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>130</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Database file</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="file_name_label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>No file selected</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="file_utils_hlayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="delete_file_button">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/file_url/trash</normaloff>:/file_url/trash</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>18</width>
|
||||||
|
<height>18</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="default">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="add_file_button">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="resources.qrc">
|
||||||
|
<normaloff>:/file_url/add_file</normaloff>:/file_url/add_file</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>18</width>
|
||||||
|
<height>18</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="database_settings_frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="database_ip_layout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="database_ip_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Database IP</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="database_ip_edit">
|
||||||
|
<property name="text">
|
||||||
|
<string>127.0.0.1</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="user_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="user_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>User</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="user_edit">
|
||||||
|
<property name="text">
|
||||||
|
<string>root</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="password_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="password_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Password</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="password_edit">
|
||||||
|
<property name="inputMethodHints">
|
||||||
|
<set>Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText|Qt::ImhSensitiveData</set>
|
||||||
|
</property>
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="port_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="port_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Port</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="port_edit">
|
||||||
|
<property name="text">
|
||||||
|
<string>3306</string>
|
||||||
|
</property>
|
||||||
|
<property name="frame">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="database_name_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="database_name_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Database name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="database_name_edit">
|
||||||
|
<property name="text">
|
||||||
|
<string>athnos</string>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="show_databases_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show available names</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListView" name="databases_view">
|
||||||
|
<property name="inputMethodHints">
|
||||||
|
<set>Qt::ImhNone</set>
|
||||||
|
</property>
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="modelColumn">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="test_save_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="test_connection_button">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="whatsThis">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Test connection</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="save_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="resources.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
32
resources/export.ui
Executable file
32
resources/export.ui
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Export</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QCheckBox" name="checkBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>110</x>
|
||||||
|
<y>180</y>
|
||||||
|
<width>88</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Inclue files</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
1
resources/images/add-file.svg
Executable file
1
resources/images/add-file.svg
Executable file
@ -0,0 +1 @@
|
|||||||
|
<svg height="682pt" viewBox="-69 -21 682 682.66669" width="682pt" xmlns="http://www.w3.org/2000/svg"><path d="m507.886719 469.332031h-158.71875c-5.894531 0-10.667969 4.773438-10.667969 10.667969 0 5.890625 4.773438 10.664062 10.667969 10.664062h158.71875c18.136719.21875 33.027343-14.285156 33.277343-32.425781v-319.46875c.003907-2.5625-.914062-5.042969-2.589843-6.984375l-110.722657-128.097656c-2.023437-2.34375-4.972656-3.69140625-8.074218-3.68359375h-240c-18.132813-.22265625-33.027344 14.28515575-33.273438 32.42187475v255.574219c0 5.886719 4.773438 10.664062 10.660156 10.664062 5.894532 0 10.671876-4.777343 10.671876-10.664062v-255.574219c.253906-6.355469 5.589843-11.308593 11.941406-11.089843h221.933594l.792968 112.175781c.136719 14.644531 12.023438 26.445312 26.664063 26.488281h90.664062v298.238281c-.253906 6.351563-5.59375 11.308594-11.945312 11.09375zm-84.050781-336-.695313-102.546875 93.167969 107.878906h-87.140625c-2.945313 0-5.332031-2.386718-5.332031-5.332031zm0 0"/><path d="m130.5 640h53.335938c14.726562 0 26.664062-11.945312 26.664062-26.671875v-79.996094h80c14.726562 0 26.664062-11.941406 26.664062-26.667969v-53.332031c0-14.726562-11.9375-26.667969-26.664062-26.667969h-80v-80c0-14.722656-11.9375-26.664062-26.664062-26.664062h-53.335938c-14.726562 0-26.664062 11.941406-26.664062 26.664062v80h-80c-14.730469 0-26.667969 11.941407-26.667969 26.667969v53.332031c0 14.726563 11.9375 26.667969 26.667969 26.667969h80v79.996094c0 14.726563 11.9375 26.671875 26.664062 26.671875zm-112-133.335938v-53.332031c0-2.945312 2.386719-5.332031 5.335938-5.332031h90.664062c5.894531 0 10.667969-4.777344 10.667969-10.671875v-90.664063c0-2.941406 2.390625-5.328124 5.332031-5.328124h53.335938c2.945312 0 5.332031 2.386718 5.332031 5.328124v90.664063c0 5.894531 4.773437 10.671875 10.664062 10.671875h90.667969c2.945312 0 5.332031 2.386719 5.332031 5.332031v53.332031c0 2.945313-2.386719 5.332032-5.332031 5.332032h-90.667969c-5.890625 0-10.664062 4.777344-10.664062 10.671875v90.660156c0 2.945313-2.386719 5.332031-5.332031 5.332031h-53.335938c-2.941406 0-5.332031-2.386718-5.332031-5.332031v-90.660156c0-5.894531-4.773438-10.671875-10.667969-10.671875h-90.664062c-2.949219 0-5.335938-2.386719-5.335938-5.332032zm0 0"/></svg>
|
After Width: | Height: | Size: 2.2 KiB |
69
resources/images/hover.svg
Executable file
69
resources/images/hover.svg
Executable file
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.0"
|
||||||
|
width="90.000000pt"
|
||||||
|
height="90.000000pt"
|
||||||
|
viewBox="0 0 90.000000 90.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet"
|
||||||
|
id="svg6"
|
||||||
|
sodipodi:docname="hover.svg"
|
||||||
|
inkscape:version="1.0.1 (1.0.1+r74)">
|
||||||
|
<metadata
|
||||||
|
id="metadata12">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs10" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1015"
|
||||||
|
id="namedview8"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.0532945"
|
||||||
|
inkscape:cx="503.80603"
|
||||||
|
inkscape:cy="73.381817"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg6"
|
||||||
|
inkscape:document-rotation="0" />
|
||||||
|
<g
|
||||||
|
transform="translate(0.000000,90.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#e74c3c"
|
||||||
|
stroke="none"
|
||||||
|
id="g4"
|
||||||
|
style="fill:#ff0000">
|
||||||
|
<path
|
||||||
|
d="M381 800 c-144 -30 -254 -145 -282 -293 -42 -232 176 -450 408 -408 230 43 361 281 270 493 -64 148 -238 240 -396 208z m16 -252 l53 -52 54 53 c55 54 87 64 94 27 3 -12 -15 -38 -49 -72 l-53 -54 53 -54 c54 -55 64 -87 27 -94 -12 -3 -38 15 -72 49 l-54 53 -54 -53 c-34 -34 -60 -52 -72 -49 -37 7 -27 39 27 94 l53 54 -52 53 c-49 49 -61 74 -45 90 16 16 41 4 90 -45z"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#ff0000" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;stroke-width:0.118675"
|
||||||
|
d="m 42.62261,79.541893 c -3.116165,-1.029612 -3.0588,-3.366808 0.188254,-7.669989 1.396469,-1.850682 2.716799,-3.287387 7.281853,-7.923686 l 3.884933,-3.945562 -4.564241,-4.658394 c -6.08555,-6.211085 -7.439709,-7.775931 -8.512559,-9.836986 -1.114091,-2.140282 -1.035053,-3.553964 0.260708,-4.663088 0.708784,-0.606692 1.585574,-0.8471 2.453647,-0.672766 1.282542,0.257572 2.893989,1.177546 4.869621,2.780065 1.428652,1.15884 1.758974,1.469999 6.924701,6.522982 l 4.598323,4.497964 3.946296,-3.885655 c 5.687488,-5.60009 7.50526,-7.188761 9.834701,-8.595197 0.995727,-0.601185 2.564775,-1.190382 3.166709,-1.189138 1.329589,0.0027 2.258471,0.928126 2.636008,2.626063 0.184424,0.829434 0.11029,1.240776 -0.424886,2.357499 -1.10469,2.3051 -2.851814,4.302544 -10.665876,12.194033 l -2.497118,2.521861 2.556276,2.581175 c 7.47895,7.551799 9.180447,9.533709 10.442026,12.162912 1.118083,2.330147 0.824343,3.732631 -0.948395,4.52819 -1.468317,0.658941 -2.46373,0.517958 -4.246791,-0.601482 -2.230843,-1.400566 -3.19545,-2.25347 -9.200683,-8.135224 l -4.599753,-4.505173 -4.538243,4.437921 c -5.125509,5.012205 -5.436854,5.305171 -6.896732,6.489619 -2.79398,2.266852 -4.569855,3.037667 -5.948779,2.582056 z"
|
||||||
|
id="path16"
|
||||||
|
transform="scale(0.75)" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
61
resources/images/internet.svg
Executable file
61
resources/images/internet.svg
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M472.178,34.62H39.822C17.864,34.62,0,52.484,0,74.442c0,17.955,0,345.234,0,363.116
|
||||||
|
c0,21.958,17.864,39.822,39.822,39.822h432.356c21.958,0,39.822-17.864,39.822-39.822c0-17.89,0-345.167,0-363.116
|
||||||
|
C512,52.484,494.136,34.62,472.178,34.62z M477.867,437.557c0,3.137-2.552,5.689-5.689,5.689H39.822
|
||||||
|
c-3.137,0-5.689-2.552-5.689-5.689V153.838h443.733V437.557z M477.867,119.705H34.133V74.442c0-3.137,2.552-5.689,5.689-5.689
|
||||||
|
h432.356c3.137,0,5.689,2.552,5.689,5.689V119.705z"/>
|
||||||
|
<circle cx="71.805" cy="94.23" r="12.836"/>
|
||||||
|
<circle cx="112.959" cy="94.23" r="12.836"/>
|
||||||
|
<circle cx="154.112" cy="94.23" r="12.836"/>
|
||||||
|
<path d="M81.581,334.442c4.44,13.701,22.872,16.101,30.636,3.9l10.454-16.432l10.454,16.432
|
||||||
|
c7.744,12.169,26.195,9.801,30.636-3.9l19.857-61.278c2.906-8.967-2.008-18.591-10.975-21.497
|
||||||
|
c-8.971-2.906-18.591,2.009-21.497,10.975l-8.681,26.791l-5.393-8.478c-6.695-10.52-22.094-10.538-28.801,0l-5.392,8.478
|
||||||
|
l-8.681-26.79c-2.906-8.966-12.526-13.882-21.497-10.975c-8.967,2.906-13.88,12.529-10.975,21.496L81.581,334.442z"/>
|
||||||
|
<path d="M214.911,334.442c4.446,13.72,22.905,16.052,30.636,3.9L256,321.911l10.454,16.432c7.762,12.2,26.196,9.8,30.636-3.9
|
||||||
|
l19.855-61.278c2.906-8.967-2.008-18.59-10.975-21.496c-8.974-2.907-18.591,2.008-21.497,10.975l-8.681,26.79l-5.392-8.478
|
||||||
|
c-6.695-10.52-22.094-10.538-28.801,0l-5.392,8.478l-8.681-26.79c-2.905-8.966-12.527-13.882-21.496-10.975
|
||||||
|
c-8.967,2.906-13.88,12.529-10.975,21.496L214.911,334.442z"/>
|
||||||
|
<path d="M348.241,334.442c4.446,13.72,22.905,16.051,30.636,3.9l10.454-16.432l10.454,16.432c7.762,12.2,26.195,9.8,30.636-3.9
|
||||||
|
l19.855-61.278c2.906-8.967-2.008-18.59-10.975-21.496c-8.973-2.907-18.591,2.008-21.496,10.975l-8.681,26.79l-5.392-8.478
|
||||||
|
c-6.695-10.52-22.095-10.538-28.801,0l-5.393,8.478l-8.681-26.791c-2.906-8.966-12.531-13.881-21.497-10.975
|
||||||
|
c-8.967,2.906-13.88,12.53-10.974,21.497L348.241,334.442z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
66
resources/images/normal.svg
Executable file
66
resources/images/normal.svg
Executable file
@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.0"
|
||||||
|
width="90.000000pt"
|
||||||
|
height="90.000000pt"
|
||||||
|
viewBox="0 0 90.000000 90.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet"
|
||||||
|
id="svg6"
|
||||||
|
sodipodi:docname="icons8-macos-schließen-90_1_.svg"
|
||||||
|
inkscape:version="1.0.1 (1.0.1+r74)">
|
||||||
|
<metadata
|
||||||
|
id="metadata12">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs10" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1015"
|
||||||
|
id="namedview8"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="5.9583333"
|
||||||
|
inkscape:cx="51.52995"
|
||||||
|
inkscape:cy="53.168328"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg6" />
|
||||||
|
<g
|
||||||
|
transform="translate(0.000000,90.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#e74c3c"
|
||||||
|
stroke="none"
|
||||||
|
id="g4">
|
||||||
|
<path
|
||||||
|
d="M381 800 c-144 -30 -254 -145 -282 -293 -42 -232 176 -450 408 -408 230 43 361 281 270 493 -64 148 -238 240 -396 208z m16 -252 l53 -52 54 53 c55 54 87 64 94 27 3 -12 -15 -38 -49 -72 l-53 -54 53 -54 c54 -55 64 -87 27 -94 -12 -3 -38 15 -72 49 l-54 53 -54 -53 c-34 -34 -60 -52 -72 -49 -37 7 -27 39 27 94 l53 54 -52 53 c-49 49 -61 74 -45 90 16 16 41 4 90 -45z"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#ffffff" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
style="fill:#808080;stroke-width:0.118675"
|
||||||
|
d="m 42.62261,79.541893 c -3.116165,-1.029612 -3.0588,-3.366808 0.188254,-7.669989 1.396469,-1.850682 2.716799,-3.287387 7.281853,-7.923686 l 3.884933,-3.945562 -4.564241,-4.658394 c -6.08555,-6.211085 -7.439709,-7.775931 -8.512559,-9.836986 -1.114091,-2.140282 -1.035053,-3.553964 0.260708,-4.663088 0.708784,-0.606692 1.585574,-0.8471 2.453647,-0.672766 1.282542,0.257572 2.893989,1.177546 4.869621,2.780065 1.428652,1.15884 1.758974,1.469999 6.924701,6.522982 l 4.598323,4.497964 3.946296,-3.885655 c 5.687488,-5.60009 7.50526,-7.188761 9.834701,-8.595197 0.995727,-0.601185 2.564775,-1.190382 3.166709,-1.189138 1.329589,0.0027 2.258471,0.928126 2.636008,2.626063 0.184424,0.829434 0.11029,1.240776 -0.424886,2.357499 -1.10469,2.3051 -2.851814,4.302544 -10.665876,12.194033 l -2.497118,2.521861 2.556276,2.581175 c 7.47895,7.551799 9.180447,9.533709 10.442026,12.162912 1.118083,2.330147 0.824343,3.732631 -0.948395,4.52819 -1.468317,0.658941 -2.46373,0.517958 -4.246791,-0.601482 -2.230843,-1.400566 -3.19545,-2.25347 -9.200683,-8.135224 l -4.599753,-4.505173 -4.538243,4.437921 c -5.125509,5.012205 -5.436854,5.305171 -6.896732,6.489619 -2.79398,2.266852 -4.569855,3.037667 -5.948779,2.582056 z"
|
||||||
|
id="path16"
|
||||||
|
transform="scale(0.75)" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
8
resources/images/trash-red.svg
Executable file
8
resources/images/trash-red.svg
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="448" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<title>trash-red</title>
|
||||||
|
<g>
|
||||||
|
<title>Layer 1</title>
|
||||||
|
<path fill="#ff0000" id="svg_1" d="m192,188l0,216c0,6.627 -5.373,12 -12,12l-24,0c-6.627,0 -12,-5.373 -12,-12l0,-216c0,-6.627 5.373,-12 12,-12l24,0c6.627,0 12,5.373 12,12zm100,-12l-24,0c-6.627,0 -12,5.373 -12,12l0,216c0,6.627 5.373,12 12,12l24,0c6.627,0 12,-5.373 12,-12l0,-216c0,-6.627 -5.373,-12 -12,-12zm132,-96c13.255,0 24,10.745 24,24l0,12c0,6.627 -5.373,12 -12,12l-20,0l0,336c0,26.51 -21.49,48 -48,48l-288,0c-26.51,0 -48,-21.49 -48,-48l0,-336l-20,0c-6.627,0 -12,-5.373 -12,-12l0,-12c0,-13.255 10.745,-24 24,-24l74.411,0l34.018,-56.696a48,48 0 0 1 41.16,-23.304l100.823,0a48,48 0 0 1 41.16,23.304l34.017,56.696l74.411,0zm-269.611,0l139.223,0l-17.452,-29.087a6,6 0 0 0 -5.145,-2.913l-94.028,0a6,6 0 0 0 -5.145,2.913l-17.453,29.087zm213.611,48l-288,0l0,330a6,6 0 0 0 6,6l276,0a6,6 0 0 0 6,-6l0,-330z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1019 B |
908
resources/main_window.ui
Executable file
908
resources/main_window.ui
Executable file
@ -0,0 +1,908 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>923</width>
|
||||||
|
<height>684</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Athnos</string>
|
||||||
|
</property>
|
||||||
|
<property name="tabShape">
|
||||||
|
<enum>QTabWidget::Rounded</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="main_splitter">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="opaqueResize">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget">
|
||||||
|
<layout class="QVBoxLayout" name="search_vlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="clip_hlayout">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QGroupBox {border: 1px solid grey; margin-top: 0.5em; font: 12px consolas;} QGroupBox::title {top: -6px; left: 10px}</string>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Search</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>5</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="search_box_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="search_input">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="filter_box">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="currentText">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="clip_view">
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::DefaultContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoScroll">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="dragEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QSplitter" name="clip_source_splitter">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QGroupBox" name="clip_group_box">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QGroupBox {border: 1px solid grey; margin-top: 0.5em; font: 12px consolas;} QGroupBox::title {top: -6px; left: 10px}</string>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Clip</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>5</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="file_url_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="file_url_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>File / URL</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="file_url_edit"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="extended_view_clip_line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="name_hlayout">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetDefaultConstraint</enum>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="name_label">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="name_edit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="description_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="description_label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Description</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="description_edit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="type_hlayout">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetDefaultConstraint</enum>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="type_label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Type</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="type_box">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="editable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="currentText">
|
||||||
|
<string>Other</string>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="duplicatesEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText" stdset="0">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Audio</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Image</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Video</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Other</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="tags_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="tags_label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Tags</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="tags_edit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>483</width>
|
||||||
|
<height>83</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="editing_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="save_button">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>15</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="enable_editing_check_box">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable editing</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>15</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="delete_button">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QGroupBox" name="source_group_box">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QGroupBox {border: 1px solid grey; margin-top: 0.5em; font: 12px consolas;} QGroupBox::title {top: -6px; left: 10px}</string>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Source</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>5</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="from_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="from_label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>From</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="source_name">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>7</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="season_label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Season</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="source_season">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="baseSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_5">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>7</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="episode_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Episode</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="source_episode">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="baseSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="source_descriptio_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="source_description_label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Description</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="source_description_edit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="source_type_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="source_type_label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>70</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Type</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="source_type_box">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Audio</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Movie</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Series</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Other</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="edit_change_hlayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="edit_source_button">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit source</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="change_source_button">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Change source</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>923</width>
|
||||||
|
<height>30</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="settings_menu">
|
||||||
|
<property name="title">
|
||||||
|
<string>Settings</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="style_menu">
|
||||||
|
<property name="title">
|
||||||
|
<string>Style</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="update_menu">
|
||||||
|
<property name="title">
|
||||||
|
<string>Updates</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="update_message_menu">
|
||||||
|
<property name="title">
|
||||||
|
<string>Update message</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="on_major_update"/>
|
||||||
|
<addaction name="on_minor_update"/>
|
||||||
|
<addaction name="on_patch"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="check_for_updates_on_startup"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="update_message_menu"/>
|
||||||
|
<addaction name="check_for_updates"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="connect_to_database"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="style_menu"/>
|
||||||
|
<addaction name="update_menu"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuHelp">
|
||||||
|
<property name="title">
|
||||||
|
<string>Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="about"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="file_menu">
|
||||||
|
<property name="title">
|
||||||
|
<string>File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="file_import"/>
|
||||||
|
<addaction name="file_export"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="add_clip"/>
|
||||||
|
<addaction name="add_source"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="close_window"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="file_menu"/>
|
||||||
|
<addaction name="settings_menu"/>
|
||||||
|
<addaction name="menuHelp"/>
|
||||||
|
</widget>
|
||||||
|
<action name="connect_to_database">
|
||||||
|
<property name="text">
|
||||||
|
<string>Connect to database...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="check_for_updates_on_startup">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Check for updates on startup</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="check_for_updates">
|
||||||
|
<property name="text">
|
||||||
|
<string>Check for updates...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="on_major_update">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>On major update</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="on_minor_update">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>On minor update</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="on_patch">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>On patch</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="about">
|
||||||
|
<property name="text">
|
||||||
|
<string>About</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="file_import">
|
||||||
|
<property name="text">
|
||||||
|
<string>Import...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="file_export">
|
||||||
|
<property name="text">
|
||||||
|
<string>Export...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="close_window">
|
||||||
|
<property name="text">
|
||||||
|
<string>Close</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="add_clip">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add clip...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="add_source">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add source...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
11
resources/resources.qrc
Executable file
11
resources/resources.qrc
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/tags">
|
||||||
|
<file alias="delete_hover">images/hover.svg</file>
|
||||||
|
<file alias="delete">images/normal.svg</file>
|
||||||
|
</qresource>
|
||||||
|
<qresource prefix="/file_url">
|
||||||
|
<file alias="internet">images/internet.svg</file>
|
||||||
|
<file alias="trash">images/trash-red.svg</file>
|
||||||
|
<file alias="add_file">images/add-file.svg</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
120
resources/show_source.ui
Executable file
120
resources/show_source.ui
Executable file
@ -0,0 +1,120 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>815</width>
|
||||||
|
<height>530</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Show source</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="main_splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QFrame" name="source_frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="source_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Source</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="search_edit">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Search for source...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="source_table_view">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="select_source_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>Select source</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="default">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QFrame" name="all_tags_frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="all_tags_label">
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>All tags using this source</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="all_tags_table_view">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
280
test.py
Executable file
280
test.py
Executable file
@ -0,0 +1,280 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
|
class PandasModel(QtCore.QAbstractTableModel):
|
||||||
|
def __init__(self, df=pd.DataFrame(), parent=None):
|
||||||
|
QtCore.QAbstractTableModel.__init__(self, parent=parent)
|
||||||
|
self._df = df.copy()
|
||||||
|
self.bolds = dict()
|
||||||
|
|
||||||
|
def toDataFrame(self):
|
||||||
|
return self._df.copy()
|
||||||
|
|
||||||
|
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
|
||||||
|
if orientation == QtCore.Qt.Horizontal:
|
||||||
|
if role == QtCore.Qt.DisplayRole:
|
||||||
|
try:
|
||||||
|
return self._df.columns.tolist()[section]
|
||||||
|
except (IndexError,):
|
||||||
|
return QtCore.QVariant()
|
||||||
|
elif role == QtCore.Qt.FontRole:
|
||||||
|
return self.bolds.get(section, QtCore.QVariant())
|
||||||
|
elif orientation == QtCore.Qt.Vertical:
|
||||||
|
if role == QtCore.Qt.DisplayRole:
|
||||||
|
try:
|
||||||
|
# return self.df.index.tolist()
|
||||||
|
return self._df.index.tolist()[section]
|
||||||
|
except (IndexError,):
|
||||||
|
return QtCore.QVariant()
|
||||||
|
return QtCore.QVariant()
|
||||||
|
|
||||||
|
def setFont(self, section, font):
|
||||||
|
self.bolds[section] = font
|
||||||
|
self.headerDataChanged.emit(QtCore.Qt.Horizontal, 0, self.columnCount())
|
||||||
|
|
||||||
|
def data(self, index, role=QtCore.Qt.DisplayRole):
|
||||||
|
if role != QtCore.Qt.DisplayRole:
|
||||||
|
return QtCore.QVariant()
|
||||||
|
|
||||||
|
if not index.isValid():
|
||||||
|
return QtCore.QVariant()
|
||||||
|
|
||||||
|
return QtCore.QVariant(str(self._df.iloc[index.row(), index.column()]))
|
||||||
|
|
||||||
|
def setData(self, index, value, role):
|
||||||
|
row = self._df.index[index.row()]
|
||||||
|
col = self._df.columns[index.column()]
|
||||||
|
if hasattr(value, "toPyObject"):
|
||||||
|
# PyQt4 gets a QVariant
|
||||||
|
value = value.toPyObject()
|
||||||
|
else:
|
||||||
|
# PySide gets an unicode
|
||||||
|
dtype = self._df[col].dtype
|
||||||
|
if dtype != object:
|
||||||
|
value = None if value == "" else dtype.type(value)
|
||||||
|
self._df.set_value(row, col, value)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def rowCount(self, parent=QtCore.QModelIndex()):
|
||||||
|
return len(self._df.index)
|
||||||
|
|
||||||
|
def columnCount(self, parent=QtCore.QModelIndex()):
|
||||||
|
return len(self._df.columns)
|
||||||
|
|
||||||
|
def sort(self, column, order):
|
||||||
|
colname = self._df.columns.tolist()[column]
|
||||||
|
self.layoutAboutToBeChanged.emit()
|
||||||
|
self._df.sort_values(
|
||||||
|
colname, ascending=order == QtCore.Qt.AscendingOrder, inplace=True
|
||||||
|
)
|
||||||
|
self._df.reset_index(inplace=True, drop=True)
|
||||||
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
|
||||||
|
class CheckablePandasModel(PandasModel):
|
||||||
|
def __init__(self, df=pd.DataFrame(), parent=None):
|
||||||
|
super().__init__(df, parent)
|
||||||
|
self.checkable_values = set()
|
||||||
|
self._checkable_column = -1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def checkable_column(self):
|
||||||
|
return self._checkable_column
|
||||||
|
|
||||||
|
@checkable_column.setter
|
||||||
|
def checkable_column(self, column):
|
||||||
|
if self.checkable_column == column:
|
||||||
|
return
|
||||||
|
last_column = self.checkable_column
|
||||||
|
self._checkable_column = column
|
||||||
|
|
||||||
|
if last_column == -1:
|
||||||
|
self.beginInsertColumns(
|
||||||
|
QtCore.QModelIndex(), self.checkable_column, self.checkable_column
|
||||||
|
)
|
||||||
|
self.endInsertColumns()
|
||||||
|
|
||||||
|
elif self.checkable_column == -1:
|
||||||
|
self.beginRemoveColumns(QtCore.QModelIndex(), last_column, last_column)
|
||||||
|
self.endRemoveColumns()
|
||||||
|
for c in (last_column, column):
|
||||||
|
if c > 0:
|
||||||
|
self.dataChanged.emit(
|
||||||
|
self.index(0, c), self.index(self.columnCount() - 1, c)
|
||||||
|
)
|
||||||
|
|
||||||
|
def columnCount(self, parent=QtCore.QModelIndex()):
|
||||||
|
return super().columnCount(parent) + (1 if self.checkable_column != -1 else 0)
|
||||||
|
|
||||||
|
def data(self, index, role=QtCore.Qt.DisplayRole):
|
||||||
|
if self.checkable_column != -1:
|
||||||
|
row, col = index.row(), index.column()
|
||||||
|
if col == self.checkable_column:
|
||||||
|
if role == QtCore.Qt.CheckStateRole:
|
||||||
|
return (
|
||||||
|
QtCore.Qt.Checked
|
||||||
|
if row in self.checkable_values
|
||||||
|
else QtCore.Qt.Unchecked
|
||||||
|
)
|
||||||
|
return QtCore.QVariant()
|
||||||
|
if col > self.checkable_column:
|
||||||
|
index = index.sibling(index.row(), col - 1)
|
||||||
|
return super().data(index, role)
|
||||||
|
|
||||||
|
def setData(self, index, value, role):
|
||||||
|
if self.checkable_column != -1:
|
||||||
|
row, col = index.row(), index.column()
|
||||||
|
if col == self.checkable_column:
|
||||||
|
if role == QtCore.Qt.CheckStateRole:
|
||||||
|
if row in self.checkable_values:
|
||||||
|
self.checkable_values.discard(row)
|
||||||
|
else:
|
||||||
|
self.checkable_values.add(row)
|
||||||
|
self.dataChanged.emit(index, index, (role,))
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
if col > self.checkable_column:
|
||||||
|
index = index.sibling(index.row(), col - 1)
|
||||||
|
return super().setData(index, value, role)
|
||||||
|
|
||||||
|
def flags(self, index):
|
||||||
|
if self.checkable_column != -1:
|
||||||
|
col = index.column()
|
||||||
|
if col == self.checkable_column:
|
||||||
|
return QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled
|
||||||
|
if col > self.checkable_column:
|
||||||
|
index = index.sibling(index.row(), col - 1)
|
||||||
|
return super().flags(index)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomProxyModel(QtCore.QSortFilterProxyModel):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self._filters = dict()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filters(self):
|
||||||
|
return self._filters
|
||||||
|
|
||||||
|
def setFilter(self, expresion, column):
|
||||||
|
if expresion:
|
||||||
|
self.filters[column] = expresion
|
||||||
|
elif column in self.filters:
|
||||||
|
del self.filters[column]
|
||||||
|
self.invalidateFilter()
|
||||||
|
|
||||||
|
def filterAcceptsRow(self, source_row, source_parent):
|
||||||
|
for column, expresion in self.filters.items():
|
||||||
|
text = self.sourceModel().index(source_row, column, source_parent).data()
|
||||||
|
regex = QtCore.QRegExp(
|
||||||
|
expresion, QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp
|
||||||
|
)
|
||||||
|
if regex.indexIn(text) == -1:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class myWindow(QtWidgets.QMainWindow):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(myWindow, self).__init__(parent)
|
||||||
|
self.centralwidget = QtWidgets.QWidget()
|
||||||
|
self.lineEdit = QtWidgets.QLineEdit()
|
||||||
|
self.view = QtWidgets.QTableView()
|
||||||
|
self.comboBox = QtWidgets.QComboBox()
|
||||||
|
self.label = QtWidgets.QLabel()
|
||||||
|
|
||||||
|
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
|
||||||
|
self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1)
|
||||||
|
self.gridLayout.addWidget(self.view, 1, 0, 1, 3)
|
||||||
|
self.gridLayout.addWidget(self.comboBox, 0, 2, 1, 1)
|
||||||
|
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
|
||||||
|
|
||||||
|
self.setCentralWidget(self.centralwidget)
|
||||||
|
self.label.setText("Regex Filter")
|
||||||
|
|
||||||
|
self.load_sites()
|
||||||
|
self.comboBox.addItems(["{0}".format(col) for col in self.model._df.columns])
|
||||||
|
|
||||||
|
self.lineEdit.textChanged.connect(self.on_lineEdit_textChanged)
|
||||||
|
|
||||||
|
self.horizontalHeader = self.view.horizontalHeader()
|
||||||
|
self.horizontalHeader.sectionClicked.connect(
|
||||||
|
self.on_view_horizontalHeader_sectionClicked
|
||||||
|
)
|
||||||
|
|
||||||
|
def load_sites(self):
|
||||||
|
df = pd.DataFrame(
|
||||||
|
{
|
||||||
|
"site_codes": ["01", "02", "03", "04"],
|
||||||
|
"status": ["open", "open", "open", "closed"],
|
||||||
|
"Location": ["east", "north", "south", "east"],
|
||||||
|
"data_quality": ["poor", "moderate", "high", "high"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.model = CheckablePandasModel(df)
|
||||||
|
self.model.checkable_column = 0
|
||||||
|
self.proxy = CustomProxyModel(self)
|
||||||
|
self.proxy.setSourceModel(self.model)
|
||||||
|
self.view.setModel(self.proxy)
|
||||||
|
self.view.resizeColumnsToContents()
|
||||||
|
|
||||||
|
@QtCore.pyqtSlot(int)
|
||||||
|
def on_view_horizontalHeader_sectionClicked(self, logicalIndex):
|
||||||
|
if logicalIndex == self.model.checkable_column:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.menuValues = QtWidgets.QMenu(self)
|
||||||
|
self.comboBox.blockSignals(True)
|
||||||
|
self.comboBox.setCurrentIndex(
|
||||||
|
logicalIndex - 1
|
||||||
|
if logicalIndex > self.model.checkable_column
|
||||||
|
else logicalIndex
|
||||||
|
)
|
||||||
|
self.comboBox.blockSignals(True)
|
||||||
|
|
||||||
|
valuesUnique = set(
|
||||||
|
self.proxy.index(i, logicalIndex).data()
|
||||||
|
for i in range(self.proxy.rowCount())
|
||||||
|
)
|
||||||
|
|
||||||
|
actionAll = QtWidgets.QAction("All", self)
|
||||||
|
self.menuValues.addAction(actionAll)
|
||||||
|
self.menuValues.addSeparator()
|
||||||
|
for i, name in enumerate(valuesUnique):
|
||||||
|
action = QtWidgets.QAction(name, self)
|
||||||
|
action.setData(i)
|
||||||
|
self.menuValues.addAction(action)
|
||||||
|
|
||||||
|
headerPos = self.view.mapToGlobal(self.horizontalHeader.pos())
|
||||||
|
pos = headerPos + QtCore.QPoint(
|
||||||
|
self.horizontalHeader.sectionPosition(logicalIndex),
|
||||||
|
self.horizontalHeader.height(),
|
||||||
|
)
|
||||||
|
action = self.menuValues.exec_(pos)
|
||||||
|
if action is not None:
|
||||||
|
font = QtGui.QFont()
|
||||||
|
if action.data() is None: # all
|
||||||
|
self.proxy.setFilter("", logicalIndex)
|
||||||
|
else:
|
||||||
|
font.setBold(True)
|
||||||
|
self.proxy.setFilter(action.text(), logicalIndex)
|
||||||
|
self.model.setFont(logicalIndex - 1, font)
|
||||||
|
|
||||||
|
@QtCore.pyqtSlot(str)
|
||||||
|
def on_lineEdit_textChanged(self, text):
|
||||||
|
self.proxy.setFilter(text, self.comboBox.currentIndex() + 1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
main = myWindow()
|
||||||
|
main.show()
|
||||||
|
main.resize(2000, 800)
|
||||||
|
sys.exit(app.exec_())
|
BIN
test.sqlite3
Executable file
BIN
test.sqlite3
Executable file
Binary file not shown.
Reference in New Issue
Block a user