[
  {
    "path": ".gitignore",
    "content": ".flatpak-builder\nbuild"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    // Debug with LLDB DAP extension\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"type\": \"lldb-dap\",\n            \"request\": \"launch\",\n            \"name\": \"Launch\",\n            \"program\": \"${workspaceFolder}/build/src/${workspaceFolderBasename}\",\n            \"cwd\": \"${workspaceFolder}\",\n            \"preLaunchTask\": \"Compile\"\n        }\n    ]\n}"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"mesonbuild.configureOnOpen\": true,\n    \"lldb.showDisassembly\": \"auto\",\n    \"lldb.dereferencePointers\": true,\n    \"lldb.consoleMode\": \"commands\"\n}"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "{\n    // See https://go.microsoft.com/fwlink/?LinkId=733558\n    // for the documentation about the tasks.json format\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"label\": \"Compile\",\n            \"type\": \"shell\",\n            \"command\": \"meson compile -C build\",\n            \"problemMatcher\": [],\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            }\n        },\n        {\n            \"label\": \"Setup\",\n            \"type\": \"shell\",\n            \"command\": \"meson setup build --reconfigure\",\n        }\n    ]\n}"
  },
  {
    "path": "COPYING",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n\n"
  },
  {
    "path": "README.md",
    "content": "<img align=\"left\" alt=\"Project logo\" src=\"data/icons/hicolor/scalable/apps/app.svg\" />\n\n# Gapless\nPlay your music elegantly.\n\n<img src=\"https://gitlab.gnome.org/neithern/screenshots/-/raw/main/g4music/window.png\" width=\"1134\"/>\n<img src=\"https://gitlab.gnome.org/neithern/screenshots/-/raw/main/g4music/albums.png\" width=\"1134\"/>\n<img src=\"https://gitlab.gnome.org/neithern/screenshots/-/raw/main/g4music/playing.png\" width=\"462\"/>\n<img src=\"https://gitlab.gnome.org/neithern/screenshots/-/raw/main/g4music/playlist.png\" width=\"466\"/>\n\nGapless (AKA: G4Music) is a light weight music player written in GTK4, focuses on large music collection.\n\n## Features\n- Supports most music file types, Samba and any other remote protocols (depends on GIO and GStreamer).\n- Fast loading and parsing thousands of music files in very few seconds, monitor local changes.\n- Low memory usage for large music collection with album covers (embedded and external), no thumbnail caches to store.\n- Group and sorts by album/artist/title, shuffle list, full-text searching.\n- Fluent adaptive user interface for different screen (Desktop, Tablet, Mobile).\n- Gaussian blurred cover as background, follows GNOME light/dark mode.\n- Supports creating and editing playlists, drag cover to change order or add to another playlist.\n- Supports drag and drop with other apps.\n- Supports audio peaks visualizer.\n- Supports gapless playback.\n- Supports normalizing volume with ReplayGain.\n- Supports specified audio sink.\n- Supports MPRIS control.\n\n## Install from Flathub\n<a href=\"https://flathub.org/apps/com.github.neithern.g4music\">\n<img src=\"https://flathub.org/assets/badges/flathub-badge-en.png\" width=\"240\"/></a>\n\n## Install from Snapcraft (unofficial)\n<a href=\"https://snapcraft.io/g4music\">\n<img alt=\"Get it from the Snap Store\" src=\"https://camo.githubusercontent.com/ab077b20ad9938c23fbdac223ab101df5ed27329bbadbe7f98bfd62d5808f0a7/68747470733a2f2f736e617063726166742e696f2f7374617469632f696d616765732f6261646765732f656e2f736e61702d73746f72652d626c61636b2e737667\" data-canonical-src=\"https://snapcraft.io/static/images/badges/en/snap-store-black.svg\" width=\"240\" style=\"max-width: 100%;\"> \n\n## FreeBSD Dependencies\n\n```bash\npkg install vala meson libadwaita gstreamer1-plugins-all gettext gtk4\n```\n\n## How to build \nIt is written in Vala, simple and clean code, with few third-party dependencies:\n\n1. Clone the code from gitlab.\n2. Install vala, develop packages of gtk4, libadwaita, gstreamer.\n3. Run in the project directory:\n\n    `meson setup build --buildtype=release`\n\n    `meson install -C build`\n\n## Change Log\nCheck the [release tags](https://gitlab.gnome.org/neithern/g4music/-/tags) for change log.\n"
  },
  {
    "path": "data/app.desktop.in",
    "content": "[Desktop Entry]\nName=Gapless\nGenericName=Music Player\nComment=Play your music elegantly\nExec=g4music %U\nIcon=@app_id@\nTerminal=false\nType=Application\nCategories=GNOME;GTK;Music;Audio;AudioVideo;\nMimeType=audio/wav;audio/webm;audio/x-aac;audio/x-aiff;audio/x-ape;audio/x-flac;audio/x-it;audio/x-m4a;audio/x-m4b;audio/x-matroska;audio/x-mod;audio/x-mp1;audio/x-mp2;audio/x-mp3;audio/x-mpg;audio/x-mpeg;audio/x-ms-asf;audio/x-ms-asx;audio/x-ms-wax;audio/x-ms-wma;audio/x-musepack;audio/x-opus+ogg;audio/x-pn-aiff;audio/x-pn-au;audio/x-pn-realaudio;audio/x-pn-realaudio-plugin;audio/x-pn-wav;audio/x-pn-windows-acm;audio/x-realaudio;audio/x-real-audio;audio/x-s3m;audio/x-sbc;audio/x-shorten;audio/x-speex;audio/x-stm;audio/x-tta;audio/x-wav;audio/x-wavpack;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-xm;audio/x-mpegurl;audio/x-scpls;\nKeywords=music;sound;player;media;audio;playlist;\nStartupNotify=true\nDBusActivatable=true\nX-SingleMainWindow=true\nX-Purism-FormFactor=Workstation;Mobile;\n"
  },
  {
    "path": "data/app.gschema.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<schemalist gettext-domain=\"g4music\">\n  <schema id=\"@app_id@\" path=\"/com/github/neithern/g4music/\">\n    <key name=\"blur-mode\" type=\"u\">\n      <range min=\"0\" max=\"2\"/>\n      <default>1</default>\n      <summary>Background blur mode</summary>\n    </key>\n    <key name=\"color-scheme\" type=\"u\">\n      <range min=\"0\" max=\"4\"/>\n      <default>0</default>\n      <summary>Prefer color scheme</summary>\n    </key>\n    <key name=\"compact-playlist\" type=\"b\">\n      <default>false</default>\n      <summary>Compact playlist view</summary>\n    </key>\n    <key name=\"grid-mode\" type=\"b\">\n      <default>true</default>\n      <summary>Grid view for artists/albums</summary>\n    </key>\n    <key name=\"monitor-changes\" type=\"b\">\n      <default>false</default>\n      <summary>Monitor local file changes</summary>\n    </key>\n    <key name=\"music-dir\" type=\"s\">\n      <default>''</default>\n      <summary>Load music from folder</summary>\n    </key>\n    <key name=\"remote-thumbnail\" type=\"b\">\n      <default>false</default>\n      <summary>Load thumbnails for non-local files</summary>\n    </key>\n    <key name=\"remain-progress\" type=\"b\">\n      <default>false</default>\n      <summary>Show remain progress</summary>\n    </key>\n    <key name=\"audio-sink\" type=\"s\">\n      <default>''</default>\n      <summary>Prefer audio sink</summary>\n    </key>\n    <key name=\"play-background\" type=\"b\">\n      <default>false</default>\n      <summary>Keep playing after window closed</summary>\n    </key>\n    <key name=\"gapless-playback\" type=\"b\">\n      <default>true</default>\n      <summary>Enable gapless playback</summary>\n    </key>\n    <key name=\"replay-gain\" type=\"u\">\n      <range min=\"0\" max=\"2\"/>\n      <default>0</default>\n      <summary>Normalize volume with ReplayGain</summary>\n    </key>\n    <key name=\"rotate-cover\" type=\"b\">\n      <default>true</default>\n      <summary>Rotate album cover</summary>\n    </key>\n    <key name=\"peak-characters\" type=\"s\">\n      <default>'='</default>\n      <summary>Peak characters</summary>\n    </key>\n    <key name=\"show-peak\" type=\"b\">\n      <default>true</default>\n      <summary>Show audio peak level</summary>\n    </key>\n    <key name=\"single-click-activate\" type=\"b\">\n      <default>true</default>\n      <summary>Single click to activate item</summary>\n    </key>\n    <key name=\"sort-mode\" type=\"u\">\n      <range min=\"0\" max=\"5\"/>\n      <default>3</default>\n      <summary>Sort Mode</summary>\n    </key>\n    <key name=\"leaflet-mode\" type=\"i\">\n      <default>0</default>\n    </key>\n    <key name=\"maximized\" type=\"b\">\n      <default>false</default>\n    </key>\n    <key name=\"width\" type=\"i\">\n      <default>800</default>\n    </key>\n    <key name=\"height\" type=\"i\">\n      <default>600</default>\n    </key>\n    <key name=\"library-uri\" type=\"s\">\n      <default>''</default>\n    </key>\n    <key name=\"recent-music\" type=\"s\">\n      <default>''</default>\n    </key>\n    <key name=\"recent-playlist\" type=\"s\">\n      <default>''</default>\n    </key>\n    <key name=\"volume\" type=\"d\">\n      <default>1</default>\n    </key>\n  </schema>\n</schemalist>\n"
  },
  {
    "path": "data/app.metainfo.xml.in",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<component type=\"desktop-application\">\n    <id>@app_id@</id>\n    <name>Gapless</name>\n    <metadata_license>CC0-1.0</metadata_license>\n    <project_license>GPL-3.0-or-later</project_license>\n    <summary>Play your music elegantly</summary>\n\n    <developer id=\"com.github.neithern\">\n        <name translate=\"no\">Nanling</name>\n    </developer>\n    <update_contact>neithern@outlook.com</update_contact>\n\n    <url type=\"homepage\">https://gitlab.gnome.org/neithern/g4music</url>\n    <url type=\"bugtracker\">https://gitlab.gnome.org/neithern/g4music/issues</url>\n    <url type=\"translate\">https://l10n.gnome.org/module/g4music</url>\n\n    <launchable type=\"desktop-id\">@app_id@.desktop</launchable>\n    <provides>@app_id@.desktop</provides>\n    <content_rating type=\"oars-1.1\"/>\n    <translation type=\"gettext\">g4music</translation>\n\n    <description>\n      \t<p>Gapless (AKA: G4Music) is a light weight music player written in GTK4, focuses on large music collection.</p>\n        <p>Features</p>\n        <ul>\n        <li>Supports most music file types, Samba and any other remote protocols (depends on GIO and GStreamer).</li>\n        <li>Fast loading and parsing thousands of music files in very few seconds, monitor local changes.</li>\n        <li>Low memory usage for large music collection with album covers (embedded and external), no thumbnail caches to store.</li>\n        <li>Group and sorts by album/artist/title, shuffle list, full-text searching.</li>\n        <li>Fluent adaptive user interface for different screen (Desktop, Tablet, Mobile).</li>\n        <li>Gaussian blurred cover as background, follows GNOME light/dark mode.</li>\n        <li>Supports creating and editing playlists, drag cover to change order or add to another playlist.</li>\n        <li>Supports drag and drop with other apps.</li>\n        <li>Supports audio peaks visualizer.</li>\n        <li>Supports gapless playback.</li>\n        <li>Supports normalizing volume with ReplayGain.</li>\n        <li>Supports specified audio sink.</li>\n        <li>Supports MPRIS control.</li>\n        </ul>\n    </description>\n\n    <branding>\n        <color type=\"primary\" scheme_preference=\"light\">#d6f6d6</color>\n        <color type=\"primary\" scheme_preference=\"dark\">#266626</color>\n    </branding>\n\n    <screenshots>\n        <screenshot type=\"default\">\n            <caption>Main window</caption>\n            <image>https://gitlab.gnome.org/neithern/screenshots/-/raw/main/g4music/window.png</image>\n        </screenshot>\n        <screenshot>\n            <caption>Albums view</caption>\n            <image>https://gitlab.gnome.org/neithern/screenshots/-/raw/main/g4music/albums.png</image>\n        </screenshot>\n        <screenshot>\n            <caption>Playing view</caption>\n            <image>https://gitlab.gnome.org/neithern/screenshots/-/raw/main/g4music/playing.png</image>\n        </screenshot>\n        <screenshot>\n            <caption>Playlist view</caption>\n            <image>https://gitlab.gnome.org/neithern/screenshots/-/raw/main/g4music/playlist.png</image>\n        </screenshot>\n    </screenshots>\n\n    <releases>\n        <release version=\"4.6\" date=\"2025-11-16\">\n            <description translate=\"no\">\n                <ul>\n                <li>Get filtered items as a playlist.</li>\n                <li>Upgrade to GNOME 49.</li>\n                <li>Add translation: Interlingua, Greek.</li>\n                <li>Update Hungarian translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"4.5\" date=\"2025-7-6\">\n            <description translate=\"no\">\n                <ul>\n                <li>Always insert to the next position when play an album.</li>\n                <li>Click index always to open the playing page.</li>\n                <li>Load the library into the queue only when it is empty.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"4.4\" date=\"2025-4-16\">\n            <description translate=\"no\">\n                <ul>\n                <li>Click index to open playing page, restore on next startup.</li>\n                <li>Set the main window as parent.</li>\n                <li>Drop MPRIS permission of flatpak.</li>\n                <li>Upgrade to GNOME 48.</li>\n                <li>Update Danish translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"4.3.1\" date=\"2025-2-15\">\n            <description translate=\"no\">\n                <ul>\n                <li>Remove unnecessary flatpak permissions.</li>\n                <li>Add Bulgarian translation</li>\n                <li>Update translation: Danish, Persian, Hebrew.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"4.3\" date=\"2024-11-30\">\n            <description translate=\"no\">\n                <ul>\n                <li>Optimize scrolling to current item at startup.</li>\n                <li>Update translation: Swedish, Finnish, Occitan, Turkish.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"4.2\" date=\"2024-11-10\">\n            <description translate=\"no\">\n                <ul>\n                <li>Optimize relative file paths for playlists.</li>\n                <li>Start drag only when the pointer inside the cover image.</li>\n                <li>Show the full date of the album if possible.</li>\n                <li>Build with low version of vala compiler.</li>\n                <li>Update translation: Slovak, German, Dutch, Occitan.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"4.1\" date=\"2024-10-27\">\n            <description translate=\"no\">\n                <ul>\n                <li>Use the main queue as the actual \"Now Playing\" and \"Playing History\".</li>\n                <li>New style for the number of files being dragging.</li>\n                <li>Optimize updating the library.</li>\n                <li>Support volume for mpris.</li>\n                <li>Update translation: German, Russian, Georgian, Belarusian.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"4.0\" date=\"2024-10-13\">\n            <description translate=\"no\">\n                <p>New features:</p>\n                <ul>\n                <li>Add music to playlist, edit/rename/remove existing playlists.</li>\n                <li>Drag cover image to re-arrange in a playlist, add to another playlist, or share to another app.</li>\n                <li>Insert music files to playlist drag from another app.</li>\n                <li>Show detail tags in a dialog.</li>\n                <li>Move music/playlist file to trash.</li>\n                <li>New option: single click to activate item.</li>\n                </ul>\n                <p>Breaking changes:</p>\n                <ul>\n                <li>Long press an item to enter multiple selection mode.</li>\n                <li>The main queue is editable and recoverable on next startup.</li>\n                <li>Except the main queue, albums/playlists are no longer sort-able, but can be random played.</li>\n                <li>Won't switch playing list unless activate manually or play end, open on next startup.</li>\n                <li>Parse ORIGINALDATE/YEAR from Extended-Comment as album's date.</li>\n                <li>Full support of color scheme: System/Light/Dark.</li>\n                <li>Don't enable pipewire manually, override the rank if still want to use it.</li>\n                </ul>\n                <p>Flatpak changes:</p>\n                <ul>\n                <li>Request writable permission of Music folder for editing playlists.</li>\n                <li>Upgrade to GNOME 47.</li>\n                </ul>\n                <p>Optimizations:</p>\n                <ul>\n                <li>Improve performance of loading large playlist.</li>\n                <li>Group popover menu actions.</li>\n                <li>Many other optimizations by code refactoring.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.9.2\" date=\"2024-9-15\">\n            <description translate=\"no\">\n                <ul>\n                <li>Fix audio seeking stutter, thanks to @dov-vai.</li>\n                <li>Load last played file first before load other files.</li>\n                <li>Update the library pages when file changes.</li>\n                <li>Many UI optimizations.</li>\n                <li>Update translation: Occitan, Persian, Hebrew, Russian, Georgian.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.9.1\" date=\"2024-9-3\">\n            <description translate=\"no\">\n                <ul>\n                <li>Play the next album after end of an album.</li>\n                <li>Optimize UI layout, shrink the window.</li>\n                <li>Fix crash when open an album with invalid utf-8 name.</li>\n                <li>Update translation: Ukrainian, Slovenian, German, Slovenian, Belarusian, Chinese.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.9\" date=\"2024-8-25\">\n            <description translate=\"no\">\n                <ul>\n                <li>Optimize UI layout and style for small screen.</li>\n                <li>Optimize loading cover of playing music.</li>\n                <li>Optimize pressing Space to toggle play/pause.</li>\n                <li>Update translation: Chinese, German.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.8.2\" date=\"2024-8-16\">\n            <description translate=\"no\">\n                <ul>\n                <li>Fix initial view when no music.</li>\n                <li>Fix Drag-drop when no music.</li>\n                <li>Update translation: Hindi, Occitan, Persian, Brazilian Portuguese, Hungarian, Swedish, Turkish, Belarusian.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.8.1\" date=\"2024-7-28\">\n            <description translate=\"no\">\n                <ul>\n                <li>Fix build issue before GTK 4.10.</li>\n                <li>Remove screen shots from flatpak package.</li>\n                <li>Update translation: Russian, Slovenian, Ukrainian.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.8\" date=\"2024-7-20\">\n            <description translate=\"no\">\n                <ul>\n                <li>Rename to 'Gapless' to follow GNOME HIG.</li>\n                <li>Marquee animation for long title.</li>\n                <li>Fix cursor for clickable label.</li>\n                <li>Tweak blur background.</li>\n                <li>Add Hebrew translation.</li>\n                <li>Update Occitan translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.7.2\" date=\"2024-6-29\">\n            <description translate=\"no\">\n                <ul>\n                <li>Drag the play-panel to move the window.</li>\n                <li>Individual sort-mode for albums.</li>\n                <li>show indicator and scroll to the playing artist/album.</li>\n                <li>Save and restore window's maximized.</li>\n                <li>Many other UI improvement and fixing.</li>\n                <li>Use playbin3 if gstreamer>=1.24.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.6.2\" date=\"2024-6-2\">\n            <description translate=\"no\">\n                <ul>\n                <li>Optimize pressing Space to play/pause.</li>\n                <li>Add translation: Persian.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.6\" date=\"2024-5-25\">\n            <description translate=\"no\">\n                <ul>\n                <li>Press Space to toggle play/pause.</li>\n                <li>Add Position property for MPRIS.</li>\n                <li>Don't change playing music after reload library.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.5.2\" date=\"2024-4-25\">\n            <description translate=\"no\">\n                <ul>\n                <li>Update current item when items changed.</li>\n                <li>Free memory when music be removed.</li>\n                <li>Add translation: Georgian, Hindi.</li>\n                <li>Update translation: Spanish, Slovenian.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.5.1\" date=\"2024-1-14\">\n            <description translate=\"no\">\n                <ul>\n                <li>Fix \"playing\" state for music entries.</li>\n                <li>Use Overlay to avoid changing list's width.</li>\n                <li>Sorting albums by Disc Number.</li>\n                <li>Add translation: Romanian, Danish, Slovenian.</li>\n                <li>Update translation: Belarusian, Occitan.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.4\" date=\"2023-10-15\">\n            <description translate=\"no\">\n                <ul>\n                <li>Build flatpak with GNOME 45.</li>\n                <li>Fix style of switch bar.</li>\n                <li>Fix loading M3U playlist.</li>\n                <li>Add Hungarian translation.</li>\n                <li>Update Swedish translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.3\" date=\"2023-9-3\">\n            <description translate=\"no\">\n                <ul>\n                <li>Make seek_bar auto width.</li>\n                <li>UI improvement and fixing.</li>\n                <li>Add translation: Ukrainian, Finnish, Indonesian, Basque.</li>\n                <li>Update translation: Spanish, French, German, Turkish, Russian.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.2\" date=\"2023-8-13\">\n            <description translate=\"no\">\n                <ul>\n                <li>Option: Grid view for artists/albums.</li>\n                <li>Bigger image size and column width for grid view.</li>\n                <li>UI improvement and fixing.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.1\" date=\"2023-8-5\">\n            <description translate=\"no\">\n                <ul>\n                <li>Group by album-artist, sort albums by year.</li>\n                <li>Save and restore the last library view.</li>\n                <li>Open a new page when play all music of an artist.</li>\n                <li>Stay in the current list when playing the whole album.</li>\n                <li>Show the local playlists.</li>\n                <li>Optimize searching.</li>\n                <li>Update German and Japanese translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"3.0\" date=\"2023-7-29\">\n            <description translate=\"no\">\n                <ul>\n                <li>Group artists/albums as library.</li>\n                <li>Optimize layout for landscape view.</li>\n                <li>Show progressbar when loading.</li>\n                <li>Add icons for preference rows.</li>\n                <li>Optimize seeking.</li>\n                <li>Add Japanese translation, thanks to @Gnuey56.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"2.4\" date=\"2023-7-7\">\n            <description translate=\"no\">\n                <ul>\n                <li>App icon refresh from @ddaudix.</li>\n                <li>Add a sort mode by: Artist/Album</li>\n                <li>Drag-drop folders works from Files.</li>\n                <li>Rotating cover sync with play progress, fix issues.</li>\n                <li>Fix gapless related issues.</li>\n                <li>Update German translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"2.3\" date=\"2023-7-1\">\n            <description translate=\"no\">\n                <ul>\n                <li>Support .m3u/.pls playlist from command line.</li>\n                <li>Modeless preferences window.</li>\n                <li>UI improvement and fixing.</li>\n                <li>Update Spanish translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"2.2\" date=\"2023-6-23\">\n            <description translate=\"no\">\n                <ul>\n                <li>Option: rotate cover when playing.</li>\n                <li>Click music title to search.</li>\n                <li>Revert to single page of preferences.</li>\n                <li>Add 2 shortcut keys.</li>\n                <li>UI improvement and fixing.</li>\n                <li>Update German translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"2.1\" date=\"2023-6-18\">\n            <description translate=\"no\">\n                <ul>\n                <li>App startup acceleration.</li>\n                <li>Option: Prefer audio sink.</li>\n                <li>Replay-gain supports album mode.</li>\n                <li>Show same album cover in app and MPRIS.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"2.0\" date=\"2023-6-11\">\n            <description translate=\"no\">\n                <ul>\n                <li>Option: Monitor local file changes.</li>\n                <li>Right click or long press to show popover menu.</li>\n                <li>Scroll playlist smoothly.</li>\n                <li>Many UI improvements.</li>\n                <li>Optimize searching by album/artist/title.</li>\n                <li>Optimize loading files and cache.</li>\n                <li>Update German translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.13\" date=\"2023-5-25\">\n            <description translate=\"no\">\n                <ul>\n                <li>Option: compact playlist view.</li>\n                <li>Option: custom characters for audio peaks.</li>\n                <li>Optimize playlist text size.</li>\n                <li>Optimize for macOS.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.12\" date=\"2023-5-18\">\n            <description translate=\"no\">\n                <ul>\n                <li>Save memory and CPU usage.</li>\n                <li>New style for no-cover images.</li>\n                <li>UI improvement and fixing.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.11\" date=\"2023-5-8\">\n            <description translate=\"no\">\n                <ul>\n                <li>MPRIS improvement.</li>\n                <li>UI improvement and fixing.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.10\" date=\"2023-5-6\">\n            <description translate=\"no\">\n                <ul>\n                <li>Build flatpak with GNOME 44.</li>\n                <li>MPRIS improvement.</li>\n                <li>UI improvement and fixing.</li>\n                <li>Update Spanish translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.9.2\" date=\"2023-4-2\">\n            <description translate=\"no\">\n                <ul>\n                <li>Fix wrong icon name of repeat-song.</li>\n                <li>Fix wrong state of Switch buttons.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.9.1\" date=\"2023-3-25\">\n            <description translate=\"no\">\n                <ul>\n                <li>Optimize loading thumbnails.</li>\n                <li>UI improvement and fixing.</li>\n                <li>Update German translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.9\" date=\"2023-3-17\">\n            <description translate=\"no\">\n                <ul>\n                <li>Select a music file to \"Play at Next\".</li>\n                <li>Lazy load thumbnails to faster startup and saving memory.</li>\n                <li>UI improvement and fixing.</li>\n                <li>Add Occitan translation, thanks to Quentin PAGÈS.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.8\" date=\"2022-10-19\">\n            <description translate=\"no\">\n                <ul>\n                <li>Build flatpak with GNOME 43.</li>\n                <li>Cache directories for faster loading.</li>\n                <li>Show peaks more smoothly.</li>\n                <li>Update Spanish and German translation, thanks to the translators.</li>\n                <li>v1.8.2: Build with vala 0.54.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.7\" date=\"2022-10-02\">\n            <description translate=\"no\">\n                <ul>\n                <li>Start to play when music changed.</li>\n                <li>Optimize audio peaks visualizer.</li>\n                <li>New style of popover menu.</li>\n                <li>Update many translation, thanks to the translators.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.6\" date=\"2022-08-06\">\n            <description translate=\"no\">\n                <ul>\n                <li>Option: Background blur mode.</li>\n                <li>Shortcut key for toggle sort.</li>\n                <li>Don't changing current song when searching.</li>\n                <li>Add Estonian translation, thanks to Henri.</li>\n                <li>Add Traditional Chinese translation, thanks to Julian.</li>\n                <li>v1.6.1: Fix wrong sort order of cached tags.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.5\" date=\"2022-07-31\">\n            <description translate=\"no\">\n                <ul>\n                <li>Show loading songs progress with percent.</li>\n                <li>Add sort by recently added, thanks to Mek101.</li>\n                <li>Add German translation, thanks to Jürgen Benvenuti.</li>\n                <li>Bug fix and UI improvement.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.4\" date=\"2022-07-23\">\n            <description translate=\"no\">\n                <ul>\n                <li>Popover menu for song entry.</li>\n                <li>Show initial status if no sound found.</li>\n                <li>Try parse album and track from file path.</li>\n                <li>Add Italian translation, thanks to Albano Aattistella.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.3\" date=\"2022-07-17\">\n            <description translate=\"no\">\n                <ul>\n                <li>App inhibit suspend to keep playing.</li>\n                <li>Performance improvement and memory saving.</li>\n                <li>Parse tags of MKV/MKA.</li>\n                <li>Add French translation, thanks to Aurélien Hamy.</li>\n                <li>Add Dutch translation, thanks to Heimen Stoffels.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.2\" date=\"2022-07-01\">\n            <description translate=\"no\">\n                <ul>\n                <li>Faster parsing OGG and MP4 tags.</li>\n                <li>Faster drawing texts using pango.</li>\n                <li>Many UI optimizations.</li>\n                <li>Add Brazilian Portuguese translation, thanks to @PedroHSilva.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.1\" date=\"2022-06-25\">\n            <description translate=\"no\">\n                <ul>\n                <li>Option: Gapless playback.</li>\n                <li>Make label clickable instead of hypelinks.</li>\n                <li>Add Turkish translation, thanks to @Sabri Ünal.</li>\n                <li>Fix cover image issues.</li>\n                <li>Fix saving tag cache issues.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"1.0\" date=\"2022-06-23\">\n            <description translate=\"no\">\n                <ul>\n                <li>Support ReplayGain to normalize volume.</li>\n                <li>Option: Keep playing after window closed.</li>\n                <li>Cache tags to make next loading faster.</li>\n                <li>Share album cover with same artist.</li>\n                <li>Fix some UI issues.</li>\n                <li>v1.0.1: Updated Russian translation.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"0.9\" date=\"2022-06-20\">\n            <description translate=\"no\">\n                <ul>\n                <li>Scale album cover to fix large window.</li>\n                <li>Navigate back if start search and folded.</li>\n                <li>Draw peak to avoid resizing the window.</li>\n                <li>Request host file permission in flatpak.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"0.8\" date=\"2022-06-18\">\n            <description translate=\"no\">\n                <ul>\n                <li>Show current song in Files.</li>\n                <li>Sort by track number in an album.</li>\n                <li>Sort text by prefix number.</li>\n                <li>Always follow sym-links when enumerate a folder.</li>\n                <li>Add spanish translation, thanks to @Radi4Ever.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"0.7\" date=\"2022-06-16\">\n            <description translate=\"no\">\n                <ul>\n                <li>Parallel parsing tags to make loading songs even faster.</li>\n                <li>Merge all kinds of tags as possible.</li>\n                <li>Fix crash when parsing some FLAC files, thanks to @GeoffreyCoulaud.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"0.6\" date=\"2022-06-15\">\n            <description translate=\"no\">\n                <ul>\n                <li>Use Adw.Leaflet to adapt to PC and phone screens.</li>\n                <li>Show a mini play bar when only the playlist on the window.</li>\n                <li>Show a spinner when loading songs.</li>\n                <li>Save and restore the window size.</li>\n                <li>Add Swedish translation, thanks to Åke Engelbrektson.</li>\n                <li>Faster parsing FLAC tags.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"0.5\" date=\"2022-06-13\">\n            <description translate=\"no\">\n                <ul>\n                <li>Detect music file type to fix incorrect parsing.</li>\n                <li>Update app icon to follow GNOME HIG, thanks to @daudix-UFO.</li>\n                <li>Add Russian translation, thanks to @daudix-UFO.</li>\n                <li>Change \"Force Dark\" to \"Prefer Dark\".</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"0.4\" date=\"2022-06-12\">\n            <description translate=\"no\">\n                <ul>\n                <li>Recognize external images as cover art, supports transparency.</li>\n                <li>Showing peak now works with pipewire in flatpak.</li>\n                <li>Don't support tracker_sparql because it is slow.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"0.3\" date=\"2022-06-11\">\n            <description translate=\"no\">\n                <ul>\n                <li>Sort songs by Album/Artist/Title.</li>\n                <li>Option: Force dark theme.</li>\n                <li>Optimized for responsiveness.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"0.2\" date=\"2022-06-10\">\n            <description translate=\"no\">\n                <ul>\n                <li>Add volume button.</li>\n                <li>Repeat single song mode.</li>\n                <li>Supports pipewire for flatpak.</li>\n                <li>Supports parsing GIO file tags for flatpak.</li>\n                <li>Press any key to search, ESC to quit search.</li>\n                <li>Show abbreviation as MPRIS's cover if no cover image.</li>\n                </ul>\n            </description>\n        </release>\n        <release version=\"0.1\" date=\"2022-06-06\">\n            <description translate=\"no\">\n                <p>First release.</p>\n            </description>\n        </release>\n    </releases>\n\n    <requires>\n        <display_length compare=\"ge\">360</display_length>\n    </requires>\n\n    <supports>\n        <control>keyboard</control>\n        <control>pointing</control>\n        <control>touch</control>\n    </supports>\n\n</component>\n"
  },
  {
    "path": "data/app.service.in",
    "content": "[D-BUS Service]\nName=@app_id@\nExec=@bindir@/g4music --gapplication-service"
  },
  {
    "path": "data/icons/meson.build",
    "content": "scalable_dir = join_paths('hicolor', 'scalable', 'apps')\nscalable_conf = configure_file(\n  input: join_paths(scalable_dir, 'app.svg'),\n  output: '@0@.svg'.format(app_id),\n  configuration: conf\n)\n\ninstall_data(\n  scalable_conf,\n  install_dir: join_paths(get_option('datadir'), 'icons', scalable_dir)\n)\n\nsymbolic_dir = join_paths('hicolor', 'symbolic', 'apps')\nsymbolic_conf = configure_file(\n  input: join_paths(symbolic_dir, 'app-symbolic.svg'),\n  output: '@0@-symbolic.svg'.format(app_id),\n  configuration: conf\n)\n\ninstall_data(\n  symbolic_conf,\n  install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir)\n)\n"
  },
  {
    "path": "data/meson.build",
    "content": "conf = configuration_data()\nconf.set('app_id', app_id)\nconf.set('version', version)\nconf.set('bindir', get_option('prefix') / get_option('bindir'))\n\ndesktop_conf = configure_file(\n  input: 'app.desktop.in',\n  output: '@0@.desktop.in'.format(app_id),\n  configuration: conf\n)\n\ndesktop_file = i18n.merge_file(\n  input: desktop_conf,\n  output: '@0@.desktop'.format(app_id),\n  type: 'desktop',\n  po_dir: '../po',\n  install: true,\n  install_dir: get_option('datadir') / 'applications'\n)\n\ndesktop_utils = find_program('desktop-file-validate', required: false)\nif desktop_utils.found()\n  test('Validate desktop file', desktop_utils,\n    args: [desktop_file]\n  )\nendif\n\nservice_file = configure_file(\n  input: 'app.service.in',\n  output: '@0@.service'.format(app_id),\n  configuration: conf,\n)\n\ninstall_data(\n  service_file,\n  install_dir: get_option('datadir') / 'dbus-1' / 'services'\n)\n\nappstream_conf = configure_file(\n  input: 'app.metainfo.xml.in',\n  output: '@0@.metainfo.xml.in'.format(app_id),\n  configuration: conf\n)\n\nappstream_file = i18n.merge_file(\n  input: appstream_conf,\n  output: '@0@.metainfo.xml'.format(app_id),\n  po_dir: '../po',\n  install: true,\n  install_dir: get_option('datadir') / 'metainfo'\n)\n\nappstreamcli = find_program('appstreamcli', required: false)\nif not appstreamcli.found()\n  appstreamcli = find_program('appstream-util', required: false)\nendif\nif appstreamcli.found()\n  test('Validate appstream file', appstreamcli,\n    args: ['validate', '--no-net', '--explain', appstream_file],\n    suite: ['lint'],\n  )\nendif\n\ngschema_file = configure_file(\n  input: 'app.gschema.xml',\n  output: app_id + '.gschema.xml',\n  configuration: conf,\n)\n\ninstall_data(\n  gschema_file,\n  install_dir: get_option('datadir') / 'glib-2.0' / 'schemas'\n)\n\ncompile_schemas = find_program('glib-compile-schemas', required: false)\nif compile_schemas.found()\n  test('Validate schema file', compile_schemas,\n    args: ['--strict', '--dry-run', meson.current_source_dir()]\n  )\nendif\n\nsubdir('icons')\n"
  },
  {
    "path": "g4music.doap",
    "content": "<Project xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n         xmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\"\n         xmlns:foaf=\"http://xmlns.com/foaf/0.1/\"\n         xmlns:gnome=\"http://api.gnome.org/doap-extensions#\"\n         xmlns=\"http://usefulinc.com/ns/doap#\">\n\n  <name xml:lang=\"en\">Gapless</name>\n  <shortdesc xml:lang=\"en\">Play your music elegantly</shortdesc>\n  <description xml:lang=\"en\">A fast, fluent, light weight music player written in GTK4, with a beautiful, adaptive user interface.</description>\n  <category rdf:resource=\"http://api.gnome.org/doap-extensions#apps\" />\n  <homepage rdf:resource=\"https://gitlab.gnome.org/neithern/g4music\" />\n  <bug-database rdf:resource=\"https://gitlab.gnome.org/neithern/g4music/issues\" />\n\n  <programming-language>Vala</programming-language>\n  <platform>GTK 4</platform>\n  <platform>Libadwaita</platform>\n\n  <maintainer>\n    <foaf:Person>\n      <foaf:name>Nanling Zheng</foaf:name>\n      <foaf:mbox rdf:resource=\"mailto:neithern@outlook.com\" />\n      <foaf:account>\n        <foaf:OnlineAccount>\n          <foaf:accountServiceHomepage rdf:resource=\"https://gitlab.gnome.org\"/>\n          <foaf:accountName>neithern</foaf:accountName>\n        </foaf:OnlineAccount>\n      </foaf:account>\n    </foaf:Person>\n  </maintainer>\n</Project>\n"
  },
  {
    "path": "meson.build",
    "content": "project(\n  'g4music', [ 'vala', 'c' ],\n  version: '4.6',\n  license: 'GPL3'\n)\n\napp_id = 'com.github.neithern.' + meson.project_name()\nversion = meson.project_version()\n\ngnome = import('gnome')\ni18n = import('i18n')\n\nc_compiler = meson.get_compiler('c')\nvala_compiler = meson.get_compiler('vala')\n\nadd_project_arguments('-DGETTEXT_PACKAGE=\"' + meson.project_name() + '\"', language: 'c')\nadd_project_arguments('--enable-experimental-non-null', language: 'vala')\n\nif vala_compiler.version().version_compare('>=0.56.10')\n  add_project_arguments('--define=VALA_56_10', language: 'vala')\nendif\n\ngtk_dep = dependency('gtk4')\nif gtk_dep.version().version_compare('>=4.8') and vala_compiler.version().version_compare('>=0.56.6')\n  add_project_arguments('--define=GTK_4_8', language: 'vala')\nendif\nif gtk_dep.version().version_compare('>=4.10') and vala_compiler.version().version_compare('>=0.56.6')\n  add_project_arguments('--define=GTK_4_10', language: 'vala')\nendif\nif gtk_dep.version().version_compare('>=4.12')\n  add_project_arguments('--define=GTK_4_12', language: 'vala')\nendif\n\nadw_dep = dependency('libadwaita-1')\nif adw_dep.version().version_compare('>=1.2')\n  add_project_arguments('--define=ADW_1_2', language: 'vala')\nendif\nif adw_dep.version().version_compare('>=1.3')\n  add_project_arguments('--define=ADW_1_3', language: 'vala')\nendif\nif adw_dep.version().version_compare('>=1.4')\n  add_project_arguments('--define=ADW_1_4', language: 'vala')\nendif\nif adw_dep.version().version_compare('>=1.5')\n  add_project_arguments('--define=ADW_1_5', language: 'vala')\nendif\nif adw_dep.version().version_compare('>=1.6')\n  add_project_arguments('--define=ADW_1_6', language: 'vala')\nendif\n\nlibm_dep = c_compiler.find_library('m', required: false)\nposix_dep = vala_compiler.find_library('posix', required: false)\n\ndependencies = [\n  dependency('gstreamer-1.0'),\n  dependency('gstreamer-tag-1.0'),\n  adw_dep,\n  libm_dep,\n  posix_dep,\n]\n\nsubdir('data')\nsubdir('po')\nsubdir('src')\n\ngnome.post_install(\n  glib_compile_schemas: true,\n  gtk_update_icon_cache: true,\n  update_desktop_database: true,\n)\n"
  },
  {
    "path": "pkgs/flatpak/com.github.neithern.g4music.json",
    "content": "{\n    \"app-id\": \"com.github.neithern.g4music\",\n    \"runtime\": \"org.gnome.Platform\",\n    \"runtime-version\": \"49\",\n    \"sdk\": \"org.gnome.Sdk\",\n    \"command\": \"g4music\",\n    \"finish-args\": [\n        \"--device=dri\",\n        \"--share=ipc\",\n        \"--share=network\",\n        \"--socket=fallback-x11\",\n        \"--socket=pulseaudio\",\n        \"--socket=wayland\",\n        \"--filesystem=xdg-music\",\n        \"--talk-name=org.gtk.vfs.*\"\n    ],\n    \"cleanup\": [\n        \"/include\",\n        \"/lib/pkgconfig\",\n        \"/man\",\n        \"/share/doc\",\n        \"/share/gtk-doc\",\n        \"/share/man\",\n        \"/share/pkgconfig\",\n        \"/share/vala\",\n        \"*.la\",\n        \"*.a\"\n    ],\n    \"modules\": [\n        {\n            \"name\": \"g4music\",\n            \"builddir\": true,\n            \"buildsystem\": \"meson\",\n            \"sources\": [\n                {\n                    \"type\": \"dir\",\n                    \"path\": \"../../\"\n                }\n            ]\n        }\n    ]\n}"
  },
  {
    "path": "po/LINGUAS",
    "content": "be\nbg\ncs\nda\nde\nel\nes\net\neu\nfa\nfi\nfr\nhe\nhi\nhu\nia\nid\nit\nja\nka\nnl\noc\npt_BR\nro\nru\nsk\nsl\nsv\ntr\nuk\nzh_CN\nzh_TW\n"
  },
  {
    "path": "po/POTFILES.in",
    "content": "data/app.desktop.in\ndata/app.metainfo.xml.in\nsrc/gtk/help-overlay.ui\nsrc/gtk/play-panel.ui\nsrc/gtk/preferences.ui\nsrc/gtk/store-panel.ui\nsrc/action-handles.vala\nsrc/application.vala\nsrc/main.vala\nsrc/ui/dialogs.vala\nsrc/ui/music-list.vala\nsrc/ui/music-widgets.vala\nsrc/ui/play-bar.vala\nsrc/ui/play-panel.vala\nsrc/ui/playlist-dialog.vala\nsrc/ui/preferences.vala\nsrc/ui/store-panel.vala\nsrc/ui/taglist-dialog.vala\nsrc/ui/volume-button.vala\nsrc/ui/window.vala\nsrc/utils/music.vala"
  },
  {
    "path": "po/UPDATE.md",
    "content": "### Run at build directory:\n1. Update main pot file: `meson compile g4music-pot`\n2. Update .po files: `meson compile g4music-update-po`\n"
  },
  {
    "path": "po/be.po",
    "content": "# Belarusian translation for g4music.\n# Copyright (C) 2023 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Yuras Shumovich <shumovichy@gmail.com>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-10-11 01:38+0000\\n\"\n\"PO-Revision-Date: 2024-10-22 16:13+0300\\n\"\n\"Last-Translator: Yuras Shumovich <shumovichy@gmail.com>\\n\"\n\"Language-Team: Belarusian <i18n-bel-gnome@googlegroups.com>\\n\"\n\"Language: be\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && \"\n\"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Прайгравальнік музыкі\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Вытанчанае прайграванне музыкі\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"music;sound;player;media;audio;playlist;музыка;гук;прайгравальнік;плэер;\"\n\"мультымедыя;аўдыя;спіс прайгравання;плэйліст;плэй-ліст;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (таксама вядомы як G4Music) легкаважны прайгравальнік музыкі, які \"\n\"напісаны на GTK4 і накіраваны на працу з вялікімі аўдыякалекцыямі.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Магчымасці\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Падтрымка вялікай колькасці аўдыяфарматаў, аддаленага пратакола Samba і \"\n\"іншых (у залежнасці ад GIO і GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Хуткая загрузка і аналіз тысяч аўдыяфайлаў за лічаныя секунды, назіранне за \"\n\"змяненнем лакальных файлаў.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Нізкае выкарыстанне памяці для вялікіх аўдыякалекцый з вокладкамі альбомаў \"\n\"(убудаваных і знешніх) без захавання кэша мініяцюр.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Групаванне і сартаванне альбомаў/выканаўцаў/назваў, выпадковы парадак, \"\n\"паўнатэкставы пошук.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Адаптыўны інтэрфейс карыстальніка, прыдатны для розных памераў экрана (ПК, \"\n\"Планшэт, Мабільныя прылады).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Фон з размытай вокладкі, змяненне светлага і цёмнага рэжыму згодна з \"\n\"наладамі сістэмы.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Стварэнне і рэдагаванне спісаў прайгравання, перацягванне вокладкі для \"\n\"змянення парадку або дадавання ў іншы спіс прайгравання.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Перацягванне з іншых праграм.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Візуалізацыя пікавага ўзроўню гуку.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Бесперапыннае прайграванне.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Нармалізацыя гучнасці праз ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Вызначэнне прыёмнікаў аўдыясігналу.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Кіраванне праз MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Галоўнае акно\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Акно «Альбомы»\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Акно «Прайграванне»\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Акно «Спіс прайгравання»\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Агульныя\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Паказаць спалучэнні клавіш\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Налады\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Выйсці\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Паказаць тэгі\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Прайграванне\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Прайграванне/паўза\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Наступная дарожка\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Папярэдняя дарожка\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Спіс прайгравання\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Пошук\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Пераключыць сартаванне\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Абнавіць бібліятэку\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Захаваць спіс\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"Назад\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Агульныя\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Рэжым размывання фону\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Кампактны спіс прайгравання\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Рэжым сеткі для выканаўцаў/альбомаў\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Актывацыя элемента адзінарным націсканнем мышы\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"Працягваць прайграванне пасля закрыцця акна\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Бібліятэка\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Загружаць музыку з папкі\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Сачыць за змяненнем лакальных файлаў\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Загружаць мініяцюры для не лакальных файлаў\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Можа выклікаць празмернае выкарыстанне і запавольванне працы сеткі\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Прайграванне\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Паказваць пікавы ўзровень гуку\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Сімвалы для вываду\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Кружэнне вокладкі альбома\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Уключыць бесперапыннае прайграванне\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Нармалізацыя гучнасці праз ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Пераважны прыёмнік сігналу GStreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Галоўнае меню\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Пошук\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"Сартаванне\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"Схема _колераў\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"Сіс_тэмная\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"_Светлая\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_Цёмная\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"_Абнавіць бібліятэку\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"_Выбраць некалькі\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"_Захаваць спіс\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"_Налады\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Спалучэнні клавіш\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"_Аб праграме\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Альбом\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"Выканаўца\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"Выканаўца/Альбом\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"Назва\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"Нядаўнія\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"Выпадковы парадак\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Файлы выяў\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Вокладка экспартавана\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Не ўдалося экспартаваць вокладку\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"Не ўдалося захаваць спіс прайгравання\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"Файлы спісаў прайгравання\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"Спіс прайгравання захаваны\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"Працягваць прайграванне\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Хуткі плаўны і лёгкі прайгравальнік музыкі напісаны на аснове GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"Юрась Шумовіч <shumovichy@gmail.com>\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"Не\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"Так\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Спіс прайгравання зменены, захаваць яго?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Паставіць _наступнай\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Дадаць у _чаргу прайгравання\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Дадаць у _спіс прайгравання…\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"_Выдаліць\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"_Перамясціць у сметніцу\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"Выбраць усе\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"Паставіць наступнай\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"Дадаць у чаргу прайгравання\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Дадаць у спіс прайгравання\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"Выдаліць\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"Прайграць\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Выпадковае прайграванне\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Паказаць _файл спіса\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Пошук па назве\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Пошук па альбому\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Пошук па выканаўцу\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Паказаць файл _вокладкі\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Экспартаваць вокладку\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Паказаць _тэгі…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Паказаць размяшчэнне _файла\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Паўтор адной песні\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Папярэдняя дарожка\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Прайграванне/паўза\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Наступная дарожка\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Перацягніце сюды аўдыяфайлы або \\n\"\n\"змяніце месца размяшчэння музыкі: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Новы спіс прайгравання\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:692\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"У «%s» спісы прайгравання не знойдзены\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Ніколі\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Заўсёды\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Толькі з вокладкай\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Дарожка\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Прайграванне\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Выканаўцы\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Альбомы\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Спісы прайгравання\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Капіяваць\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Гучнасць %d%%\"\n\n#: src/ui/window.vala:112\nmsgid \"Show\"\nmsgstr \"Паказаць\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Невядомы альбом\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Невядомы выканаўца\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"Прайграванне музыкі\"\n\n# аўтар праграмы, Nanling Zheng\n#~ msgid \"Nanling\"\n#~ msgstr \"Nanling\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"\"\n#~ \"Перацягванне з праграмы «Файлы» і паказ размяшчэння музыкі з яе дапамогай.\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"Аддаваць перавагу цёмнай тэме\"\n\n#~ msgid \"Close\"\n#~ msgstr \"Закрыць\"\n\n#, c-format\n#~ msgid \"No playlist found in: %s\"\n#~ msgstr \"Спісы прайгравання не знойдзены ў: «%s»\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"G4Music\"\n"
  },
  {
    "path": "po/bg.po",
    "content": "# Bulgarian translation of g4music po-file.\n# Copyright (C) 2024 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# twlvnn kraftwerk <kraft_werk@tutanota.com>, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-11-30 13:45+0000\\n\"\n\"PO-Revision-Date: 2024-12-25 18:49+0100\\n\"\n\"Last-Translator: twlvnn kraftwerk <kraft_werk@tutanota.com>\\n\"\n\"Language-Team: Bulgarian <dict-notifications@fsa-bg.org>\\n\"\n\"Language: bg\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1)\\n\"\n\"X-Generator: Gtranslator 47.0\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:273\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Програма за музика\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Елегантно си слушайте музика\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"музика;музикално устройство;медия;звук;аудио;списък с \"\n\"песни;music;sound;player;media;audio;playlist;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"„Gapless“ (известен още като: G4Music) е лек музикален плеър за GTK4, който \"\n\"се фокусира върху големи музикални колекции.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Функции\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Поддържа повечето видове музикални файлове, Samba и всякакви други \"\n\"отдалечени протоколи (зависи от GIO и GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Бързо зареждане и анализ на хиляди музикални файлове за секунди и наблюдение \"\n\"на локалните промени.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Ниски изисквания за памет за голяма музикална колекция с обложки на албуми \"\n\"(вградени и външни), без кеширане на миниатюри.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Групиране и подреждане по албум/изпълнител/заглавие, списък за разбъркване, \"\n\"пълнотекстово търсене.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Адаптивен потребителски интерфейс за различни екрани (настолен компютър, \"\n\"таблет, мобилен телефон).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Гаусово замъглена обложка на песните като за фон, поддържа светъл/тъмен \"\n\"режим на стил за GNOME.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Поддържа създаване и редактиране на списъци за изпълняване и плъзгане на \"\n\"корицата, за да промените реда или да добавите към друг списък.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Поддържа изтегляне и пускане с други програми.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Поддържа визуализатор за аудио пиковете.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Поддържа изпълняване без интервали между песните.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Поддържа нормализиране на силата на звука чрез изравняване на звука.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Поддържа посочения аудио приемник.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Поддържа контрол с MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Основен прозорец\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Изглед на албуми\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Изглед на изпълняване\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Изглед на списъка\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Общи\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Показване на клавишните комбинации\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Настройки\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Спиране на програмата\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Показване на етикетите\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Изпълнение\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Изпълнение/Пауза\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Изпълняване на следващата\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Изпълняване на предишната\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Списък с песни\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Търсене\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Превключване на подреждането\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Презареждане на фонотеката\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Запазване на списъка\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:632\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"Назад\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Общи\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Режим на замъгляване на фона\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Компактен изглед на списъка\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Мрежов изглед за изпълнители/албуми\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Единично натискане за включване на елемент\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:434\nmsgid \"Keep playing after window closed\"\nmsgstr \"Продължаване на изпълняването след затваряне\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Фонотека\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Зареждане на музика от папка\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Наблюдаване за промени в локалните файлове\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Зареждане на миниатюри за нелокални файлове\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Може да причини забавяне и високо използване на мрежата\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Изпълнение\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Показване на пиковото ниво на звука\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Показване на знаците\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Обръщане на обложката на албума\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Включване на изпълняване без интервали\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Нормализиране на силата на звука с регулиране\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Предпочитане на GStreamer аудио приемник\"\n\n#: src/gtk/store-panel.ui:23\nmsgid \"Main Menu\"\nmsgstr \"Основно меню\"\n\n#: src/gtk/store-panel.ui:30 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Търсене\"\n\n#: src/gtk/store-panel.ui:40\nmsgid \"Sort By\"\nmsgstr \"Подреждане по\"\n\n#: src/gtk/store-panel.ui:71\nmsgid \"_Color Scheme\"\nmsgstr \"_Цветова схема\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_System\"\nmsgstr \"_Системен стил\"\n\n#: src/gtk/store-panel.ui:78\nmsgid \"_Light\"\nmsgstr \"_Светла\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Dark\"\nmsgstr \"_Тъмна\"\n\n#: src/gtk/store-panel.ui:90\nmsgid \"_Reload Library\"\nmsgstr \"_Презареждане на фонотеката\"\n\n#: src/gtk/store-panel.ui:94\nmsgid \"_Multiple Select\"\nmsgstr \"_Множествен избор\"\n\n#: src/gtk/store-panel.ui:98\nmsgid \"_Save List\"\nmsgstr \"_Запазване на списъка\"\n\n#: src/gtk/store-panel.ui:104\nmsgid \"_Preferences\"\nmsgstr \"_Настройки\"\n\n#: src/gtk/store-panel.ui:108\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Клавишни комбинации\"\n\n#: src/gtk/store-panel.ui:112\nmsgid \"_About\"\nmsgstr \"_Относно\"\n\n#: src/gtk/store-panel.ui:121 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Албум\"\n\n#: src/gtk/store-panel.ui:126\nmsgid \"Artist\"\nmsgstr \"Автор\"\n\n#: src/gtk/store-panel.ui:131\nmsgid \"Artist/Album\"\nmsgstr \"Изпълнител/Албум\"\n\n#: src/gtk/store-panel.ui:136\nmsgid \"Title\"\nmsgstr \"Заглавие\"\n\n#: src/gtk/store-panel.ui:141\nmsgid \"Recent\"\nmsgstr \"Скорошни\"\n\n#: src/gtk/store-panel.ui:146\nmsgid \"Shuffle\"\nmsgstr \"Разбъркване\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Файлове с изображения\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Обложката е успешно изнесена\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Обложката не може да бъде изнесена\"\n\n#: src/application.vala:346\nmsgid \"Save playlist failed\"\nmsgstr \"Списъкът не може да бъде запазен\"\n\n#: src/application.vala:470\nmsgid \"Playlist Files\"\nmsgstr \"Файлове на списъка\"\n\n#: src/application.vala:485\nmsgid \"Save playlist successfully\"\nmsgstr \"Списъкът е успешно запазен\"\n\n#: src/application.vala:620\nmsgid \"Keep playing\"\nmsgstr \"Продължаване\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Бърза, адаптивна и лека програма за музика, написана на GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"\"\n\"Twlvnn Kraftwerk &lt;<a \"\n\"href='mailto:kraft_werk@tutanota.com'>kraft_werk@tutanota.com</a>&gt;\\n\"\n\"\\n\"\n\"\\n\"\n\"Проектът за превод на GNOME има нужда от подкрепа.\\n\"\n\"Научете повече за нас на <a href='https://fsa-bg.org/project/gtp'>уеб сайта</\"\n\"a> ни.\\n\"\n\"Докладвайте за грешки в превода в <a href='https://fsa-bg.org/project/gtp/\"\n\"newticket'>съответния раздел</a>.\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:112\nmsgid \"No\"\nmsgstr \"Не\"\n\n#: src/ui/dialogs.vala:101 src/ui/dialogs.vala:112\nmsgid \"Yes\"\nmsgstr \"Да\"\n\n#: src/ui/music-list.vala:276\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Списъкът е променен, искате ли да го запазите?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:405 src/ui/music-list.vala:421\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Изпълняване при _следваща\"\n\n#: src/ui/music-list.vala:407 src/ui/music-list.vala:423\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Добавяне в _опашката\"\n\n#: src/ui/music-list.vala:408 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Добавяне в _списък…\"\n\n#: src/ui/music-list.vala:409 src/ui/music-list.vala:427\nmsgid \"_Remove\"\nmsgstr \"_Премахване\"\n\n#: src/ui/music-list.vala:428 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"_Преместване в кошчето\"\n\n#: src/ui/music-list.vala:636\nmsgid \"Select All\"\nmsgstr \"Избор на всички\"\n\n#: src/ui/music-list.vala:653\nmsgid \"Play at Next\"\nmsgstr \"Изпълняване при следваща\"\n\n#: src/ui/music-list.vala:660\nmsgid \"Add to Queue\"\nmsgstr \"Добавяне в опашката\"\n\n#: src/ui/music-list.vala:667 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Добавяне в списък\"\n\n#: src/ui/music-list.vala:674\nmsgid \"Remove\"\nmsgstr \"Премахване\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"Изпълнение\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Случайна песен\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Показване на _файла на списъка\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Търсене на заглавие\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Търсене на албум\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Търсене на изпълнител\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Показване на _файла на обложката\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Изнасяне на обложката\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Показване на _етикетите…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Показване на музикалния _файл\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Повторение\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Предишна\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Изпълнение/Пауза\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Следваща\"\n\n#: src/ui/play-panel.vala:263\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Изтеглете и пуснете музикални файлове тук,\\n\"\n\"или променете местоположението на музиката: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Нов списък\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:703\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Няма намерен списък за песни в %s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Никога\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Винаги\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Само обложка\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Песен\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"В момента слушате\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Автори\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Албуми\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Списъци за изпълнение\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Копиране\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Сила на звука %d%%\"\n\n#: src/ui/window.vala:119\nmsgid \"Show\"\nmsgstr \"Показване\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Неизвестен албум\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Неизвестен автор\"\n"
  },
  {
    "path": "po/cs.po",
    "content": "# Czech translation for g4music.\n# Copyright (C) 2024 Nanling\n# This file is distributed under the same license as the g4music package.\n# Peri123214 <codegemjava@gmail.com>, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-09-30 04:20+0000\\n\"\n\"PO-Revision-Date: 2024-09-30 13:20+0200\\n\"\n\"Last-Translator: Daniel Rusek <mail@asciiwolf.com>\\n\"\n\"Language-Team: Czech <gnome-cs-list@gnome.org>\\n\"\n\"Language: cs\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:234\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Přehrávač hudby\"\n\n#: data/app.desktop.in:5\nmsgid \"Play music\"\nmsgstr \"Přehrát hudbu\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"hudba;zvuk;přehrávač;média;audio;seznam skladeb;\"\n\n#: data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Přehrávejte hudbu elegantně\"\n\n#: data/app.metainfo.xml.in:9\nmsgid \"Nanling\"\nmsgstr \"Nanling\"\n\n#: data/app.metainfo.xml.in:22\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (také známý jako G4Music) je lehký hudební přehrávač napsaný v GTK4, \"\n\"zaměřuje se na velkou hudební sbírku.\"\n\n#: data/app.metainfo.xml.in:23\nmsgid \"Features\"\nmsgstr \"Funkce\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Podporuje většinu typů hudebních souborů, Sambu a jakékoli další vzdálené \"\n\"protokoly (závisí na GIO a GStreamer).\"\n\n#: data/app.metainfo.xml.in:26\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Rychlé načítání a analýza tisíců hudebních souborů během několika sekund, \"\n\"sledování místních změn.\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Nízké využití paměti při velké hudební sbírce s obaly alb (vloženými i \"\n\"externími), žádná mezipaměť pro miniatury k ukládání.\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Seskupení a řazení podle alba / umělce / názvu, náhodného seznamu, \"\n\"fulltextového vyhledávání.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Plynule adaptivní uživatelské rozhraní pro různé obrazovky (desktop, tablet, \"\n\"telefon).\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Gaussovský rozmazaný přebal jako pozadí, následuje světlý / tmavý režim \"\n\"GNOME.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"Drag-drop from GNOME Files, showing music in Files.\"\nmsgstr \"Přetažení ze Souborů GNOME, zobrazení hudby v Souborech.\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Podporuje vizualizér maximálních úrovní zvuku.\"\n\n# Myslím si, že v kontextu aplikace toto bude lepší překlad než ten doslovný\n#: data/app.metainfo.xml.in:33\nmsgid \"Supports gapless playback.\"\nmsgstr \"Podporuje automatické opakování.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Podporuje normalizaci hlasitosti s ReplayGain.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports PipeWire and other audio sink.\"\nmsgstr \"Podporuje PipeWire a další vstupní body zvuku.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Podporuje ovládání MPRIS.\"\n\n#: data/app.metainfo.xml.in:47\nmsgid \"Main window\"\nmsgstr \"Hlavní okno\"\n\n#: data/app.metainfo.xml.in:51\nmsgid \"Albums view\"\nmsgstr \"Zobrazení alb\"\n\n#: data/app.metainfo.xml.in:55\nmsgid \"Playing view\"\nmsgstr \"Zobrazení přehrávání\"\n\n#: data/app.metainfo.xml.in:59\nmsgid \"Playlist view\"\nmsgstr \"Zobrazení seznamu skladeb\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Obecné\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Zobrazit zkratky\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Předvolby\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Ukončit\"\n\n#: src/gtk/help-overlay.ui:34\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Přehrávání\"\n\n#: src/gtk/help-overlay.ui:37\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Přehrát / pozastavit\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Přehrát další\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Přehrát předchozí\"\n\n#: src/gtk/help-overlay.ui:57\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Seznam skladeb\"\n\n#: src/gtk/help-overlay.ui:60\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Hledat\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Přepnout řazení\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Obnovit knihovnu\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:606\n#: src/ui/store-panel.vala:413\nmsgid \"Back\"\nmsgstr \"Zpět\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Obecné\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Režim rozostření pozadí\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Kompaktní zobrazení seznamu skladeb\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Mřížkové zobrazení umělců / alb\"\n\n#: src/gtk/preferences.ui:44 src/application.vala:403\nmsgid \"Keep playing after window closed\"\nmsgstr \"Nechat přehrávat po zavření okna\"\n\n#: src/gtk/preferences.ui:57\nmsgid \"Library\"\nmsgstr \"Knihovna\"\n\n#: src/gtk/preferences.ui:61\nmsgid \"Load music from folder\"\nmsgstr \"Načíst hudbu ze složky\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Monitor local file changes\"\nmsgstr \"Kontrolovat místní změny souborů\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Načítat přebaly vzdálených souborů\"\n\n#: src/gtk/preferences.ui:86\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Může způsobit zpomalení a přebytečné použití sítě\"\n\n#: src/gtk/preferences.ui:99\nmsgid \"Playback\"\nmsgstr \"Přehrávání\"\n\n#: src/gtk/preferences.ui:103\nmsgid \"Show audio peak level\"\nmsgstr \"Zobrazovat maximální úrovně zvuku\"\n\n# Myslím si, že v kontextu aplikace toto bude lepší překlad než ten doslovný\n#: src/gtk/preferences.ui:107\nmsgid \"Display characters\"\nmsgstr \"Zobrazováno pomocí\"\n\n#: src/gtk/preferences.ui:122\nmsgid \"Rotate album cover\"\nmsgstr \"Otáčet přebal alba\"\n\n# Myslím si, že v kontextu aplikace toto bude lepší překlad než ten doslovný\n#: src/gtk/preferences.ui:134\nmsgid \"Enable gapless playback\"\nmsgstr \"Povolit automatické opakování\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalizovat hlasitost s ReplayGain\"\n\n#: src/gtk/preferences.ui:152\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Preferovaný vstupní bod GStreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Hlavní nabídka\"\n\n#: src/gtk/store-panel.ui:29 src/ui/dialogs.vala:75\nmsgid \"Search\"\nmsgstr \"Hledat\"\n\n#: src/gtk/store-panel.ui:35\nmsgid \"Sort By\"\nmsgstr \"Seřadit podle\"\n\n#: src/gtk/store-panel.ui:58\nmsgid \"_Color Scheme\"\nmsgstr \"Barevné s_chéma\"\n\n#: src/gtk/store-panel.ui:60\nmsgid \"_System\"\nmsgstr \"S_ystémové\"\n\n#: src/gtk/store-panel.ui:65\nmsgid \"_Light\"\nmsgstr \"_Světlé\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Dark\"\nmsgstr \"_Tmavé\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Reload Library\"\nmsgstr \"O_bnovit knihovnu\"\n\n#: src/gtk/store-panel.ui:81\nmsgid \"_Select\"\nmsgstr \"_Vybrat\"\n\n#: src/gtk/store-panel.ui:87\nmsgid \"_Preferences\"\nmsgstr \"_Předvolby\"\n\n#: src/gtk/store-panel.ui:91\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Klávesové zkratky\"\n\n#: src/gtk/store-panel.ui:95\nmsgid \"_About\"\nmsgstr \"O _aplikaci\"\n\n#: src/gtk/store-panel.ui:104 src/ui/preferences.vala:63\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:109\nmsgid \"Artist\"\nmsgstr \"Umělec\"\n\n#: src/gtk/store-panel.ui:114\nmsgid \"Artist/Album\"\nmsgstr \"Umělec / album\"\n\n#: src/gtk/store-panel.ui:119\nmsgid \"Title\"\nmsgstr \"Název\"\n\n#: src/gtk/store-panel.ui:124\nmsgid \"Recent\"\nmsgstr \"Nedávné\"\n\n#: src/gtk/store-panel.ui:129\nmsgid \"Shuffle\"\nmsgstr \"Náhodné\"\n\n#: src/action-handles.vala:97\nmsgid \"Image Files\"\nmsgstr \"Soubory obrázků\"\n\n#: src/action-handles.vala:104\nmsgid \"Export cover successfully\"\nmsgstr \"Přebal byl úspěšně exportován\"\n\n#: src/action-handles.vala:104\nmsgid \"Export cover failed\"\nmsgstr \"Exportování přebalu se nezdařilo\"\n\n#: src/action-handles.vala:196\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Rychlý, plynulý a lehký hudební přehrávač napsaný v GTK4.\"\n\n# Pozn.: V šabloně pro překlad chybí některé klíče (např. pro tlačítko smazání ve vyhledávání)\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/action-handles.vala:198\nmsgid \"translator-credits\"\nmsgstr \"Peri123214 <codegemjava@gmail.com>\"\n\n#: src/application.vala:307\nmsgid \"Save playlist failed\"\nmsgstr \"Uložení seznamu skladeb se nezdařilo\"\n\n#: src/application.vala:425\nmsgid \"Playlist Files\"\nmsgstr \"Soubory seznamu skladeb\"\n\n#: src/application.vala:439\nmsgid \"Save playlist successfully\"\nmsgstr \"Seznam skladeb byl úspěšně uložen\"\n\n#: src/application.vala:618\nmsgid \"Keep playing\"\nmsgstr \"Nechat přehrávat\"\n\n#: src/ui/dialogs.vala:50 src/ui/music-list.vala:641\nmsgid \"Add to Playlist\"\nmsgstr \"Přidat do seznamu skladeb\"\n\n#: src/ui/dialogs.vala:55\nmsgid \"New Playlist\"\nmsgstr \"Nový seznam skladeb\"\n\n#: src/ui/dialogs.vala:62\nmsgid \"Close\"\nmsgstr \"Zavřít\"\n\n#: src/ui/dialogs.vala:127 src/ui/store-panel.vala:662\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"V %s nebyl nalezen žádný seznam skladeb\"\n\n#: src/ui/dialogs.vala:253\nmsgid \"Copy\"\nmsgstr \"Kopírovat\"\n\n#: src/ui/dialogs.vala:344 src/ui/dialogs.vala:356\nmsgid \"No\"\nmsgstr \"Ne\"\n\n#: src/ui/dialogs.vala:345 src/ui/dialogs.vala:356\nmsgid \"Yes\"\nmsgstr \"Ano\"\n\n#: src/ui/music-list.vala:262\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Seznam skladeb je upraven, uložit jej?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:390 src/ui/music-list.vala:407\n#: src/ui/music-list.vala:627 src/ui/music-widgets.vala:219\n#: src/ui/music-widgets.vala:230\nmsgid \"Play at Next\"\nmsgstr \"Přehrát jako další\"\n\n#: src/ui/music-list.vala:392 src/ui/music-list.vala:405\n#: src/ui/music-list.vala:634 src/ui/music-widgets.vala:220\n#: src/ui/music-widgets.vala:231\nmsgid \"Add to Queue\"\nmsgstr \"Přidat do fronty\"\n\n#: src/ui/music-list.vala:393 src/ui/music-widgets.vala:221\n#: src/ui/music-widgets.vala:232 src/ui/music-widgets.vala:245\nmsgid \"Add to Playlist…\"\nmsgstr \"Přidat do seznamu skladeb…\"\n\n#: src/ui/music-list.vala:394 src/ui/music-list.vala:648\nmsgid \"Remove\"\nmsgstr \"Odstranit\"\n\n#: src/ui/music-list.vala:410 src/ui/play-panel.vala:145\nmsgid \"Show _Cover File\"\nmsgstr \"Zob_razit přebal alba\"\n\n#: src/ui/music-list.vala:412 src/ui/play-panel.vala:147\nmsgid \"_Export Cover\"\nmsgstr \"_Exportovat přebal\"\n\n#: src/ui/music-list.vala:610\nmsgid \"Select All\"\nmsgstr \"Vybrat vše\"\n\n#: src/ui/music-widgets.vala:223\nmsgid \"Show List File\"\nmsgstr \"Zobrazit seznam\"\n\n#: src/ui/music-widgets.vala:238 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Vyhledat název\"\n\n#: src/ui/music-widgets.vala:239 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Vyhledat album\"\n\n#: src/ui/music-widgets.vala:240 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Vyhledat umělce\"\n\n#: src/ui/music-widgets.vala:242\nmsgid \"Show _Tags…\"\nmsgstr \"Zobrazit š_títky…\"\n\n#: src/ui/music-widgets.vala:243\nmsgid \"_Show Music File\"\nmsgstr \"_Zobrazit hudební soubor\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Opakovat jednu skladbu\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Přehrát předchozí\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Přehrát / pozastavit\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Přehrát další\"\n\n#: src/ui/play-panel.vala:264\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Táhněte a pusťte sem soubory s hudbou,\\n\"\n\"nebo změňte umístění hudby: \"\n\n#: src/ui/preferences.vala:42 src/ui/preferences.vala:63\nmsgid \"Never\"\nmsgstr \"Nikdy\"\n\n#: src/ui/preferences.vala:42\nmsgid \"Always\"\nmsgstr \"Vždy\"\n\n#: src/ui/preferences.vala:42\nmsgid \"Art Only\"\nmsgstr \"Pouze u skladeb s přebalem\"\n\n#: src/ui/preferences.vala:63\nmsgid \"Track\"\nmsgstr \"Skladba\"\n\n#: src/ui/store-panel.vala:82\nmsgid \"Playing\"\nmsgstr \"Přehrává se\"\n\n#: src/ui/store-panel.vala:86\nmsgid \"Artists\"\nmsgstr \"Umělci\"\n\n#: src/ui/store-panel.vala:90\nmsgid \"Albums\"\nmsgstr \"Alba\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Playlists\"\nmsgstr \"Seznamy skladeb\"\n\n#: src/ui/store-panel.vala:421\nmsgid \"Play\"\nmsgstr \"Přehrát\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Hlasitost %d%%\"\n\n#: src/ui/window.vala:110\nmsgid \"Show\"\nmsgstr \"Zobrazit\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Neznámé album\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Neznámý umělec\"\n"
  },
  {
    "path": "po/da.po",
    "content": "# Danish translation for g4music.\n# Copyright (C) 2023 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Alan Mortensen <alanmortensen.am@gmail.com>, 2023-25.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2025-01-21 14:09+0000\\n\"\n\"PO-Revision-Date: 2025-02-18 15:06+0100\\n\"\n\"Last-Translator: Alan Mortensen <alanmortensen.am@gmail.com>\\n\"\n\"Language-Team: Danish <dansk@dansk-gruppen.dk>\\n\"\n\"Language: da\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.4.2\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:273\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Uden pauser\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Musikafspiller\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Afspil din musik på en elegant måde\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"musik;lyd;afspiller;medie;afspilningsliste;playliste;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (også kendt som G4Music) er en letvægtsmusikafspiller skrevet i \"\n\"GTK4, der fokuserer på store musiksamlinger.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Funktioner\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Understøtter de fleste musikfiltyper, Samba og andre fjernprotokoller \"\n\"(afhænger af GIO og GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Hurtig indlæsning og analyse af tusindvis af musikfiler på meget få sekunder \"\n\"plus overvågning af lokale ændringer.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Lavt hukommelsesforbrug til store musiksamlinger med albumcovers (indlejrede \"\n\"og eksterne) og gemmer ingen miniaturecache.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Gruppering og sortering efter album/kunstner/titel, blande-liste, \"\n\"fuldtekstsøgning.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Flydende tilpasning af brugergrænseflade til forskellige skærme (desktop, \"\n\"tablet, mobil).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"Gaussisk sløret cover som baggrund, følger GNOMEs lyse/mørke tilstand.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Understøtter oprettelse og redigering af afspilningslister, trækning af \"\n\"cover for at ændre rækkefølge eller tilføjelse til en anden afspilningsliste.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Understøtter træk-og-slip med andre programmer.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Understøtter visualisering af lydtoppe.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Understøtter afspilning uden pauser.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Understøtter normalisering af lydstyrke med ReplayGain\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Understøtter angivet lyddatamodtager.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Understøtter MPRIS-kontrol.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Hovedvindue\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Albumvisning\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Afspilningsvisning\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Afspilningslistevisning\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Generelt\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Vis genveje\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Indstillinger\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Afslut\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Vis mærkater\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Afspilning\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Afspil/pause\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Afspil næste\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Afspil forrige\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Afspilningsliste\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Søgning\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Skift sortering\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Genindlæs bibliotek\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Gem liste\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:632\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"Tilbage\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Generelt\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Baggrundssløringstilstand\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Kompakt visning af afspilningsliste\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Gittervisning af kunstnere/album\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Enkeltklik for at aktivere element\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:434\nmsgid \"Keep playing after window closed\"\nmsgstr \"Fortsæt med at afspille, efter vinduet er lukket\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Bibliotek\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Indlæs musik fra mappe\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Overvåg lokale filændringer\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Indlæs ikkelokale filers miniaturebilleder\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Kan forårsage langsommere afvikling og forøget netværksforbrug\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Afspilning\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Vis topniveau for lyd\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Vis tegn\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Rotér albumcover\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Aktivér afspilning uden mellemrum\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalisér lydstyrke med ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Foretræk GSteamers lyddatamodtager\"\n\n#: src/gtk/store-panel.ui:23\nmsgid \"Main Menu\"\nmsgstr \"Hovedmenu\"\n\n#: src/gtk/store-panel.ui:30 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Søg\"\n\n#: src/gtk/store-panel.ui:40\nmsgid \"Sort By\"\nmsgstr \"Sortér efter\"\n\n#: src/gtk/store-panel.ui:71\nmsgid \"_Color Scheme\"\nmsgstr \"_Farveskema\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_System\"\nmsgstr \"_System\"\n\n#: src/gtk/store-panel.ui:78\nmsgid \"_Light\"\nmsgstr \"_Lys\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Dark\"\nmsgstr \"_Mørk\"\n\n#: src/gtk/store-panel.ui:90\nmsgid \"_Reload Library\"\nmsgstr \"_Genindlæs bibliotek\"\n\n#: src/gtk/store-panel.ui:94\nmsgid \"_Multiple Select\"\nmsgstr \"_Vælg flere\"\n\n#: src/gtk/store-panel.ui:98\nmsgid \"_Save List\"\nmsgstr \"G_em liste\"\n\n#: src/gtk/store-panel.ui:104\nmsgid \"_Preferences\"\nmsgstr \"_Indstillinger\"\n\n#: src/gtk/store-panel.ui:108\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Tastaturgenveje\"\n\n#: src/gtk/store-panel.ui:112\nmsgid \"_About\"\nmsgstr \"_Om\"\n\n#: src/gtk/store-panel.ui:121 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:126\nmsgid \"Artist\"\nmsgstr \"Kunstner\"\n\n#: src/gtk/store-panel.ui:131\nmsgid \"Artist/Album\"\nmsgstr \"Kunstner/Album\"\n\n#: src/gtk/store-panel.ui:136\nmsgid \"Title\"\nmsgstr \"Titel\"\n\n#: src/gtk/store-panel.ui:141\nmsgid \"Recent\"\nmsgstr \"Seneste\"\n\n#: src/gtk/store-panel.ui:146\nmsgid \"Shuffle\"\nmsgstr \"Bland\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Billedfiler\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Eksport af cover gennemført\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Eksport af cover mislykkedes\"\n\n#: src/application.vala:346\nmsgid \"Save playlist failed\"\nmsgstr \"Afspilningsliste kunne ikke gemmes\"\n\n#: src/application.vala:470\nmsgid \"Playlist Files\"\nmsgstr \"Afspilningslistefiler\"\n\n#: src/application.vala:485\nmsgid \"Save playlist successfully\"\nmsgstr \"Afspilningsliste blev gemt\"\n\n#: src/application.vala:620\nmsgid \"Keep playing\"\nmsgstr \"Fortsæt med at afspille\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"En hurtig og flydende letvægtsmusikafspiller skrevet i GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"\"\n\"Alan Mortensen <alanmortensen.am@gmail.com>\\n\"\n\"\\n\"\n\"Dansk-gruppen\\n\"\n\"Websted http://dansk-gruppen.dk\\n\"\n\"E-mail <dansk@dansk-gruppen.dk>\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:112\nmsgid \"No\"\nmsgstr \"Nej\"\n\n#: src/ui/dialogs.vala:101 src/ui/dialogs.vala:112\nmsgid \"Yes\"\nmsgstr \"Ja\"\n\n#: src/ui/music-list.vala:276\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Vil du gemme den ændrede afspilningsliste?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:405 src/ui/music-list.vala:421\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Afspil ved _næste\"\n\n#: src/ui/music-list.vala:407 src/ui/music-list.vala:423\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"_Føj til afspilningskø\"\n\n#: src/ui/music-list.vala:408 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"F_øj til afspilningsliste …\"\n\n#: src/ui/music-list.vala:409 src/ui/music-list.vala:427\nmsgid \"_Remove\"\nmsgstr \"F_jern\"\n\n#: src/ui/music-list.vala:428 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"Fl_yt til papirkurven\"\n\n#: src/ui/music-list.vala:636\nmsgid \"Select All\"\nmsgstr \"Markér alt\"\n\n#: src/ui/music-list.vala:653\nmsgid \"Play at Next\"\nmsgstr \"Afspil ved næste\"\n\n#: src/ui/music-list.vala:660\nmsgid \"Add to Queue\"\nmsgstr \"Føj til afspilningskø\"\n\n#: src/ui/music-list.vala:667 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Føj til afspilningsliste\"\n\n#: src/ui/music-list.vala:674\nmsgid \"Remove\"\nmsgstr \"Fjern\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"Afspil\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Tilfældig afspilning\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"_Vis listefil\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Søg efter titel\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Søg efter album\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Søg efter kunstner\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Vis _coverfil\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Eksportér cover\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Vis _mærkater …\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Vis musikfil\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Enkelt afspilning\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Afspil forrige\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Afspil/pause\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Afspil næste\"\n\n#: src/ui/play-panel.vala:263\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Træk og slip musikfiler her,\\n\"\n\"eller ændr musikplacering: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Ny afspilningsliste\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:703\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Fandt ingen afspilningsliste i %s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Aldrig\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Altid\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Kun kunst\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Spor\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Afspiller\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Kunstnere\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Albummer\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Afspilningslister\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Kopiér\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Lydstyrke %d %%\"\n\n#: src/ui/window.vala:119\nmsgid \"Show\"\nmsgstr \"Vis\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Ukendt album\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Ukendt kunstner\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"Afspil musik\"\n\n#~ msgid \"Nanling\"\n#~ msgstr \"Nanling\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"Træk-og-slip fra GNOME Filer og få vist musik i Filer.\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"Foretræk mørkt tema\"\n\n#~ msgid \"Close\"\n#~ msgstr \"Luk\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"G4Musik\"\n"
  },
  {
    "path": "po/de.po",
    "content": "# GERMAN TRANSLATION FOR G4MUSIC.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# Jürgen Benvenuti <gastornis@posteo.org>, 2022-2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-10-14 16:49+0000\\n\"\n\"PO-Revision-Date: 2024-10-28 10:35+0100\\n\"\n\"Last-Translator: Jürgen Benvenuti <gastornis@posteo.org>\\n\"\n\"Language-Team: German <gnome-de@gnome.org>\\n\"\n\"Language: de\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.4.4\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:271\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Musikwiedergabe\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Geben Sie Ihre Musik auf elegante Weise wieder\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"music;sound;player;media;audio;playlist;Musik;Klang;Wiedergabe;Medien;Audio;\"\n\"Wiedergabeliste;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (alias »G4Music«) ist eine leichtgewichtige Musikwiedergabe, \"\n\"geschrieben in GTK, die sich auf große Musiksammlungen konzentriert.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Funktionen\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Unterstützt die meisten Musikdateitypen, Samba und alle anderen \"\n\"Fernzugriffsprotokolle (abhängig von GIO und GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Schnelles Laden und Verarbeiten von Tausenden von Musikdateien in wenigen \"\n\"Sekunden, Überwachen von lokalen Änderungen.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Geringer Speicherbedarf für große Musiksammlungen mit Albumbildern \"\n\"(eingebettet und extern), kein Zwischenspeichern von Vorschaubildern.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Gruppieren und sortieren nach Album/Interpret/Titel, Liste durchmischen, \"\n\"Volltextsuche.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Geschmeidige adaptive Benutzeroberfläche für unterschiedliche Bildschirme \"\n\"(Desktop, Tablet, mobiles Gerät).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Gauß-weichgezeichnete Albumbilder als Hintergrund, folgt dem hellen bzw. \"\n\"dunklen GNOME-Modus.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Unterstützt das Erstellen und Bearbeiten von Wiedergabelisten; ziehen Sie \"\n\"das Albumbild, um die Reihenfolge zu ändern oder zu einer anderen \"\n\"Wiedergabeliste hinzuzufügen.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Unterstützt Ziehen und Ablegen mit anderen Anwendungen.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Unterstützt die Visualisierung von Audiospitzenpegeln.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Unterstützt lückenlose Wiedergabe.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Unterstützt die Normalisierung der Lautstärke durch ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Unterstützt angegebenen Audio-Ausgang.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Unterstützt MPRIS-Steuerung.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Hauptfenster\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Albenansicht\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Wiedergabeansicht\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Wiedergabelistenansicht\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Allgemein\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Tastenkürzel anzeigen\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Einstellungen\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Beenden\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Schlagwörter anzeigen\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Wiedergabe\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Wiedergabe/Pause\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Den nächsten Titel wiedergeben\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Den vorherigen Titel wiedergeben\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Wiedergabeliste\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Suchen\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Sortiermodus umschalten\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Bibliothek neu laden\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Liste speichern\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:420\nmsgid \"Back\"\nmsgstr \"Zurück\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Allgemein\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Hintergrund weichzeichnen\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Kompaktansicht der Wiedergabeliste\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Rasteransicht für Interpreten/Alben\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Einfacher Klick zum Aktivieren des Elements\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:419\nmsgid \"Keep playing after window closed\"\nmsgstr \"Musik weiterspielen nach dem Schließen des Fensters\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Bibliothek\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Musik aus Ordner laden\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Lokale Dateiänderungen überwachen\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Vorschaubilder für nicht lokale Dateien laden\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Kann zu Verlangsamungen und übermäßiger Netznutzung führen\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Wiedergabe\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Audiospitzenpegel anzeigen\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Zeichen anzeigen\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Sich drehendes Albumbild\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Lückenlose Wiedergabe aktivieren\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"ReplayGain zur Normalisierung der Lautstärke verwenden\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Bevorzugter GStreamer-Audio-Ausgang\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Hauptmenü\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Suchen\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"Sortieren nach\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"_Farbschema\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"_System\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"_Hell\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_Dunkel\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"Bibliothek neu _laden\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"_Mehrere auswählen\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"Liste _speichern\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"_Einstellungen\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Tastenkürzel\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"_Info\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"Interpret\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"Interpret/Album\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"Titel\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"Zuletzt gespielt\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"Durchmischen\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Bilddateien\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Exportieren des Albumbilds erfolgreich\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Exportieren des Albumbilds fehlgeschlagen\"\n\n#: src/application.vala:344\nmsgid \"Save playlist failed\"\nmsgstr \"Speichern der Wiedergabeliste fehlgeschlagen\"\n\n#: src/application.vala:441\nmsgid \"Playlist Files\"\nmsgstr \"Wiedergabelistendateien\"\n\n#: src/application.vala:455\nmsgid \"Save playlist successfully\"\nmsgstr \"Speichern der Wiedergabeliste erfolgreich\"\n\n#: src/application.vala:591\nmsgid \"Keep playing\"\nmsgstr \"Musik weiterspielen\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"\"\n\"Eine schnelle, geschmeidige, leichtgewichtige Musikwiedergabe, geschrieben \"\n\"in GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"Jürgen Benvenuti <gastornis@posteo.org>, 2022-2024\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"Nein\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"Ja\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Wiedergabeliste wurde geändert, soll sie gespeichert werden?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Als _Nächstes wiedergeben\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Zur _Warteschlange hinzufügen\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Zur Wieder_gabeliste hinzufügen …\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"_Entfernen\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"In den _Papierkorb verschieben\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"Alle auswählen\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"Als Nächstes wiedergeben\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"Zur Warteschlange hinzufügen\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Zur Wiedergabeliste hinzufügen\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"Entfernen\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:428\nmsgid \"Play\"\nmsgstr \"Wiedergeben\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Zufällige Wiedergabe\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Listen_datei anzeigen\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:63\nmsgid \"Search Title\"\nmsgstr \"Titel suchen\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:61\nmsgid \"Search Album\"\nmsgstr \"Album suchen\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:62\nmsgid \"Search Artist\"\nmsgstr \"Interpret suchen\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Albumbild-_Datei anzeigen\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"Albumbild expo_rtieren\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"_Schlagwörter anzeigen …\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Musik_datei anzeigen\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Einfachschleife\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Den vorherigen Titel wiedergeben\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Wiedergabe/Pause\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Den nächsten Titel wiedergeben\"\n\n#: src/ui/play-panel.vala:258\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Musikdateien hierher ziehen und ablegen,\\n\"\n\"oder den Musikspeicherort ändern: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Neue Wiedergabeliste\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:697\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Keine Wiedergabeliste gefunden in %s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Nie\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Immer\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Nur mit Albumbild\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Titel\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Aktuelle Wiedergabe\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Interpreten\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Alben\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Wiedergabelisten\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Kopieren\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Lautstärke %d%%\"\n\n#: src/ui/window.vala:119\nmsgid \"Show\"\nmsgstr \"Anzeigen\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Unbekanntes Album\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Unbekannter Interpret\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"Musik wiedergeben\"\n\n#~ msgid \"Nanling\"\n#~ msgstr \"Nanling\"\n\n#~ msgid \"Close\"\n#~ msgstr \"Schließen\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"\"\n#~ \"Ziehen und ablegen aus GNOME-»Dateien«, zeigt Musik in »Dateien« an.\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"Dunkles Thema verwenden\"\n\n#~ msgid \"_Add to Playlist…\"\n#~ msgstr \"Zur Wiedergabeliste _hinzufügen …\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"G4Music\"\n\n#~ msgid \"Repeat Music\"\n#~ msgstr \"Den Titel wiederholen\"\n\n#~ msgid \"Music Location\"\n#~ msgstr \"Musikspeicherort\"\n\n#~ msgid \"Loading…\"\n#~ msgstr \"Wird geladen …\"\n\n#~ msgid \"By Album\"\n#~ msgstr \"Nach Album\"\n\n#~ msgid \"By Date\"\n#~ msgstr \"Nach Datum\"\n\n#~ msgid \"Appearance\"\n#~ msgstr \"Erscheinungsbild\"\n\n#~ msgid \"Experimental\"\n#~ msgstr \"Experimentell\"\n"
  },
  {
    "path": "po/el.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: \\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2025-09-11 07:33+0000\\n\"\n\"PO-Revision-Date: 2025-09-13 00:09+0300\\n\"\n\"Last-Translator: Dimitris Spentzos <jimspentzos2000@gmail.com>\\n\"\n\"Language-Team: \\n\"\n\"Language: el\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"X-Generator: Poedit 3.7\\n\"\n\n#: data/app.desktop.in:2 data/app.metainfo.xml.in:4 src/application.vala:273\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:3\nmsgid \"Music Player\"\nmsgstr \"Αναπαραγωγή μουσικής\"\n\n#: data/app.desktop.in:4 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Ακούστε τη μουσική σας με κομψότητα\"\n\n#: data/app.desktop.in:11\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"music;sound;player;media;audio;playlist;μουσική;λίστα;αναπαραγωγή;τραγούδια;ήχος;πολυμέσα;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Το Gapless (γνωστό κι ως «G4Music») είναι μια λιτή εφαρμογή αναπαραγωγής \"\n\"μουσικής, γραμμένη σε GTK4, που εστιάζει σε μεγάλες συλλογές μουσικής.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Δυνατότητες\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Υποστηρίζει τους περισσότερους τύπους αρχείων μουσικής, το Samba και \"\n\"οποιοδήποτε άλλο απομακρυσμένο πρωτόκολλο (εξαρτάται από τα GIO και \"\n\"GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Γρήγορη φόρτωση και ανάλυση χιλιάδων αρχείων μουσικής σε πολύ λίγα \"\n\"δευτερόλεπτα, εποπτεία για τοπικές αλλαγές.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Χαμηλή χρήση μνήμης για μεγάλες συλλογές μουσικής με εξώφυλλα άλμπουμ \"\n\"(ενσωματωμένα και εξωτερικά), χωρίς αποθήκευση προσωρινών μικρογραφιών.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Ομαδοποίηση και ταξινόμηση κατά άλμπουμ/καλλιτέχνη/τίτλο, τυχαία \"\n\"αναπαραγωγή λίστας, αναζήτηση πλήρους κειμένου.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Ευέλικτο και προσαρμοστικό γραφικό περιβάλλον για διαφορετικές οθόνες \"\n\"(υπολογιστές, tablet, κινητές συσκευές).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Γκαουσιανό θόλωμα εξωφύλλου ως εφέ παρασκηνίου, προσαρμογή στην \"\n\"ανοιχτόχρωμη/σκουρόχρωμη λειτουργία του GNOME.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Υποστηρίζει δημιουργία και επεξεργασία λιστών αναπαραγωγής, μεταφορά \"\n\"εξώφυλλων για αλλαγή της σειράς ή προσθήκη σε άλλη λίστα αναπαραγωγής.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Υποστηρίζει μεταφορά και απόθεση με άλλες εφαρμογές.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Υποστηρίζει οπτικοποίηση κορυφώσεων ήχου.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Υποστηρίζει απρόσκοπτη αναπαραγωγή.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Υποστηρίζει κανονικοποίηση έντασης με το ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Υποστηρίζει ορισμό συγκεκριμένης διεπαφής ήχου.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Υποστηρίζει έλεγχο MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Κύριο παράθυρο\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Προβολή άλμπουμ\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Προβολή αναπαραγωγής\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Προβολή λιστών αναπαραγωγής\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Γενικά\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Εμφάνιση συντομεύσεων\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Προτιμήσεις\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Έξοδος\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Εμφάνιση ετικετών\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Αναπαραγωγή\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Αναπαραγωγή/παύση\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Αναπαραγωγή επόμενου\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Αναπαραγωγή προηγούμενου\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Λίστα αναπαραγωγής\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Αναζήτηση\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Εναλλαγή ταξινόμησης\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Επαναφόρτωση βιβλιοθήκης\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Αποθήκευση λίστας\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:626\n#: src/ui/store-panel.vala:420\nmsgid \"Back\"\nmsgstr \"Πϊσω\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Γενικά\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Λειτουργία θολώματος φόντου\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Συμπαγής προβολή λίστας αναπαραγωγής\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Προβολή πλέγματος για καλλιτέχνες/άλμπουμ\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Ενεργοποίηση στοιχείων με ένα κλικ\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:434\nmsgid \"Keep playing after window closed\"\nmsgstr \"Συνέχεια αναπαραγωγής μετά το κλείσιμο του παραθύρου\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Βιβλιοθήκη\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Φόρτωση μουσικής από φάκελο\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Εποπτεία για αλλαγές στα τοπικά αρχεία\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Φόρτωση μικρογραφιών για μη τοπικά αρχεία\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Ενδέχεται να προκαλέσει καθυστερήσεις και υπερβολική χρήση δικτύου\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Αναπαραγωγή\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Εμφάνιση επιπέδου κορύφωσης ήχου\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Εμφανιζόμενοι χαρακτήρες\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Περιστροφή εξώφυλλου άλμπουμ\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Ενεργοποίηση απρόσκοπτης αναπαραγωγής\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Κανονικοποίηση έντασης με το ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Προτιμώμενη διεπαφή ήχου για το GStreamer\"\n\n#: src/gtk/store-panel.ui:23\nmsgid \"Main Menu\"\nmsgstr \"Κύριο μενού\"\n\n#: src/gtk/store-panel.ui:30 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Αναζήτηση\"\n\n#: src/gtk/store-panel.ui:40\nmsgid \"Sort By\"\nmsgstr \"Ταξινόμηση κατά\"\n\n#: src/gtk/store-panel.ui:71\nmsgid \"_Color Scheme\"\nmsgstr \"_Σύνολο χρωμάτων\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_System\"\nmsgstr \"_Θέμα συστήματος\"\n\n#: src/gtk/store-panel.ui:78\nmsgid \"_Light\"\nmsgstr \"_Ανοιχτόχρωμο\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Dark\"\nmsgstr \"Σ_κουρόχρωμο\"\n\n#: src/gtk/store-panel.ui:90\nmsgid \"_Reload Library\"\nmsgstr \"_Επαναφόρτωση βιβλιοθήκης\"\n\n#: src/gtk/store-panel.ui:94\nmsgid \"_Multiple Select\"\nmsgstr \"_Πολλαπλή επιλογή\"\n\n#: src/gtk/store-panel.ui:98\nmsgid \"_Save List\"\nmsgstr \"_Αποθήκευση λίστας\"\n\n#: src/gtk/store-panel.ui:104\nmsgid \"_Preferences\"\nmsgstr \"_Προτιμήσεις\"\n\n#: src/gtk/store-panel.ui:108\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"Συντομεύσεις π_ληκτρολογίου\"\n\n#: src/gtk/store-panel.ui:112\nmsgid \"_About\"\nmsgstr \"Πλ_ηροφορίες\"\n\n#: src/gtk/store-panel.ui:121 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Άλμπουμ\"\n\n#: src/gtk/store-panel.ui:126\nmsgid \"Artist\"\nmsgstr \"Καλλιτέχνης\"\n\n#: src/gtk/store-panel.ui:131\nmsgid \"Artist/Album\"\nmsgstr \"Καλλιτέχνης/άλμπουμ\"\n\n#: src/gtk/store-panel.ui:136\nmsgid \"Title\"\nmsgstr \"Τίτλος\"\n\n#: src/gtk/store-panel.ui:141\nmsgid \"Recent\"\nmsgstr \"Πρόσφατα\"\n\n#: src/gtk/store-panel.ui:146\nmsgid \"Shuffle\"\nmsgstr \"Τυχαία αναπαραγωγή\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Αρχεία εικόνων\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Επιτυχής εξαγωγή εξώφυλλου\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Αποτυχία εξαγωγής εξώφυλλου\"\n\n#: src/application.vala:346\nmsgid \"Save playlist failed\"\nmsgstr \"Αποτυχία αποθήκευσης λίστας αναπαραγωγής\"\n\n#: src/application.vala:470\nmsgid \"Playlist Files\"\nmsgstr \"Αρχεία λιστών αναπαραγωγής\"\n\n#: src/application.vala:485\nmsgid \"Save playlist successfully\"\nmsgstr \"Επιτυχής αποθήκευση λίστας αναπαραγωγής\"\n\n#: src/application.vala:620\nmsgid \"Keep playing\"\nmsgstr \"Συνέχεια αναπαραγωγής\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:52\nmsgid \"translator-credits\"\nmsgstr \"\"\n\"Ομάδα ελληνικής μετάφρασης GNOME\\n\"\n\" Δημήτριος Σπέντζος <jimspentzos2000@gmail.com>\"\n\n#: src/ui/dialogs.vala:98 src/ui/dialogs.vala:110\nmsgid \"No\"\nmsgstr \"Όχι\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:110\nmsgid \"Yes\"\nmsgstr \"Ναι\"\n\n#: src/ui/music-list.vala:270\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Η λίστα αναπαραγωγής τροποποιήθηκε, θέλετε να κάνετε αποθήκευση;\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:399 src/ui/music-list.vala:415\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Αναπαραγωγή στο _επόμενο\"\n\n#: src/ui/music-list.vala:401 src/ui/music-list.vala:417\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Προσθήκη στην _ουρά αναπαραγωγής\"\n\n#: src/ui/music-list.vala:402 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Προσθήκη σε _λίστα αναπαραγωγής…\"\n\n#: src/ui/music-list.vala:403 src/ui/music-list.vala:421\nmsgid \"_Remove\"\nmsgstr \"_Αφαίρεση\"\n\n#: src/ui/music-list.vala:422 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"_Μετακίνηση στα απορρίμματα\"\n\n#: src/ui/music-list.vala:630\nmsgid \"Select All\"\nmsgstr \"Επιλογή όλων\"\n\n#: src/ui/music-list.vala:647\nmsgid \"Play at Next\"\nmsgstr \"Αναπαραγωγή στο επόμενο\"\n\n#: src/ui/music-list.vala:654\nmsgid \"Add to Queue\"\nmsgstr \"Προσθήκη στην ουρά αναπαραγωγής\"\n\n#: src/ui/music-list.vala:661 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Προσθήκη σε λίστα αναπαραγωγής\"\n\n#: src/ui/music-list.vala:668\nmsgid \"Remove\"\nmsgstr \"Αφαίρεση\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:428\nmsgid \"Play\"\nmsgstr \"Αναπαραγωγή\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Τυχαία αναπαραγωγή\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Εμφάνιση _αρχείου λίστας\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:63\nmsgid \"Search Title\"\nmsgstr \"Αναζήτηση τίτλου\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:61\nmsgid \"Search Album\"\nmsgstr \"Αναζήτηση άλμπουμ\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:62\nmsgid \"Search Artist\"\nmsgstr \"Αναζήτηση καλλιτέχνη\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Εμφάνιση _αρχείου εξώφυλλου\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Εξαγωγή εξώφυλλου\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Εμφάνιση _ετικετών…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Εμφάνιση _αρχείου μουσικής\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Επανάληψη κομματιού\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Αναπαραγωγή προηγούμενου\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Αναπαραγωγή/παύση\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Αναπαραγωγή επόμενου\"\n\n#: src/ui/play-panel.vala:56 src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Αναπαραγωγή\"\n\n#: src/ui/play-panel.vala:266\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Σύρετε και αποθέστε αρχεία μουσικής εδώ\\n\"\n\"ή αλλάξτε την τοποθεσία μουσικής: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Νέα λίστα\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:712\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Δεν βρέθηκε λίστα αναπαραγωγής στον φάκελο «%s»\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Ποτέ\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Πάντα\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Μόνο με εξώφυλλο\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Κομμάτι\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Καλλιτέχνες\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Άλμπουμ\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Λίστες αναπαραγωγής\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Αντιγραφή\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Ένταση: %d%%\"\n\n#: src/ui/window.vala:126\nmsgid \"Show\"\nmsgstr \"Εμφάνιση\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Άγνωστο άλμπουμ\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Άγνωστος καλλιτέχνης\"\n"
  },
  {
    "path": "po/es.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n# Daniel Mustieles <daniel.mustieles@gmail.com>, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/-/issues\\n\"\n\"POT-Creation-Date: 2023-08-19 04:11+0000\\n\"\n\"PO-Revision-Date: 2024-01-30 09:43+0100\\n\"\n\"Last-Translator: Daniel Mustieles <daniel.mustieles@gmail.com>\\n\"\n\"Language-Team: Spanish - Spain <gnome-es-list@gnome.org>\\n\"\n\"Language: es_ES\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1)\\n\"\n\"X-Generator: Gtranslator 45.alpha0\\n\"\n\n#: data/app.desktop.in:3 src/application.vala:232 src/main.vala:24\nmsgid \"G4Music\"\nmsgstr \"G4Music\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Reproductor de Musica\"\n\n#: data/app.desktop.in:5\nmsgid \"Play music\"\nmsgstr \"Reproducir musica\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"musica;sonido;reproductor;medios;audio;lista de reproduccion\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"General\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Mostrar Atajos\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Preferencias\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Salir\"\n\n#: src/gtk/help-overlay.ui:34\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Reproduccion\"\n\n#: src/gtk/help-overlay.ui:37\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Reproducir/Pausar\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Reproducir Siguiente\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Reproducir Anterior\"\n\n#: src/gtk/help-overlay.ui:57\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Lista de Reproduccion\"\n\n#: src/gtk/help-overlay.ui:60\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Buscar\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Cambiar Orden\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Recargar Biblioteca\"\n\n#: src/gtk/play-panel.ui:16 src/ui/store-panel.vala:340\nmsgid \"Back\"\nmsgstr \"Atras\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"General\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Prefer dark theme\"\nmsgstr \"Preferir modo oscuro\"\n\n#: src/gtk/preferences.ui:26\nmsgid \"Background blur mode\"\nmsgstr \"Modo de blur de fondo\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Compact playlist view\"\nmsgstr \"Playlist compacta\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Vista en cuadricula para artistas/albums\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:432\nmsgid \"Keep playing after window closed\"\nmsgstr \"Seguir reproduciendo despues de cerrar la ventana\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Biblioteca\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Cargar musica desde carpeta\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Monitorear cambios de archivos locales\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Cargar miniatura de archivos no-locales\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Puede causar ralentizacion y exceso de uso de red\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Reproduccion\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Mostrar pico de nivel de audio\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Mostrar Caracteres\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Rotar portada del album\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Activar reproduccion sin interrupciones\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Usar ReplayGain para normalizar el volumen\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Reproducir\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Menu Principal\"\n\n#: src/gtk/store-panel.ui:28\nmsgid \"Sort By\"\nmsgstr \"Ordenar Por\"\n\n#: src/gtk/store-panel.ui:35\nmsgid \"Search\"\nmsgstr \"Buscar\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_Reload Library\"\nmsgstr \"_Recargar Biblioteca\"\n\n#: src/gtk/store-panel.ui:79\nmsgid \"_Preferences\"\nmsgstr \"_Preferencias\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Atajos de Teclado\"\n\n#: src/gtk/store-panel.ui:87\nmsgid \"_About\"\nmsgstr \"_Acerca de\"\n\n#: src/gtk/store-panel.ui:96 src/ui/preferences.vala:67\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:101\nmsgid \"Artist\"\nmsgstr \"Artista\"\n\n#: src/gtk/store-panel.ui:106\nmsgid \"Artist/Album\"\nmsgstr \"Artista/Album\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"Title\"\nmsgstr \"Titulo\"\n\n#: src/gtk/store-panel.ui:116\nmsgid \"Recent\"\nmsgstr \"Reciente\"\n\n#: src/gtk/store-panel.ui:121\nmsgid \"Shuffle\"\nmsgstr \"Aleatorio\"\n\n#: src/action-handles.vala:184\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Un rapido, fluido y ligero reproductor de musica escrito en GTK4\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/action-handles.vala:186\nmsgid \"translator-credits\"\nmsgstr \"Radi4ever\"\n\n#: src/application.vala:613\nmsgid \"Keep playing\"\nmsgstr \"Seguir Reproduciendo\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-widgets.vala:252 src/ui/music-widgets.vala:293\n#: src/ui/music-widgets.vala:303\nmsgid \"Play at Next\"\nmsgstr \"Reproducir a la Siguiente\"\n\n#: src/ui/music-widgets.vala:253 src/ui/music-widgets.vala:292\n#: src/ui/music-widgets.vala:302 src/ui/store-panel.vala:345\nmsgid \"Play\"\nmsgstr \"Reproducir\"\n\n#: src/ui/music-widgets.vala:256 src/ui/play-panel.vala:237\nmsgid \"Show _Cover File\"\nmsgstr \"Mostrar _Portada\"\n\n#: src/ui/music-widgets.vala:258 src/ui/play-panel.vala:239\nmsgid \"_Export Cover\"\nmsgstr \"_Exportar Portada\"\n\n#: src/ui/music-widgets.vala:295\nmsgid \"Show List File\"\nmsgstr \"Mostrar lista de archivos\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:56\nmsgid \"Search Title\"\nmsgstr \"Buscar Titulo\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:54\nmsgid \"Search Album\"\nmsgstr \"Buscar Album\"\n\n#: src/ui/music-widgets.vala:311 src/ui/play-panel.vala:55\nmsgid \"Search Artist\"\nmsgstr \"Buscar Artista\"\n\n#: src/ui/music-widgets.vala:312\nmsgid \"_Show Music File\"\nmsgstr \"_Mostrar Archivo de Pista\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:74\nmsgid \"Single Loop\"\nmsgstr \"Repetir una vez\"\n\n#: src/ui/play-bar.vala:84\nmsgid \"Play Previous\"\nmsgstr \"Reproducir Anterior\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:90\nmsgid \"Play/Pause\"\nmsgstr \"Reproducir/Pausar\"\n\n#: src/ui/play-bar.vala:97\nmsgid \"Play Next\"\nmsgstr \"Reproducir Siguiente\"\n\n#: src/ui/play-panel.vala:280\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Arrastra y suelta las canciones aqui,\\n\"\n\"o cambia la ubicacion de la musica\"\n\n#: src/ui/preferences.vala:46 src/ui/preferences.vala:67\nmsgid \"Never\"\nmsgstr \"Nunca\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Always\"\nmsgstr \"Siempre\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Art Only\"\nmsgstr \"Solo Portada\"\n\n#: src/ui/preferences.vala:67\nmsgid \"Track\"\nmsgstr \"Pista\"\n\n#: src/ui/store-panel.vala:74\nmsgid \"Playing\"\nmsgstr \"Reproduciendo Ahora\"\n\n#: src/ui/store-panel.vala:79\nmsgid \"Artists\"\nmsgstr \"Artistas\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Albums\"\nmsgstr \"Albums\"\n\n#: src/ui/store-panel.vala:374\nmsgid \"Playlists\"\nmsgstr \"Listas De Reproduccion\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Volumen %d%%\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Album Desconocido\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Artista Desconocido\"\n\n#~ msgid \"Repeat Music\"\n#~ msgstr \"Repetir Pista\"\n\n#~ msgid \"Appearance\"\n#~ msgstr \"Apariencia\"\n\n#~ msgid \"Music Location\"\n#~ msgstr \"Localizacion de la Musica\"\n\n#~ msgid \"By Date\"\n#~ msgstr \"Por Fecha\"\n\n#~ msgid \"Show Album\"\n#~ msgstr \"Mostrar Album\"\n\n#~ msgid \"Show Artist\"\n#~ msgstr \"Mostrar Artista\"\n\n#~ msgid \"Loading...\"\n#~ msgstr \"Cargando...\"\n"
  },
  {
    "path": "po/et.po",
    "content": "# G4Music Estonian translation.\n# Copyright (C) 2022\n# This file is distributed under the same license as the G4Music software.\n# Henri <contact@hen.ee>, 2022.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2023-07-26 21:16+0800\\n\"\n\"PO-Revision-Date: 2022-08-01 18:49+0300\\n\"\n\"Last-Translator: \\n\"\n\"Language-Team: \\n\"\n\"Language: et\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.1.1\\n\"\n\n#: data/app.desktop.in:3 src/application.vala:225 src/main.vala:24\nmsgid \"G4Music\"\nmsgstr \"G4Music\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Muusikamängija\"\n\n#: data/app.desktop.in:5\nmsgid \"Play music\"\nmsgstr \"Kuula muusikat\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"music;sound;player;media;audio;playlist;muusika;heli;muusikamängija;meedia;\"\n\"esitusloend;\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Üldine\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Kiirklahvide näitamine\"\n\n#: src/gtk/help-overlay.ui:20\n#, fuzzy\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"_Eelistused\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Sulge\"\n\n#: src/gtk/help-overlay.ui:34\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Esitamine\"\n\n#: src/gtk/help-overlay.ui:37\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Esita/Peata\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Järgmine lugu\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Eelmine lugu\"\n\n#: src/gtk/help-overlay.ui:57\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Esitusloend\"\n\n#: src/gtk/help-overlay.ui:60\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Otsi\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:72\n#, fuzzy\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"_Loetelu värskendamine\"\n\n#: src/gtk/play-panel.ui:16 src/ui/store-panel.vala:290\nmsgid \"Back\"\nmsgstr \"Tagasi\"\n\n#: src/gtk/preferences.ui:10\n#, fuzzy\nmsgid \"General\"\nmsgstr \"Üldine\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Prefer dark theme\"\nmsgstr \"Eelista tumedat teemat\"\n\n#: src/gtk/preferences.ui:26\nmsgid \"Background blur mode\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Compact playlist view\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:44 src/application.vala:424\nmsgid \"Keep playing after window closed\"\nmsgstr \"Mängi ka siis kui aken on suletud\"\n\n#: src/gtk/preferences.ui:57\nmsgid \"Library\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:61\nmsgid \"Load music from folder\"\nmsgstr \"Lae muusikat kaustast\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Monitor local file changes\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Lae pisipilt võõrate failide jaoks\"\n\n#: src/gtk/preferences.ui:86\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Võib põhjustada aeglustusi ja tekitada üleliigset võrgukasutust\"\n\n#: src/gtk/preferences.ui:99\nmsgid \"Playback\"\nmsgstr \"Esitamine\"\n\n#: src/gtk/preferences.ui:103\nmsgid \"Show audio peak level\"\nmsgstr \"Heli valjutaseme näitamine\"\n\n#: src/gtk/preferences.ui:107\nmsgid \"Display characters\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:122\nmsgid \"Rotate album cover\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Enable gapless playback\"\nmsgstr \"Ilma auguta järjest esitamine\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"ReplayGain'i helitugevuse normaliseerimise kasutamine\"\n\n#: src/gtk/preferences.ui:152\n#, fuzzy\nmsgid \"Prefer audio sink\"\nmsgstr \"Pipewire tarkvara kasutamine\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Peamine menüü\"\n\n#: src/gtk/store-panel.ui:28\n#, fuzzy\nmsgid \"Sort By\"\nmsgstr \"Sorteerimine\"\n\n#: src/gtk/store-panel.ui:35\nmsgid \"Search\"\nmsgstr \"Otsi\"\n\n#: src/gtk/store-panel.ui:73\n#, fuzzy\nmsgid \"_Reload Library\"\nmsgstr \"_Loetelu värskendamine\"\n\n#: src/gtk/store-panel.ui:79\nmsgid \"_Preferences\"\nmsgstr \"_Eelistused\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Kiirklahvid\"\n\n#: src/gtk/store-panel.ui:87\nmsgid \"_About\"\nmsgstr \"_Teave\"\n\n#: src/gtk/store-panel.ui:96 src/ui/preferences.vala:64\n#, fuzzy\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:101\n#, fuzzy\nmsgid \"Artist\"\nmsgstr \"Esitaja\"\n\n#: src/gtk/store-panel.ui:106\nmsgid \"Artist/Album\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:111\n#, fuzzy\nmsgid \"Title\"\nmsgstr \"Pealkiri\"\n\n#: src/gtk/store-panel.ui:116\nmsgid \"Recent\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:121\nmsgid \"Shuffle\"\nmsgstr \"Juhuesitus\"\n\n#: src/action-handles.vala:188\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Kiire, sidus ja lihtne muusikamängija GTK4 alustel.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/action-handles.vala:190\nmsgid \"translator-credits\"\nmsgstr \"Henri <contact@hen.ee>, 2022\"\n\n#: src/application.vala:573\nmsgid \"Keep playing\"\nmsgstr \"Jätka mängimist\"\n\n#: src/ui/music-widgets.vala:232 src/ui/music-widgets.vala:260\n#, fuzzy\nmsgid \"Play at Next\"\nmsgstr \"Järgmine lugu\"\n\n#: src/ui/music-widgets.vala:233 src/ui/music-widgets.vala:259\n#, fuzzy\nmsgid \"Play\"\nmsgstr \"Esitamine\"\n\n#: src/ui/music-widgets.vala:236 src/ui/play-panel.vala:222\n#, fuzzy\nmsgid \"Show _Cover File\"\nmsgstr \"_Kuva failides\"\n\n#: src/ui/music-widgets.vala:238 src/ui/play-panel.vala:224\nmsgid \"_Export Cover\"\nmsgstr \"_Ekspordi loo pilt\"\n\n#: src/ui/music-widgets.vala:266 src/ui/play-panel.vala:56\n#, fuzzy\nmsgid \"Search Title\"\nmsgstr \"Otsi\"\n\n#: src/ui/music-widgets.vala:267 src/ui/play-panel.vala:54\n#, fuzzy\nmsgid \"Search Album\"\nmsgstr \"Kuva album\"\n\n#: src/ui/music-widgets.vala:268 src/ui/play-panel.vala:55\n#, fuzzy\nmsgid \"Search Artist\"\nmsgstr \"Kuva esitaja\"\n\n#: src/ui/music-widgets.vala:269\n#, fuzzy\nmsgid \"_Show Music File\"\nmsgstr \"_Kuva failides\"\n\n#: src/ui/play-bar.vala:75\nmsgid \"Repeat Music\"\nmsgstr \"Loo kordamine\"\n\n#: src/ui/play-bar.vala:85\nmsgid \"Play Previous\"\nmsgstr \"Eelmine lugu\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:91\nmsgid \"Play/Pause\"\nmsgstr \"Esita/Peata\"\n\n#: src/ui/play-bar.vala:98\nmsgid \"Play Next\"\nmsgstr \"Järgmine lugu\"\n\n#: src/ui/play-panel.vala:263\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Lohista muusikafail siia,\\n\"\n\"või muuda muusika asukoht: \"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:64\nmsgid \"Never\"\nmsgstr \"\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"\"\n\n#: src/ui/preferences.vala:64\nmsgid \"Track\"\nmsgstr \"\"\n\n#: src/ui/store-panel.vala:66\n#, fuzzy\nmsgid \"Playing\"\nmsgstr \"Esitusloend\"\n\n#: src/ui/store-panel.vala:72\n#, fuzzy\nmsgid \"Artists\"\nmsgstr \"Esitaja\"\n\n#: src/ui/store-panel.vala:77\n#, fuzzy\nmsgid \"Albums\"\nmsgstr \"Album\"\n\n#: src/ui/volume-button.vala:32\nmsgid \"Volume: \"\nmsgstr \"\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Tundmatu album\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Tundmatu esitaja\"\n\n#~ msgid \"Appearance\"\n#~ msgstr \"Välimus\"\n\n#~ msgid \"Music Location\"\n#~ msgstr \"Muusika asukoht\"\n\n#~ msgid \"Experimental\"\n#~ msgstr \"Eksperimentaalne\"\n\n#~ msgid \"By Date\"\n#~ msgstr \"Kuupäev\"\n\n#~ msgid \"Loading...\"\n#~ msgstr \"Laadimine…\"\n"
  },
  {
    "path": "po/eu.po",
    "content": "# Basque translation for g4music.\n# Copyright (C) 2023 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Asier Sarasua Garmendia <asiersarasua@ni.eus>, 2023.\n#\nmsgid \"\"\nmsgstr \"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/-/issues\\n\"\n\"POT-Creation-Date: 2023-08-17 10:19+0000\\n\"\n\"PO-Revision-Date: 2023-08-18 18:04+0000\\n\"\n\"Last-Translator: Asier Sarasua Garmendia <asiersarasua@ni.eus>\\n\"\n\"Language-Team: Basque <librezale@librezale.eus>\\n\"\n\"Language: eu\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: data/app.desktop.in:3 src/application.vala:232 src/main.vala:24\nmsgid \"G4Music\"\nmsgstr \"G4Music\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Musika-erreproduzitzailea\"\n\n#: data/app.desktop.in:5\nmsgid \"Play music\"\nmsgstr \"Erreproduzitu musika\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"musika;soinua;erreproduzigailua;multimedia;audioa;erreprodukzio-zerrenda;\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Orokorra\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Erakutsi lasterbideak\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Hobespenak\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Irten\"\n\n#: src/gtk/help-overlay.ui:34\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Erreproduzitu\"\n\n#: src/gtk/help-overlay.ui:37\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Erreproduzitu/pausarazi\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Erreproduzitu hurrengoa\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Erreproduzitu aurrekoa\"\n\n#: src/gtk/help-overlay.ui:57\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Erreprodukzio-zerrenda\"\n\n#: src/gtk/help-overlay.ui:60\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Bilatu\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Txandakatu ordena\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Birkargatu liburutegia\"\n\n#: src/gtk/play-panel.ui:16 src/ui/store-panel.vala:340\nmsgid \"Back\"\nmsgstr \"Atzera\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Orokorra\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Prefer dark theme\"\nmsgstr \"Hobetsi gai iluna\"\n\n#: src/gtk/preferences.ui:26\nmsgid \"Background blur mode\"\nmsgstr \"Atzeko plano lausoaren modua\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Compact playlist view\"\nmsgstr \"Erreprodukzio-zerrendaren ikuspegi trinkoa\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Sareta-ikuspegia artistetarako/albumetarako\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:432\nmsgid \"Keep playing after window closed\"\nmsgstr \"Jarraitu erreproduzitzen leihoa itxi ondoren\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Liburutegia\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Kargatu musika karpetatik\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Monitorizatu fitxategi lokalen aldaketak\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Kargatu miniaturak fitxategi ez lokaletarako\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Moteltzeak eta sarearen gehiegizko erabilera gertatu daitezke\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Erreproduzitu\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Erakutsi audioaren gailur-maila\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Bistaratu karaktereak\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Biratu albumaren azala\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Gaitu tarterik gabeko erreprodukzioa\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalizatu bolumena ReplayGain bidez\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Hobetsi GStreamer-en audio-hustubidea\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Menu nagusia\"\n\n#: src/gtk/store-panel.ui:28\nmsgid \"Sort By\"\nmsgstr \"Ordenatu honen arabera\"\n\n#: src/gtk/store-panel.ui:35\nmsgid \"Search\"\nmsgstr \"Bilatu\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_Reload Library\"\nmsgstr \"Birkargatu _liburutegia\"\n\n#: src/gtk/store-panel.ui:79\nmsgid \"_Preferences\"\nmsgstr \"_Hobespenak\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"Las_ter-teklak\"\n\n#: src/gtk/store-panel.ui:87\nmsgid \"_About\"\nmsgstr \"Honi _buruz\"\n\n#: src/gtk/store-panel.ui:96 src/ui/preferences.vala:67\nmsgid \"Album\"\nmsgstr \"Albuma\"\n\n#: src/gtk/store-panel.ui:101\nmsgid \"Artist\"\nmsgstr \"Artista\"\n\n#: src/gtk/store-panel.ui:106\nmsgid \"Artist/Album\"\nmsgstr \"Artista/Albuma\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"Title\"\nmsgstr \"Titulua\"\n\n#: src/gtk/store-panel.ui:116\nmsgid \"Recent\"\nmsgstr \"Azken aldikoa\"\n\n#: src/gtk/store-panel.ui:121\nmsgid \"Shuffle\"\nmsgstr \"Ausaz\"\n\n#: src/action-handles.vala:184\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"GTK4 teknologiarekin idatzitako musika-erreproduzigailu arin eta azkarra.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/action-handles.vala:186\nmsgid \"translator-credits\"\nmsgstr \"translator-credits\"\n\n#: src/application.vala:613\nmsgid \"Keep playing\"\nmsgstr \"Jarraitu erreproduzitzen\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-widgets.vala:252 src/ui/music-widgets.vala:293\n#: src/ui/music-widgets.vala:303\nmsgid \"Play at Next\"\nmsgstr \"Erreproduzitu hurrengoan\"\n\n#: src/ui/music-widgets.vala:253 src/ui/music-widgets.vala:292\n#: src/ui/music-widgets.vala:302 src/ui/store-panel.vala:345\nmsgid \"Play\"\nmsgstr \"Erreproduzitu\"\n\n#: src/ui/music-widgets.vala:256 src/ui/play-panel.vala:231\nmsgid \"Show _Cover File\"\nmsgstr \"Erakutsi _azaleko fitxategia\"\n\n#: src/ui/music-widgets.vala:258 src/ui/play-panel.vala:233\nmsgid \"_Export Cover\"\nmsgstr \"_Esportatu azala\"\n\n#: src/ui/music-widgets.vala:295\nmsgid \"Show List File\"\nmsgstr \"Erakusti zerrenda-fitxategia\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:55\nmsgid \"Search Title\"\nmsgstr \"Bilatu titulua\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:53\nmsgid \"Search Album\"\nmsgstr \"Bilatu albuma\"\n\n#: src/ui/music-widgets.vala:311 src/ui/play-panel.vala:54\nmsgid \"Search Artist\"\nmsgstr \"Bilatu artista\"\n\n#: src/ui/music-widgets.vala:312\nmsgid \"_Show Music File\"\nmsgstr \"_Erakutsi musika-fitxategia\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:76\nmsgid \"Single Loop\"\nmsgstr \"Begizta bakarra\"\n\n#: src/ui/play-bar.vala:86\nmsgid \"Play Previous\"\nmsgstr \"Erreproduzitu aurrekoa\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:92\nmsgid \"Play/Pause\"\nmsgstr \"Erreproduzitu/pausarazi\"\n\n#: src/ui/play-bar.vala:99\nmsgid \"Play Next\"\nmsgstr \"Erreproduzitu hurrengoa\"\n\n#: src/ui/play-panel.vala:274\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"Arrastatu eta jaregin musika-fitxategiak hemen,\\n\"\n\"edo aldatu musikaren kokalekua: \"\n\n#: src/ui/preferences.vala:46 src/ui/preferences.vala:67\nmsgid \"Never\"\nmsgstr \"Inoiz ere ez\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Always\"\nmsgstr \"Beti\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Art Only\"\nmsgstr \"Artea soilik\"\n\n#: src/ui/preferences.vala:67\nmsgid \"Track\"\nmsgstr \"Pista\"\n\n#: src/ui/store-panel.vala:74\nmsgid \"Playing\"\nmsgstr \"Erreproduzitzen\"\n\n#: src/ui/store-panel.vala:79\nmsgid \"Artists\"\nmsgstr \"Artistak\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Albums\"\nmsgstr \"Albumak\"\n\n#: src/ui/store-panel.vala:374\nmsgid \"Playlists\"\nmsgstr \"Erreprodukzio-zerrendak\"\n\n#. Translators: Current volume: 0~100\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d\"\nmsgstr \"%d. bolumena\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Album ezezaguna\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Artista ezezaguna\"\n"
  },
  {
    "path": "po/fa.po",
    "content": "# Persian translation for g4music.\n# Copyright (C) 2024 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# sohrabbehdani <behdanisohrab@gmail.com>, 2024.\n#\n# SPDX-FileCopyrightText: 2024 Sohrab Behdani <behdanisohrab@proton.me>\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-11-24 11:17+0000\\n\"\n\"PO-Revision-Date: 2025-01-13 16:21+0330\\n\"\n\"Last-Translator: Danial Behzadi <dani.behzi@ubuntu.com>\\n\"\n\"Language-Team: Persian <kde-i18n-doc@kde.org>\\n\"\n\"Language: fa\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:273\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"بی‌وقفه\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"پخش‌کنندهٔ آهنگ\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"پخش شیک آهنگ‌هایتان\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"music;sound;player;media;audio;playlist;آهنگ;صدا;پخش‌کننده;رسانه;صوت;سیاهه‌پخش;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, focuses on \"\n\"large music collection.\"\nmsgstr \"\"\n\"بی‌وقفه (G4Music) پخش‌کنندهٔ آهنگی سبک است که با GTK4 نوشته شده و بر مجموعه‌های آهنگ \"\n\"بزرگ تمرکز دارد.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"ویژگی‌ها\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols (depends on \"\n\"GIO and GStreamer).\"\nmsgstr \"\"\n\"پشتیبانی از بیش‌تر گونه‌های پروندهٔ آهنگ، سامبا و دیگر شیوه‌نامه‌های دوردست (بسته به \"\n\"GIO و GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, monitor \"\n\"local changes.\"\nmsgstr \"بار کردن سریع و تجزیهٔ هزاران پروندهٔ آهنگ در چند ثانیه. پایش تغییرات محلی.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"استفادهٔ کم حافظه برای مجموعهٔ آهنگ بزرگ با طرح جلد (تعبیه شده و خارجی). بدون \"\n\"نگه‌داری انبارهٔ بندانگشی.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"گروه‌بندی و چینش بر اساس آلبوم، هنرمند و عنوان. بر زدن سیاهه. جست‌وجوی متن کامل.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, Mobile).\"\nmsgstr \"میانای کاربری سازوا برای صفحه‌های مختلف (میزکار، رایانک، تلفن همراه).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"طرح جلد مات گوسی به عنوان پس‌زمینه. پیروی از حالت تیره و روشن گنوم.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add to \"\n\"another playlist.\"\nmsgstr \"\"\n\"پشیبانی از ایجاد و ویرایشسیاهه‌های پخش، کشیدن طرح جلد برای تغییر ترتیب یا افزودن \"\n\"به سیاههٔ پخشی دیگر.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"پشتیانی از کشیدن و رها کردن با دیگر کاره‌ها.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"پشتیبانی از نمایش سطح اوج صدا.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"پشتیبانی از پخش بی‌وقفه.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"پشتیبانی از عادی سازی حجم صدا با ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"پشتیانی از سامانهٔ صوتی مشخّص.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"پشتیبانی از واپایش MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"پنجرهٔ اصلی\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"نمای آلبوم‌ها\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"نمای پخش کردن\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"نمایهٔ سیاههٔ پخش\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"عمومی\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"نمایش میان‌برها\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"ترجیحات\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"خروج\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"نمایش برچسب‌ها\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"پخش\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"پخش یا مکث\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"پخش بعدی\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"پخش پیشین\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"سیاههٔ پخش\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"جست‌وجو\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"تغییر ‌حالت چینش\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"بازخوانی کتابخانه\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"ذخیرهٔ سیاهه\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:632 src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"بازگشت\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"عمومی\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"حالت محوی پس‌زمینه\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"نمای‌ سیاههٔ پخش فشرده\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"نمای شبکه‌ای برای هنرمند‌ها و آلبوم‌ها\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"یک بار زدن برای فعّال کردن مورد\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:434\nmsgid \"Keep playing after window closed\"\nmsgstr \"ادامهٔ پخش پس از بستن پنجره\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"کتابخانه\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"بار کردن آهنگ‌ها از شاخه\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"پایش تغییرات پرونده‌های محلی\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"بار کردن بندانگشتی‌ها برای پرونده‌های غیرمحلی\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"ممکن است موجب کندی و افزایش استفاده از شبکه شود\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"پخش\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"نمایش سطح اوج صدا\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"نمایش نویسه‌ها\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"چرخاندن طرح جلد آلبوم\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"به کار انداختن پخش بی‌وقفه\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"عادی سازی حجم صدا با ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"ترجیح سینک صدای GStreamer\"\n\n#: src/gtk/store-panel.ui:23\nmsgid \"Main Menu\"\nmsgstr \"فهرست اصلی\"\n\n#: src/gtk/store-panel.ui:30 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"جست‌وجو\"\n\n#: src/gtk/store-panel.ui:40\nmsgid \"Sort By\"\nmsgstr \"چینش بر پایه\"\n\n#: src/gtk/store-panel.ui:71\nmsgid \"_Color Scheme\"\nmsgstr \"_طرحوارهٔ رنگی\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_System\"\nmsgstr \"_سامانه\"\n\n#: src/gtk/store-panel.ui:78\nmsgid \"_Light\"\nmsgstr \"_روشن\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Dark\"\nmsgstr \"_تیره\"\n\n#: src/gtk/store-panel.ui:90\nmsgid \"_Reload Library\"\nmsgstr \"_بازخوانی کتابخانه\"\n\n#: src/gtk/store-panel.ui:94\nmsgid \"_Multiple Select\"\nmsgstr \"گزینش _چندگانه\"\n\n#: src/gtk/store-panel.ui:98\nmsgid \"_Save List\"\nmsgstr \"_ذخیرهٔ سیاهه\"\n\n#: src/gtk/store-panel.ui:104\nmsgid \"_Preferences\"\nmsgstr \"_ترجیحات\"\n\n#: src/gtk/store-panel.ui:108\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"میان‌برهای _صفحه‌کلید\"\n\n#: src/gtk/store-panel.ui:112\nmsgid \"_About\"\nmsgstr \"_درباره‌\"\n\n#: src/gtk/store-panel.ui:121 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"آلبوم\"\n\n#: src/gtk/store-panel.ui:126\nmsgid \"Artist\"\nmsgstr \"هنرمند\"\n\n#: src/gtk/store-panel.ui:131\nmsgid \"Artist/Album\"\nmsgstr \"هنرمند یا آلبوم\"\n\n#: src/gtk/store-panel.ui:136\nmsgid \"Title\"\nmsgstr \"عنوان\"\n\n#: src/gtk/store-panel.ui:141\nmsgid \"Recent\"\nmsgstr \"اخیر\"\n\n#: src/gtk/store-panel.ui:146\nmsgid \"Shuffle\"\nmsgstr \"بُرزنی\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"پرونده‌های تصویر\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"برون‌ریزی موفّق طرح جلد\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"برون‌ریزی طرح جلد شکست خورد\"\n\n#: src/application.vala:346\nmsgid \"Save playlist failed\"\nmsgstr \"ذخیرهٔ سیاههٔ پخش شکست خورد\"\n\n#: src/application.vala:470\nmsgid \"Playlist Files\"\nmsgstr \"پرونده‌های سیاههٔ پخش\"\n\n#: src/application.vala:485\nmsgid \"Save playlist successfully\"\nmsgstr \"ذخیرهٔ موفّق سیاههٔ پخش\"\n\n#: src/application.vala:620\nmsgid \"Keep playing\"\nmsgstr \"ادامهٔ پخش\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"پخش‌کنندهٔ آهنگ سریع، زیبا و سبک نوشته شده با GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"\"\n\"سهراب بهدانی <behdanisohrab@gmail.com>\\n\"\n\"دانیال بهزادی <dani.behzi@ubuntu.com>\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:112\nmsgid \"No\"\nmsgstr \"نه\"\n\n#: src/ui/dialogs.vala:101 src/ui/dialogs.vala:112\nmsgid \"Yes\"\nmsgstr \"بله\"\n\n#: src/ui/music-list.vala:276\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"سیاههٔ پخش دستگاری شده. ذخیره شود؟\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:405 src/ui/music-list.vala:421\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"پخش در _بعدی\"\n\n#: src/ui/music-list.vala:407 src/ui/music-list.vala:423\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"افزودن به _صف\"\n\n#: src/ui/music-list.vala:408 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"افزودن به _سیاههٔ پخش…\"\n\n#: src/ui/music-list.vala:409 src/ui/music-list.vala:427\nmsgid \"_Remove\"\nmsgstr \"_برداشتن\"\n\n#: src/ui/music-list.vala:428 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"انداختن به _زباله‌دان\"\n\n#: src/ui/music-list.vala:636\nmsgid \"Select All\"\nmsgstr \"گزینش همه\"\n\n#: src/ui/music-list.vala:653\nmsgid \"Play at Next\"\nmsgstr \"پخش در بعدی\"\n\n#: src/ui/music-list.vala:660\nmsgid \"Add to Queue\"\nmsgstr \"افزودن به صف\"\n\n#: src/ui/music-list.vala:667 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"افزودن به سیاههٔ پخش\"\n\n#: src/ui/music-list.vala:674\nmsgid \"Remove\"\nmsgstr \"برداشتن\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"پخش\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"پخش _کاتوره‌ای\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"نمایش _پروندهٔ سیاهه\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"جست‌وجوی عنوان\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"جست‌وجوی آلبوم\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"جست‌وجوی هنرمند\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"نمایش _پروندهٔ طرح جلد\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_برون‌ریزی طرح جلد\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"نمایش _برچسب‌ها…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"نمایش _پروندهٔ آهنگ\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"تکرار تکی\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"پخش پیشین\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"پخش یا مکث\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"پخش بعدی\"\n\n#: src/ui/play-panel.vala:263\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"کشیدن و رها سازی پرونده‌های آهنگ‌ها در این‌جا،\\n\"\n\"یا تغییر مکان آهنگ‌ها: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"سیاههٔ پخش جدید\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:703\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"هیچ سیاههٔ پخشی در %s پیدا نشد.\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"هرگز\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"همیشه\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"فقط کار هنری\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"قطعه\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"پخش کردن\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"هنرمندان\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"آلبوم‌ها\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"سیاهه‌‌های پخش\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"رونوشت\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"حجم صدا %d٪\"\n\n#: src/ui/window.vala:119\nmsgid \"Show\"\nmsgstr \"نمایش\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"آلبوم ناشناخته\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"هنرمند ناشناس\"\n\n#~ msgid \"Nanling\"\n#~ msgstr \"نانلینگ\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"کشیدن-رها کردن از پرونده‌های کنوم، نمایش آهنگ در پرونده‌ها.\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"پخش آهنگ‌ها\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"ترجیح پوستهٔ تیره\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"آهنگ‌های جی‌فور\"\n"
  },
  {
    "path": "po/fi.po",
    "content": "# Finnish translation for g4music.\n# Copyright (C) 2023 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Jiri Grönroos <jiri.gronroos@iki.fi>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-10-11 01:38+0000\\n\"\n\"PO-Revision-Date: 2024-11-11 20:34+0200\\n\"\n\"Last-Translator: Jiri Grönroos <jiri.gronroos+l10n@iki.fi>\\n\"\n\"Language-Team: Finnish <lokalisointi-lista@googlegroups.com>\\n\"\n\"Language: fi\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.4.4\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Musiikkisoitin\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Toista musiikkia hienostuneesti\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"music;sound;player;media;audio;playlist;musiikki;ääni;soittolista;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (tunnettu myös nimellä G4Music) on kevyt musiikintoistosovellus, \"\n\"joka on kirjoitettu GTK4:llä, ja sen huomion kohteena on suuret \"\n\"musiikkikokoelmat.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Ominaisuudet\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Tukee useimpia musiikkitiedostoja sekä Samba- ja muita etäyhteyskäytäntöjä \"\n\"(riippuvuus GIO:on ja Gstreameriin).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Tuhansien musiikkitiedostojen lataaminen ja jäsentäminen erittäin nopeasti, \"\n\"tarkkailee paikallisia muutoksia.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Matala muistinkäyttö suurilla musiikkikokoelmilla ja albumien kansikuvilla \"\n\"(upotettuna tai ulkoisesti), ei pikkukuvien välimuistia talletettavaksi.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Ryhmitä ja järjestä albumin, esittäjän tai kappaleen mukaan, sekoita \"\n\"listoja, koko tekstin haku.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Mukautuva käyttöliittymä eri näyttökooille (työpöytä, tabletti, mobiili).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"Sumennettu kansikuva taustaksi, seuraa Gnomen vaaleaa ja tummaa tilaa.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Tukee soittolistojen luomista ja muokkausta, vedä kansikuva vaihtaaksesi \"\n\"järjestystä tai lisätäksesi toiseen soittolistaan.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Tukee vedä ja pudota -toimintoa muiden sovellusten kanssa.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Tukee äänihuippujen visualisointia.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Tukee tautonta toistoa.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Tukee äänenvoimakkuuden normalisointia ReplayGainilla.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Tukee määritettyä ääniallasta.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Tukee MPRIS-ohjaimia.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Pääikkuna\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Albuminäkymä\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Toistonäkymä\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Soittolistanäkymä\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Yleiset\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Näytä pikanäppäimet\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Asetukset\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Lopeta\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Näytä tunnisteet\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Toisto\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Toista/keskeytä\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Toista seuraava\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Toista edellinen\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Soittolista\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Etsi\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Järjestys päälle/pois\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Lataa kirjasto uudelleen\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Tallenna lista\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"Takaisin\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Yleiset\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Taustan sumennustila\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Kompakti soittolistanäkymä\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Ruudukkonäkymä esittäjille/albumeille\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Kertanapsautus aktivoi kohteen\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"Jatka toistamista ikkunan sulkemisen jälkeen\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Kirjasto\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Lataa musiikki kansiosta\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Tarkkaile paikallisia tiedostomuutoksia\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Lataa pienoiskuvat myös muille kuin paikallisille tiedostoille\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Saattaa aiheuttaa hidastumista ja paljon verkkoliikennettä\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Toisto\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Näytä äänen\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Näytä merkit\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Kierrä albumin kansikuvaa\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Käytä tauotonta toistoa\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalisoi äänenvoimakkuus ReplayGainilla\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Suosi GStreamerin ääniallasta\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Päävalikko\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Etsi\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"Järjestä\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"_Väriteema\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"_Järjestelmä\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"_Vaalea\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_Tumma\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"_Lataa kirjasto uudelleen\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"_Monivalinta\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"_Tallenna lista\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"_Asetukset\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Pikanäppäimet\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"_Tietoja\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Albumi\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"Esittäjä\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"Esittäjä/albumi\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"Nimi\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"Viimeisimmät\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"Sekoita\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Kuvatiedostot\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Kansi viety onnistuneesti\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Kannen vienti epäonnistui\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"Soittolistan tallentaminen epäonnistui\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"Soittolistatiedostot\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"Soittolista tallennettu\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"Jatka toistamista\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Nopea ja kevyt musiikkisoitin GTK4:llä toteutettuna.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"Jiri Grönroos\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"Ei\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"Kyllä\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Soittolistaa on muokattu, tallennetaanko se?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Toista _seuraavaksi\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Lisää _jonoon\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Lisää _soittolistalle…\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"_Poista\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"_Siirrä roskakoriin\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"Valitse kaikki\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"Toista seuraavaksi\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"Lisää jonoon\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Lisää soittolistalle\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"Poista\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"Toista\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Satunnaistoisto\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Näytä _listatiedosto\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Etsi nimeä\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Etsi albumia\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Etsi esittäjää\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Näytä _kansitiedosto\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Vie kansi\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Näytä _tunnisteet…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Näytä _musiikkitiedosto\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Kertakierto\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Toista edellinen\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Toista/keskeytä\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Toista seuraava\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Vedä ja pudota musiikkitiedostot tähän\\n\"\n\"tai vaihda musiikin sijaintia: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Uusi soittolista\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:692\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Soittolistaa %s ei löytynyt\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Ei koskaan\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Aina\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Vain kuvitus\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Kappale\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Toistetaan\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Esittäjät\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Albumit\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Soittolistat\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Kopioi\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Äänenvoimakkuus %d% %\"\n\n#: src/ui/window.vala:112\nmsgid \"Show\"\nmsgstr \"Näytä\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Tuntematon albumi\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Tuntematon esittäjä\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"G4Music\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"Toista musiikkia\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"Suosi tummaa teemaa\"\n"
  },
  {
    "path": "po/fr.po",
    "content": "# French translation for G4Music.\n# Copyright (C) 2022\n# This file is distributed under the same license as the G4Music package.\n# Aurélien Hamy <aunetx@yandex.com>, 2022.\n# Naqua Darazaki <n.darazaki@gmail.com>, 2022.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: \\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/-/issues\\n\"\n\"POT-Creation-Date: 2023-08-16 08:46+0000\\n\"\n\"PO-Revision-Date: 2023-08-16 08:46+0000\\n\"\n\"Last-Translator: Alexandre Franke <afranke@gnome.org>\\n\"\n\"Language-Team: \\n\"\n\"Language: fr\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: data/app.desktop.in:3 src/application.vala:232 src/main.vala:24\nmsgid \"G4Music\"\nmsgstr \"G4Music\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Lecteur de musique\"\n\n#: data/app.desktop.in:5\nmsgid \"Play music\"\nmsgstr \"Jouer de la musique\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"musique;son;lecteur;média;audio;liste de lecture;\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Général\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Afficher les raccourcis\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Préférences\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Quitter\"\n\n#: src/gtk/help-overlay.ui:34\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Lecture\"\n\n#: src/gtk/help-overlay.ui:37\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Lire/Suspendre\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Lire la prochaine piste\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Lire la piste précédente\"\n\n#: src/gtk/help-overlay.ui:57\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Playlist\"\n\n#: src/gtk/help-overlay.ui:60\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Recherche\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Basculer le tri\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Recharger la collection\"\n\n#: src/gtk/play-panel.ui:16 src/ui/store-panel.vala:340\nmsgid \"Back\"\nmsgstr \"Précédent\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Général\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Prefer dark theme\"\nmsgstr \"Préférer le thème sombre\"\n\n#: src/gtk/preferences.ui:26\nmsgid \"Background blur mode\"\nmsgstr \"Mode de flou du fond\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Compact playlist view\"\nmsgstr \"Vue compacte de la liste de lecture\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Vue en grille pour les artistes/albums\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:432\nmsgid \"Keep playing after window closed\"\nmsgstr \"Continuer la lecture après la fermeture de la fenêtre\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Collection\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Charger la musique depuis le dossier\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Surveiller les changements sur les fichiers locaux\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Charger les miniatures des fichier externes\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Peut causer des ralentissements et une utilisation excessive du réseau\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Lecture\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Afficher les pics sonores\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Afficher les caractères\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Tourner la pochette d’album\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Activer la lecture sans interruption\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Utiliser ReplayGain pour normaliser le volume\"\n\n#: src/gtk/preferences.ui:164\n#, fuzzy\nmsgid \"Prefer audio sink\"\nmsgstr \"Utiliser la sortie audio pipewire\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Menu principal\"\n\n#: src/gtk/store-panel.ui:28\nmsgid \"Sort By\"\nmsgstr \"Critère de tri\"\n\n#: src/gtk/store-panel.ui:35\nmsgid \"Search\"\nmsgstr \"Recherche\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_Reload Library\"\nmsgstr \"_Recharger la collection\"\n\n#: src/gtk/store-panel.ui:79\nmsgid \"_Preferences\"\nmsgstr \"_Préférences\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Raccourcis clavier\"\n\n#: src/gtk/store-panel.ui:87\nmsgid \"_About\"\nmsgstr \"À _propos\"\n\n#: src/gtk/store-panel.ui:96 src/ui/preferences.vala:67\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:101\nmsgid \"Artist\"\nmsgstr \"Artiste\"\n\n#: src/gtk/store-panel.ui:106\nmsgid \"Artist/Album\"\nmsgstr \"Artiste/album\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"Title\"\nmsgstr \"Titre\"\n\n#: src/gtk/store-panel.ui:116\nmsgid \"Recent\"\nmsgstr \"Récent\"\n\n#: src/gtk/store-panel.ui:121\nmsgid \"Shuffle\"\nmsgstr \"Mélanger\"\n\n#: src/action-handles.vala:184\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Un lecteur de musique GTK4 rapide, joli et léger.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/action-handles.vala:186\nmsgid \"translator-credits\"\nmsgstr \"Aurélien Hamy\\n\"\n\"Naqua Darazaki\\n\"\n\"Alexandre Franke\"\n\n#: src/application.vala:613\nmsgid \"Keep playing\"\nmsgstr \"Continuer à jouer\"\n\n#: src/ui/music-widgets.vala:251 src/ui/music-widgets.vala:292\n#: src/ui/music-widgets.vala:302\n#, fuzzy\nmsgid \"Play at Next\"\nmsgstr \"Lire la piste suivante\"\n\n#: src/ui/music-widgets.vala:252 src/ui/music-widgets.vala:291\n#: src/ui/music-widgets.vala:301 src/ui/store-panel.vala:345\nmsgid \"Play\"\nmsgstr \"Lire\"\n\n#: src/ui/music-widgets.vala:255 src/ui/play-panel.vala:232\nmsgid \"Show _Cover File\"\nmsgstr \"Afficher le fichier couverture\"\n\n#: src/ui/music-widgets.vala:257 src/ui/play-panel.vala:234\nmsgid \"_Export Cover\"\nmsgstr \"_Exporter la couverture\"\n\n#: src/ui/music-widgets.vala:294\nmsgid \"Show List File\"\nmsgstr \"Afficher le fichier liste\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:57\nmsgid \"Search Title\"\nmsgstr \"Recherche le titre\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:55\nmsgid \"Search Album\"\nmsgstr \"Recherche l’album\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:56\nmsgid \"Search Artist\"\nmsgstr \"Rechercher l'artiste\"\n\n#: src/ui/music-widgets.vala:311\nmsgid \"_Show Music File\"\nmsgstr \"_Afficher le fichier musique\"\n\n#: src/ui/play-bar.vala:75\n#, fuzzy\nmsgid \"Repeat Music\"\nmsgstr \"Répéter la piste\"\n\n#: src/ui/play-bar.vala:85\nmsgid \"Play Previous\"\nmsgstr \"Lire la piste précédente\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:91\nmsgid \"Play/Pause\"\nmsgstr \"Lire/Suspendre\"\n\n#: src/ui/play-bar.vala:98\nmsgid \"Play Next\"\nmsgstr \"Lire la piste suivante\"\n\n#: src/ui/play-panel.vala:275\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Glissez et déposez vos fichiers de musique ici,\\n\"\n\"ou changez l’emplacement de la musique : \"\n\n#: src/ui/preferences.vala:46 src/ui/preferences.vala:67\nmsgid \"Never\"\nmsgstr \"Jamais\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Always\"\nmsgstr \"Toujours\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Art Only\"\nmsgstr \"Art uniquement\"\n\n#: src/ui/preferences.vala:67\nmsgid \"Track\"\nmsgstr \"Piste\"\n\n#: src/ui/store-panel.vala:74\nmsgid \"Playing\"\nmsgstr \"Lecture\"\n\n#: src/ui/store-panel.vala:79\nmsgid \"Artists\"\nmsgstr \"Artiste\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Albums\"\nmsgstr \"Album\"\n\n#: src/ui/store-panel.vala:374\nmsgid \"Playlists\"\nmsgstr \"Liste de lecture\"\n\n#: src/ui/volume-button.vala:32\nmsgid \"Volume: \"\nmsgstr \"Volume : \"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Album inconnu\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Artiste inconnu\"\n\n"
  },
  {
    "path": "po/g4music.pot",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-10-11 09:34+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:692\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"\"\n\n#: src/ui/window.vala:112\nmsgid \"Show\"\nmsgstr \"\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"\"\n"
  },
  {
    "path": "po/he.po",
    "content": "# Hebrew translation for g4music.\n# Copyright (C) 2024 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Yosef Or Boczko <yoseforb@gmail.com>, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-11-24 11:17+0000\\n\"\n\"PO-Revision-Date: 2025-01-09 09:25+0200\\n\"\n\"Last-Translator: Yosef Or Boczko <yoseforb@gmail.com>\\n\"\n\"Language-Team: Hebrew <yoseforb@gmail.com>\\n\"\n\"Language: he\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n==2 ? 1 : n>10 && n%10==0 ? \"\n\"2 : 3);\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:273\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"נגן מוזיקה\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"לנגן את המוזיקה שלך באלגנטיות\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"מוסיקה;מוזיקה;שמע;צליל;נגן;מדיה;רשימת נגינה;רשימות נגינה;רשימת השמעה;\"\n\"פלייליסט;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"‏Gapless (הידוע גם בשם: G4Music) הוא נגן מוזיקה קל משקל שנכתב ב־GTK4, המתמקד \"\n\"באוספי מוזיקה גדולים.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"תכונות\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"תמיכה ברוב סוגי קבצי המוזיקה, Samba ופרוטוקולים מרוחקים אחרים (תלוי ב־GIO \"\n\"ו־GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"טעינה ופענוח מהירים של אלפי קובצי מוזיקה תוך שניות ספורות, מעקב אחר שינויים \"\n\"מקומיים.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"שימוש מועט בזיכרון עבור אוסף מוזיקה גדול עם עטיפות אלבומים (מוטבעות \"\n\"וחיצוניות), ללא צורך באחסון מטמון של תמונות ממוזערות.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"קיבוץ ומיון לפי אלבום/אומן/כותרת, ערבוב רשימה, חיפוש טקסט מלא.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"ממשק משתמש מסתגל ומותאם למסכים שונים (מחשב שולחני, מחשב לוח, נייד).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"עטיפת אלבום מטושטשת כרקע, מעקב אחר סגנון מערכת בהיר/כהה של GNOME.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"תמיכה ביצירה ועריכה של רשימות נגינה, גרירת העטיפה תשנה את הסדר או תוסיף \"\n\"לרשימת נגינה אחרת.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"תמיכה בגרירה מיישומים אחרים ואליהם.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"תמיכה בהדמיית שיאי אודיו.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"תמיכה בנגינה ללא הפסקות.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"תמיכה באיזון עצמת קול עם ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"תמיכה בשקע השמע שצוין.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"תמיכה בשליטת MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"חלון ראשי\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"תצוגת אלבומים\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"תצוגת נגינה\"\n\n# msgctxt \"shortcut window\"\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"תצוגת רשימת נגינה\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"כללי\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"הצגת צירופי מקשים\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"העדפות\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"יציאה\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"הצגת תגיות\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"בִצוע מוקלט\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"נגינה/השהיה\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"ניגון הרצועה הבאה\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"ניגון הרצועה הקודמת\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"רשימת נגינה\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"חיפוש\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"שינוי סדר נגינה\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"טעינה הספרייה מחדש\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"שמירת הרשימה\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:632\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"אחורה\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"כללי\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"מצב רקע מטושטש\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"תצוגת רשימת נגינה קומפקטית\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"תצוגת רשת לאלבומים/אומנים\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"לחיצה אחת מפעילה פעיל\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:434\nmsgid \"Keep playing after window closed\"\nmsgstr \"להמשיך להשמיע לאחר סגירת החלון\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"ספרייה\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"טעינת מוזיקה מתיקייה\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"מעקב אחר שינוי בקבצים\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"טעינת תמונות ממוזערות לקבצים לא מקומיים\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"עשוי לגרום להאטה ולשימוש יתר ברשת\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"בִצוע מוקלט\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"הצגת עצמת שיאי שמע\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"תווים להצגה\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"סיבוב כיסוי אלבום\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"לאפשר נגינה ללא הפסקה בין רצועות\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"איזון עצמת שמע עם ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"העדפת יציאת שמע של GStreamer\"\n\n#: src/gtk/store-panel.ui:23\nmsgid \"Main Menu\"\nmsgstr \"תפריט ראשי\"\n\n#: src/gtk/store-panel.ui:30 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"חיפוש\"\n\n#: src/gtk/store-panel.ui:40\nmsgid \"Sort By\"\nmsgstr \"מיון לפי\"\n\n#: src/gtk/store-panel.ui:71\nmsgid \"_Color Scheme\"\nmsgstr \"ע_רכת צבעים\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_System\"\nmsgstr \"מ_ערכת\"\n\n#: src/gtk/store-panel.ui:78\nmsgid \"_Light\"\nmsgstr \"_בהירה\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Dark\"\nmsgstr \"_כהה\"\n\n#: src/gtk/store-panel.ui:90\nmsgid \"_Reload Library\"\nmsgstr \"_טעינה מחדש של הספרייה\"\n\n#: src/gtk/store-panel.ui:94\nmsgid \"_Multiple Select\"\nmsgstr \"רב _בחירה\"\n\n#: src/gtk/store-panel.ui:98\nmsgid \"_Save List\"\nmsgstr \"_שמירת הרשימה\"\n\n#: src/gtk/store-panel.ui:104\nmsgid \"_Preferences\"\nmsgstr \"_העדפות\"\n\n#: src/gtk/store-panel.ui:108\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_צירופי מקשים\"\n\n#: src/gtk/store-panel.ui:112\nmsgid \"_About\"\nmsgstr \"על _אודות\"\n\n#: src/gtk/store-panel.ui:121 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"אלבום\"\n\n#: src/gtk/store-panel.ui:126\nmsgid \"Artist\"\nmsgstr \"אומן\"\n\n#: src/gtk/store-panel.ui:131\nmsgid \"Artist/Album\"\nmsgstr \"אומן האלבום\"\n\n#: src/gtk/store-panel.ui:136\nmsgid \"Title\"\nmsgstr \"כותרת\"\n\n#: src/gtk/store-panel.ui:141\nmsgid \"Recent\"\nmsgstr \"הושמעו לאחרונה\"\n\n#: src/gtk/store-panel.ui:146\nmsgid \"Shuffle\"\nmsgstr \"ערבוב\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"קובצי תמונה\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"העטיפה יוצאה בהצלחה\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"ייצוא עטיפה נכשל\"\n\n#: src/application.vala:346\nmsgid \"Save playlist failed\"\nmsgstr \"שמירת רשימת הנגינה נכשלה\"\n\n# msgctxt \"shortcut window\"\n#: src/application.vala:470\nmsgid \"Playlist Files\"\nmsgstr \"קובצי רשימת נגינה\"\n\n#: src/application.vala:485\nmsgid \"Save playlist successfully\"\nmsgstr \"רשימת הנגינה נשמרה בהצלחה\"\n\n#: src/application.vala:620\nmsgid \"Keep playing\"\nmsgstr \"להמשיך לנגן\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"נגן מוזיקה קל, מהיר וגמיש שנכתב ב־GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"\"\n\"יוסף אור בוצ׳קו <yoseforb@gmail.com>\\n\"\n\"מיזם תרגום GNOME לעברית https://l10n.gnome.org/teams/he/\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:112\nmsgid \"No\"\nmsgstr \"לא\"\n\n#: src/ui/dialogs.vala:101 src/ui/dialogs.vala:112\nmsgid \"Yes\"\nmsgstr \"כן\"\n\n#: src/ui/music-list.vala:276\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"רשימה הנגינה שונתה, לשמור אותה?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:405 src/ui/music-list.vala:421\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"הבא שית_נגן\"\n\n#: src/ui/music-list.vala:407 src/ui/music-list.vala:423\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"הוספה ל_תור\"\n\n# msgctxt \"shortcut window\"\n#: src/ui/music-list.vala:408 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"הוספה לרשימת _נגינה…\"\n\n#: src/ui/music-list.vala:409 src/ui/music-list.vala:427\nmsgid \"_Remove\"\nmsgstr \"ה_סרה\"\n\n#: src/ui/music-list.vala:428 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"העברה ל_אשפה\"\n\n#: src/ui/music-list.vala:636\nmsgid \"Select All\"\nmsgstr \"בחירת הכול\"\n\n#: src/ui/music-list.vala:653\nmsgid \"Play at Next\"\nmsgstr \"הבא בתור\"\n\n#: src/ui/music-list.vala:660\nmsgid \"Add to Queue\"\nmsgstr \"הוספה לתור\"\n\n# msgctxt \"shortcut window\"\n#: src/ui/music-list.vala:667 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"הוספה לרשימת נגינה\"\n\n#: src/ui/music-list.vala:674\nmsgid \"Remove\"\nmsgstr \"הסרה\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"ניגון\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"נגינה א_קראית\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"הצגת _קובצי הרשימה\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"חיפוש כותרת\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"חיפוש אלבום\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"חיפוש אומן\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"הצגת קובץ _עטיפה\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_ייצוא כיסוי אלבום\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"הצגת _תגיות…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"ה_צגת קובץ מוזיקה\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"השמעה חוזרת של הרצועה\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"ניגון הרצועה הקודמת\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"נגינה/השהיה\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"ניגון הרצועה הבאה\"\n\n#: src/ui/play-panel.vala:263\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"יש לגרור ולשחרר לכאן קובצי מוזיקה,\\n\"\n\"או לשנות את מיקום המוזיקה: \"\n\n# msgctxt \"shortcut window\"\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"רשימת נגינה חדשה\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:703\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"לא נמצאו רשימות נגינה ב־%s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"לעולם לא\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"תמיד\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"עם אומנות בלבד\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"רצועה\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"נגינה\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"אומנים\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"אלבומים\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"רשימות נגינה\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"העתקה\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"עצמת שמע ‎%d%%\"\n\n#: src/ui/window.vala:119\nmsgid \"Show\"\nmsgstr \"הצגה\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"אלבום לא ידוע\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"אומן לא ידוע\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"השמעת מוזיקה\"\n\n#~ msgid \"Nanling\"\n#~ msgstr \"Nanling\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"גרירה ושחרור מקובצי GNOME, הצגת מוזיקה בקבצים.\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"להשתמש בערכת עיצוב כהה\"\n\n#~ msgid \"Close\"\n#~ msgstr \"סגירה\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"G4Music\"\n"
  },
  {
    "path": "po/hi.po",
    "content": "# Hindi translation for g4music.\n# Copyright (C) 2024 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Scrambled777 <weblate.scrambled777@simplelogin.com>, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-07-20 09:24+0000\\n\"\n\"PO-Revision-Date: 2024-07-21 09:56+0530\\n\"\n\"Last-Translator: Scrambled777 <weblate.scrambled777@simplelogin.com>\\n\"\n\"Language-Team: Hindi <indlinux-hindi@lists.sourceforge.net>\\n\"\n\"Language: hi\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"X-DL-Lang: hi\\n\"\n\"X-DL-Module: g4music\\n\"\n\"X-DL-Branch: master\\n\"\n\"X-DL-Domain: po\\n\"\n\"X-DL-State: None\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n\"X-Generator: Gtranslator 46.1\\n\"\n\n#: data/app.desktop.in:3 src/application.vala:237 src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"गैपलेस\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"म्यूजिक प्लेयर\"\n\n#: data/app.desktop.in:5\nmsgid \"Play music\"\nmsgstr \"संगीत बजाएं\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"संगीत;ध्वनि;प्लेयर;मीडिया;ऑडियो;प्लेलिस्ट;\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"सामान्य\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"शॉर्टकट दिखाएं\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"प्राथमिकताएं\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"बंद करें\"\n\n#: src/gtk/help-overlay.ui:34\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"प्लेबैक\"\n\n#: src/gtk/help-overlay.ui:37\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"बजाएं/रोकें\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"अगला बजाएं\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"पिछला बजाएं\"\n\n#: src/gtk/help-overlay.ui:57\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"प्लेलिस्ट\"\n\n#: src/gtk/help-overlay.ui:60\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"खोजें\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"छंटाई टॉगल करें\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"लाइब्रेरी पुनः लोड करें\"\n\n#: src/gtk/play-panel.ui:16 src/ui/store-panel.vala:350\nmsgid \"Back\"\nmsgstr \"पीछे\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"सामान्य\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Prefer dark theme\"\nmsgstr \"गहरी थीम को प्राथमिकता\"\n\n#: src/gtk/preferences.ui:26\nmsgid \"Background blur mode\"\nmsgstr \"पृष्ठभूमि धुंधला मोड\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Compact playlist view\"\nmsgstr \"सघन प्लेलिस्ट दृश्य\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Grid view for artists/albums\"\nmsgstr \"कलाकारों/एल्बमों के लिए ग्रिड दृश्य\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:428\nmsgid \"Keep playing after window closed\"\nmsgstr \"विंडो बंद होने के बाद भी बजाते रहें\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"लाइब्रेरी\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"फोल्डर से संगीत लोड करें\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"स्थानीय फाइल परिवर्तनों पर नज़र रखें\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"गैर-स्थानीय फाइलों के लिए थंबनेल लोड करें\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"धीमेपन और अत्यधिक नेटवर्क उपयोग का कारण बन सकता है\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"प्लेबैक\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"ऑडियो चरम स्तर दिखाएं\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"वर्ण प्रदर्शित करें\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"एल्बम कवर घुमाएं\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"अंतराल रहित प्लेबैक सक्षम करें\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"रीप्लेगैन के साथ वॉल्यूम सामान्य करें\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"GStreamer ऑडियो सिंक को प्राथमिकता दें\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"मुख्य मेनू\"\n\n#: src/gtk/store-panel.ui:29\nmsgid \"Search\"\nmsgstr \"खोजें\"\n\n#: src/gtk/store-panel.ui:35\nmsgid \"Sort By\"\nmsgstr \"ऐसे छांटें\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_Reload Library\"\nmsgstr \"लाइब्रेरी पुनः लोड करें (_R)\"\n\n#: src/gtk/store-panel.ui:79\nmsgid \"_Preferences\"\nmsgstr \"प्राथमिकताएं (_P)\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"कीबोर्ड शॉर्टकट (_K)\"\n\n#: src/gtk/store-panel.ui:87\nmsgid \"_About\"\nmsgstr \"परिचय (_A)\"\n\n#: src/gtk/store-panel.ui:96 src/ui/preferences.vala:67\nmsgid \"Album\"\nmsgstr \"एल्बम\"\n\n#: src/gtk/store-panel.ui:101\nmsgid \"Artist\"\nmsgstr \"कलाकार\"\n\n#: src/gtk/store-panel.ui:106\nmsgid \"Artist/Album\"\nmsgstr \"कलाकार/एल्बम\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"Title\"\nmsgstr \"शीर्षक\"\n\n#: src/gtk/store-panel.ui:116\nmsgid \"Recent\"\nmsgstr \"हालिया\"\n\n#: src/gtk/store-panel.ui:121\nmsgid \"Shuffle\"\nmsgstr \"शफ़ल\"\n\n#: src/action-handles.vala:184\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"GTK4 में लिखा गया एक तेज़, धाराप्रवाह, हल्के वजन वाला म्यूजिक प्लेयर।\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/action-handles.vala:186\nmsgid \"translator-credits\"\nmsgstr \"Scrambled777 <weblate.scrambled777@simplelogin.com>\"\n\n#: src/application.vala:625\nmsgid \"Keep playing\"\nmsgstr \"बजते रहें\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-widgets.vala:211 src/ui/music-widgets.vala:252\n#: src/ui/music-widgets.vala:262\nmsgid \"Play at Next\"\nmsgstr \"आगे यह बजाएं\"\n\n#: src/ui/music-widgets.vala:212 src/ui/music-widgets.vala:251\n#: src/ui/music-widgets.vala:261 src/ui/store-panel.vala:355\nmsgid \"Play\"\nmsgstr \"बजाएं\"\n\n#: src/ui/music-widgets.vala:215 src/ui/play-panel.vala:130\nmsgid \"Show _Cover File\"\nmsgstr \"कवर फाइल दिखाएं (_C)\"\n\n#: src/ui/music-widgets.vala:217 src/ui/play-panel.vala:132\nmsgid \"_Export Cover\"\nmsgstr \"कवर निर्यात (_E)\"\n\n#: src/ui/music-widgets.vala:254\nmsgid \"Show List File\"\nmsgstr \"सूची फाइल दिखाएं\"\n\n#: src/ui/music-widgets.vala:268 src/ui/play-panel.vala:61\nmsgid \"Search Title\"\nmsgstr \"शीर्षक खोजें\"\n\n#: src/ui/music-widgets.vala:269 src/ui/play-panel.vala:59\nmsgid \"Search Album\"\nmsgstr \"एल्बम खोजें\"\n\n#: src/ui/music-widgets.vala:270 src/ui/play-panel.vala:60\nmsgid \"Search Artist\"\nmsgstr \"कलाकार खोजें\"\n\n#: src/ui/music-widgets.vala:271\nmsgid \"_Show Music File\"\nmsgstr \"संगीत फाइल दिखाएं (_S)\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:74\nmsgid \"Single Loop\"\nmsgstr \"एकल लूप\"\n\n#: src/ui/play-bar.vala:84\nmsgid \"Play Previous\"\nmsgstr \"पिछला बजाएं\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:90\nmsgid \"Play/Pause\"\nmsgstr \"बजाएं/रोकें\"\n\n#: src/ui/play-bar.vala:97\nmsgid \"Play Next\"\nmsgstr \"अगला बजाएं\"\n\n#: src/ui/play-panel.vala:285\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"संगीत फाइलों को यहां खींचें और छोड़ें,\\n\"\n\"या संगीत स्थान बदलें: \"\n\n#: src/ui/preferences.vala:46 src/ui/preferences.vala:67\nmsgid \"Never\"\nmsgstr \"कभी नहीं\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Always\"\nmsgstr \"हमेशा\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Art Only\"\nmsgstr \"केवल कला\"\n\n#: src/ui/preferences.vala:67\nmsgid \"Track\"\nmsgstr \"ट्रैक\"\n\n#: src/ui/store-panel.vala:75\nmsgid \"Playing\"\nmsgstr \"बज रहा है\"\n\n#: src/ui/store-panel.vala:80\nmsgid \"Artists\"\nmsgstr \"कलाकार\"\n\n#: src/ui/store-panel.vala:85\nmsgid \"Albums\"\nmsgstr \"एलबम\"\n\n#: src/ui/store-panel.vala:384\nmsgid \"Playlists\"\nmsgstr \"प्लेलिस्ट\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"आवाज़ %d%% \"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"अज्ञात एल्बम\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"अज्ञात कलाकार\"\n"
  },
  {
    "path": "po/hu.po",
    "content": "# Hungarian translation for g4music.\n# Copyright (C) 2023, 2024, 2025 Free Software Foundation, Inc.\n# This file is distributed under the same license as the g4music package.\n#\n# Balázs Úr <ur.balazs at fsf dot hu>, 2023, 2024, 2025.\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2025-09-10 13:36+0000\\n\"\n\"PO-Revision-Date: 2025-09-11 09:31+0200\\n\"\n\"Last-Translator: Balázs Úr <ur.balazs at fsf dot hu>\\n\"\n\"Language-Team: Hungarian <openscope at fsf dot hu>\\n\"\n\"Language: hu\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Lokalize 24.12.3\\n\"\n\n#: data/app.desktop.in:2 data/app.metainfo.xml.in:4 src/application.vala:273\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Szünetmentes\"\n\n#: data/app.desktop.in:3\nmsgid \"Music Player\"\nmsgstr \"Zenelejátszó\"\n\n#: data/app.desktop.in:4 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Zenék elegáns lejátszása\"\n\n#: data/app.desktop.in:11\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"zene;zaj;lejátszó;média;hang;lejátszási lista;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"A Szünetmentes (más néven: G4Music) egy GTK4-ben írt, könnyűsúlyú zenelejátszó\"\n\", amely nagy zenei gyűjteményekre összpontosít.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Funkciók\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Támogatja a legtöbb zenefájltípust, a Sambát és egyéb távoli protokollokat (a \"\n\"GIO-tól és a GStreamertől függően).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Több ezer zenefájl gyors betöltése és feldolgozása néhány másodperc alatt, a h\"\n\"elyi változtatások figyelése.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Alacsony memóriahasználat albumborítókkal (beágyazott és külső) rendelkező nag\"\n\"y zenei gyűjteményeknél, tárolandó bélyegkép-gyorsítótárak nélkül.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Csoportosítás és rendezés album, előadó vagy cím szerint, véletlenszerű lejáts\"\n\"zási lista, teljes szöveges keresés.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Folyékony, adaptív felhasználói felület különböző képernyőkhöz (asztali számít\"\n\"ógép, táblagép, mobiltelefon).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Gauss-elmosást alkalmazott borító háttérként, ami követi a GNOME világos vagy \"\n\"sötét módját.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Támogatja a lejátszási listák létrehozását és szerkesztését, a borító húzásáva\"\n\"l megváltoztathatja a sorrendet vagy hozzáadhatja egy másik lejátszási listáho\"\n\"z.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Támogatja a fogd és vidd funkciót más alkalmazásokkal.\"\n\n#: data/app.metainfo.xml.in:35\n#| msgid \"Show audio peak level\"\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Támogatja a hangcsúcsok grafikus megjelenítését.\"\n\n#: data/app.metainfo.xml.in:36\n#| msgid \"Enable gapless playback\"\nmsgid \"Supports gapless playback.\"\nmsgstr \"Támogatja a szünetmentes lejátszást.\"\n\n#: data/app.metainfo.xml.in:37\n#| msgid \"Normalize volume with ReplayGain\"\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Támogatja a hangerő normalizálását hangerő-korrekcióval.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Támogatja a megadott hangelnyelőt.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Támogatja az MPRIS-vezérlést.\"\n\n#: data/app.metainfo.xml.in:50\n#| msgid \"Main Menu\"\nmsgid \"Main window\"\nmsgstr \"Főablak\"\n\n#: data/app.metainfo.xml.in:54\n#| msgid \"Albums\"\nmsgid \"Albums view\"\nmsgstr \"Albumok nézet\"\n\n#: data/app.metainfo.xml.in:58\n#| msgid \"Playing\"\nmsgid \"Playing view\"\nmsgstr \"Lejátszás nézet\"\n\n#: data/app.metainfo.xml.in:62\n#| msgctxt \"shortcut window\"\n#| msgid \"Playlist\"\nmsgid \"Playlist view\"\nmsgstr \"Lejátszási lista nézet\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Általános\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Gyorsbillentyűk megjelenítése\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Beállítások\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Kilépés\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Címkék megjelenítése\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Lejátszás\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Lejátszás vagy szüneteltetés\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Következő lejátszása\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Előző lejátszása\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Lejátszási lista\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Keresés\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Rendezés be- és kikapcsolása\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Gyűjtemény újratöltése\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Lista mentése\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:626\n#: src/ui/store-panel.vala:420\nmsgid \"Back\"\nmsgstr \"Vissza\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Általános\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Háttér elmosásának módja\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Tömör lejátszási lista nézet\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Előadók vagy albumok rácsnézete\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Egy kattintás az elem aktiválásához\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:434\nmsgid \"Keep playing after window closed\"\nmsgstr \"Lejátszás folytatása az ablak bezárása után\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Gyűjtemény\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Zenék betöltése mappából\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Helyi fájlváltozások figyelése\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Bélyegképek betöltése a nem helyi fájlokhoz\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Lassulást és túlzott hálózathasználatot okozhat\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Lejátszás\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Hang csúcsszintjének megjelenítése\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Karakterek megjelenítése\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Albumborító forgatása\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Szünetmentes lejátszás engedélyezése\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Hangerő normalizálása hangerő-korrekcióval\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"A GStreamer hangnyelőjének előnyben részesítése\"\n\n#: src/gtk/store-panel.ui:23\nmsgid \"Main Menu\"\nmsgstr \"Főmenü\"\n\n#: src/gtk/store-panel.ui:30 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Keresés\"\n\n#: src/gtk/store-panel.ui:40\nmsgid \"Sort By\"\nmsgstr \"Rendezési sorrend\"\n\n#: src/gtk/store-panel.ui:71\nmsgid \"_Color Scheme\"\nmsgstr \"S_zínséma\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_System\"\nmsgstr \"_Rendszer\"\n\n#: src/gtk/store-panel.ui:78\nmsgid \"_Light\"\nmsgstr \"_Világos\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Dark\"\nmsgstr \"_Sötét\"\n\n#: src/gtk/store-panel.ui:90\nmsgid \"_Reload Library\"\nmsgstr \"Gyűjtemény újra_töltése\"\n\n#: src/gtk/store-panel.ui:94\nmsgid \"_Multiple Select\"\nmsgstr \"_Több kiválasztása\"\n\n#: src/gtk/store-panel.ui:98\nmsgid \"_Save List\"\nmsgstr \"Lista _mentése\"\n\n#: src/gtk/store-panel.ui:104\nmsgid \"_Preferences\"\nmsgstr \"_Beállítások\"\n\n#: src/gtk/store-panel.ui:108\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Gyorsbillentyűk\"\n\n#: src/gtk/store-panel.ui:112\nmsgid \"_About\"\nmsgstr \"_Névjegy\"\n\n#: src/gtk/store-panel.ui:121 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:126\nmsgid \"Artist\"\nmsgstr \"Előadó\"\n\n#: src/gtk/store-panel.ui:131\nmsgid \"Artist/Album\"\nmsgstr \"Előadó vagy album\"\n\n#: src/gtk/store-panel.ui:136\nmsgid \"Title\"\nmsgstr \"Cím\"\n\n#: src/gtk/store-panel.ui:141\nmsgid \"Recent\"\nmsgstr \"Legutóbbi\"\n\n#: src/gtk/store-panel.ui:146\nmsgid \"Shuffle\"\nmsgstr \"Keverés\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Képfájlok\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"A borító sikeresen exportálva\"\n\n#: src/action-handles.vala:121\n#| msgid \"_Export Cover\"\nmsgid \"Export cover failed\"\nmsgstr \"Nem sikerült a borító exportálása\"\n\n#: src/application.vala:346\n#| msgid \"Compact playlist view\"\nmsgid \"Save playlist failed\"\nmsgstr \"Nem sikerült a lejátszási lista mentése\"\n\n#: src/application.vala:470\n#| msgid \"Playlists\"\nmsgid \"Playlist Files\"\nmsgstr \"Lejátszási lista fájlok\"\n\n#: src/application.vala:485\nmsgid \"Save playlist successfully\"\nmsgstr \"A lejátszási lista sikeresen elmentve\"\n\n#: src/application.vala:620\nmsgid \"Keep playing\"\nmsgstr \"Lejátszás folytatása\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:52\nmsgid \"translator-credits\"\nmsgstr \"Úr Balázs <ur dot balazs at fsf dot hu>, 2023, 2024, 2025.\"\n\n#: src/ui/dialogs.vala:98 src/ui/dialogs.vala:110\nmsgid \"No\"\nmsgstr \"Nem\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:110\nmsgid \"Yes\"\nmsgstr \"Igen\"\n\n#: src/ui/music-list.vala:270\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"A lejátszási lista megváltozott, elmenti?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:399 src/ui/music-list.vala:415\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\n#| msgid \"Play at Next\"\nmsgid \"Play at _Next\"\nmsgstr \"Lejátszás a _következőnél\"\n\n#: src/ui/music-list.vala:401 src/ui/music-list.vala:417\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Hozzáadás _sorhoz\"\n\n#: src/ui/music-list.vala:402 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Hozzáadás _lejátszási listához…\"\n\n#: src/ui/music-list.vala:403 src/ui/music-list.vala:421\nmsgid \"_Remove\"\nmsgstr \"_Eltávolítás\"\n\n#: src/ui/music-list.vala:422 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"Áthelyezés a _kukába\"\n\n#: src/ui/music-list.vala:630\nmsgid \"Select All\"\nmsgstr \"Összes kijelölése\"\n\n#: src/ui/music-list.vala:647\nmsgid \"Play at Next\"\nmsgstr \"Lejátszás a következőnél\"\n\n#: src/ui/music-list.vala:654\nmsgid \"Add to Queue\"\nmsgstr \"Hozzáadás sorhoz\"\n\n#: src/ui/music-list.vala:661 src/ui/playlist-dialog.vala:19\n#| msgctxt \"shortcut window\"\n#| msgid \"Playlist\"\nmsgid \"Add to Playlist\"\nmsgstr \"Hozzáadás lejátszási listához\"\n\n#: src/ui/music-list.vala:668\nmsgid \"Remove\"\nmsgstr \"Eltávolítás\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:428\nmsgid \"Play\"\nmsgstr \"Lejátszás\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Véletlenszerű lejátszás\"\n\n#: src/ui/music-widgets.vala:285\n#| msgid \"Show List File\"\nmsgid \"Show List _File\"\nmsgstr \"Lista_fájl megjelenítése\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:63\nmsgid \"Search Title\"\nmsgstr \"Cím keresése\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:61\nmsgid \"Search Album\"\nmsgstr \"Album keresése\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:62\nmsgid \"Search Artist\"\nmsgstr \"Előadó keresése\"\n\n#: src/ui/music-widgets.vala:314\n#| msgid \"Show _Cover File\"\nmsgid \"Show Cover _File\"\nmsgstr \"Borító_fájl megjelenítése\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"Borító _exportálása\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"_Címkék megjelenítése…\"\n\n#: src/ui/music-widgets.vala:318\n#| msgid \"_Show Music File\"\nmsgid \"Show Music _File\"\nmsgstr \"Zene_fájl megjelenítése\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Ismételt lejátszás\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Előző lejátszása\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Lejátszás vagy szüneteltetés\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Következő lejátszása\"\n\n#: src/ui/play-panel.vala:56 src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Lejátszás\"\n\n#: src/ui/play-panel.vala:266\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Fogjon meg és ejtsen ide zenefájlokat,\\n\"\n\"vagy változtassa meg a zenék helyét: \"\n\n#: src/ui/playlist-dialog.vala:24\n#| msgctxt \"shortcut window\"\n#| msgid \"Playlist\"\nmsgid \"New Playlist\"\nmsgstr \"Új lejátszási lista\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:712\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Nem található lejátszási lista ebben: %s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Soha\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Mindig\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Csak borító\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Szám\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Előadók\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Albumok\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Lejátszási listák\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Másolás\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Hangerő %d%%\"\n\n#: src/ui/window.vala:126\nmsgid \"Show\"\nmsgstr \"Megjelenítés\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Ismeretlen album\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Ismeretlen előadó\"\n"
  },
  {
    "path": "po/ia.po",
    "content": "# Interlingua translation for g4music.\n# Copyright (C) 2025 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n# Emilio Sepúlveda <emism.translations@gmail.com>, 2025.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2025-09-11 07:33+0000\\n\"\n\"PO-Revision-Date: 2025-09-23 16:19-0300\\n\"\n\"Last-Translator: Emilio Sepúlveda <emism.translations@gmail.com>\\n\"\n\"Language-Team: Interlingua <softinterlingua@gmail.com>\\n\"\n\"Language: ia\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"X-DL-Lang: ia\\n\"\n\"X-DL-Module: g4music\\n\"\n\"X-DL-Branch: master\\n\"\n\"X-DL-Domain: po\\n\"\n\"X-DL-State: Translating\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n\"X-Generator: Gtranslator 48.0\\n\"\n\n#: data/app.desktop.in:2 data/app.metainfo.xml.in:4 src/application.vala:273\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"\"\n\n#: data/app.desktop.in:3\nmsgid \"Music Player\"\nmsgstr \"Reproductor de musica\"\n\n#: data/app.desktop.in:4 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Reproduce tu musica con elegantia\"\n\n#: data/app.desktop.in:11\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"music;sound;player;media;audio;playlist;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Functionalitates\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Fenestra principal\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Vista de albumes\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Vista de reproduction\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Vista de lista de reproduction\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"General\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Monstrar vias breve\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Preferentias\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Quitar\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Monstrar etiquettas\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Reproduction\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Reproducer/Pausar\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Reproducer sequente\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Reproducer precedente\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Lista de reproduction\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Cercar\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Commutar ordinamento\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Recargar bibliotheca\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Salvar lista\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:626\n#: src/ui/store-panel.vala:420\nmsgid \"Back\"\nmsgstr \"Retro\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"General\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Vista de lista de reproduction compacte\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Vista de grillia pro artistas/albumes\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Clicca un vice pro activar le elemento\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:434\nmsgid \"Keep playing after window closed\"\nmsgstr \"Mantener reproduction depost le claudimento del fenestra\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Bibliotheca\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Cargar musica ab dossier\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Reproduction\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Monstrar characteres\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalisar volumine con ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"\"\n\n#: src/gtk/store-panel.ui:23\nmsgid \"Main Menu\"\nmsgstr \"Menu principal\"\n\n#: src/gtk/store-panel.ui:30 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Cercar\"\n\n#: src/gtk/store-panel.ui:40\nmsgid \"Sort By\"\nmsgstr \"Ordinar per\"\n\n#: src/gtk/store-panel.ui:71\nmsgid \"_Color Scheme\"\nmsgstr \"Schema de _color\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_System\"\nmsgstr \"_Systema\"\n\n#: src/gtk/store-panel.ui:78\nmsgid \"_Light\"\nmsgstr \"C_lar\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Dark\"\nmsgstr \"_Obscur\"\n\n#: src/gtk/store-panel.ui:90\nmsgid \"_Reload Library\"\nmsgstr \"_Recargar bibliotheca\"\n\n#: src/gtk/store-panel.ui:94\nmsgid \"_Multiple Select\"\nmsgstr \"Selection _multiple\"\n\n#: src/gtk/store-panel.ui:98\nmsgid \"_Save List\"\nmsgstr \"_Salvar lista\"\n\n#: src/gtk/store-panel.ui:104\nmsgid \"_Preferences\"\nmsgstr \"_Preferentias\"\n\n#: src/gtk/store-panel.ui:108\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"Vias breve de _claviero\"\n\n#: src/gtk/store-panel.ui:112\nmsgid \"_About\"\nmsgstr \"_A proposito\"\n\n#: src/gtk/store-panel.ui:121 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:126\nmsgid \"Artist\"\nmsgstr \"Artista\"\n\n#: src/gtk/store-panel.ui:131\nmsgid \"Artist/Album\"\nmsgstr \"Artista/Album\"\n\n#: src/gtk/store-panel.ui:136\nmsgid \"Title\"\nmsgstr \"Titulo\"\n\n#: src/gtk/store-panel.ui:141\nmsgid \"Recent\"\nmsgstr \"Recente\"\n\n#: src/gtk/store-panel.ui:146\nmsgid \"Shuffle\"\nmsgstr \"Miscer\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Files de imagine\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"\"\n\n#: src/application.vala:346\nmsgid \"Save playlist failed\"\nmsgstr \"\"\n\n#: src/application.vala:470\nmsgid \"Playlist Files\"\nmsgstr \"Files de lista de reproduction\"\n\n#: src/application.vala:485\nmsgid \"Save playlist successfully\"\nmsgstr \"\"\n\n#: src/application.vala:620\nmsgid \"Keep playing\"\nmsgstr \"Mantener le reproduction\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:52\nmsgid \"translator-credits\"\nmsgstr \"Emilio Sepúlveda <emism.translations@gmail.com>\"\n\n#: src/ui/dialogs.vala:98 src/ui/dialogs.vala:110\nmsgid \"No\"\nmsgstr \"No\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:110\nmsgid \"Yes\"\nmsgstr \"Si\"\n\n#: src/ui/music-list.vala:270\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Le lista de reproduction es modificate, salvar lo?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:399 src/ui/music-list.vala:415\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:401 src/ui/music-list.vala:417\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Adder al _cauda\"\n\n#: src/ui/music-list.vala:402 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Adder al lista de re_production\"\n\n#: src/ui/music-list.vala:403 src/ui/music-list.vala:421\nmsgid \"_Remove\"\nmsgstr \"_Remover\"\n\n#: src/ui/music-list.vala:422 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"Displaciar al i_mmunditia\"\n\n#: src/ui/music-list.vala:630\nmsgid \"Select All\"\nmsgstr \"Seliger toto\"\n\n#: src/ui/music-list.vala:647\nmsgid \"Play at Next\"\nmsgstr \"\"\n\n#: src/ui/music-list.vala:654\nmsgid \"Add to Queue\"\nmsgstr \"Adder al cauda\"\n\n#: src/ui/music-list.vala:661 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Adder al lista de reproduction\"\n\n#: src/ui/music-list.vala:668\nmsgid \"Remove\"\nmsgstr \"Remover\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:428\nmsgid \"Play\"\nmsgstr \"Reproducer\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Reproduction aleatori\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:63\nmsgid \"Search Title\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:61\nmsgid \"Search Album\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:62\nmsgid \"Search Artist\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Monstrar _file de musica\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Reproducer precedente\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Reproducer/Pausar\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Reproducer sequente\"\n\n#: src/ui/play-panel.vala:56 src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"\"\n\n#: src/ui/play-panel.vala:266\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Nove lista de reproduction\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:712\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Nunquam\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Sempre\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Pista\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Artistas\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Albumes\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Listas de reproduction\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Copiar\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Volumine %d%%\"\n\n#: src/ui/window.vala:126\nmsgid \"Show\"\nmsgstr \"Monstrar\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Album incognite\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Artista incognite\"\n"
  },
  {
    "path": "po/id.po",
    "content": "# Indonesian translation for g4music.\n# Copyright (C) 2023 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Andika Triwidada <atriwidada@gnome.org>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/-/issues\\n\"\n\"POT-Creation-Date: 2023-08-17 01:27+0000\\n\"\n\"PO-Revision-Date: 2023-08-17 17:18+0700\\n\"\n\"Last-Translator: Andika Triwidada <andika@gmail.com>\\n\"\n\"Language-Team: Indonesian <gnome-l10n-id@googlegroups.com>\\n\"\n\"Language: id\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"X-Generator: Poedit 3.3.2\\n\"\n\n#: data/app.desktop.in:3 src/application.vala:232 src/main.vala:24\nmsgid \"G4Music\"\nmsgstr \"G4Music\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Pemutar Musik\"\n\n#: data/app.desktop.in:5\nmsgid \"Play music\"\nmsgstr \"Putar musik\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"musik;suara;pemutar;media;audio;daftar putar;\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Umum\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Tampilkan Pintasan\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Preferensi\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Keluar\"\n\n#: src/gtk/help-overlay.ui:34\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Putar\"\n\n#: src/gtk/help-overlay.ui:37\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Putar/Jeda\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Putar Berikutnya\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Putar Sebelumnya\"\n\n#: src/gtk/help-overlay.ui:57\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Daftar Putar\"\n\n#: src/gtk/help-overlay.ui:60\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Pencarian\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Jungkitkan Urutan\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Muat Ulang Pustaka\"\n\n#: src/gtk/play-panel.ui:16 src/ui/store-panel.vala:340\nmsgid \"Back\"\nmsgstr \"Kembali\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Umum\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Prefer dark theme\"\nmsgstr \"Lebih suka tema gelap\"\n\n#: src/gtk/preferences.ui:26\nmsgid \"Background blur mode\"\nmsgstr \"Mode pengaburan latar\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Compact playlist view\"\nmsgstr \"Tampilan daftar putar ringkas\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Tampilan kisi bagi artis/album\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:432\nmsgid \"Keep playing after window closed\"\nmsgstr \"Tetap memutar setelah jendela ditutup\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Pustaka\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Muat musik dari folder\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Pantau perubahan berkas lokal\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Muat gambar mini bagi berkas bukan lokal\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Bisa menyebabkan melambat dan penggunaan jaringan berlebihan\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Putar\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Tampilkan tingkat puncak audio\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Tampilkan karakter\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Putar sampul album\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Aktifkan putar balik tanpa jeda\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalkan volume dengan ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Lebih suka muara audio dari GStreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Menu Utama\"\n\n#: src/gtk/store-panel.ui:28\nmsgid \"Sort By\"\nmsgstr \"Urut Berdasarkan\"\n\n#: src/gtk/store-panel.ui:35\nmsgid \"Search\"\nmsgstr \"Pencarian\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_Reload Library\"\nmsgstr \"Muat U_lang Pustaka\"\n\n#: src/gtk/store-panel.ui:79\nmsgid \"_Preferences\"\nmsgstr \"_Preferensi\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Tombol Pintas\"\n\n#: src/gtk/store-panel.ui:87\nmsgid \"_About\"\nmsgstr \"Tent_ang\"\n\n#: src/gtk/store-panel.ui:96 src/ui/preferences.vala:67\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:101\nmsgid \"Artist\"\nmsgstr \"Artis\"\n\n#: src/gtk/store-panel.ui:106\nmsgid \"Artist/Album\"\nmsgstr \"Artis/Album\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"Title\"\nmsgstr \"Judul\"\n\n#: src/gtk/store-panel.ui:116\nmsgid \"Recent\"\nmsgstr \"Terkini\"\n\n#: src/gtk/store-panel.ui:121\nmsgid \"Shuffle\"\nmsgstr \"Acak\"\n\n#: src/action-handles.vala:184\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Pemutar musik yang cepat, fasih, dan ringan yang ditulis dalam GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/action-handles.vala:186\nmsgid \"translator-credits\"\nmsgstr \"Andika Triwidada <andika@gmail.com>, 2023\"\n\n#: src/application.vala:613\nmsgid \"Keep playing\"\nmsgstr \"Tetap memutar\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-widgets.vala:252 src/ui/music-widgets.vala:293\n#: src/ui/music-widgets.vala:303\nmsgid \"Play at Next\"\nmsgstr \"Putar pada Berikutnya\"\n\n#: src/ui/music-widgets.vala:253 src/ui/music-widgets.vala:292\n#: src/ui/music-widgets.vala:302 src/ui/store-panel.vala:345\nmsgid \"Play\"\nmsgstr \"Putar\"\n\n#: src/ui/music-widgets.vala:256 src/ui/play-panel.vala:231\nmsgid \"Show _Cover File\"\nmsgstr \"Tampilkan Berkas _Sampul\"\n\n#: src/ui/music-widgets.vala:258 src/ui/play-panel.vala:233\nmsgid \"_Export Cover\"\nmsgstr \"_Ekspor Sampul\"\n\n#: src/ui/music-widgets.vala:295\nmsgid \"Show List File\"\nmsgstr \"Tampilkan Berkas Daftar\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:55\nmsgid \"Search Title\"\nmsgstr \"Cari Judul\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:53\nmsgid \"Search Album\"\nmsgstr \"Cari Album\"\n\n#: src/ui/music-widgets.vala:311 src/ui/play-panel.vala:54\nmsgid \"Search Artist\"\nmsgstr \"Cari Artis\"\n\n#: src/ui/music-widgets.vala:312\nmsgid \"_Show Music File\"\nmsgstr \"Tampilkan Berka_s Musik\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:76\nmsgid \"Single Loop\"\nmsgstr \"Pengulangan Tunggal\"\n\n#: src/ui/play-bar.vala:86\nmsgid \"Play Previous\"\nmsgstr \"Putar Sebelumnya\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:92\nmsgid \"Play/Pause\"\nmsgstr \"Putar/Jeda\"\n\n#: src/ui/play-bar.vala:99\nmsgid \"Play Next\"\nmsgstr \"Putar Berikutnya\"\n\n#: src/ui/play-panel.vala:274\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Seret dan jatuhkan berkas musik di sini,\\n\"\n\"atau ubah lokasi musik: \"\n\n#: src/ui/preferences.vala:46 src/ui/preferences.vala:67\nmsgid \"Never\"\nmsgstr \"Tidak pernah\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Always\"\nmsgstr \"Selalu\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Art Only\"\nmsgstr \"Hanya Seni\"\n\n#: src/ui/preferences.vala:67\nmsgid \"Track\"\nmsgstr \"Lacak\"\n\n#: src/ui/store-panel.vala:74\nmsgid \"Playing\"\nmsgstr \"Memutar\"\n\n#: src/ui/store-panel.vala:79\nmsgid \"Artists\"\nmsgstr \"Artis\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Albums\"\nmsgstr \"Album\"\n\n#: src/ui/store-panel.vala:374\nmsgid \"Playlists\"\nmsgstr \"Daftar Putar\"\n\n#. Translators: Current volume: 0~100\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d\"\nmsgstr \"Volume %d\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Album Tak Dikenal\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Artis Tak Dikenal\"\n"
  },
  {
    "path": "po/it.po",
    "content": "# ITALIAN TANSLATION FOR G4MUSIC.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# Albano Battistella <albano_battistella@hotmail.com>, 2022,2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2023-07-26 21:16+0800\\n\"\n\"PO-Revision-Date: 2023-08-14 12:29+0200\\n\"\n\"Last-Translator: Albano Battistella <albano_battistella@hotmail.com>\\n\"\n\"Language-Team: Italian <LL@li.org>\\n\"\n\"Language: it\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"X-Generator: Poedit 3.1.1\\n\"\n\n#: data/app.desktop.in:3 src/application.vala:225 src/main.vala:24\nmsgid \"G4Music\"\nmsgstr \"G4Music\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Lettore musicale\"\n\n#: data/app.desktop.in:5\nmsgid \"Play music\"\nmsgstr \"Riproduci musica\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"musica;suono;lettore;media;audio;playlist;\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Generale\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Mostra scorciatoie\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Preferenze\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Esci\"\n\n#: src/gtk/help-overlay.ui:34\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Riproduzione\"\n\n#: src/gtk/help-overlay.ui:37\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Riproduci/Pausa\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Riproduci prossimo\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Riproduci precedente\"\n\n#: src/gtk/help-overlay.ui:57\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Riproduci\"\n\n#: src/gtk/help-overlay.ui:60\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Cerca\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Cambia l'ordine\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Ricarica libreria\"\n\n#: src/gtk/play-panel.ui:16 src/ui/store-panel.vala:290\nmsgid \"Back\"\nmsgstr \"Indietro\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Generale\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Prefer dark theme\"\nmsgstr \"Preferisci il tema scuro\"\n\n#: src/gtk/preferences.ui:26\nmsgid \"Background blur mode\"\nmsgstr \"Applica blur allo sfondo\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Compact playlist view\"\nmsgstr \"Visualizza playlist compatta\"\n\n#: src/gtk/preferences.ui:44 src/application.vala:424\nmsgid \"Keep playing after window closed\"\nmsgstr \"Continua a riprodurre dopo aver chiuso la finestra\"\n\n#: src/gtk/preferences.ui:57\nmsgid \"Library\"\nmsgstr \"Libreria\"\n\n#: src/gtk/preferences.ui:61\nmsgid \"Load music from folder\"\nmsgstr \"Carica musica dalla cartella\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Monitor local file changes\"\nmsgstr \"Monitora cambiamenti dei file locali\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Carica miniature per file non locali\"\n\n#: src/gtk/preferences.ui:86\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Potrebbe causare rallentamenti e un uso della rete eccessivo\"\n\n#: src/gtk/preferences.ui:99\nmsgid \"Playback\"\nmsgstr \"Riproduci\"\n\n#: src/gtk/preferences.ui:103\nmsgid \"Show audio peak level\"\nmsgstr \"Mostra il livello di picco dell'audio\"\n\n#: src/gtk/preferences.ui:107\nmsgid \"Display characters\"\nmsgstr \"Mostra caratteri\"\n\n#: src/gtk/preferences.ui:122\nmsgid \"Rotate album cover\"\nmsgstr \"Ruota copertina album\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Enable gapless playback\"\nmsgstr \"Abilita la riproduzione senza interruzioni\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Usa ReplayGain per normalizzare il volume\"\n\n#: src/gtk/preferences.ui:152\nmsgid \"Prefer audio sink\"\nmsgstr \"Audio sink preferito\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Menu principale\"\n\n#: src/gtk/store-panel.ui:28\nmsgid \"Sort By\"\nmsgstr \"Ordina per\"\n\n#: src/gtk/store-panel.ui:35\nmsgid \"Search\"\nmsgstr \"Cerca\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_Reload Library\"\nmsgstr \"_Ricarica libreria\"\n\n#: src/gtk/store-panel.ui:79\nmsgid \"_Preferences\"\nmsgstr \"_Preferenze\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Scorciatoie da tastiera\"\n\n#: src/gtk/store-panel.ui:87\nmsgid \"_About\"\nmsgstr \"_Informazioni\"\n\n#: src/gtk/store-panel.ui:96 src/ui/preferences.vala:64\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:101\nmsgid \"Artist\"\nmsgstr \"Artista\"\n\n#: src/gtk/store-panel.ui:106\nmsgid \"Artist/Album\"\nmsgstr \"Artista/Album\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"Title\"\nmsgstr \"Titolo\"\n\n#: src/gtk/store-panel.ui:116\nmsgid \"Recent\"\nmsgstr \"Recente\"\n\n#: src/gtk/store-panel.ui:121\nmsgid \"Shuffle\"\nmsgstr \"Mescola\"\n\n#: src/action-handles.vala:188\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Un lettore musicale veloce, scorrevole e leggero scritto in GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/action-handles.vala:190\nmsgid \"translator-credits\"\nmsgstr \"Albano Battistella, Mek101\"\n\n#: src/application.vala:573\nmsgid \"Keep playing\"\nmsgstr \"Continuare a riprodurre\"\n\n#: src/ui/music-widgets.vala:232 src/ui/music-widgets.vala:260\nmsgid \"Play at Next\"\nmsgstr \"Riproduci il prossimo\"\n\n#: src/ui/music-widgets.vala:233 src/ui/music-widgets.vala:259\nmsgid \"Play\"\nmsgstr \"Riproduci\"\n\n#: src/ui/music-widgets.vala:236 src/ui/play-panel.vala:222\nmsgid \"Show _Cover File\"\nmsgstr \"Mostra file copertina\"\n\n#: src/ui/music-widgets.vala:238 src/ui/play-panel.vala:224\nmsgid \"_Export Cover\"\nmsgstr \"Exporta Cover\"\n\n#: src/ui/music-widgets.vala:266 src/ui/play-panel.vala:56\nmsgid \"Search Title\"\nmsgstr \"Cerca titolo\"\n\n#: src/ui/music-widgets.vala:267 src/ui/play-panel.vala:54\nmsgid \"Search Album\"\nmsgstr \"Cerca album\"\n\n#: src/ui/music-widgets.vala:268 src/ui/play-panel.vala:55\nmsgid \"Search Artist\"\nmsgstr \"Cerca artista\"\n\n#: src/ui/music-widgets.vala:269\nmsgid \"_Show Music File\"\nmsgstr \"_Mostra file musicali\"\n\n#: src/ui/play-bar.vala:75\nmsgid \"Repeat Music\"\nmsgstr \"Ripeti canzone\"\n\n#: src/ui/play-bar.vala:85\nmsgid \"Play Previous\"\nmsgstr \"Riproduci precedente\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:91\nmsgid \"Play/Pause\"\nmsgstr \"Riproduci/Pausa\"\n\n#: src/ui/play-bar.vala:98\nmsgid \"Play Next\"\nmsgstr \"Riproduci prossimo\"\n\n#: src/ui/play-panel.vala:263\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Trascina e rilascia i file delle canzoni qui,\\n\"\n\"oppure cambia la posizione della libreria: \"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:64\nmsgid \"Never\"\nmsgstr \"Mai\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Sempre\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Solo alla copertina\"\n\n#: src/ui/preferences.vala:64\nmsgid \"Track\"\nmsgstr \"Traccia\"\n\n#: src/ui/store-panel.vala:66\nmsgid \"Playing\"\nmsgstr \"Riprodurre\"\n\n#: src/ui/store-panel.vala:72\nmsgid \"Artists\"\nmsgstr \"Artisti\"\n\n#: src/ui/store-panel.vala:77\nmsgid \"Albums\"\nmsgstr \"Album\"\n\n#: src/ui/volume-button.vala:32\nmsgid \"Volume: \"\nmsgstr \"Volume: \"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Album sconosciuto\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Artista sconosciuto\"\n\n#~ msgid \"Appearance\"\n#~ msgstr \"Aspetto\"\n\n#~ msgid \"Music Location\"\n#~ msgstr \"Posizione della musica\"\n\n#~ msgid \"Experimental\"\n#~ msgstr \"Sperimentale\"\n\n#~ msgid \"By Date\"\n#~ msgstr \"Per data\"\n\n#~ msgid \"Loading...\"\n#~ msgstr \"Caricamento in corso...\"\n\n"
  },
  {
    "path": "po/ja.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n# Gnuey56 <gnuey56@proton.me>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2023-07-26 21:16+0800\\n\"\n\"PO-Revision-Date: 2023-08-01 16:05+0900\\n\"\n\"Last-Translator: Gnuey56 <gnuey56@proton.me>\\n\"\n\"Language-Team: Japanese\\n\"\n\"Language: ja\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=1; plural=0\\n\"\n\"X-Generator: Gtranslator 42.0\\n\"\n\n#: data/app.desktop.in:3 src/application.vala:225 src/main.vala:24\nmsgid \"G4Music\"\nmsgstr \"G4Music\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"ミュージックプレイヤー\"\n\n#: data/app.desktop.in:5\nmsgid \"Play music\"\nmsgstr \"音楽を再生\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"music;sound;player;media;audio;playlist;音楽;サウンド;プレイヤー;メディア;\"\n\"オーディオ;プレイリスト;\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"一般\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"ショートカットを表示\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"設定\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"終了\"\n\n#: src/gtk/help-overlay.ui:34\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"再生\"\n\n#: src/gtk/help-overlay.ui:37\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"再生/一時停止\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"次の曲を再生\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"前の曲を再生\"\n\n#: src/gtk/help-overlay.ui:57\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"プレイリスト\"\n\n#: src/gtk/help-overlay.ui:60\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"検索\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"プレイリストの並びを切り替え\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"ライブラリを再読み込み\"\n\n#: src/gtk/play-panel.ui:16 src/ui/store-panel.vala:290\nmsgid \"Back\"\nmsgstr \"戻る\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"一般\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Prefer dark theme\"\nmsgstr \"ダークテーマを使用\"\n\n#: src/gtk/preferences.ui:26\nmsgid \"Background blur mode\"\nmsgstr \"背景ぼかしモード\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Compact playlist view\"\nmsgstr \"プレイリストをコンパクトにする\"\n\n#: src/gtk/preferences.ui:44 src/application.vala:424\nmsgid \"Keep playing after window closed\"\nmsgstr \"ウィンドウが閉じても再生を続ける\"\n\n#: src/gtk/preferences.ui:57\nmsgid \"Library\"\nmsgstr \"ライブラリ\"\n\n#: src/gtk/preferences.ui:61\nmsgid \"Load music from folder\"\nmsgstr \"フォルダーから音源を読み込み\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Monitor local file changes\"\nmsgstr \"ローカルファイルの変更を表示\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"サムネイルを外部から読み込む\"\n\n#: src/gtk/preferences.ui:86\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"動作が遅くなり、ネットワークを過剰に使用するかもしれません\"\n\n#: src/gtk/preferences.ui:99\nmsgid \"Playback\"\nmsgstr \"再生\"\n\n#: src/gtk/preferences.ui:103\nmsgid \"Show audio peak level\"\nmsgstr \"オーディオレベルを表示\"\n\n#: src/gtk/preferences.ui:107\nmsgid \"Display characters\"\nmsgstr \"文字で表示\"\n\n#: src/gtk/preferences.ui:122\nmsgid \"Rotate album cover\"\nmsgstr \"アルバムカバーを回転させる\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Enable gapless playback\"\nmsgstr \"ギャップレス再生を有効化\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"ReplayGain で音量を調整\"\n\n#: src/gtk/preferences.ui:152\nmsgid \"Prefer audio sink\"\nmsgstr \"オーディオシンクを設定\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"メインメニュー\"\n\n#: src/gtk/store-panel.ui:28\nmsgid \"Sort By\"\nmsgstr \"並び替え\"\n\n#: src/gtk/store-panel.ui:35\nmsgid \"Search\"\nmsgstr \"検索\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_Reload Library\"\nmsgstr \"ライブラリを再読み込み(_R)\"\n\n#: src/gtk/store-panel.ui:79\nmsgid \"_Preferences\"\nmsgstr \"設定(_P)\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"キーボードショートカット(_K)\"\n\n#: src/gtk/store-panel.ui:87\nmsgid \"_About\"\nmsgstr \"G4Music について(_A)\"\n\n#: src/gtk/store-panel.ui:96 src/ui/preferences.vala:64\nmsgid \"Album\"\nmsgstr \"アルバム\"\n\n#: src/gtk/store-panel.ui:101\nmsgid \"Artist\"\nmsgstr \"アーティスト\"\n\n#: src/gtk/store-panel.ui:106\nmsgid \"Artist/Album\"\nmsgstr \"アーティスト/アルバム\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"Title\"\nmsgstr \"タイトル\"\n\n#: src/gtk/store-panel.ui:116\nmsgid \"Recent\"\nmsgstr \"最近\"\n\n#: src/gtk/store-panel.ui:121\nmsgid \"Shuffle\"\nmsgstr \"シャッフル\"\n\n#: src/action-handles.vala:188\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"GTK4 で書かれた、高速で、なめらかなUI、軽量なミュージックプレイヤー。\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/action-handles.vala:190\nmsgid \"translator-credits\"\nmsgstr \"Gnuey56\"\n\n#: src/application.vala:573\nmsgid \"Keep playing\"\nmsgstr \"再生を続ける\"\n\n#: src/ui/music-widgets.vala:232 src/ui/music-widgets.vala:260\nmsgid \"Play at Next\"\nmsgstr \"次に再生\"\n\n#: src/ui/music-widgets.vala:233 src/ui/music-widgets.vala:259\nmsgid \"Play\"\nmsgstr \"再生\"\n\n#: src/ui/music-widgets.vala:236 src/ui/play-panel.vala:222\nmsgid \"Show _Cover File\"\nmsgstr \"カバーファイルを表示(_C)\"\n\n#: src/ui/music-widgets.vala:238 src/ui/play-panel.vala:224\nmsgid \"_Export Cover\"\nmsgstr \"オーディオカバーをエクスポート(_E)\"\n\n#: src/ui/music-widgets.vala:266 src/ui/play-panel.vala:56\nmsgid \"Search Title\"\nmsgstr \"タイトルを探す\"\n\n#: src/ui/music-widgets.vala:267 src/ui/play-panel.vala:54\nmsgid \"Search Album\"\nmsgstr \"アルバムを探す\"\n\n#: src/ui/music-widgets.vala:268 src/ui/play-panel.vala:55\nmsgid \"Search Artist\"\nmsgstr \"アーティストを探す\"\n\n#: src/ui/music-widgets.vala:269\nmsgid \"_Show Music File\"\nmsgstr \"音楽ファイルを表示(_S)\"\n\n#: src/ui/play-bar.vala:75\nmsgid \"Repeat Music\"\nmsgstr \"再生をリピート\"\n\n#: src/ui/play-bar.vala:85\nmsgid \"Play Previous\"\nmsgstr \"前の曲を再生\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:91\nmsgid \"Play/Pause\"\nmsgstr \"再生/一時停止\"\n\n#: src/ui/play-bar.vala:98\nmsgid \"Play Next\"\nmsgstr \"次の曲を再生\"\n\n#: src/ui/play-panel.vala:263\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"音源ファイルをここにドラッグアンドドロップ、\\n\"\n\"または音源の場所を変更: \"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:64\nmsgid \"Never\"\nmsgstr \"しない\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"常に\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"カバーがある場合のみ\"\n\n#: src/ui/preferences.vala:64\nmsgid \"Track\"\nmsgstr \"トラック\"\n\n#: src/ui/store-panel.vala:66\nmsgid \"Playing\"\nmsgstr \"再生\"\n\n#: src/ui/store-panel.vala:72\nmsgid \"Artists\"\nmsgstr \"アーティスト\"\n\n#: src/ui/store-panel.vala:77\nmsgid \"Albums\"\nmsgstr \"アルバム\"\n\n#: src/ui/volume-button.vala:32\nmsgid \"Volume: \"\nmsgstr \"音量: \"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"不明のアルバム\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"不明のアーティスト\"\n\n#~ msgid \"Music Location\"\n#~ msgstr \"音源の場所\"\n\n#~ msgid \"Loading…\"\n#~ msgstr \"読み込み中…\"\n"
  },
  {
    "path": "po/ka.po",
    "content": "# Georgian translation for g4music.\n# Copyright (C) 2024 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Ekaterine Papava <papava.e@gtu.ge>, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-10-11 01:38+0000\\n\"\n\"PO-Revision-Date: 2024-10-18 06:28+0200\\n\"\n\"Last-Translator: Ekaterine Papava <papava.e@gtu.ge>\\n\"\n\"Language-Team: Georgian <ka@li.org>\\n\"\n\"Language: ka\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"პაუზის გარეშე\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"მედია დამკვრელი\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"დაუკარით თქვენი მუსიკა ელეგანტურად\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"music;sound;player;media;audio;playlist;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"მახასიათებლები\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"აუდიოს პიკების დონის ჩვენება.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"პაუზის-გარეშე დაკვრის ჩართვა.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"ხმის ნორმალიზაცია ReplayGain-ით.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"მთავარი ფანჯარა\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"ალბომების ხედი\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"დაკვრის ხედი\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"დასაკრავი სიის ხედი\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"ზოგადი\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"მალსახმობების ჩვენება\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"მორგება\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"გასვლა\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"ჭდეების ჩვენება\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"დაკვრა\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"დაკვრა/პაუზა\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"შემდეგის დაკვრა\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"წინას დაკვრა\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"დასაკრავი სია\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"ძებნა\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"დალაგების გადართვა\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"ბიბლიოთეკის თავიდან ჩატვირთვა\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"სიის შენახვა\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"უკან\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"ზოგადი\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"ფონის გაბუნდოვნების რეჟიმი\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"კომპაქტური დასაკრავი სიის რეჟიმი\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"ბადის ხედი შემსრულებლებისთვის/ალბომებისთვის\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"დაკვრის გაგრძელება ფანჯრის დახურვის შემდეგ\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"ბიბლიოთეკა\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"მუსიკის ჩატვირთვა საქაღალდიდან\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"ლოკალური ფაილის ცვლილებების თვალყურის დევნება\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"მინიატურების ჩატვირთვა არალოკალური ფაილებისთვის\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"შეიძლება, გამოიწვიოს შენელება და გადამეტებული ქსელის დატვირთვა\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"დაკვრა\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"აუდიოს პიკების დონის ჩვენება\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"სიმბოლოების ჩვენება\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"ალბომის ყდის შებრუნება\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"პაუზის-გარეშე დაკვრის ჩართვა\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"ხმის ნორმალიზაცია ReplayGain-ით\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"GStreamer-ის აუდიო კოდეკის გამოყენება\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"მთავარი მენიუ\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"ძებნა\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"დახარისხება\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"_ფერების სქემა\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"სისტემური\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"_ღია\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_მუქი\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"ბიბლიოთეკის თავიდან ჩატვი_რთვა\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"_ერთზე მეტის არჩევა\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"_სიის შენახვა\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"გამართვა\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_კლავიატურის მალსახმობები\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"შესახებ\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"ალბომი\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"შემსრულებელი\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"შემსრულებელი/ალბომი\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"სათაური\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"Ბოლო\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"შემთხვევით\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"გამოსახულების ფაილები\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"ყდის გატანა წარმატებულია\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"ყდის გატანა ჩავარდა\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"დასაკრავი სიის შენახვა ჩავარდა\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"დასაკრავი სიის ფაილები\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"დასაკრავი სიის შენახვა წარმატებულია\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"დაკვრის გაგრძელება\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"სწრაფი, წმინდა, მსუბუქი მუსიკმკვრელი GTK4-ში.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"თარგმანი-შესრულებულია\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"არა\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"კი\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"დასაკრავი სია შეცვლილია, შეინახავთ?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"შემდეგზე დაკვრა\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"_რიგში ჩამატება\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"_დასაკრავი სიაში დამატება…\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"_წაშლა\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"_სანაგვე ყუთში გადატანა\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"ყველას მონიშვნა\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"შემდეგზე დაკვრა\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"რიგში ჩამატება\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"დასაკრავი სიაში დამატება\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"წაშლა\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"თამაში\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"შემთხვევითი დაკვ_რა\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"სიის _ფაილის ჩვენება\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"სათაურის ძებნა\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"ალბომის ძებნა\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"შემსრულებლის ძებნა\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"ყდის _ფაილის ჩვენება\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"ყდის _ფაილის გატანა\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"ჭ_დეების ჩვენება…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"მ_უსიკის ფაილის ჩვენება\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"ერთხელ გამეორება\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"წინას დაკვრა\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"დაკვრა/პაუზა\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"შემდეგის დაკვრა\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"გადმოათრიეთ და დაყარეთ მუსიკის ფაილები აქ,\\n\"\n\"ან შეცვალეთ მუსიკის მდებარეობა: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"ახალი დასაკრავი სია\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:692\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"არასდროს\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"ყოველთვის\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"მხოლოდ ყდა\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"ტრეკი\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"მიმდინარეობს დაკვრა\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"შემსრულებლები\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"ალბომები\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"დასაკრავი სიები\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"კოპირება\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"ხმის სიმძლავრე %d%%\"\n\n#: src/ui/window.vala:112\nmsgid \"Show\"\nmsgstr \"ჩვენება\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"უცნობი ალბომი\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"უცნობი შემსრულებელი\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"მუსიკის დაკვრა\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"მუქი თემის არჩევანი\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"G4Music\"\n"
  },
  {
    "path": "po/meson.build",
    "content": "i18n.gettext(meson.project_name(), preset: 'glib')\n"
  },
  {
    "path": "po/nl.po",
    "content": "# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n#\n# Heimen Stoffels <vistausss@fastmail.com>, 2022.\n# Nathan Follens <nfollens@gnome.org>, 2024.\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: \\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-10-11 01:38+0000\\n\"\n\"PO-Revision-Date: 2024-10-30 18:08+0100\\n\"\n\"Last-Translator: Nathan Follens <nfollens@gnome.org>\\n\"\n\"Language-Team: GNOME-NL https://matrix.to/#/#nl:gnome.org\\n\"\n\"Language: nl\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.4.4\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Muziekspeler\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Speel uw muziek op elegante wijze af\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"music;sound;player;media;audio;playlist;muziek;geluid;speler;muziekspeler;\"\n\"speellijst;afspeellijst;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (AKA: G4Music) is een lichte muziekspeler, gemaakt in GTK4, gericht \"\n\"op grote muziekverzamelingen.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Functies\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Ondersteunt de meeste muziekbestandstypes, Samba en andere \"\n\"netwerkprotocollen (afhankelijk van GIO en GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Laadt snel en kan duizenden muziekbestanden verwerken in luttele seconden, \"\n\"controleert op lokale wijzigingen.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Heeft een laag geheugengebruik voor grote muziekverzamelingen met \"\n\"albumhoezen (ingebed en extern), zonder miniatuurcaches bij te houden.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Kan groeperen en sorteren op album/artiest/titel, willekeurig afspelen en \"\n\"zoeken in de volledige tekst.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Heeft een vlotte, adaptieve gebruikersinterface voor verschillende \"\n\"schermgroottes (desktop, tablet, mobiel).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Heeft een gaussiaans vervaagde hoes als achtergrond, volgt de lichte/\"\n\"donkere modus van GNOME.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Ondersteunt het aanmaken en bewerken van afspeellijsten, versleep de hoes \"\n\"om de volgorde te wijzigen of aan een andere afspeellijst toe te voegen.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Ondersteunt inslepen uit andere toepassingen.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Ondersteunt visualisatie van het piekvolume.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Ondersteunt ononderbroken afspelen.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Ondersteunt ReplayGain om het volume te normaliseren.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Ondersteunt de opgegeven audiosink.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Ondersteunt MPRIS-besturing.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Hoofdvenster\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Albumweergave\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Afspeelweergave\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Afspeellijstweergave\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Algemeen\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Sneltoetsen tonen\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Voorkeuren\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Afsluiten\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Tags tonen\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Afspelen\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Afspelen/pauzeren\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Volgend nummer afspelen\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Vorig nummer afspelen\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Afspeellijst\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Zoeken\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Tussen sorteervolgordes schakelen\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Bibliotheek herladen\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Lijst opslaan\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"Terug\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Algemeen\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Achtergrond vervagen\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Compacte afspeellijstweergave\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Rasterweergave voor artiesten/albums\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Eén keer klikken om item te activeren\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"Doorgaan met afspelen wanneer het venster gesloten is\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Bibliotheek\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Muziek laden uit map\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Controleren op lokale wijzigingen aan bestanden\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Miniaturen van externe bestanden laden\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Let op: dit kan vertragingen en bovenmatig netwerkgebruik veroorzaken\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Afspelen\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Piekvolume tonen\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Gebruik deze tekens\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Albumhoes ronddraaien\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Ononderbroken afspelen\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"ReplayGain gebruiken om volume te normaliseren\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Voorkeur voor audiosink van GStreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Hoofdmenu\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Zoeken\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"Sorteren op\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"_Kleurenschema\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"_Systeem\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"_Licht\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_Donker\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"Bibliotheek he_rladen\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"_Meerdere selecteren\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"Lijst op_slaan\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"_Voorkeuren\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"Snel_toetsen\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"_Over\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"Artiest\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"Artiest/album\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"Titel\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"Recent\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"Willekeurig\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Afbeeldingsbestanden\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Albumhoes geëxporteerd\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Exporteren van hoes mislukt\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"Opslaan van afspeellijst mislukt\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"Afspeellijstbestanden\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"Afspeellijst opgeslagen\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"Blijven afspelen\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Een eenvoudige, lichte en snelle muziekspeler, gemaakt met GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"\"\n\"Heimen Stoffels <vistausss@fastmail.com>\\n\"\n\"Nathan Follens <nfollens@gnome.org>\\n\"\n\"Meer info over GNOME-NL http://nl.gnome.org\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"Nee\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"Ja\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"De afspeellijst is bewerkt, wilt u deze opslaan?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Afspelen na huidige\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Toevoegen aan _wachtrij\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Toevoegen aan afs_peellijst…\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"Ve_rwijderen\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"Verplaatsen naar _prullenbak\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"Alles selecteren\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"Afspelen na huidige\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"Toevoegen aan wachtrij\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Toevoegen aan afspeellijst\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"Verwijderen\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"Afspelen\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"Willekeu_rig afspelen\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Afspeellijst_bestand tonen\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Titel zoeken\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Album zoeken\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Artiest zoeken\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Hoes_bestand tonen\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"Hoes _exporteren\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"_Tags tonen…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Muziek_bestand tonen\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"1 keer herhalen\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Vorig nummer afspelen\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Afspelen/pauzeren\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Volgend nummer afspelen\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Sleep bestanden hierheen\\n\"\n\"of wijzig de muzieklocatie: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Nieuwe afspeellijst\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:692\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Geen afspeellijst gevonden in %s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Nooit\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Altijd\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Enkel albumhoezen\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Nummer\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"U luistert naar\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Artiesten\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Albums\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Afspeellijsten\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Kopiëren\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Volume %d%%\"\n\n#: src/ui/window.vala:112\nmsgid \"Show\"\nmsgstr \"Tonen\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Onbekend album\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Onbekende artiest\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"G4Music\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"Luister naar muziek\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"Donker thema gebruiken\"\n\n#~ msgid \"Repeat Music\"\n#~ msgstr \"Nummer herhalen\"\n\n#~ msgid \"Appearance\"\n#~ msgstr \"Vormgeving\"\n\n#~ msgid \"Music Location\"\n#~ msgstr \"Muzieklocatie\"\n\n#~ msgid \"Experimental\"\n#~ msgstr \"Experimenteel\"\n\n#~ msgid \"By Date\"\n#~ msgstr \"Op datum\"\n\n#~ msgid \"Loading...\"\n#~ msgstr \"Bezig met laden…\"\n"
  },
  {
    "path": "po/oc.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: \\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-11-02 21:22+0000\\n\"\n\"PO-Revision-Date: 2024-11-15 20:00+0100\\n\"\n\"Last-Translator: Quentin PAGÈS\\n\"\n\"Language-Team: \\n\"\n\"Language: oc\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=n > 1;\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:271\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Lector de musica\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Legissètz vòstra music amb elegància\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"musica;son;lector;mèdia;àudio;audio;lista de lectura;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (tanben conegut coma G4Music) es un lector de musica leugièr escrich \"\n\"en GTK4, se concentra sus las grandas colleccions musicalas.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Foncionalitats\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Pren en carga la màger part dels tipes de fichièrs musicals, Samba e quin \"\n\"autre protocòl a distància que siá (depend de GIO e GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Cargament rapid e analisi de milièrs de fichièrs musicals en fòrça paucas \"\n\"segondas, susvelhança dels cambiaments locals.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Utilizacion de memòria bassa per una granda colleccion de musica amb de \"\n\"coberturas d'albums (integradas e extèrnas), pas de caches de vinhetas \"\n\"d’emmagazinar.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Gropar e triar per album/artista/títol, lista de mescla, recèrca de tèxte \"\n\"complèt.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Interfàcia d'utilizaire adaptativa fluida per mantun ecran (burèu, tauleta, \"\n\"mobil).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Cobertura en fosc gaussian coma rèireplan, seguís lo mòde clar/escur GNOME.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Pren en carga la creacion e modificacion de listas de lectura, lisar \"\n\"depausar per cambiar l’òrdre o apondre a una autra lista de lectura.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Pren en carga del lisar depausar d’autras aplicacions.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Permet d’afichar lo nivèl àudio de poncha.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Pren en carga la lectura sens interrupcion.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Compatible amb la normalizacion del volum amb ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Pren en carga un receptors àudio especificat.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Compatible amb los contraròtles MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Fenèstra principala\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Vista albums\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Vista lectura\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Vista lista de lectura\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"General\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Afichar los acorchis\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Preferéncias\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Sortir\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Afichar las etiquetas\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Lectura\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Lectura/Pausa\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Legir la seguenta\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Legir la precedenta\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Lista de lectura\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Cercar\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Alternar sens de triada\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Recargar la lista\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Enregistrar la lista\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:633\n#: src/ui/store-panel.vala:423\nmsgid \"Back\"\nmsgstr \"Tornar\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"General\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Mòde del rèireplan fosc\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Vista compacta lista de lectura\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Vista grasilha per artista/albums\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Clic simple per activar l’element\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:430\nmsgid \"Keep playing after window closed\"\nmsgstr \"Téner de legir un còp la fenèstra tampada\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Bibliotèca\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Cargar la musica a partir del dossièr\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Susvelhar las modificacions dels fichièrs locals\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Cargar las miniaturas dels fichièrs non locals\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Pòt alentir e sollicitar mai la ret\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Lectura\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Afichar lo nivèl àudio de poncha\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Afichar los caractèrs\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Pivotar la cobertura dels album\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Activa la lectura sens interrupcion\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalizar lo volum amb ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Preferir lo contenedor àudio de Gstreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Menú principal\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Cercar\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"Triar per\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"Esquèma de _colors\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"_Sistèma\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"_Clar\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_Escur\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"_Recargar la bibliotèca\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"_Seleccion multipla\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"_Enregistrar la lista\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"_Preferéncias\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Acorchis de clavièr\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"_A prepaus\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"Artista\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"Artista/album\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"Títol\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"Recents\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"Aleatòri\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Fichièrs imatges\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Succès de l’expòrt de la pocheta\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Fracàs de l’expòrt de la pocheta\"\n\n#: src/application.vala:344\nmsgid \"Save playlist failed\"\nmsgstr \"Fracàs de l’expòrt de la lista de lectura\"\n\n#: src/application.vala:466\nmsgid \"Playlist Files\"\nmsgstr \"Fichièrs de lista de lectura\"\n\n#: src/application.vala:480\nmsgid \"Save playlist successfully\"\nmsgstr \"Succès de l’enregistrament de la lista de lectura\"\n\n#: src/application.vala:615\nmsgid \"Keep playing\"\nmsgstr \"Contunhar de legir\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Un lector de musica rapid e leugièr esrich en GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"Quentin PAGÈS\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:112\nmsgid \"No\"\nmsgstr \"Non\"\n\n#: src/ui/dialogs.vala:101 src/ui/dialogs.vala:112\nmsgid \"Yes\"\nmsgstr \"Òc\"\n\n#: src/ui/music-list.vala:276\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Lista de lectura modificada, l’enregistrar ?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:422\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Legir a la _seguida\"\n\n#: src/ui/music-list.vala:408 src/ui/music-list.vala:424\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"_Apondre a la lista d'espèra\"\n\n#: src/ui/music-list.vala:409 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"_Apondre a la lista de lectura…\"\n\n#: src/ui/music-list.vala:410 src/ui/music-list.vala:428\nmsgid \"_Remove\"\nmsgstr \"_Levar\"\n\n#: src/ui/music-list.vala:429 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"_Metre a l'escobilhièr\"\n\n#: src/ui/music-list.vala:637\nmsgid \"Select All\"\nmsgstr \"Tot seleccionar\"\n\n#: src/ui/music-list.vala:654\nmsgid \"Play at Next\"\nmsgstr \"Legir a la seguida\"\n\n#: src/ui/music-list.vala:661\nmsgid \"Add to Queue\"\nmsgstr \"Apondre a la lista d'espèra\"\n\n#: src/ui/music-list.vala:668 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Apondre a la lista de lectura\"\n\n#: src/ui/music-list.vala:675\nmsgid \"Remove\"\nmsgstr \"Levar\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:431\nmsgid \"Play\"\nmsgstr \"Lectura\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"Lectura _aleatòria\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Afichar fichièr de lista\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Recercar de títols\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Recercar d’albums\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Recercar d’artistas\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"_Afichar fichièr de cobertura\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Exportar la pocheta\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Afichar las _etiquetas…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"_Afichar fichièr musical\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Bocla simpla\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Legir la precedenta\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Lectura/Pausa\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Legir la seguenta\"\n\n#: src/ui/play-panel.vala:263\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Lisatz depausatz los fichièrs musicals aicí,\\n\"\n\"o modificatz l’emplaçament de la musica : \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Lista de lectura novèla\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:702\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Cap de lista de lectura pas trobada dins %s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Pas jamai\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Totjorn\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Pocheta de l'album sonque\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Pista\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"En lectura\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Artistas\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Albums\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Listas de lectura\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Copiar\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Volum %d%%\"\n\n#: src/ui/window.vala:119\nmsgid \"Show\"\nmsgstr \"Mostrar\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Album desconegut\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Artista desconegut\"\n\n#~ msgid \"Nanling\"\n#~ msgstr \"Nanling\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"\"\n#~ \"Lisar-depausar de GNOME Fichièrs estant, afichatge de la musica dins \"\n#~ \"Fichièrs.\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"Legir de fichièrs àudio\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"Preferir lo tèma escur\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"G4Music\"\n\n#~ msgid \"Repeat Music\"\n#~ msgstr \"Repetir la cançon\"\n\n#~ msgid \"Appearance\"\n#~ msgstr \"Aparéncia\"\n\n#~ msgid \"Music Location\"\n#~ msgstr \"Emplaçament de la musica\"\n\n#~ msgid \"Experimental\"\n#~ msgstr \"Experimental\"\n\n#~ msgid \"By Date\"\n#~ msgstr \"Per data\"\n\n#~ msgid \"Loading...\"\n#~ msgstr \"Cargament…\"\n"
  },
  {
    "path": "po/pt_BR.po",
    "content": "# Brazilian Portuguese translation for g4music.\n# Copyright (C) 2022-2024 g4music'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Pedro Henrique da Silva <pedrohsilva.dev@protonmail.com>, 2023.\n# Fúlvio Leo <fulviokaldas@outlook.com>, 2024.\n# Rafael Fontenelle <rafaelff@gnome.org>, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-10-11 01:38+0000\\n\"\n\"PO-Revision-Date: 2024-10-13 00:14-0300\\n\"\n\"Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\\n\"\n\"Language-Team: Brazilian Portuguese <https://br.gnome.org/traducao>\\n\"\n\"Language: pt_BR\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1)\\n\"\n\"X-Generator: Gtranslator 47.0\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Reprodutor de música\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Reproduza suas músicas de forma elegante\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"música;som;player;reprodutor;mídia;audio;playlist;lista de reprodução;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (também conhecido como G4Music) é um reprodutor de música leve \"\n\"escrito em GTK4, focado em grandes coleções de músicas.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Recursos\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Suporte à maioria dos tipos de arquivos de música, Samba e quaisquer outros \"\n\"protocolos remotos (depende do GIO e do GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Carregamento rápido e análise de milhares de arquivos de música em poucos \"\n\"segundos, monitora alterações locais.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Baixo uso de memória para grandes coleções de músicas com capas de álbuns \"\n\"(incorporadas e externas), sem caches de miniaturas para armazenar.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Agrupa e classifica por álbum/artista/título, lista aleatória, pesquisa de \"\n\"texto completo.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Interface de usuário adaptável e fluida para diferentes telas (desktop, \"\n\"tablet, celular).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Capa desfocada gaussiana como plano de fundo, segue o modo claro/escuro do \"\n\"GNOME.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Suporta criação e edição de listas de reprodução, arraste a capa para \"\n\"alterar a ordem ou adicionar a outra lista de reprodução.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Suporte a arrastar e soltar com outros aplicativos.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Suporte a um visualizador de picos de áudio.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Suporte à reprodução sem intervalos.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Suporte a normalização de volume com ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Suporte a sink de áudio especificado.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Suporte a controle MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Menu principal\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Visão dos álbuns\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Visão da reprodução\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Visão da lista de Reprodução\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Geral\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Mostra atalhos\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Preferências\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Sai\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Mostra tags\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Reprodução\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Reproduz/Pausa\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Próxima música\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Música anterior\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Lista de reprodução\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Procura\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Alterna a classificação\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Recarrega a biblioteca\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Salvar lista\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"Voltar\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Geral\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Modo de desfoque de fundo\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Visualização compacta da lista de reprodução\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Visualização em grade para artistas/álbuns\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Clique único para ativar item\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"Continuar reproduzindo após fechar a janela\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Biblioteca\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Carregar músicas da pasta\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Monitorar mudanças nos arquivos locais\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Carregar miniaturas para arquivos não-locais\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Pode causar lentidão e uso excessivo da rede\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Reprodução\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Mostrar níveis de pico do áudio\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Exibir caracteres\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Girar capa do álbum\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Permitir reprodução sem intervalos\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalizar voluma com ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Preferência de receptor de áudio do GStreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Menu principal\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Procurar\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"Ordenar por\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"Esquema de _cor\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"_Sistema\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"_Claro\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_Escuro\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"_Recarregar biblioteca\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"_Múltipla seleção\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"_Salvar lista\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"_Preferências\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Atalhos de teclado\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"_Sobre\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Álbum\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"Artista\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"Artista/Álbum\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"Título\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"Recente\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"Aleatório\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Arquivos de imagem\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Capa exportada com sucesso\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Falha ao exportar a capa\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"Falha ao salvar a lista de reprodução\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"Arquivos de lista de reprodução\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"Lista de reprodução salvada com sucesso\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"Continuar tocando\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Um reprodutor de música leve, rápido e fluido escrito em GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"\"\n\"Pedro Henrique da Silva <pedrohsilva.dev@protonmail.com>\\n\"\n\"Fúlvio Leo <fulviokaldas@outlook.com>\\n\"\n\"Rafael Fontenelle <rafaelff@gnome.org>\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"Não\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"Sim\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"A lista de reprodução foi modificada, deseja salvá-la?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Reproduzir na _próxima\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Adicionar à _fila\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Adicionar à _lista de reprodução…\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"_Remover\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"_Mover para lixeira\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"Selecionar tudo\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"Reproduzir na próxima\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"Adicionar à fila\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Adicionar à lista de Reprodução\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"Remover\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"Reproduzir\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Reprodução aleatória\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Mostrar _arquivo de lista\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Procurar título\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Procurar álbum\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Procurar artista\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Mostrar _arquivo de capa\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Exportar capa\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Mostrar _tags…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Mostrar _arquivo de música\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Loop único\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Reproduzir anterior\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Reproduzir/Pausar\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Reproduzir próxima\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Arraste e solte arquivos de música aqui,\\n\"\n\"ou mude o local das músicas: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Nova lista de reprodução\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:692\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Nenhuma lista de reprodução encontrada em %s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Nunca\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Sempre\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Apenas arte\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Faixa\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Tocando\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Artistas\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Álbuns\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Listas de reprodução\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Copiar\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Volume %d%%\"\n\n#: src/ui/window.vala:112\nmsgid \"Show\"\nmsgstr \"Mostrar\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Álbum desconhecido\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Artista desconhecido\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"Reproduzir música\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"Preferir tema escuro\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"G4Music\"\n\n#~ msgid \"Repeat Music\"\n#~ msgstr \"Repetir Música\"\n\n#~ msgid \"Appearance\"\n#~ msgstr \"Aparência\"\n\n#~ msgid \"Music Location\"\n#~ msgstr \"Localização das Músicas\"\n\n#~ msgid \"Experimental\"\n#~ msgstr \"Experimental\"\n\n#~ msgid \"Loading...\"\n#~ msgstr \"Carregando...\"\n"
  },
  {
    "path": "po/ro.po",
    "content": "# Romanian translation for g4music.\n# Copyright (C) 2023 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Florentina Mușat <florentina.musat.28@gmail.com>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/-/issues\\n\"\n\"POT-Creation-Date: 2023-10-17 17:12+0000\\n\"\n\"PO-Revision-Date: 2023-10-25 13:16+0300\\n\"\n\"Last-Translator: Florentina Mușat <florentina [dot] musat [dot] 28 [at] gmail [dot] com>\\n\"\n\"Language-Team: Romanian <gnomero-list@lists.sourceforge.net>\\n\"\n\"Language: ro\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2);;\\n\"\n\"X-Generator: Poedit 3.4\\n\"\n\n#: data/app.desktop.in:3 src/application.vala:235 src/main.vala:24\nmsgid \"G4Music\"\nmsgstr \"G4Music\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Player de muzică\"\n\n#: data/app.desktop.in:5\nmsgid \"Play music\"\nmsgstr \"Redă muzică\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"music;sound;player;media;audio;playlist;muzică;sunet;listă de redare;\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Generale\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Arată scurtăturile\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Preferințe\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Ieșire\"\n\n#: src/gtk/help-overlay.ui:34\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Redare\"\n\n#: src/gtk/help-overlay.ui:37\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Redare/pauză\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Redă următoarea\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Redă anterioara\"\n\n#: src/gtk/help-overlay.ui:57\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Listă de redare\"\n\n#: src/gtk/help-overlay.ui:60\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Caută\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Comută sortarea\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Reîncarcă biblioteca\"\n\n#: src/gtk/play-panel.ui:16 src/ui/store-panel.vala:340\nmsgid \"Back\"\nmsgstr \"Înapoi\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Generale\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Prefer dark theme\"\nmsgstr \"Preferă tema întunecată\"\n\n#: src/gtk/preferences.ui:26\nmsgid \"Background blur mode\"\nmsgstr \"Mod de estompare a fundalului\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Compact playlist view\"\nmsgstr \"Vizualizare compactă a listei de redare\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Vizualizare grilă pentru artiști/albume\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:435\nmsgid \"Keep playing after window closed\"\nmsgstr \"Continuă redarea după ce s-a închis fereastra\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Bibliotecă\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Încarcă muzică din dosar\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Monitorizează modificările fișierelor locale\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Încarcă miniaturile pentru fișierele nelocale\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Poate cauza încetiniri și utilizarea excesivă a rețelei\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Redare\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Arată nivelul de vârf audio\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Afișează caracterele\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Rotește coperta albumului\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Activează redarea fără întrerupere\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalizează volumul cu ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Preferă receptorul audio al GStreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Meniu principal\"\n\n#: src/gtk/store-panel.ui:28\nmsgid \"Sort By\"\nmsgstr \"Sortează după\"\n\n#: src/gtk/store-panel.ui:35\nmsgid \"Search\"\nmsgstr \"Caută\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_Reload Library\"\nmsgstr \"_Reîncarcă biblioteca\"\n\n#: src/gtk/store-panel.ui:79\nmsgid \"_Preferences\"\nmsgstr \"_Preferințe\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"Scurtături de _tastatură\"\n\n#: src/gtk/store-panel.ui:87\nmsgid \"_About\"\nmsgstr \"_Despre\"\n\n#: src/gtk/store-panel.ui:96 src/ui/preferences.vala:67\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:101\nmsgid \"Artist\"\nmsgstr \"Artist\"\n\n#: src/gtk/store-panel.ui:106\nmsgid \"Artist/Album\"\nmsgstr \"Artist/album\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"Title\"\nmsgstr \"Titlu\"\n\n#: src/gtk/store-panel.ui:116\nmsgid \"Recent\"\nmsgstr \"Recente\"\n\n#: src/gtk/store-panel.ui:121\nmsgid \"Shuffle\"\nmsgstr \"Amestecă\"\n\n#: src/action-handles.vala:184\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Un player de muzică rapid, fluent și ușor scris în GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/action-handles.vala:186\nmsgid \"translator-credits\"\nmsgstr \"Florentina Mușat <florentina [dot] musat [dot] 28 [at] gmail [dot] com>, 2023\"\n\n#: src/application.vala:626\nmsgid \"Keep playing\"\nmsgstr \"Continuă redarea\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-widgets.vala:252 src/ui/music-widgets.vala:293\n#: src/ui/music-widgets.vala:303\nmsgid \"Play at Next\"\nmsgstr \"Redă la următoarea\"\n\n#: src/ui/music-widgets.vala:253 src/ui/music-widgets.vala:292\n#: src/ui/music-widgets.vala:302 src/ui/store-panel.vala:345\nmsgid \"Play\"\nmsgstr \"Redare\"\n\n#: src/ui/music-widgets.vala:256 src/ui/play-panel.vala:237\nmsgid \"Show _Cover File\"\nmsgstr \"Arată fișierul de _copertă\"\n\n#: src/ui/music-widgets.vala:258 src/ui/play-panel.vala:239\nmsgid \"_Export Cover\"\nmsgstr \"_Exportă coperta\"\n\n#: src/ui/music-widgets.vala:295\nmsgid \"Show List File\"\nmsgstr \"Arată fișierul de listă\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:56\nmsgid \"Search Title\"\nmsgstr \"Caută titlu\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:54\nmsgid \"Search Album\"\nmsgstr \"Caută album\"\n\n#: src/ui/music-widgets.vala:311 src/ui/play-panel.vala:55\nmsgid \"Search Artist\"\nmsgstr \"Caută artist\"\n\n#: src/ui/music-widgets.vala:312\nmsgid \"_Show Music File\"\nmsgstr \"_Arată fișierul de muzică\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:74\nmsgid \"Single Loop\"\nmsgstr \"O singură buclă\"\n\n#: src/ui/play-bar.vala:84\nmsgid \"Play Previous\"\nmsgstr \"Redă anterioara\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:90\nmsgid \"Play/Pause\"\nmsgstr \"Redare/pauză\"\n\n#: src/ui/play-bar.vala:97\nmsgid \"Play Next\"\nmsgstr \"Redă următoarea\"\n\n#: src/ui/play-panel.vala:280\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Trageți și plasați fișiere de muzică aici,\\n\"\n\"sau modificați locația muzicii: \"\n\n#: src/ui/preferences.vala:46 src/ui/preferences.vala:67\nmsgid \"Never\"\nmsgstr \"Niciodată\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Always\"\nmsgstr \"Întotdeauna\"\n\n#: src/ui/preferences.vala:46\nmsgid \"Art Only\"\nmsgstr \"Doar arta\"\n\n#: src/ui/preferences.vala:67\nmsgid \"Track\"\nmsgstr \"Pistă\"\n\n#: src/ui/store-panel.vala:74\nmsgid \"Playing\"\nmsgstr \"Redare\"\n\n#: src/ui/store-panel.vala:79\nmsgid \"Artists\"\nmsgstr \"Artiști\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Albums\"\nmsgstr \"Albume\"\n\n#: src/ui/store-panel.vala:374\nmsgid \"Playlists\"\nmsgstr \"Liste de redare\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Volum %d%%\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Album necunoscut\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Artist necunoscut\"\n"
  },
  {
    "path": "po/ru.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# David Lapshin <ddaudix@gmail.com>, 2022.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: \\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-10-11 06:29+0000\\n\"\n\"PO-Revision-Date: 2024-10-11 13:49+0300\\n\"\n\"Last-Translator: Artur So <arturios2005@mail.ru>\\n\"\n\"Language-Team: \\n\"\n\"Language: ru\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:271\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Музыкальный проигрыватель\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Воспроизводите музыку элегантно\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"music;sound;player;media;audio;playlist;музыка;звук;проигрыватель;медиа;\"\n\"аудио;список;воспроизведения;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (AKA: G4Music) - это легкий музыкальный проигрыватель, написанный на \"\n\"GTK4, ориентированный на работу с большими музыкальными коллекциями.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Возможности\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Поддерживает большинство типов музыкальных файлов, Samba и любые другие \"\n\"удаленные протоколы (зависит от GIO и GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Быстрая загрузка и разбор тысяч музыкальных файлов за считанные секунды, \"\n\"отслеживание локальных изменений.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Низкое потребление памяти для большой музыкальной коллекции с обложками \"\n\"альбомов (встроенными и внешними), отсутствие кэша миниатюр для хранения.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Группировка и сортировка по альбомам/исполнителям/названиям, список в \"\n\"случайном порядке, полнотекстовый поиск.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Адаптивный пользовательский интерфейс для различных экранов (ПК, планшета, \"\n\"мобильного устройства).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Гауссово размытие обложки в качестве фона, соответствует светлому/темному \"\n\"режиму GNOME.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Поддерживает создание и редактирование списков воспроизведения, \"\n\"перетаскивание обложки для изменения порядка или добавления в другой список \"\n\"воспроизведения.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Поддерживает перетаскивание с других приложений.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Поддерживает визуализатор аудиопиков.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Поддерживает непрерывное воспроизведение.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Поддерживает нормализацию громкости с помощью ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Поддерживает указанный аудиопоток.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Поддерживает управление с помощью MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Главное окно\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Альбомы\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Играет сейчас\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Список воспроизведения\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Общие\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Комбинации клавиш\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Параметры\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Выйти\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Показать метки\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Воспроизведение\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Воспроизведение/Пауза\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Воспроизвести следующую\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Воспроизвести предыдущую\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Список воспроизведения\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Поиск\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Переключить сортировку\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Перезагрузить библиотеку\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Сохранить список\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:420\nmsgid \"Back\"\nmsgstr \"Назад\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Общие\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Режим размытия фона\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Компактный вид списка\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Вид сеткой для исполнителей/альбомов\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Активация элемента одним щелчком мыши\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:419\nmsgid \"Keep playing after window closed\"\nmsgstr \"Продолжать воспроизведение после закрытия окна\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Библиотека\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Загружать музыку из папки\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Следить за изменениями в локальных файлах\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Загружать миниатюры для нелокальных файлов\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Может вызвать замедление работы и чрезмерное использование сети\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Воспроизведение\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Показывать уровень звука\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Показывать символы\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Вращать обложку альбома\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Включить непрерывное воспроизведение\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Нормализовывать громкость с помощью ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Отдавать предпочтение приёмнику звука GStreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Главное меню\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Поиск\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"Сортировать\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"_Цветовая схема\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"С_истемная\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"_Светлая\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_Темная\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"П_ерезагрузить библиотеку\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"_Выбрать несколько\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"_Сохранить список\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"_Параметры\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Комбинации клавиш\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"_О приложении\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Альбом\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"Исполнитель\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"Исполнитель/Альбом\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"Название\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"Недавние\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"Перемешать\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Файлы изображения\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Обложка успешно экспортирована\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Экспортировать обложку не удалось\"\n\n#: src/application.vala:344\nmsgid \"Save playlist failed\"\nmsgstr \"Сохранить список воспроизведения не удалось\"\n\n#: src/application.vala:441\nmsgid \"Playlist Files\"\nmsgstr \"Файлы списка воспроизведения\"\n\n#: src/application.vala:455\nmsgid \"Save playlist successfully\"\nmsgstr \"Список воспроизведения успешно сохранен\"\n\n#: src/application.vala:591\nmsgid \"Keep playing\"\nmsgstr \"Продолжать воспроизведение\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"\"\n\"Быстрый, плавный и лёгкий музыкальный проигрыватель, написанный на GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"Давид Лапшин <ddaudix@gmail.com>, 2022\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"Нет\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"Да\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Список воспроизведения изменен, сохранить его?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Воспроизвести _следующую\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Добавить в _очередь\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Добавить в список _воспроизведения…\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"_Удалить\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"О_тправить в корзину\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"Выбрать все\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"Воспроизвести следующую\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"Добавить в очередь\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Добавить в список воспроизведения\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"Удалить\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:428\nmsgid \"Play\"\nmsgstr \"Воспроизвести\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"Воспроизвести в _случайном порядке\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Показать список _файлов\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Поиск названия\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Поиск альбома\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Поиск исполнителя\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Показать ф_айл обложки\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Экспортировать обложку\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Показать _метки…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"_Показать музыкальный файл\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Зациклить повторение на одной\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Воспроизвести предыдущую\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Воспроизведение/Пауза\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Воспроизвести следующую\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Перетащите файлы песен сюда,\\n\"\n\"или измените расположение музыки: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Новый список воспроизведения\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:694\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Список воспроизведения не найден в %s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Никогда\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Всегда\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Только оформление\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Композиция\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Играет сейчас\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Исполнители\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Альбомы\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Списки воспроизведения\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Копировать\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Громкость %d%%\"\n\n#: src/ui/window.vala:116\nmsgid \"Show\"\nmsgstr \"Показать\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Неизвестный альбом\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Неизвестный исполнитель\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"Воспроизведение музыки\"\n\n#~ msgid \"Nanling\"\n#~ msgstr \"Nanling\"\n\n#~ msgid \"Close\"\n#~ msgstr \"Закрыть\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"Перетаскивание из Файлов GNOME, отображение музыки в Файлах.\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"Предпочтительна тёмная тема\"\n\n#~ msgid \"Appearance\"\n#~ msgstr \"Внешний вид\"\n\n#~ msgid \"Music Location\"\n#~ msgstr \"Расположение музыки\"\n\n#~ msgid \"Experimental\"\n#~ msgstr \"Экспериментальное\"\n\n#~ msgid \"By Date\"\n#~ msgstr \"По дате\"\n\n#~ msgid \"Loading...\"\n#~ msgstr \"Загрузка...\"\n"
  },
  {
    "path": "po/sk.po",
    "content": "# Slovak translation for g4music.\n# Copyright (C) 2024 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Patrik Tapušík <2tapusik00patrik6@gmail.com>,  2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-10-08 18:25+0000\\n\"\n\"PO-Revision-Date: 2024-11-04 09:02+0100\\n\"\n\"Last-Translator: Patrik Tapušík <2tapusik00patrik6@gmail.com>\\n\"\n\"Language-Team: Slovak <Slovak>\\n\"\n\"Language: sk\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Hudobný prehrávač\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Prehrávajte svoju hudbu elegantne\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"hudba;zvuk;prehrávač;multimédia;audio;zoznam;playlist;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (AKA: G4Music) je jednoduchý hudobný prehrávač napísaný v GTK4, \"\n\"ktorý sa orientuje na prehrávanie veľkých hudobných zbierok.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Vlastnosti\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Podporuje väčšinu hudobných formátov, SMB a akékoľvek iné vzdialené protokoly \"\n\"(závisí na GIO a GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Rýchle načítanie a spracovanie tisícok hudobných súborov v krátkom čase, \"\n\"sledovanie lokálnych zmien.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Nízka spotreba pamäte pri veľkých hudobných zbierkach s obalmi albumov (vnorené a \"\n\"externé), žiadne náhľady na ukladanie.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Zoskupuje a triedi podľa albumu/umelca/názvu, náhodné zamiešanie zoznamu, vyhľadávanie.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Plynulé adaptívne užívateľské rozhranie pre rôzne obrazovky (Desktop, Tablet, \"\n\"Telefón).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"Gaussovsky rozmazaný obal ako pozadie, aplikuje GNOME svetlý/tmavý režim.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Podporuje vytváranie a úpravu zoznamov, pretiahnite obal na zmenu poradia alebo \"\n\"pridajte do iného zoznamu.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Podporuje pretiahnutie a pustenie s inými aplikáciami.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Podporuje vizualizáciu zvukových vrcholov.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Podporuje gapless prehrávanie.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Podporuje normalizáciu hlasitosti s ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Podporuje špecifikovaný zvukový výstup.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Podporuje ovládanie MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Hlavné okno\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Albumy\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Prehrávanie\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Zoznamy\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Všeobecné\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Zobraziť skratky\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Nastavenia\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Ukončiť\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Zobraziť štítky\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Prehrávanie\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Prehrať/Pozastaviť\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Ďalšia skladba\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Predchádzajúca skladba\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Zoznam\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Vyhľadať\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Zapnúť/vypnúť triedenie\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Znovu načítať knižnicu\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Uložiť zoznam\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:630\n#: src/ui/store-panel.vala:425\nmsgid \"Back\"\nmsgstr \"Späť\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Všeobecné\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Režim rozmazania pozadia\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Kompaktné zobrazenie zoznamu\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Zobrazenie interpretov/albumov v mriežke\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Aktivovať položku jedným kliknutím\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"Pokračovať v prehrávaní po zatvorení okna\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Knižnica\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Načítať hudbu z priečinka\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Kontrolovať lokálne zmeny súborov\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Načítať náhľady pre nelokálne súbory\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Môže spôsobiť spomalenie a nadmerné využitie siete\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Prehrávanie\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Zobraziť úroveň zvukového vrcholu\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Znaky\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Rotovať obal albumu\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Povoliť gapless prehrávanie\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalizovať hlasitosť s ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Preferovať zvukový výstup GStreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Hlavná ponuka\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Vyhľadávať\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"Zoradiť podľa\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"_Farebná schéma\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"_Systém\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"_Svetlý\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_Tmavý\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"_Znova načítať knižnicu\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Select\"\nmsgstr \"_Vybrať\"\n\n#: src/gtk/store-panel.ui:99\nmsgid \"_Preferences\"\nmsgstr \"_Nastavenia\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Klávesové skratky\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_About\"\nmsgstr \"_O programe\"\n\n#: src/gtk/store-panel.ui:116 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:121\nmsgid \"Artist\"\nmsgstr \"_Umelec\"\n\n#: src/gtk/store-panel.ui:126\nmsgid \"Artist/Album\"\nmsgstr \"Umelec/_Album\"\n\n#: src/gtk/store-panel.ui:131\nmsgid \"Title\"\nmsgstr \"Titulok\"\n\n#: src/gtk/store-panel.ui:136\nmsgid \"Recent\"\nmsgstr \"Nedávne\"\n\n#: src/gtk/store-panel.ui:141\nmsgid \"Shuffle\"\nmsgstr \"Náhodne\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Obrázky\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Export obalu bol úspešný\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Export obalu zlyhal\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"Uloženie zoznamu zlyhalo\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"Súbory zoznamu\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"Uloženie zoznamu bolo úspešné\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"Pokračovať v prehrávaní\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Rýchly, plynulý, jednoduchý hudobný prehrávač napísaný v GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"Patrik Tapušík\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"Nie\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"Áno\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Zoznam je upravený, uložiť?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:222 src/ui/music-widgets.vala:244\nmsgid \"Play at _Next\"\nmsgstr \"Prehrať _nasledujúcu\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:223 src/ui/music-widgets.vala:245\nmsgid \"Add to _Queue\"\nmsgstr \"Pridať do _poradia\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:224\n#: src/ui/music-widgets.vala:246 src/ui/music-widgets.vala:265\nmsgid \"Add to _Playlist…\"\nmsgstr \"Pridať do _zoznamu…\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"_Odstrániť\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:231\nmsgid \"_Move to Trash\"\nmsgstr \"_Presunúť do koša\"\n\n#: src/ui/music-list.vala:634\nmsgid \"Select All\"\nmsgstr \"Označiť všetko\"\n\n#: src/ui/music-list.vala:651\nmsgid \"Play at Next\"\nmsgstr \"Prehrať nasledujúcu\"\n\n#: src/ui/music-list.vala:658\nmsgid \"Add to Queue\"\nmsgstr \"Pridať do poradia\"\n\n#: src/ui/music-list.vala:665 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Pridať do zoznamu\"\n\n#: src/ui/music-list.vala:672\nmsgid \"Remove\"\nmsgstr \"Odstrániť\"\n\n#: src/ui/music-widgets.vala:219 src/ui/music-widgets.vala:241\n#: src/ui/store-panel.vala:433\nmsgid \"Play\"\nmsgstr \"Prehrať\"\n\n#: src/ui/music-widgets.vala:220 src/ui/music-widgets.vala:242\nmsgid \"_Random Play\"\nmsgstr \"_Prehrať náhodne\"\n\n#: src/ui/music-widgets.vala:230\nmsgid \"Show List _File\"\nmsgstr \"Zobraziť zoznam _súborov\"\n\n#: src/ui/music-widgets.vala:253 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Vyhľadať názov\"\n\n#: src/ui/music-widgets.vala:254 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Vyhľadať album\"\n\n#: src/ui/music-widgets.vala:255 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Vyhľadať umelca\"\n\n#: src/ui/music-widgets.vala:259\nmsgid \"Show Cover _File\"\nmsgstr \"Zobraziť obal _súboru\"\n\n#: src/ui/music-widgets.vala:261\nmsgid \"_Export Cover\"\nmsgstr \"_Exportovať obal\"\n\n#: src/ui/music-widgets.vala:262\nmsgid \"Show _Tags…\"\nmsgstr \"Zobraziť _štítky…\"\n\n#: src/ui/music-widgets.vala:263\nmsgid \"Show Music _File\"\nmsgstr \"Zobraziť _hudobný súbor\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Jedno opakovanie\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Prehrať predchádzajúcu\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Prehrať/Pozastaviť\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Prehrať nasledujúcu\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Sem pretiahnite a pustite hudobné súbory,\\n\"\n\"alebo zmeňte umiestnenie hudby: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Nový zoznam\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:688\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Nebol nájdený žiadny zoznam v %s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Nikdy\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Vždy\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Iba obrázok\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Skladba\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Práve hrá\"\n\n#: src/ui/store-panel.vala:88\nmsgid \"Artists\"\nmsgstr \"Interpreti\"\n\n#: src/ui/store-panel.vala:92\nmsgid \"Albums\"\nmsgstr \"Albumy\"\n\n#: src/ui/store-panel.vala:96\nmsgid \"Playlists\"\nmsgstr \"Zoznamy\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Kopírovať\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Hlasitosť %d%%\"\n\n#: src/ui/window.vala:113\nmsgid \"Show\"\nmsgstr \"Zobraziť\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Neznámy album\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Neznámy umelec\"\n"
  },
  {
    "path": "po/sl.po",
    "content": "# Slovenian translation for g4music.\n# Copyright (C) 2024 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# Martin Srebotnjak <miles@filmsi.net>, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-10-11 01:38+0000\\n\"\n\"PO-Revision-Date: 2024-10-11 14:31+0200\\n\"\n\"Last-Translator: Martin Srebotnjak <miles@filmsi.net>\\n\"\n\"Language-Team: Slovenian <gnome-si@googlegroups.com>\\n\"\n\"Language: sl\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || \"\n\"n%100==4 ? 3 : 0);\\n\"\n\"X-Generator: Poedit 2.2.1\\n\"\n\"X-Poedit-SourceCharset: ISO-8859-1\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Brez vrzeli\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Predvajalnik glasbe\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Elegantno predvajajte glasbo\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"glasba;zvok;predvajalnik;medij;avdio;seznam predvajanja;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Brez vrzeli (AKA: G4Music) je lahek glasbeni predvajalnik, napisan v GTK4, \"\n\"ki se osredotoča na veliko glasbeno zbirko.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Zmožnosti\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Podpira večino vrst glasbenih datotek, Sambo in vse druge oddaljene \"\n\"protokole (odvisno od GIO in GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Hitro nalaganje in razčlenjevanje na tisoče glasbenih datotek v zelo nekaj \"\n\"sekundah, spremljajte krajevne spremembe.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Nizka poraba pomnilnika za veliko glasbeno zbirko z naslovnicami albumov \"\n\"(vdelanimi in zunanjimi), brez predpomnilnikov sličic za shranjevanje.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Združevanje in razvrščanje po albumu/izvajalcu/naslovu, naključni seznami, \"\n\"iskanju po celotnem besedilu.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Tekoč prilagodljiv uporabniški vmesnik za različne zaslone (namizje, \"\n\"tablični računalnik, mobilnik).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Gaussova zabrisana naslovnica kot ozadje, sledi svetlemu/temnemu načinu \"\n\"GNOME.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Podpira ustvarjanje in urejanje seznamov predvajanja, povlek naslovnice za \"\n\"spremembo vrstnega reda ali dodajanje na drug seznam predvajanja.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Podpira povleci in spusti z drugimi programi.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Podpira vizualizacijo najvišjih ravni zvoka.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Podpira predvajanje brez premorov.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Podpira normaliziranje glasnosti s funkcijo ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Podpira navedeni zvočni ponor.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Podpira nadzor MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Glavno okno\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Pogled albumov\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Predvajalni pogled\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Pogled seznama predvajanja\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Splošno\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Pokaže tipkovne bližnjice‫\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Nastavitve\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Izhod\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Pokaži značke\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Predvajanje\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Predvajaj / premor\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Predvajaj naslednje\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Predvajaj prejšnje\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Seznam predvajanja\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Iskanje\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Preklopi razvrščanje\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Znova naloži knjižnico\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Shrani seznam\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"Nazaj\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Splošno\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Način zabrisanosti ozadja\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Strnjen pogled seznama predvajanja\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Mrežni pogled za izvajalce/albume\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"En klik za aktiviranje elementa\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"Nadaljuj s predvajanjem po zaprtju okna\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Knjižnica\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Naloži glasbo iz mape\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Spremljaj krajevne spremembe datotek\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Naloži sličice za datoteke, ki niso krajevne\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Lahko povzroči upočasnitve in prekomerno porabo omrežja\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Predvajanje\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Pokaži najvišjo raven zvoka\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Prikaz znakov\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Zasukaj naslovnico albuma\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Omogoči predvajanje brez premorov\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normaliziraj glasnost s funkcijo ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Prednost naj ima zvočni odtok GStreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Glavni meni\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Iskanje\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"Razvrsti po\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"_Barvna shema\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"S_istemska\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"_Svetla\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_Temna\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"Znova naloži _knjižnico\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"_Večdelni izbor\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"_Shrani seznam\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"_Možnosti\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Tipkovne bližnjice\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"_O programu\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"Izvajalec\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"Izvajalec/album\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"Naslov\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"Nedavno\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"Premešaj\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Slikovne datoteke\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Izvoz ovitka je uspešno zaključen\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Izvoz ovitka je spodletel\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"Shranjevanje seznama predvajanja je spodletelo\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"Datoteke seznama predvajanja\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"Seznam predvajanja uspešno shranjen\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"Nadaljuj s predvajanjem\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"Hiter, tekoč, lahek predvajalnik glasbe, napisan v GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"Martin Srebotnjak <miles@filmsi.net>\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"Ne\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"Da\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Seznam predvajanja je spremenjen, ga želite shraniti?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Predvajaj kot nas_lednje\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Dodaj v _čakalno vrsto\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Dodaj na seznam _predvajanja …\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"_Odstrani\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"_Premakni v smeti\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"Izberi vse\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"Predvajaj kot naslednje\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"Dodaj v čakalno vrsto\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Dodaj na seznam predvajanja\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"Odstrani\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"Predvajaj\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Naključno predvajanje\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Pokaži _datoteko seznama\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Iskanje po naslovu\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Iskanje po albumu\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Iskanje po izvajalcu\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Pokaži datoteko _ovitka\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Izvozi ovitek\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Pokaži _značke ...\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Pokaži _glasbeno datoteko\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Enojna zanka\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Predvajaj prejšnje\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Predvajaj / premor\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Predvajaj naslednje\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Povlecite in spustite glasbene datoteke semkaj\\n\"\n\"ali spremenite mesto glasbe: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Nov seznam predvajanja\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:692\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"V %s ni mogoče najti seznama predvajanja\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Nikoli\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Vedno\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Samo grafika\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Skladba/posnetek\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Trenutno se predvaja\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Izvajalci\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Albumi\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Seznami predvajanja\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Kopiraj\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Glasnost %d %%\"\n\n#: src/ui/window.vala:112\nmsgid \"Show\"\nmsgstr \"Pokaži\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Neznani album\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Neznani izvajalec\"\n"
  },
  {
    "path": "po/sv.po",
    "content": "# Swedish translation for G4Music.\n# Copyright 2022-2024 G4Music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the G4Music package.\n# Åke Engelbrektson <eson@svenskasprakfiler.se>, 2022.\n# Anders Jonsson <anders.jonsson@norsjovallen.se>, 2023, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-11-10 04:13+0000\\n\"\n\"PO-Revision-Date: 2024-11-10 13:22+0100\\n\"\n\"Last-Translator: Anders Jonsson <anders.jonsson@norsjovallen.se>\\n\"\n\"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\\n\"\n\"Language: sv\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\n# Namnet på spelaren.\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:271\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Gapless\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Musikspelare\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Spela din musik elegant\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"musik;ljud;spelare;media;audio;spelningslista;spellista;\"\n\n# TODO: collection**s**\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (även kallad G4Music) är en lättviktig musikspelare skriven i GTK4 \"\n\"som fokuserar på stora musiksamlingar.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Funktioner\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Stöder de flesta filtyper för musik, Samba och andra fjärrprotokoll (beror \"\n\"på GIO och GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Snabb inläsning och tolkning av tusentals musikfiler på några få sekunder, \"\n\"övervaka lokala ändringar.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Låg minnesanvändning för stora musiksamlingar med albumomslag (inbäddade och \"\n\"externa), inga miniatyrbildscachar att lagra.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Gruppering och sortering efter album/artist/titel, slumplista, \"\n\"fulltextsökning.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Helt adaptivt användargränssnitt för olika skärmar (skrivbord, platta, \"\n\"mobil).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"Gaussiskt oskärpt omslag som bakgrund, följer GNOMEs ljusa/mörka läge.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Stöder skapande och redigering av spellistor, dra omslag för att ändra \"\n\"ordning eller lägga till i en annan spellista.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Stöder dra-och-släpp med andra program.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Stöder visualisering av ljudtoppnivå.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Stöder mellanrumslös uppspelning.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Stöder normalisering av volym med ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Stöder specificerad ljudutgång.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Stöder MPRIS-kontroll.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Huvudfönster\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Albumvy\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Uppspelningsvy\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Spellistevy\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Allmänt\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Visa kortkommandon\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Inställningar\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Avsluta\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Visa taggar\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Uppspelning\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Spela/Pausa\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Spela nästa\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Spela förra\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Spellista\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Sök\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Växla sortering\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Uppdatera bibliotek\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Spara lista\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:633\n#: src/ui/store-panel.vala:423\nmsgid \"Back\"\nmsgstr \"Bakåt\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Allmänt\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Läge med bakgrundsoskärpa\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Kompakt spellistevy\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Rutnätsvy för artister/album\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Enkelklick för att aktivera objekt\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:430\nmsgid \"Keep playing after window closed\"\nmsgstr \"Fortsätt spela efter att fönstret har stängts\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Bibliotek\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Hämta musik från mapp\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Övervaka lokala filändringar\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Hämta miniatyrer för icke-lokala filer\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Kan orsaka nedsaktning och överdriven nätverksanvändning\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Uppspelning\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Visa ljudtoppnivå\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Visa tecken\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Rotera albumomslag\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Aktivera mellanrumslös uppspelning\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Normalisera volym med ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Föredra ljudutgång för GStreamer\"\n\n#: src/gtk/store-panel.ui:23\nmsgid \"Main Menu\"\nmsgstr \"Huvudmeny\"\n\n#: src/gtk/store-panel.ui:30 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Sök\"\n\n#: src/gtk/store-panel.ui:40\nmsgid \"Sort By\"\nmsgstr \"Sortera efter\"\n\n#: src/gtk/store-panel.ui:71\nmsgid \"_Color Scheme\"\nmsgstr \"_Färgschema\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_System\"\nmsgstr \"_System\"\n\n#: src/gtk/store-panel.ui:78\nmsgid \"_Light\"\nmsgstr \"_Ljust\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Dark\"\nmsgstr \"_Mörkt\"\n\n#: src/gtk/store-panel.ui:90\nmsgid \"_Reload Library\"\nmsgstr \"_Uppdatera bibliotek\"\n\n#: src/gtk/store-panel.ui:94\nmsgid \"_Multiple Select\"\nmsgstr \"_Välj flera\"\n\n#: src/gtk/store-panel.ui:98\nmsgid \"_Save List\"\nmsgstr \"_Spara lista\"\n\n#: src/gtk/store-panel.ui:104\nmsgid \"_Preferences\"\nmsgstr \"_Inställningar\"\n\n#: src/gtk/store-panel.ui:108\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Tangentbordsgenvägar\"\n\n#: src/gtk/store-panel.ui:112\nmsgid \"_About\"\nmsgstr \"_Om\"\n\n#: src/gtk/store-panel.ui:121 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Album\"\n\n#: src/gtk/store-panel.ui:126\nmsgid \"Artist\"\nmsgstr \"Artist\"\n\n#: src/gtk/store-panel.ui:131\nmsgid \"Artist/Album\"\nmsgstr \"Artist/Album\"\n\n#: src/gtk/store-panel.ui:136\nmsgid \"Title\"\nmsgstr \"Titel\"\n\n#: src/gtk/store-panel.ui:141\nmsgid \"Recent\"\nmsgstr \"Senaste\"\n\n#: src/gtk/store-panel.ui:146\nmsgid \"Shuffle\"\nmsgstr \"Blanda\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Bildfiler\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Omslag exporterades\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Omslagsexport misslyckades\"\n\n#: src/application.vala:344\nmsgid \"Save playlist failed\"\nmsgstr \"Sparning av spellista misslyckades\"\n\n#: src/application.vala:466\nmsgid \"Playlist Files\"\nmsgstr \"Spellistefiler\"\n\n#: src/application.vala:480\nmsgid \"Save playlist successfully\"\nmsgstr \"Spellistan sparades\"\n\n#: src/application.vala:615\nmsgid \"Keep playing\"\nmsgstr \"Fortsätt spela\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"En snabb lättflytande musikspelare skriven i GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"Åke Engelbrektson\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:112\nmsgid \"No\"\nmsgstr \"Nej\"\n\n#: src/ui/dialogs.vala:101 src/ui/dialogs.vala:112\nmsgid \"Yes\"\nmsgstr \"Ja\"\n\n#: src/ui/music-list.vala:276\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Spellistan är ändrad, spara den?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:422\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Spela _härnäst\"\n\n#: src/ui/music-list.vala:408 src/ui/music-list.vala:424\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Lägg till i _kö\"\n\n#: src/ui/music-list.vala:409 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Lägg till i _spellista…\"\n\n#: src/ui/music-list.vala:410 src/ui/music-list.vala:428\nmsgid \"_Remove\"\nmsgstr \"_Ta bort\"\n\n#: src/ui/music-list.vala:429 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"Flytta till _papperskorgen\"\n\n#: src/ui/music-list.vala:637\nmsgid \"Select All\"\nmsgstr \"Markera alla\"\n\n#: src/ui/music-list.vala:654\nmsgid \"Play at Next\"\nmsgstr \"Spela härnäst\"\n\n#: src/ui/music-list.vala:661\nmsgid \"Add to Queue\"\nmsgstr \"Lägg till i kö\"\n\n#: src/ui/music-list.vala:668 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Lägg till i spellista\"\n\n#: src/ui/music-list.vala:675\nmsgid \"Remove\"\nmsgstr \"Ta bort\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:431\nmsgid \"Play\"\nmsgstr \"Spela\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"S_pela slumpmässigt\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Visa list_fil\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Sök titel\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Sök album\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Sök artist\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Visa omslags_fil\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Exportera omslag\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Visa _taggar…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Visa musik_fil\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Upprepa en\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Spela förra\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Spela/Pausa\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Spela nästa\"\n\n#: src/ui/play-panel.vala:263\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Dra och släpp musikfiler här,\\n\"\n\"eller ändra musikplats: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Ny spellista\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:702\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"Ingen spellista hittades i %s\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Aldrig\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Alltid\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Endast omslag\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Spår\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Spelar\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Artister\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Album\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Spellistor\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Kopiera\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Volym %d%%\"\n\n#: src/ui/window.vala:119\nmsgid \"Show\"\nmsgstr \"Visa\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Okänt album\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Okänd artist\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"Spela musik\"\n\n#~ msgid \"Nanling\"\n#~ msgstr \"Nanling\"\n\n#~ msgid \"Close\"\n#~ msgstr \"Stäng\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"Dra-och-släpp från GNOME Filer, visa musik i Filer.\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"Föredra mörkt tema\"\n\n#~ msgid \"No playlist found in: %s\"\n#~ msgstr \"Ingen spellista hittades i: %s\"\n\n#~ msgid \"_Add to Playlist…\"\n#~ msgstr \"_Lägg till i spellista…\"\n"
  },
  {
    "path": "po/tr.po",
    "content": "# Turkish translation for g4music.\n# Copyright (C) 2022-2024 g4music'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n#\n# Sabri Ünal <yakushabb@gmail.com>, 2022-2024.\n# Emin Tufan Çetin <etcetin@gmail.com>, 2023, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-11-18 01:03+0000\\n\"\n\"PO-Revision-Date: 2024-10-23 22:55+0300\\n\"\n\"Last-Translator: Sabri Ünal <yakushabb@gmail.com>\\n\"\n\"Language-Team: Turkish <takim@gnome.org.tr>\\n\"\n\"Language: tr\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:271\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Aralıksız\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Müzik Çalar\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Müziğinizi zarifçe çalın\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"music;sound;player;media;audio;playlist;müzik;ses;çalıcı;medya;ortam;çalma \"\n\"listesi;oynatma listesi;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (Yani: G4Music), GTK4 ile yazılmış hafif bir müzik oynatıcıdır ve \"\n\"büyük müzik derlemelerine odaklanır.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Özellikler\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Çoğu müzik dosyası türününün yanında Samba ve diğer uzak iletişim \"\n\"kurallarını destekler (GIO ve GStreamerʼa bağlıdır).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Binlerce müzik dosyasını birkaç saniyede yükleme ve ayrıştırma, yerel \"\n\"değişiklikleri izleme.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Albüm kapakları (gömülü ve harici) içeren büyük müzik derlemeleri için düşük \"\n\"bellek kullanımı, küçük resim önbellekleri depolanmaz.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Albüme/sanatçıya/başlığa göre gruplama ve sıralama, liste karıştırma, tam \"\n\"metin arama.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Farklı ekranlar (Masaüstü, Tablet, Cep Telefonu) için akıcı uyarlanabilir \"\n\"kullanıcı arayüzü.\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"Arka plan için bulanıklaştırılmış kapak, GNOME açık/koyu kipini takip.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Oynatma listeleri oluşturmayı ve düzenlemeyi destekler. Sırayı değiştirmek \"\n\"ya da başka oynatma listesine eklemek için kapağı sürükleyin.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Diğer uygulamalarla sürükle ve bırak özelliğini destekler.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Ses tepe seviyesi görselleyiciyi destekler.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Aralıksız çalmayı destekler.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"ReplayGain ile sesi normalleştirmeyi destekler.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Belirtilen ses alıcılarını destekler.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"MPRIS denetimini destekler.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Ana pencere\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Albümler görünümü\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Çalıyor görünümü\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Çalma listesi görünümü\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Genel\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Kısayolları Göster\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Tercihler\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Çık\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Etiketleri Göster\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Çalma\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Çal/Duraklat\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Sonrakini Çal\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Öncekini Çal\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Çalma Listesi\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Ara\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Sıralamayı Aç/Kapat\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Kitaplığı Yeniden Yükle\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Listeyi Kaydet\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:632\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"Geri\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Genel\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Arka plan bulanıklık kipi\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Sıkışık oynatma listesi görünümü\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Sanatçılar/albümler için ızgara görünümü\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Tek tıkla ögeyi etkinleştir\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:432\nmsgid \"Keep playing after window closed\"\nmsgstr \"Pencere kapatıldıktan sonra oynatmayı sürdür\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Kitaplık\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Müziği klasörden yükle\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Yerel dosya değişikliklerini izle\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Yerel olmayan dosyalar için küçük resimleri yükle\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Yavaşlığa ve aşırı ağ kullanımına neden olabilir\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Çalma\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Ses tepe seviyesini göster\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Karakterleri göster\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Albüm kapağını çevir\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Aralıksız oynatmayı etkinleştir\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Sesi normalleştirmek için ReplayGain kullan\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"GStreamer ses havuzunu yeğle\"\n\n#: src/gtk/store-panel.ui:23\nmsgid \"Main Menu\"\nmsgstr \"Ana Menü\"\n\n#: src/gtk/store-panel.ui:30 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Ara\"\n\n#: src/gtk/store-panel.ui:40\nmsgid \"Sort By\"\nmsgstr \"Sıralama\"\n\n#: src/gtk/store-panel.ui:71\nmsgid \"_Color Scheme\"\nmsgstr \"_Renk Şeması\"\n\n#: src/gtk/store-panel.ui:73\nmsgid \"_System\"\nmsgstr \"_Sistem\"\n\n#: src/gtk/store-panel.ui:78\nmsgid \"_Light\"\nmsgstr \"_Açık\"\n\n#: src/gtk/store-panel.ui:83\nmsgid \"_Dark\"\nmsgstr \"_Koyu\"\n\n#: src/gtk/store-panel.ui:90\nmsgid \"_Reload Library\"\nmsgstr \"Kitaplığı _Yeniden Yükle\"\n\n#: src/gtk/store-panel.ui:94\nmsgid \"_Multiple Select\"\nmsgstr \"Ç_oklu Seçim\"\n\n#: src/gtk/store-panel.ui:98\nmsgid \"_Save List\"\nmsgstr \"_Listeyi Kaydet\"\n\n#: src/gtk/store-panel.ui:104\nmsgid \"_Preferences\"\nmsgstr \"_Tercihler\"\n\n#: src/gtk/store-panel.ui:108\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Klavye Kısayolları\"\n\n#: src/gtk/store-panel.ui:112\nmsgid \"_About\"\nmsgstr \"_Hakkında\"\n\n#: src/gtk/store-panel.ui:121 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Albüm\"\n\n#: src/gtk/store-panel.ui:126\nmsgid \"Artist\"\nmsgstr \"Sanatçı\"\n\n#: src/gtk/store-panel.ui:131\nmsgid \"Artist/Album\"\nmsgstr \"Sanatçı/Albüm\"\n\n#: src/gtk/store-panel.ui:136\nmsgid \"Title\"\nmsgstr \"Başlık\"\n\n#: src/gtk/store-panel.ui:141\nmsgid \"Recent\"\nmsgstr \"Son\"\n\n#: src/gtk/store-panel.ui:146\nmsgid \"Shuffle\"\nmsgstr \"Karıştır\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"Görüntü Dosyaları\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Kapak dışa aktarıldı\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Kapak dışa aktarılamadı\"\n\n#: src/application.vala:344\nmsgid \"Save playlist failed\"\nmsgstr \"Oynatma listesi kaydedilemedi\"\n\n#: src/application.vala:468\nmsgid \"Playlist Files\"\nmsgstr \"Çalma Listesi Dosyaları\"\n\n#: src/application.vala:483\nmsgid \"Save playlist successfully\"\nmsgstr \"Oynatma listesi kaydedildi\"\n\n#: src/application.vala:618\nmsgid \"Keep playing\"\nmsgstr \"Oynamayı sürdür\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"GTK4 ile yazılmış hızlı, akıcı, hafif bir müzik çalar.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"Sabri Ünal <libreajans@gmail.com>\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:112\nmsgid \"No\"\nmsgstr \"Hayır\"\n\n#: src/ui/dialogs.vala:101 src/ui/dialogs.vala:112\nmsgid \"Yes\"\nmsgstr \"Evet\"\n\n#: src/ui/music-list.vala:276\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"Oynatma listesi değiştirildi, kaydedilsin mi?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:405 src/ui/music-list.vala:421\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"_Sonra Çal\"\n\n#: src/ui/music-list.vala:407 src/ui/music-list.vala:423\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"_Kuyruğa Ekle\"\n\n#: src/ui/music-list.vala:408 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"_Oynatma Listesine Ekle…\"\n\n#: src/ui/music-list.vala:409 src/ui/music-list.vala:427\nmsgid \"_Remove\"\nmsgstr \"_Kaldır\"\n\n#: src/ui/music-list.vala:428 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"Çöpe _Taşı\"\n\n#: src/ui/music-list.vala:636\nmsgid \"Select All\"\nmsgstr \"Tümünü Seç\"\n\n#: src/ui/music-list.vala:653\nmsgid \"Play at Next\"\nmsgstr \"Sonra Çal\"\n\n#: src/ui/music-list.vala:660\nmsgid \"Add to Queue\"\nmsgstr \"Kuyruğa Ekle\"\n\n#: src/ui/music-list.vala:667 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Çalma Listesine Ekle\"\n\n#: src/ui/music-list.vala:674\nmsgid \"Remove\"\nmsgstr \"Kaldır\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"Çal\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Rastgele Oynat\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Liste _Dosyasını Göster\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Başlığı Göster\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Albüm Ara\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Sanatçı Ara\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Kapak _Dosyalasını Göster\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Kapağı Dışa Aktar\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"_Etiketleri Göster…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Müzik _Dosyasını Göster\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Tek Döngü\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Öncekini Çal\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Çal/Duraklat\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Sonrakini Çal\"\n\n#: src/ui/play-panel.vala:263\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Şarkı dosyalarını sürükleyip buraya bırakın\\n\"\n\"veya müzik konumunu değiştirin: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Yeni Oynatma Listesi\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:703\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"%s içinde oynatma listesi bulunamadı\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Asla\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Daima\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Yalnızca Kapak\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Parça\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Çalıyor\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Sanatçılar\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Albümler\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Çalma Listesi\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Kopyala\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Ses %%%d\"\n\n#: src/ui/window.vala:119\nmsgid \"Show\"\nmsgstr \"Göster\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Bilinmeyen Albüm\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Bilinmeyen Sanatçı\"\n"
  },
  {
    "path": "po/uk.po",
    "content": "# Ukrainian translation for g4music.\n# Copyright (C) 2023 g4music's COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n#\n# Yuri Chornoivan <yurchor@ukr.net>, 2023, 2024.\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music master\\n\"\n\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/neithern/g4music/issues\\n\"\n\"POT-Creation-Date: 2024-10-11 01:38+0000\\n\"\n\"PO-Revision-Date: 2024-10-11 23:39+0300\\n\"\n\"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\\n\"\n\"Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\\n\"\n\"Language: uk\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n\"\n\"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\\n\"\n\"X-Generator: Lokalize 23.04.3\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"Неперервний\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"Програвач музики\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"Елегантне відтворення вашої музики\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"music;sound;player;media;audio;playlist;музика;звук;програвач;мультимедіа;\"\n\"звук;список відтворення;відтворення;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"Gapless (або G4Music) — невибагливий до ресурсів засіб відтворення музики, \"\n\"який написано на GTK4 і акцент у якому зроблено на великих музичних збірках.\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"Можливості\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"Підтримка більшості типів музичних файлів, Samba та усіх інших протоколів \"\n\"віддаленої роботи (залежить від GIO і GStreamer).\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"\"\n\"Швидке завантаження і обробка тисяч музичних файлів за декілька секунд, \"\n\"спостереження за змінами у локальному каталозі.\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"Незначне споживання пам'яті для великих музичних збірок із обкладинками \"\n\"альбомів (вбудованими або зовнішніми), у сховищі даних не кешуються \"\n\"мініатюри.\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"\"\n\"Групування та упорядкування за альбомом, виконавцем та назвою, перемішування \"\n\"списку, повнотекстовий пошук.\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"Гнучкий інтерфейс для різних розмірів екрана (робоча станція, планшет, \"\n\"мобільний телефон).\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"\"\n\"Тло у вигляді обкладинки із гаусовим розмиванням, використання світлого або \"\n\"темного режиму GNOME.\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"\"\n\"Передбачено підтримку створення та редагування списків відтворення, \"\n\"перетягування за обкладинку для зміни порядку або додавання до іншого списку \"\n\"відтворення.\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"Підтримка перетягування зі скиданням з інших програм.\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"Підтримка візуалізації піків звукового сигналу.\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"Підтримка неперервного відтворення.\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"Підтримка нормалізації гучності за допомогою ReplayGain.\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"Підтримка вказаного приймача звукових даних.\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"Підтримка керування за допомогою MPRIS.\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"Головне вікно\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"Перегляд «Альбоми»\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"Перегляд «Відтворення»\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"Перегляд «Список відтворення»\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"Загальне\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"Показати клавіатурні скорочення\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"Налаштування\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"Вийти\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"Показувати мітки\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"Відтворення\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"Пуск/Пауза\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"Відтворити наступну\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"Відтворити попередній\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"Список відтворення\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"Пошук\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"Перемкнути упорядковування\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"Перезавантажити бібліотеку\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"Зберегти список\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"Назад\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"Загальне\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"Режим розмивання тла\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"Стислий перегляд списку\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"Таблиця для виконавців/альбомів\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"Активація одинарним клацанням\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"Продовжити відтворення після закриття вікна\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"Бібліотека\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"Завантажити музику з теки\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"Стежити за змінами у локальних файлах\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"Завантажувати мініатюри для нелокальних файлів\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"Може спричинити уповільнення роботи та зайве використання мережі\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"Відтворення\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"Показувати піковий рівень звуку\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"Показати символи\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"Обертати обкладинку альбому\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"Увімкнути неперервне відтворення\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"Нормалізувати гучність за допомогою ReplayGain\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"Перевага приймача звуку GStreamer\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"Головне меню\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"Пошук\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"Критерій впорядкування\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"Схема _кольорів\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"Загальнос_истемна\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"С_вітла\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"_Темна\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"П_ерезавантажити бібліотеку\"\n\n#: src/gtk/store-panel.ui:93\n#| msgid \"_Select\"\nmsgid \"_Multiple Select\"\nmsgstr \"Вибрати д_екілька\"\n\n#: src/gtk/store-panel.ui:97\n#| msgctxt \"shortcut window\"\n#| msgid \"Save List\"\nmsgid \"_Save List\"\nmsgstr \"З_берегти список\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"_Налаштування\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"_Клавіатурні скорочення\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"_Про програму\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"Альбом\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"Виконавець\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"Виконавець/Альбом\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"Назва\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"Нещодавні\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"Перемішати\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"файли зображень\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"Обкладинку успішно експортовано\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"Не вдалося експортувати обкладинку\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"Не вдалося зберегти список відтворення\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"файли списків відтворення\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"Список відтворення успішно збережено\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"Продовжувати відтворення\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"\"\n\"Швидкий, плавний, невибагливий програвач музики, який засновано на GTK4.\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"Юрій Чорноіван <yurchor@ukr.net>, 2023\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"Ні\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"Так\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"До списку відтворення внесено зміни, зберегти їх?\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"Відтворити _наступною\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"Додати до _черги відтворення\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"Додати до с_писку відтворення…\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"В_илучити\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"П_ересунути до смітника\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"Позначити все\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"Відтворити наступною\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"Додати до черги відтворення\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"Додати до списку відтворення\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"Вилучити\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"Відтворити\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"_Випадкове відтворення\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"Показати _файл списку\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"Шукати за назвою\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"Шукати альбом\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"Шукати виконавця\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"Показати файл _обкладинки\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"_Експортувати обкладинку\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"Показати _мітки…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"Показати файл _музики\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"Одне повторення\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"Відтворити попередній\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"Пуск/Пауза\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"Відтворити наступну\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"Перетягніть і скиньте музику сюди\\n\"\n\"або змініть розташування музики: \"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"Новий список\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:692\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"У %s не виявлено списку відтворення\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"Ніколи\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"Завжди\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"Лише оформлення\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"Композиція\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"Відтворення\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"Виконавці\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"Альбоми\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"Списки відтворення\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"Копіювати\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"Гучність %d%%\"\n\n#: src/ui/window.vala:112\nmsgid \"Show\"\nmsgstr \"Показати\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"Невідомий альбом\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"Невідомий виконавець\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"Відтворення музики\"\n\n#~ msgid \"Nanling\"\n#~ msgstr \"Nanling\"\n\n#~ msgid \"Close\"\n#~ msgstr \"Закрити\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"\"\n#~ \"Перетягування зі скиданням з «Файлів GNOME», показ музичних даних у \"\n#~ \"«Файлах».\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"Перевага темної теми\"\n\n#~ msgid \"_Add to Playlist…\"\n#~ msgstr \"_Додати до списку відтворення…\"\n\n#~ msgid \"G4Music\"\n#~ msgstr \"G4Music\"\n"
  },
  {
    "path": "po/zh_CN.po",
    "content": "# Chinese translations for g4music package.\n# Copyright (C) 2022 THE g4music'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the g4music package.\n# lumingzh <lumingzh@qq.com>, 2024.\n# Nanling <neithern@outlook.com>, 2022-2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-10-11 09:34+0800\\n\"\n\"PO-Revision-Date: 2024-10-11 09:35+0800\\n\"\n\"Last-Translator: Nanling <neithern@outlook.com>\\n\"\n\"Language-Team: Chinese - China <i18n-zh@googlegroups.com>\\n\"\n\"Language: zh_CN\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=1; plural=0\\n\"\n\"X-Generator: Gtranslator 46.1\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"无暇\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"音乐播放器\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"优雅地播放您的音乐\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"music;sound;player;media;audio;playlist;音乐;声音;播放器;媒体;音频;播放列表;\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"无暇（又名：G4Music）是一款用 GTK4 编写的轻量级音乐播放器，专注于大型音乐收\"\n\"藏。\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"特点\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"支持大多数音乐文件类型、Samba 和任何其他远程协议（取决于 GIO 和 GStreamer）。\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"在数秒内快速加载和解析数千个音乐文件，监控本地文件变化。\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"对于带有专辑封面（嵌入式和外置式）的大型音乐收藏，内存使用率低，无需存储缩略\"\n\"图缓存。\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"按专辑/艺术家/标题分组和排序、随机播放列表、全文搜索。\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"针对不同屏幕（台式机、平板电脑、手机）的流畅自适应用户界面。\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"高斯模糊封面作为背景，跟随 GNOME 亮色/暗色模式。\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"支持创建和编辑播放列表，拖拽封面更改排序或添加到另一个播放列表。\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"支持通过其它应用拖放文件。\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"支持音频峰值可视化。\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"支持无缝播放。\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"支持通过回放增益实现音量平衡。\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"支持指定音频输出。\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"支持 MPRIS 控制。\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"主窗口\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"专辑视图\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"正在播放视图\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"播放列表视图\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"常规\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"显示快捷键\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"首选项\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"退出\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"显示标签\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"播放\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"播放/暂停\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"播放下一首\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"播放上一首\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"播放列表\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"搜索\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"切换排序\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"重载曲库\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"保存列表\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"返回\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"常规\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"背景模糊模式\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"紧凑播放列表\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"艺术家/专辑使用网格视图\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"单击激活项目\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"关闭窗口后继续播放\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"曲库\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"从文件夹加载音乐\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"监控本地文件变化\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"加载非本地文件的缩略图\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"可能会导致速度减慢和过多的网络使用\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"播放\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"显示音频峰值\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"显示的字符\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"旋转专辑封面\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"启用无缝续播\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"自动音量平衡\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"首选音频输出\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"主菜单\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"搜索\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"排序\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"配色方案(_C)\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"系统(_S)\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"亮色(_L)\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"暗色(_D)\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"重载曲库(_R)\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"多重选择(_M)\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"保存列表(_S)\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"首选项(_P)\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"键盘快捷键(_K)\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"关于(_A)\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"专辑\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"艺术家\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"艺术家/专辑\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"标题\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"最近\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"乱序\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"图像文件\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"导出封面成功\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"导出封面失败\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"保存播放列表失败\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"播放列表文件\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"保存播放列表成功\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"持续播放\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"一个快速、流畅、轻量的，基于 GTK4 的音乐播放器。\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"\"\n\"Nanling <neithern@outlook.com>, 2022-2024.\\n\"\n\"lumingzh <lumingzh@qq.com>, 2024.\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"否\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"是\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"播放列表已修改，是否保存？\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"插播(_N)\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"添加到队列(_Q)\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"添加到播放列表(_P)…\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"移除(_R)\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"移至回收站(_M)\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"全选\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"插播\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"添加到队列\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"添加到播放列表\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"移除\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"播放\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"随机播放(_R)\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"显示列表文件(_F)\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"搜索标题\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"搜索专辑\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"搜索艺术家\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"显示封面文件(_F)\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"导出封面(_E)\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"显示标签(_T)…\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"显示音乐文件(_F)\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"单曲循环\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"播放上一首\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"播放/暂停\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"播放下一首\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"拖放音乐文件到这里，\\n\"\n\"或者修改曲库的位置：\"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"新建播放列表\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:692\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"在 %s 中未找到播放列表\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"从不\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"总是\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"仅封面\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"曲目\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"正在播放\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"艺术家\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"专辑\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"播放列表\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"复制\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"音量 %d%%\"\n\n#: src/ui/window.vala:112\nmsgid \"Show\"\nmsgstr \"显示\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"未知专辑\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"未知艺术家\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"播放音乐\"\n\n#~ msgid \"Close\"\n#~ msgstr \"关闭\"\n\n#~ msgid \"Nanling\"\n#~ msgstr \"Nanling\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"从 GNOME 文件管理器拖放音乐文件，显示文件管理器中的音乐文件。\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"首选深色主题\"\n\n#, fuzzy, c-format\n#~ msgid \"No playlist found in: %s\"\n#~ msgstr \"未找到播放列表\"\n\n#~ msgid \"_Add to Playlist…\"\n#~ msgstr \"添加到播放列表(_A)…\"\n"
  },
  {
    "path": "po/zh_TW.po",
    "content": "# Traditional Chinese translations for g4music package\n# g 套件的繁體中文翻譯.\n# Copyright (C) 2022 THE g4music'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the g package.\n# Julian <s9209122222@gmail.com>, 2022.\n# Nanling <neithern@outlook.com>, 2023-2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: g4music\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-10-11 09:34+0800\\n\"\n\"PO-Revision-Date: 2024-10-11 09:36+0800\\n\"\n\"Last-Translator: Nanling <neithern@outlook.com>\\n\"\n\"Language-Team: Chinese - China <i18n-zh@googlegroups.com>\\n\"\n\"Language: zh_CN\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=1; plural=0\\n\"\n\"X-Generator: Gtranslator 46.1\\n\"\n\n#: data/app.desktop.in:3 data/app.metainfo.xml.in:4 src/application.vala:277\n#: src/main.vala:24\nmsgid \"Gapless\"\nmsgstr \"無暇\"\n\n#: data/app.desktop.in:4\nmsgid \"Music Player\"\nmsgstr \"音樂播放器\"\n\n#: data/app.desktop.in:5 data/app.metainfo.xml.in:7\nmsgid \"Play your music elegantly\"\nmsgstr \"優雅地播放您的音樂\"\n\n#: data/app.desktop.in:12\nmsgid \"music;sound;player;media;audio;playlist;\"\nmsgstr \"\"\n\"music;sound;player;media;audio;playlist;音樂;聲音;播放器;媒體;音訊;播放列表\"\n\n#: data/app.metainfo.xml.in:24\nmsgid \"\"\n\"Gapless (AKA: G4Music) is a light weight music player written in GTK4, \"\n\"focuses on large music collection.\"\nmsgstr \"\"\n\"無暇 (又名: G4Music) 是以 GTK4 寫成的輕量級音樂播放器，專注於大型音樂收藏。\"\n\n#: data/app.metainfo.xml.in:25\nmsgid \"Features\"\nmsgstr \"特點\"\n\n#: data/app.metainfo.xml.in:27\nmsgid \"\"\n\"Supports most music file types, Samba and any other remote protocols \"\n\"(depends on GIO and GStreamer).\"\nmsgstr \"\"\n\"支援大多數音樂檔案類型、Samba 及任何其他遠端通訊協定 (取決於 GIO 及 \"\n\"GStreamer)。\"\n\n#: data/app.metainfo.xml.in:28\nmsgid \"\"\n\"Fast loading and parsing thousands of music files in very few seconds, \"\n\"monitor local changes.\"\nmsgstr \"在幾秒鐘內快速載入和解析數以千計的音樂檔案，監控本機變更。\"\n\n#: data/app.metainfo.xml.in:29\nmsgid \"\"\n\"Low memory usage for large music collection with album covers (embedded and \"\n\"external), no thumbnail caches to store.\"\nmsgstr \"\"\n\"對於包含專輯封面 (內嵌與外接) 的大型音樂收藏，記憶體使用量低，無須儲存縮圖快\"\n\"取。\"\n\n#: data/app.metainfo.xml.in:30\nmsgid \"\"\n\"Group and sorts by album/artist/title, shuffle list, full-text searching.\"\nmsgstr \"依專輯/歌手/標題分類與排序、隨機播放清單、全文檢索。\"\n\n#: data/app.metainfo.xml.in:31\nmsgid \"\"\n\"Fluent adaptive user interface for different screen (Desktop, Tablet, \"\n\"Mobile).\"\nmsgstr \"\"\n\"適用於不同螢幕 (桌上型電腦、平板電腦、行動裝置) 的流暢自適應使用者介面。\"\n\n#: data/app.metainfo.xml.in:32\nmsgid \"Gaussian blurred cover as background, follows GNOME light/dark mode.\"\nmsgstr \"高斯模糊封面作為背景，遵循 GNOME 明暗模式。\"\n\n#: data/app.metainfo.xml.in:33\nmsgid \"\"\n\"Supports creating and editing playlists, drag cover to change order or add \"\n\"to another playlist.\"\nmsgstr \"支援建立與編輯播放清單，拖曳封面可變更順序或加入另一個播放清單。\"\n\n#: data/app.metainfo.xml.in:34\nmsgid \"Supports drag and drop with other apps.\"\nmsgstr \"支援與其他應用拖放功能。\"\n\n#: data/app.metainfo.xml.in:35\nmsgid \"Supports audio peaks visualizer.\"\nmsgstr \"支援音訊峰值顯示器。\"\n\n#: data/app.metainfo.xml.in:36\nmsgid \"Supports gapless playback.\"\nmsgstr \"支援無間隙播放。\"\n\n#: data/app.metainfo.xml.in:37\nmsgid \"Supports normalizing volume with ReplayGain.\"\nmsgstr \"支援使用 ReplayGain 將音量正常化。\"\n\n#: data/app.metainfo.xml.in:38\nmsgid \"Supports specified audio sink.\"\nmsgstr \"支援指定的音訊輸出。\"\n\n#: data/app.metainfo.xml.in:39\nmsgid \"Supports MPRIS control.\"\nmsgstr \"支援 MPRIS 控制。\"\n\n#: data/app.metainfo.xml.in:50\nmsgid \"Main window\"\nmsgstr \"主視窗\"\n\n#: data/app.metainfo.xml.in:54\nmsgid \"Albums view\"\nmsgstr \"專輯檢視\"\n\n#: data/app.metainfo.xml.in:58\nmsgid \"Playing view\"\nmsgstr \"正在播放檢視\"\n\n#: data/app.metainfo.xml.in:62\nmsgid \"Playlist view\"\nmsgstr \"播放清單檢視\"\n\n#: src/gtk/help-overlay.ui:11\nmsgctxt \"shortcut window\"\nmsgid \"General\"\nmsgstr \"一般\"\n\n#: src/gtk/help-overlay.ui:14\nmsgctxt \"shortcut window\"\nmsgid \"Show Shortcuts\"\nmsgstr \"顯示快捷鍵\"\n\n#: src/gtk/help-overlay.ui:20\nmsgctxt \"shortcut window\"\nmsgid \"Preferences\"\nmsgstr \"偏好設定\"\n\n#: src/gtk/help-overlay.ui:26\nmsgctxt \"shortcut window\"\nmsgid \"Quit\"\nmsgstr \"退出\"\n\n#: src/gtk/help-overlay.ui:32\nmsgctxt \"shortcut window\"\nmsgid \"Show Tags\"\nmsgstr \"顯示標籤\"\n\n#: src/gtk/help-overlay.ui:40\nmsgctxt \"shortcut window\"\nmsgid \"Playback\"\nmsgstr \"播放\"\n\n#: src/gtk/help-overlay.ui:43\nmsgctxt \"shortcut window\"\nmsgid \"Play/Pause\"\nmsgstr \"播放/暫停\"\n\n#: src/gtk/help-overlay.ui:49\nmsgctxt \"shortcut window\"\nmsgid \"Play Next\"\nmsgstr \"播放下一首\"\n\n#: src/gtk/help-overlay.ui:55\nmsgctxt \"shortcut window\"\nmsgid \"Play Previous\"\nmsgstr \"播放上一首\"\n\n#: src/gtk/help-overlay.ui:63\nmsgctxt \"shortcut window\"\nmsgid \"Playlist\"\nmsgstr \"播放清單\"\n\n#: src/gtk/help-overlay.ui:66\nmsgctxt \"shortcut window\"\nmsgid \"Search\"\nmsgstr \"搜尋\"\n\n#: src/gtk/help-overlay.ui:72\nmsgctxt \"shortcut window\"\nmsgid \"Toggle Sort\"\nmsgstr \"切換排序\"\n\n#: src/gtk/help-overlay.ui:78\nmsgctxt \"shortcut window\"\nmsgid \"Reload Library\"\nmsgstr \"更新音樂庫\"\n\n#: src/gtk/help-overlay.ui:84\nmsgctxt \"shortcut window\"\nmsgid \"Save List\"\nmsgstr \"儲存清單\"\n\n#: src/gtk/play-panel.ui:16 src/ui/music-list.vala:629\n#: src/ui/store-panel.vala:421\nmsgid \"Back\"\nmsgstr \"返回\"\n\n#: src/gtk/preferences.ui:10\nmsgid \"General\"\nmsgstr \"一般\"\n\n#: src/gtk/preferences.ui:14\nmsgid \"Background blur mode\"\nmsgstr \"背景模糊模式\"\n\n#: src/gtk/preferences.ui:20\nmsgid \"Compact playlist view\"\nmsgstr \"緊湊播放列表\"\n\n#: src/gtk/preferences.ui:32\nmsgid \"Grid view for artists/albums\"\nmsgstr \"藝術家/專輯使用網格檢視\"\n\n#: src/gtk/preferences.ui:44\nmsgid \"Single click to activate item\"\nmsgstr \"單擊啟動項目\"\n\n#: src/gtk/preferences.ui:56 src/application.vala:425\nmsgid \"Keep playing after window closed\"\nmsgstr \"關閉視窗後繼續播放\"\n\n#: src/gtk/preferences.ui:69\nmsgid \"Library\"\nmsgstr \"音樂庫\"\n\n#: src/gtk/preferences.ui:73\nmsgid \"Load music from folder\"\nmsgstr \"從資料夾載入音樂\"\n\n#: src/gtk/preferences.ui:85\nmsgid \"Monitor local file changes\"\nmsgstr \"監控本地檔案變化\"\n\n#: src/gtk/preferences.ui:97\nmsgid \"Load thumbnails for non-local files\"\nmsgstr \"載入非本機檔案的縮圖\"\n\n#: src/gtk/preferences.ui:98\nmsgid \"May cause slowdowns and excess network usage\"\nmsgstr \"可能會導致速度減慢與增加網路使用\"\n\n#: src/gtk/preferences.ui:111\nmsgid \"Playback\"\nmsgstr \"播放\"\n\n#: src/gtk/preferences.ui:115\nmsgid \"Show audio peak level\"\nmsgstr \"顯示音訊峰值\"\n\n#: src/gtk/preferences.ui:119\nmsgid \"Display characters\"\nmsgstr \"顯示的字元\"\n\n#: src/gtk/preferences.ui:134\nmsgid \"Rotate album cover\"\nmsgstr \"旋轉專輯封面\"\n\n#: src/gtk/preferences.ui:146\nmsgid \"Enable gapless playback\"\nmsgstr \"啟用無縫播放\"\n\n#: src/gtk/preferences.ui:158\nmsgid \"Normalize volume with ReplayGain\"\nmsgstr \"使用 ReplayGain 正規化音量\"\n\n#: src/gtk/preferences.ui:164\nmsgid \"Prefer audio sink of GStreamer\"\nmsgstr \"首選音訊輸出\"\n\n#: src/gtk/store-panel.ui:22\nmsgid \"Main Menu\"\nmsgstr \"主選單\"\n\n#: src/gtk/store-panel.ui:29 src/ui/playlist-dialog.vala:36\nmsgid \"Search\"\nmsgstr \"搜尋\"\n\n#: src/gtk/store-panel.ui:39\nmsgid \"Sort By\"\nmsgstr \"排序\"\n\n#: src/gtk/store-panel.ui:70\nmsgid \"_Color Scheme\"\nmsgstr \"配色方案(_C)\"\n\n#: src/gtk/store-panel.ui:72\nmsgid \"_System\"\nmsgstr \"系統(_S)\"\n\n#: src/gtk/store-panel.ui:77\nmsgid \"_Light\"\nmsgstr \"亮色(_L)\"\n\n#: src/gtk/store-panel.ui:82\nmsgid \"_Dark\"\nmsgstr \"暗色(_D)\"\n\n#: src/gtk/store-panel.ui:89\nmsgid \"_Reload Library\"\nmsgstr \"更新音樂庫(_R)\"\n\n#: src/gtk/store-panel.ui:93\nmsgid \"_Multiple Select\"\nmsgstr \"多重選擇(_M)\"\n\n#: src/gtk/store-panel.ui:97\nmsgid \"_Save List\"\nmsgstr \"儲存清單(_S)\"\n\n#: src/gtk/store-panel.ui:103\nmsgid \"_Preferences\"\nmsgstr \"偏好設定(_P)\"\n\n#: src/gtk/store-panel.ui:107\nmsgid \"_Keyboard Shortcuts\"\nmsgstr \"快捷鍵(_K)\"\n\n#: src/gtk/store-panel.ui:111\nmsgid \"_About\"\nmsgstr \"關於(_A)\"\n\n#: src/gtk/store-panel.ui:120 src/ui/preferences.vala:66\nmsgid \"Album\"\nmsgstr \"專輯\"\n\n#: src/gtk/store-panel.ui:125\nmsgid \"Artist\"\nmsgstr \"藝術家\"\n\n#: src/gtk/store-panel.ui:130\nmsgid \"Artist/Album\"\nmsgstr \"藝術家/專輯\"\n\n#: src/gtk/store-panel.ui:135\nmsgid \"Title\"\nmsgstr \"歌名\"\n\n#: src/gtk/store-panel.ui:140\nmsgid \"Recent\"\nmsgstr \"最近\"\n\n#: src/gtk/store-panel.ui:145\nmsgid \"Shuffle\"\nmsgstr \"亂序播放\"\n\n#: src/action-handles.vala:114\nmsgid \"Image Files\"\nmsgstr \"圖像檔案\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover successfully\"\nmsgstr \"輸出封面成功\"\n\n#: src/action-handles.vala:121\nmsgid \"Export cover failed\"\nmsgstr \"輸出封面失败\"\n\n#: src/application.vala:350\nmsgid \"Save playlist failed\"\nmsgstr \"儲存播放清單失敗\"\n\n#: src/application.vala:447\nmsgid \"Playlist Files\"\nmsgstr \"播放清單檔案\"\n\n#: src/application.vala:461\nmsgid \"Save playlist successfully\"\nmsgstr \"儲存播放清單成功\"\n\n#: src/application.vala:597\nmsgid \"Keep playing\"\nmsgstr \"持續播放\"\n\n#: src/ui/dialogs.vala:51\nmsgid \"A fast, fluent, light weight music player written in GTK4.\"\nmsgstr \"一個快速、流暢、輕量，基於 GTK4 的音樂播放軟體。\"\n\n#. Translators: Replace \"translator-credits\" with your names, one name per line\n#: src/ui/dialogs.vala:53\nmsgid \"translator-credits\"\nmsgstr \"\"\n\"Julian\\n\"\n\"Nanling\"\n\n#: src/ui/dialogs.vala:99 src/ui/dialogs.vala:111\nmsgid \"No\"\nmsgstr \"否\"\n\n#: src/ui/dialogs.vala:100 src/ui/dialogs.vala:111\nmsgid \"Yes\"\nmsgstr \"是\"\n\n#: src/ui/music-list.vala:272\nmsgid \"Playlist is modified, save it?\"\nmsgstr \"播放清單已修改，要儲存嗎？\"\n\n#. Translators: Play this music at next position of current playing music\n#: src/ui/music-list.vala:402 src/ui/music-list.vala:418\n#: src/ui/music-widgets.vala:277 src/ui/music-widgets.vala:299\nmsgid \"Play at _Next\"\nmsgstr \"插播(_N)\"\n\n#: src/ui/music-list.vala:404 src/ui/music-list.vala:420\n#: src/ui/music-widgets.vala:278 src/ui/music-widgets.vala:300\nmsgid \"Add to _Queue\"\nmsgstr \"加入列隊(_Q)\"\n\n#: src/ui/music-list.vala:405 src/ui/music-widgets.vala:279\n#: src/ui/music-widgets.vala:301 src/ui/music-widgets.vala:320\nmsgid \"Add to _Playlist…\"\nmsgstr \"加入播放清單(_P)…\"\n\n#: src/ui/music-list.vala:406 src/ui/music-list.vala:424\nmsgid \"_Remove\"\nmsgstr \"移除(_R)\"\n\n#: src/ui/music-list.vala:425 src/ui/music-widgets.vala:286\nmsgid \"_Move to Trash\"\nmsgstr \"移至垃圾桶(_M)\"\n\n#: src/ui/music-list.vala:633\nmsgid \"Select All\"\nmsgstr \"全選\"\n\n#: src/ui/music-list.vala:650\nmsgid \"Play at Next\"\nmsgstr \"插播\"\n\n#: src/ui/music-list.vala:657\nmsgid \"Add to Queue\"\nmsgstr \"加入列隊\"\n\n#: src/ui/music-list.vala:664 src/ui/playlist-dialog.vala:19\nmsgid \"Add to Playlist\"\nmsgstr \"加入播放清單\"\n\n#: src/ui/music-list.vala:671\nmsgid \"Remove\"\nmsgstr \"移除\"\n\n#: src/ui/music-widgets.vala:274 src/ui/music-widgets.vala:296\n#: src/ui/store-panel.vala:429\nmsgid \"Play\"\nmsgstr \"播放\"\n\n#: src/ui/music-widgets.vala:275 src/ui/music-widgets.vala:297\nmsgid \"_Random Play\"\nmsgstr \"隨機播放(_R)\"\n\n#: src/ui/music-widgets.vala:285\nmsgid \"Show List _File\"\nmsgstr \"顯示清單檔案(_F)\"\n\n#: src/ui/music-widgets.vala:308 src/ui/play-panel.vala:60\nmsgid \"Search Title\"\nmsgstr \"搜尋歌名\"\n\n#: src/ui/music-widgets.vala:309 src/ui/play-panel.vala:58\nmsgid \"Search Album\"\nmsgstr \"搜尋專輯\"\n\n#: src/ui/music-widgets.vala:310 src/ui/play-panel.vala:59\nmsgid \"Search Artist\"\nmsgstr \"搜尋藝術家\"\n\n#: src/ui/music-widgets.vala:314\nmsgid \"Show Cover _File\"\nmsgstr \"顯示封面檔案(_F)\"\n\n#: src/ui/music-widgets.vala:316\nmsgid \"_Export Cover\"\nmsgstr \"輸出封面(_E)\"\n\n#: src/ui/music-widgets.vala:317\nmsgid \"Show _Tags…\"\nmsgstr \"顯示標籤(_T)...\"\n\n#: src/ui/music-widgets.vala:318\nmsgid \"Show Music _File\"\nmsgstr \"顯示音樂檔案(_F)\"\n\n#. Translators: single loop the current music\n#: src/ui/play-bar.vala:72\nmsgid \"Single Loop\"\nmsgstr \"單曲迴圈\"\n\n#: src/ui/play-bar.vala:82\nmsgid \"Play Previous\"\nmsgstr \"播放上一首\"\n\n#. media-playback-pause-symbolic\n#: src/ui/play-bar.vala:88\nmsgid \"Play/Pause\"\nmsgstr \"播放/暫停\"\n\n#: src/ui/play-bar.vala:95\nmsgid \"Play Next\"\nmsgstr \"播放下一首\"\n\n#: src/ui/play-panel.vala:255\nmsgid \"\"\n\"Drag and drop music files here,\\n\"\n\"or change music location: \"\nmsgstr \"\"\n\"將音樂拖曳至這裡，\\n\"\n\"或者修改音樂庫位置：\"\n\n#: src/ui/playlist-dialog.vala:24\nmsgid \"New Playlist\"\nmsgstr \"新建播放清單\"\n\n#: src/ui/playlist-dialog.vala:98 src/ui/store-panel.vala:692\n#, c-format\nmsgid \"No playlist found in %s\"\nmsgstr \"在 %s 中找不到播放清單\"\n\n#: src/ui/preferences.vala:44 src/ui/preferences.vala:66\nmsgid \"Never\"\nmsgstr \"從不\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Always\"\nmsgstr \"總是\"\n\n#: src/ui/preferences.vala:44\nmsgid \"Art Only\"\nmsgstr \"僅封面\"\n\n#: src/ui/preferences.vala:66\nmsgid \"Track\"\nmsgstr \"曲目\"\n\n#: src/ui/store-panel.vala:84\nmsgid \"Playing\"\nmsgstr \"正在播放\"\n\n#: src/ui/store-panel.vala:89\nmsgid \"Artists\"\nmsgstr \"藝術家\"\n\n#: src/ui/store-panel.vala:94\nmsgid \"Albums\"\nmsgstr \"專輯\"\n\n#: src/ui/store-panel.vala:99\nmsgid \"Playlists\"\nmsgstr \"播放清單\"\n\n#: src/ui/taglist-dialog.vala:125\nmsgid \"Copy\"\nmsgstr \"複製\"\n\n#. Translators: Current volume percent: 0~100%\n#: src/ui/volume-button.vala:33\n#, c-format\nmsgid \"Volume %d%%\"\nmsgstr \"音量 %d%%\"\n\n#: src/ui/window.vala:112\nmsgid \"Show\"\nmsgstr \"顯示\"\n\n#: src/utils/music.vala:2\nmsgid \"Unknown Album\"\nmsgstr \"未知專輯\"\n\n#: src/utils/music.vala:3\nmsgid \"Unknown Artist\"\nmsgstr \"未知藝術家\"\n\n#~ msgid \"Play music\"\n#~ msgstr \"播放音樂\"\n\n#~ msgid \"Close\"\n#~ msgstr \"关闭\"\n\n#~ msgid \"Drag-drop from GNOME Files, showing music in Files.\"\n#~ msgstr \"從 GNOME 檔案拖放、顯示檔案中的音樂。\"\n\n#~ msgid \"Prefer dark theme\"\n#~ msgstr \"首選暗色主題\"\n\n#, fuzzy, c-format\n#~ msgid \"No playlist found in: %s\"\n#~ msgstr \"未找到播放清單\"\n"
  },
  {
    "path": "src/action-handles.vala",
    "content": "namespace G4 {\n\n    public const string ACTION_APP = \"app.\";\n    public const string ACTION_ABOUT = \"about\";\n    public const string ACTION_PREFS = \"preferences\";\n    public const string ACTION_ADD_TO_PLAYLIST = \"add-to-playlist\";\n    public const string ACTION_ADD_TO_QUEUE = \"add-to-queue\";\n    public const string ACTION_EXPORT_COVER = \"export-cover\";\n    public const string ACTION_PLAY = \"play\";\n    public const string ACTION_PLAY_AT_NEXT = \"play-at-next\";\n    public const string ACTION_PLAY_PAUSE = \"play-pause\";\n    public const string ACTION_PREV = \"prev\";\n    public const string ACTION_NEXT = \"next\";\n    public const string ACTION_RANDOM_PLAY = \"random-play\";\n    public const string ACTION_RELOAD = \"reload\";\n    public const string ACTION_REMOVE = \"remove\";\n    public const string ACTION_SAVE_LIST = \"save-list\";\n    public const string ACTION_SCHEME = \"scheme\";\n    public const string ACTION_SHOW_FILE = \"show-file\";\n    public const string ACTION_SHOW_TAGS = \"show-tags\";\n    public const string ACTION_SHOW_TAGS_CURRENT = \"show-cur-tags\";\n    public const string ACTION_SORT = \"sort\";\n    public const string ACTION_TOGGLE_SORT = \"toggle-sort\";\n    public const string ACTION_TRASH_FILE = \"trash-file\";\n    public const string ACTION_QUIT = \"quit\";\n\n    public const string ACTION_WIN = \"win.\";\n    public const string ACTION_BUTTON = \"button\";\n    public const string ACTION_SEARCH = \"search\";\n    public const string ACTION_SELECT = \"select\";\n    public const string ACTION_TOGGLE_SEARCH = \"toggle-search\";\n\n    struct ActionShortKey {\n        public unowned string name;\n        public unowned string key;\n    }\n\n    public class ActionHandles : Object {\n        private Application _app;\n        private Portal _portal = new Portal ();\n\n        public ActionHandles (Application app) {\n            _app = app;\n\n            ActionEntry[] action_entries = {\n                { ACTION_ABOUT, () => show_about_dialog (_app) },\n                { ACTION_ADD_TO_PLAYLIST, add_to_playlist, \"s\" },\n                { ACTION_ADD_TO_QUEUE, play_or_queue, \"s\" },\n                { ACTION_EXPORT_COVER, export_cover, \"s\" },\n                { ACTION_NEXT, () => _app.play_next () },\n                { ACTION_PLAY, play_or_queue, \"s\" },\n                { ACTION_PLAY_AT_NEXT, play_at_next, \"s\" },\n                { ACTION_PLAY_PAUSE, () => _app.play_pause () },\n                { ACTION_PREV, () => _app.play_previous () },\n                { ACTION_PREFS, show_preferences },\n                { ACTION_RANDOM_PLAY, play_or_queue, \"s\" },\n                { ACTION_RELOAD, () => _app.reload_library () },\n                { ACTION_SCHEME, scheme, \"s\", \"'0'\" },\n                { ACTION_SHOW_FILE, show_file, \"s\" },\n                { ACTION_SHOW_TAGS, show_tags, \"s\" },\n                { ACTION_SHOW_TAGS_CURRENT, show_tags },\n                { ACTION_SORT, sort_by, \"s\", \"'2'\" },\n                { ACTION_TOGGLE_SORT, toggle_sort },\n                { ACTION_TRASH_FILE, trash_file, \"s\" },\n                { ACTION_QUIT, () => _app.quit () }\n            };\n            app.add_action_entries (action_entries, this);\n\n            ActionShortKey[] app_keys = {\n                { ACTION_PREFS, \"<primary>comma\" },\n                { ACTION_PLAY_PAUSE, \"<primary>p\" },\n                { ACTION_PREV, \"<primary>Left\" },\n                { ACTION_NEXT, \"<primary>Right\" },\n                { ACTION_RELOAD, \"<primary>r\" },\n                { ACTION_SHOW_TAGS_CURRENT, \"<primary>t\" },\n                { ACTION_TOGGLE_SORT, \"<primary>m\" },\n                { ACTION_QUIT, \"<primary>q\" }\n            };\n            foreach (var item in app_keys) {\n                app.set_accels_for_action (ACTION_APP + item.name, {item.key});\n            }\n\n            ActionShortKey[] win_keys = {\n                { ACTION_SAVE_LIST, \"<primary>s\" },\n                { ACTION_TOGGLE_SEARCH, \"<primary>f\" },\n            };\n            foreach (var item in win_keys) {\n                app.set_accels_for_action (ACTION_WIN + item.name, {item.key});\n            }\n        }\n\n        public Portal portal {\n            get {\n                return _portal;\n            }\n        }\n\n        private async void _export_cover_async (Music music) {\n            var cover = _app.current_cover;\n            if (cover == null || music != _app.current_music) {\n                var file = File.new_for_uri (music.uri);\n                cover = yield run_async<Gst.Sample?> (() => {\n                    var tags = parse_gst_tags (file);\n                    return tags != null ? parse_image_from_tag_list ((!)tags) : null;\n                });\n            }\n            if (cover != null) {\n                var sample = (!)cover;\n                var itype = sample.get_caps ()?.get_structure (0)?.get_name ();\n                var pos = itype?.index_of_char ('/') ?? -1;\n                var ext = itype?.substring (pos + 1) ?? \"\";\n                var name = music.get_artist_and_title ().replace (\"/\", \"&\") + \".\" + ext;\n                var filter = new Gtk.FileFilter ();\n                filter.name = _(\"Image Files\");\n                filter.add_mime_type (\"image/*\");\n                var initial = File.new_build_filename (name);\n                var file = yield show_save_file_dialog (_app.active_window, initial, {filter});\n                if (file != null) {\n                    var saved = yield save_sample_to_file_async ((!)file, sample);\n                    (_app.active_window as Window)?.show_toast (\n                        saved ? _(\"Export cover successfully\") : _(\"Export cover failed\"), saved ? file?.get_uri () : (string?) null);\n                }\n            }\n        }\n\n        private void add_to_playlist (SimpleAction action, Variant? parameter) {\n            var uri = parameter?.get_string ();\n            var playlist = parse_playlist_from_music_uri (uri);\n            if (playlist != null) {\n                _app.show_add_playlist_dialog.begin ((!)playlist, (obj, res) => _app.show_add_playlist_dialog.end (res));\n            }\n        }\n\n        private void export_cover (SimpleAction action, Variant? parameter) {\n            var uri = parameter?.get_string ();\n            var music = uri != null ? _app.loader.find_cache ((!)uri) : null;\n            if (music != null)\n                _export_cover_async.begin ((!)music, (obj, res) => _export_cover_async.end (res));\n        }\n\n        private Playlist? parse_playlist_from_music_uri (string? uri) {\n            Music? node = null;\n            if (uri != null) {\n                string? ar = null, al = null, pl = null;\n                parse_library_uri ((!)uri, out ar, out al, out pl);\n                var loader = _app.loader;\n                var library = loader.library;\n                if (ar != null) {\n                    var artist = library.get_artist ((!)ar);\n                    if (artist != null && al != null && ((!)al).length > 0)\n                        node = ((!)artist)[(!)al];\n                    else\n                        node = artist;\n                } else if (al != null) {\n                    node = library.get_album ((!)al);\n                } else if (pl != null) {\n                    node = library.get_playlist ((!)pl);\n                } else {\n                    node = loader.find_cache ((!)uri);\n                }\n            }\n            return node != null ? to_playlist ({(!)node}) : (Playlist?) null;\n        }\n\n        private void play_or_queue (SimpleAction action, Variant? parameter) {\n            var uri = parameter?.get_string ();\n            if (action.name.has_suffix (ACTION_ADD_TO_QUEUE)) {\n                var playlist = parse_playlist_from_music_uri (uri);\n                if (playlist != null)\n                    _app.insert_to_queue ((!)playlist);\n            } else if (uri != null) {\n                Window.get_default ()?.open_page ((!)uri, true, action.name.has_suffix (ACTION_RANDOM_PLAY));\n            }\n        }\n\n        private void play_at_next (SimpleAction action, Variant? parameter) {\n            var uri = parameter?.get_string ();\n            var playlist = parse_playlist_from_music_uri (uri);\n            if (playlist != null)\n                _app.insert_after_current ((!)playlist);\n        }\n\n        private void scheme (SimpleAction action, Variant? state) {\n            uint scheme = 0;\n            if (uint.try_parse (state?.get_string () ?? \"\", out scheme))\n                _app.settings.set_uint (\"color-scheme\", scheme);\n        }\n\n        private void show_file (SimpleAction action, Variant? parameter) {\n            var uri = parameter?.get_string ();\n            if (uri != null) {\n                if (((!)uri).has_prefix (LIBRARY_SCHEME)) {\n                    Window.get_default ()?.open_page ((!)uri, false);\n                } else {\n                    _portal.open_directory_async.begin ((!)uri, (obj, res) => {\n                        try {\n                            _portal.open_directory_async.end (res);\n                        } catch (Error e) {\n                            Window.get_default ()?.show_toast (e.message);\n                        }\n                    });\n                }\n            }\n        }\n\n        private void show_tags (SimpleAction action, Variant? parameter) {\n            var uri = parameter?.get_string () ?? _app.current_music?.uri;\n            if (uri != null) {\n                var tags = strcmp (_app.current_music?.uri, uri) == 0 ? _app.player.tag_list : (Gst.TagList?) null;\n                var dialog = new TagListDialog ((!)uri, tags);\n                dialog.present (Window.get_default ());\n            }\n        }\n\n        private PreferencesWindow? _pref_window = null;\n\n        private void show_preferences () {\n            var win = _pref_window ?? new PreferencesWindow (_app);\n            _pref_window = win;\n            win.destroy_with_parent = true;\n            win.modal = false;\n            win.transient_for = _app.active_window;\n            win.close_request.connect (() => {\n                _pref_window = null;\n                return false;\n            });\n            win.present ();\n        }\n\n        private void sort_by (SimpleAction action, Variant? state) {\n            unowned var value = state?.get_string () ?? \"\";\n            int mode = 2;\n            if (int.try_parse (value, out mode))\n                _app.sort_mode = mode;\n        }\n\n        private void toggle_sort () {\n            if (_app.sort_mode >= SortMode.MAX)\n                _app.sort_mode = SortMode.ALBUM;\n            else\n                _app.sort_mode = _app.sort_mode + 1;\n        }\n\n        private void trash_file (SimpleAction action, Variant? parameter) {\n            var uri = parameter?.get_string ();\n            if (uri != null) {\n                _portal.trash_file_async.begin ((!)uri, (obj, res) => {\n                    try {\n                        if (_portal.trash_file_async.end (res)) {\n                            _app.loader.on_file_removed.begin (File.new_for_uri ((!)uri),\n                                (obj, res) => _app.loader.on_file_removed.end (res));\n                        }\n                    } catch (Error e) {\n                        Window.get_default ()?.show_toast (e.message);\n                    }\n                });\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/application.vala",
    "content": "namespace G4 {\n\n    public class Application : Adw.Application {\n        private ActionHandles? _actions = null;\n        private int _current_index = -1;\n        private uint _current_list_size = 0;\n        private Music? _current_music = null;\n        private string _current_uri = \"\";\n        private Gst.Sample? _current_cover = null;\n        private bool _list_modified = false;\n        private bool _loading = false;\n        private string _music_folder = \"\";\n        private uint _mpris_id = 0;\n        private MusicLoader _loader = new MusicLoader ();\n        private Gtk.FilterListModel _current_list = new Gtk.FilterListModel (null, null);\n        private ListStore _music_queue = new ListStore (typeof (Music));\n        private StringBuilder _next_uri = new StringBuilder ();\n        private GstPlayer _player = new GstPlayer ();\n        private Settings _settings;\n        private uint _sort_mode = SortMode.TITLE;\n        private bool _store_external_changed = false;\n        private Thumbnailer _thumbnailer = new Thumbnailer ();\n\n        public signal void index_changed (int index, uint size);\n        public signal void music_changed (Music? music);\n        public signal void music_cover_parsed (Music music, Gdk.Pixbuf? cover, string? cover_uri);\n        public signal void music_library_changed (bool external);\n        public signal void playlist_added (Playlist playlist);\n        public signal void thumbnail_changed (Music music, Gdk.Paintable paintable);\n\n        public Application () {\n            Object (application_id: Config.APP_ID, flags: ApplicationFlags.HANDLES_OPEN);\n        }\n\n        public override void startup () {\n            base.startup ();\n\n            //  Must load tag cache after the app register (GLib init), to make sort works\n            _loader.load_tag_cache ();\n\n            _actions = new ActionHandles (this);\n\n            _current_list.model = _music_queue;\n            _current_list.items_changed.connect (on_music_list_changed);\n            _music_queue.items_changed.connect (on_music_library_changed);\n            _loader.loading_changed.connect ((loading) => _loading = loading);\n            _loader.music_found.connect (on_music_found);\n            _loader.music_lost.connect (on_music_lost);\n\n            _thumbnailer.cover_finder = _loader.cover_cache;\n            _thumbnailer.tag_updated.connect (_loader.add_to_cache);\n\n            _player.end_of_stream.connect (on_player_end);\n            _player.error.connect (on_player_error);\n            _player.next_uri_request.connect (on_player_next_uri_request);\n            _player.next_uri_start.connect (on_player_next_uri_start);\n            _player.state_changed.connect (on_player_state_changed);\n            _player.tag_parsed.connect (on_player_tag_parsed);\n\n            _mpris_id = Bus.own_name (BusType.SESSION,\n                \"org.mpris.MediaPlayer2.\" + application_id,\n                BusNameOwnerFlags.NONE,\n                on_bus_acquired,\n                null, null\n            );\n            if (_mpris_id == 0)\n                warning (\"Initialize MPRIS session failed\\n\");\n\n            var settings = _settings = new Settings (application_id); \n            settings.bind (\"color-scheme\", this, \"color-scheme\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"music-dir\", this, \"music-folder\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"sort-mode\", this, \"sort-mode\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"monitor-changes\", _loader, \"monitor-changes\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"remote-thumbnail\", _thumbnailer, \"remote-thumbnail\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"gapless-playback\", _player, \"gapless\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"replay-gain\", _player, \"replay-gain\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"audio-sink\", _player, \"audio-sink\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"volume\", _player, \"volume\", SettingsBindFlags.DEFAULT);\n        }\n\n        public override void activate () {\n            base.activate ();\n\n            var window = Window.get_default ();\n            if (window != null) {\n                ((!)window).present ();\n            } else {\n                open ({}, \"\");\n            }\n        }\n\n        public override void open (File[] files, string hint) {\n            var window = Window.get_default ();\n            var initial = window == null;\n            (window ?? new Window (this))?.present ();\n\n            if (initial && _current_music == null) {\n                var folders = files;\n                folders.resize (folders.length + 1);\n                folders[folders.length - 1] = File.new_for_uri (music_folder);\n                var recent_uri = _current_music?.uri ?? _settings.get_string (\"recent-music\");\n                foreach (var file in folders) {\n                    if (recent_uri.has_prefix (file.get_uri ())) {\n                        // 1.Load recent played uri if in folders\n                        _current_music = new Music (recent_uri, \"\", 0);\n                        _player.uri = _current_uri = recent_uri;\n                        _player.state = Gst.State.PAUSED;\n                        break;\n                    }\n                }\n            }\n\n            var saved_modified = _list_modified;\n            var plist_file = get_playing_list_file ();\n            var load_plist = initial && files.length == 0;\n            var files_ref = load_plist ? new File[] { plist_file } : files;\n            // 2.Load last playing queue if no other files to load\n            open_files_async.begin (files_ref, -1, files.length > 0, (obj, res) => {\n                var ret = open_files_async.end (res);\n                if (ret) {\n                    _list_modified = saved_modified;\n                    if (load_plist)\n                        _loader.library.remove_playlist (plist_file.get_uri ());\n                }\n                if (initial) {\n                    // 3. Load music folder to build the library\n                    load_music_folder_async.begin ((obj, res)\n                        => load_music_folder_async.end (res));\n                }\n            });\n        }\n\n        public override void shutdown () {\n            _actions = null;\n            _loader.save_tag_cache ();\n            delete_cover_tmp_file_async.begin ((obj, res) => delete_cover_tmp_file_async.end (res));\n\n            if (_mpris_id != 0) {\n                Bus.unown_name (_mpris_id);\n                _mpris_id = 0;\n            }\n            base.shutdown ();\n        }\n\n        public uint color_scheme {\n            get {\n                return (uint) style_manager.color_scheme;\n            }\n            set {\n                var action = lookup_action (ACTION_SCHEME);\n                (action as SimpleAction)?.set_state (value.to_string ());\n                style_manager.color_scheme = (Adw.ColorScheme) value;\n            }\n        }\n\n        public unowned Gst.Sample? current_cover {\n            get {\n                return _current_cover;\n            }\n        }\n\n        public int current_item {\n            get {\n                return _current_index;\n            }\n            set {\n                if (value >= (int) _current_list.get_n_items ()) {\n                    value = Window.get_default ()?.open_next_playable_page () ?? value;\n                }\n                current_music = _current_list.get_item (value) as Music;\n                _current_index = value;\n                _current_list_size = _current_list.get_n_items ();\n                index_changed (value, _current_list_size);\n                update_next_item ();\n            }\n        }\n\n        public Gtk.FilterListModel current_list {\n            get {\n                return _current_list;\n            }\n            set {\n                if (_current_list != value) {\n                    _current_list.items_changed.disconnect (on_music_list_changed);\n                    _current_list = value;\n                    _current_list.items_changed.connect (on_music_list_changed);\n                    update_current_item ();\n                }\n            }\n        }\n\n        public Music? current_music {\n            get {\n                return _current_music;\n            }\n            set {\n                var playing = _current_music != null || _player.state == Gst.State.PLAYING;\n                if (_current_music != value || value == null) {\n                    _current_music = value;\n                    music_changed (value);\n                }\n                var uri = value?.uri ?? \"\";\n                if (_current_uri != uri) {\n                    _current_cover = null;\n                    _player.state = Gst.State.READY;\n                    _player.uri = _current_uri = uri;\n                    if (uri.length > 0)\n                        _player.state = playing ? Gst.State.PLAYING : Gst.State.PAUSED;\n                }\n                _settings.set_string (\"recent-music\", uri);\n            }\n        }\n\n        private Gtk.IconPaintable? _icon = null;\n\n        public Gtk.IconPaintable? icon {\n            get {\n                if (_icon == null) {\n                    var theme = Gtk.IconTheme.get_for_display (active_window.display);\n                    _icon = theme.lookup_icon (application_id, null, _cover_size,\n                        active_window.scale_factor, Gtk.TextDirection.NONE, Gtk.IconLookupFlags.FORCE_REGULAR);\n                }\n                return _icon;\n            }\n        }\n\n        public bool list_modified {\n            get {\n                return _list_modified;\n            }\n            set {\n                _list_modified = value;\n            }\n        }\n\n        public MusicLoader loader {\n            get {\n                return _loader;\n            }\n        }\n\n        public bool loading {\n            get {\n                return _loading;\n            }\n        }\n\n        public string music_folder {\n            get {\n                if (_music_folder.length == 0) {\n                    var path = ((string?) Environment.get_user_special_dir (UserDirectory.MUSIC)) ?? \"Music\";\n                    _music_folder = File.new_build_filename (path).get_uri ();\n                }\n                return _music_folder;\n            }\n            set {\n                if (_music_folder != value) {\n                    _music_folder = value;\n                    if (Window.get_default () != null)\n                        reload_library ();\n                }\n            }\n        }\n\n        public ListStore music_queue {\n            get {\n                return _music_queue;\n            }\n        }\n\n        public string name {\n            get {\n                return _(\"Gapless\");\n            }\n        }\n\n        public GstPlayer player {\n            get {\n                return _player;\n            }\n        }\n\n        public Settings settings {\n            get {\n                return _settings;\n            }\n        }\n\n        public bool single_loop { get; set; }\n\n        public uint sort_mode {\n            get {\n                return _sort_mode;\n            }\n            set {\n                var action = lookup_action (ACTION_SORT);\n                var state = new Variant.string (value.to_string ());\n                (action as SimpleAction)?.set_state (state);\n\n                if (_sort_mode != value) {\n                    _sort_mode = value;\n                    sort_music_store ((ListStore) _music_queue, value);\n                }\n            }\n        }\n\n        public Thumbnailer thumbnailer {\n            get {\n                return _thumbnailer;\n            }\n        }\n\n        public async bool add_playlist_to_file_async (Playlist playlist, bool append) {\n            var file = File.new_for_uri (playlist.list_uri);\n            var uris = new GenericArray<string> (1024);\n            var saved = yield run_async <bool> (() => {\n                string? title = null;\n                var map = new GenericSet<string> (str_hash, str_equal);\n                if (append) {\n                    title = load_playlist_file (file, uris);\n                    uris.foreach ((uri) => map.add (uri));\n                }\n                foreach (var music in playlist.items) {\n                    var uri = music.uri;\n                    if (!map.contains (uri))\n                        uris.add (uri);\n                }\n                var ret = save_playlist_file (file, uris, title ?? playlist.title);\n                if (ret) {\n                    //  Replace items if loaded from existing file\n                    playlist.clear ();\n                    foreach (var uri in uris) {\n                        var music = _loader.find_cache (uri);\n                        if (music != null)\n                            playlist.add_music ((!)music);\n                    }\n                    playlist.set_cover_uri ();\n                    if (title != null)\n                        playlist.set_title ((!)title);\n                }\n                return ret;\n            });\n            if (saved)\n                playlist_added (_loader.library.add_playlist (playlist));\n            else\n                Window.get_default ()?.show_toast (_(\"Save playlist failed\"));\n            return saved;\n        }\n\n        public int insert_after_current (Playlist playlist) {\n            uint position = _current_index;\n            if (_current_music != null && _music_queue.find ((!)_current_music, out position)) {\n                position++;\n            }\n            var changed = merge_items_to_store (_music_queue, playlist.items, ref position);\n            list_modified |= changed;\n            if (changed) {\n                update_current_item ();\n            }\n            return (int) position;\n        }\n\n        public bool insert_to_queue (Playlist playlist, uint position = -1, bool play_now = false) {\n            var changed = merge_items_to_store (_music_queue, playlist.items, ref position);\n            list_modified |= changed;\n            if (play_now) {\n                current_item = (int) position;\n                _player.play ();\n            } else if (changed) {\n                update_current_item ();\n            }\n            return changed;\n        }\n\n        public async void load_music_folder_async () {\n            var files = new File[] { File.new_for_uri (music_folder) };\n            var musics = new GenericArray<Music> (4096);\n            yield _loader.load_files_async (files, musics, false, false, _sort_mode);\n            _store_external_changed = true;\n            if (_music_queue.get_n_items () == 0) {\n                _music_queue.splice (0, _music_queue.get_n_items (), (Object[]) musics.data);\n            } else {\n                on_music_library_changed (0, 1, 1);\n            }\n            if (_current_music == null && _current_list.get_n_items () > 0) {\n                current_item = 0;\n            } else {\n                update_current_item ();\n            }\n        }\n\n        public async bool open_files_async (File[] files, uint position = -1, bool play_now = false) {\n            var playlist = new Playlist (\"\");\n            yield _loader.load_files_async (files, playlist.items);\n            return playlist.length > 0 && insert_to_queue (playlist, position, play_now || _current_music == null);\n        }\n\n        public void play_next () {\n            current_item++;\n            _player.play ();\n        }\n\n        public void play_pause() {\n            _player.playing = !_player.playing;\n        }\n\n        public void play_previous () {\n            current_item--;\n            _player.play ();\n        }\n\n        private bool _reloading = false;\n\n        public void reload_library () {\n            if (!_loading && !_reloading) {\n                _reloading = true;\n                var file = get_playing_list_file ();\n                file.delete_async.begin (Priority.DEFAULT, null, (obj, res) => {\n                    try {\n                        file.delete_async.end (res);\n                    } catch (Error e) {\n                    }\n                    _loader.remove_all ();\n                    load_music_folder_async.begin ((obj, res) => {\n                        load_music_folder_async.end (res);\n                        _reloading = false;\n                    });\n                });\n            }\n        }\n\n        public void request_background () {\n            var portal = _actions?.portal ?? new Portal ();\n            portal.request_background_async.begin (_(\"Keep playing after window closed\"),\n                (obj, res) => portal.request_background_async.end (res));\n        }\n\n        public async bool rename_playlist_async (Playlist playlist, string title) {\n            var file = File.new_for_uri (playlist.list_uri);\n            var uris = new GenericArray<string> (playlist.length);\n            playlist.items.foreach ((music) => uris.add (music.uri));\n            var saved = yield run_async<bool> (() => save_playlist_file (file, uris, title));\n            if (saved) {\n                playlist.set_title (title);\n                playlist_added (_loader.library.add_playlist (playlist));\n            }\n            return saved;\n        }\n\n        public async bool save_queue_to_file () {\n            var count = _music_queue.get_n_items ();\n            var uris = new GenericArray<string> (count);\n            for (var i = 0; i < count; i++) {\n                var music = (Music) _music_queue.get_item (i);\n                uris.add (music.uri);\n            }\n            var file = get_playing_list_file ();\n            var ret = yield run_async<bool> (() => save_playlist_file (file, uris, null, false), false, true);\n            if (ret)\n                _list_modified = false;\n            return ret;\n        }\n\n        public async void save_to_playlist_file_async (Playlist playlist) {\n            var uri = playlist.list_uri;\n            var file = File.new_for_uri (uri);\n            var append = uri.length == 0;\n            if (append) {\n                var filter = new Gtk.FileFilter ();\n                filter.name = _(\"Playlist Files\");\n                filter.add_mime_type (\"audio/x-mpegurl\");\n                filter.add_mime_type (\"audio/x-scpls\");\n                filter.add_mime_type (\"public.m3u-playlist\");\n                var initial = File.new_for_uri (music_folder).get_child (playlist.title + \".m3u\");\n                var file_new = yield show_save_file_dialog (active_window, initial, {filter});\n                if (file_new == null)\n                    return;\n                file = (!)file_new;\n                playlist.set_list_uri (file.get_uri ());\n                playlist.set_title (get_file_display_name (file));\n                _settings.set_string (\"recent-playlist\", playlist.list_uri);\n            }\n            var saved = yield add_playlist_to_file_async (playlist, append);\n            if (saved && append)\n                Window.get_default ()?.show_toast (_(\"Save playlist successfully\"), build_library_uri (null, playlist));\n        }\n\n        public async void show_add_playlist_dialog (Playlist playlist) {\n            var dialog = new PlaylistDialog (this);\n            var pls = yield dialog.choose (Window.get_default ());\n            if (pls != null) {\n                var list_uri = ((!)pls).list_uri;\n                if (list_uri.length > 0) {\n                    playlist.set_list_uri (list_uri);\n                    yield add_playlist_to_file_async (playlist, true);\n                } else {\n                    yield save_to_playlist_file_async (playlist);\n                }\n            }\n        }\n\n        private File? _cover_tmp_file = null;\n\n        private async void delete_cover_tmp_file_async () {\n            try {\n                if (_cover_tmp_file != null) {\n                    yield ((!)_cover_tmp_file).delete_async ();\n                    _cover_tmp_file = null;\n                }\n            } catch (Error e) {\n            }\n        }\n\n        private int find_music_item_by_uri (string uri) {\n            var music = _loader.find_cache (uri);\n            if (music != null) {\n                var index = find_item_in_model (_current_list, music, _current_index);\n                if (index != -1)\n                    return index;\n            }\n            var count = _current_list.get_n_items ();\n            for (var i = 0; i < count; i++) {\n                var m = (Music) _current_list.get_item (i);\n                if (m.uri == uri)\n                    return (int) i;\n            }\n            return -1;\n        }\n\n        private void on_bus_acquired (DBusConnection connection, string name) {\n            try {\n                connection.register_object (\"/org/mpris/MediaPlayer2\", new MprisPlayer (this, connection));\n                connection.register_object (\"/org/mpris/MediaPlayer2\", new MprisRoot (this));\n            } catch (Error e) {\n                warning (\"Register MPRIS failed: %s\\n\", e.message);\n            }\n        }\n\n        private void on_music_found (GenericArray<Music> arr) {\n            _store_external_changed = true;\n            if (arr.length > 0) {\n                _music_queue.splice (_music_queue.get_n_items (), 0, (Object[]) arr.data);\n            } else {\n                on_music_library_changed (0, 1, 1);\n            }\n        }\n\n        private uint _pending_mic_handler = 0;\n        private uint _pending_msc_handler = 0;\n\n        private void on_music_list_changed (uint position, uint removed, uint added) {\n            if (removed != 0 || added != 0) {\n                if (_pending_mic_handler != 0)\n                    Source.remove (_pending_mic_handler);\n                _pending_mic_handler = run_idle_once (() => {\n                    _pending_mic_handler = 0;\n                    update_current_item ();\n                }, Priority.LOW);\n            }\n        }\n\n        private void on_music_library_changed (uint position, uint removed, uint added) {\n            if (removed != 0 || added != 0) {\n                if (_pending_msc_handler != 0)\n                    Source.remove (_pending_msc_handler);\n                _pending_msc_handler = run_idle_once (() => {\n                    _pending_msc_handler = 0;\n                    music_library_changed (_store_external_changed);\n                    _store_external_changed = false;\n                }, Priority.LOW);\n            }\n        }\n\n        private void on_music_lost (GenericSet<Music> removed) {\n            _store_external_changed = true;\n            if (removed.length > 0) {\n                var arr = new GenericArray<Music> (removed.length);\n                removed.foreach ((music) => arr.add (music));\n                remove_items_from_store (_music_queue, arr);\n            } else {\n                on_music_library_changed (0, 1, 1);\n            }\n        }\n\n        private void on_player_end () {\n            if (_single_loop) {\n                _player.seek (0);\n                _player.play ();\n            } else {\n                current_item++;\n            }\n        }\n\n        private void on_player_error (Error err) {\n            Window.get_default ()?.show_toast (err.message);\n            if (!_player.gapless) {\n                on_player_end ();\n            }\n        }\n\n        private string? on_player_next_uri_request () {\n            //  This is NOT called in main UI thread\n            lock (_next_uri) {\n                if (!_single_loop)\n                    _current_uri = _next_uri.str;\n                //  next_uri_start will be received soon later\n                return _current_uri;\n            }\n        }\n\n        private void on_player_next_uri_start () {\n            //  Received after next_uri_request\n            on_player_end ();\n        }\n\n        private uint _inhibit_id = 0;\n\n        private void on_player_state_changed (Gst.State state) {\n            if (state == Gst.State.PLAYING && _inhibit_id == 0) {\n                _inhibit_id = this.inhibit (Window.get_default (), Gtk.ApplicationInhibitFlags.SUSPEND, _(\"Keep playing\"));\n            } else if (state != Gst.State.PLAYING && _inhibit_id != 0) {\n                this.uninhibit (_inhibit_id);\n                _inhibit_id = 0;\n            }\n        }\n\n        private int _cover_size = 360;\n\n        private async void on_player_tag_parsed (string? u, Gst.TagList? tags) {\n            var uri = u ?? \"\";\n            if (_current_music != null && _current_uri == uri) {\n                var music = _loader.find_cache (_current_uri) ?? (!)_current_music;\n                if (music != _current_music) {\n                    _current_music = music;\n                    music_changed (music);\n                } else if (music.has_unknown () && tags != null && music.from_gst_tags ((!)tags)) {\n                    _loader.add_to_cache (music);\n                    music_changed (music);\n                }\n\n                _current_cover = tags != null ? parse_image_from_tag_list ((!)tags) : null;\n                if (_current_cover == null && u != null) {\n                    _current_cover = yield run_async<Gst.Sample?> (() => {\n                        var file = File.new_for_uri ((!)uri);\n                        var t = parse_gst_tags (file);\n                        return t != null ? parse_image_from_tag_list ((!)t) : null;\n                    });\n                }\n\n                Gdk.Pixbuf? pixbuf = null;\n                var image = _current_cover;\n                if (_current_uri == uri) {\n                    var size = _cover_size * _thumbnailer.scale_factor;\n                    if (image != null) {\n                        pixbuf = yield run_async<Gdk.Pixbuf?> (\n                            () => load_clamp_pixbuf_from_sample ((!)image, size), true);\n                    }\n                    if (pixbuf == null) {\n                        pixbuf = yield _thumbnailer.load_directly_async (music, size);\n                    }\n                }\n\n                if (_current_uri == uri) {\n                    var cover_uri = music.cover_uri;\n                    if (cover_uri == null) {\n                        var dir = File.new_build_filename (Environment.get_user_cache_dir (), application_id);\n                        var name = Checksum.compute_for_string (ChecksumType.MD5, music.cover_key);\n                        var file = dir.get_child (name);\n                        cover_uri = file.get_uri ();\n                        if (image != null) {\n                            yield save_sample_to_file_async (file, (!)image);\n                        } else {\n                            var svg = _thumbnailer.create_music_text_svg (music);\n                            yield save_text_to_file_async (file, svg);\n                        }\n                        if (strcmp (cover_uri, _cover_tmp_file?.get_uri ()) != 0) {\n                            yield delete_cover_tmp_file_async ();\n                            _cover_tmp_file = file;\n                        }\n                    }\n                    if (_current_uri == uri) {\n                        music_cover_parsed (music, pixbuf, cover_uri);\n                    }\n                }\n\n                //  Update thumbnail cache if remote thumbnail not loaded\n                if (pixbuf != null && !(_thumbnailer.find (music) is Gdk.Texture)) {\n                    var minbuf = yield run_async<Gdk.Pixbuf?> (\n                        () => create_clamp_pixbuf ((!)pixbuf, Thumbnailer.ICON_SIZE * _thumbnailer.scale_factor)\n                    );\n                    if (minbuf != null) {\n                        var paintable = Gdk.Texture.for_pixbuf ((!)minbuf);\n                        _thumbnailer.put (music, paintable, true, Thumbnailer.ICON_SIZE);\n                        thumbnail_changed (music, paintable);\n                    }\n                }\n            }\n        }\n\n        private void update_current_item () {\n            var index = find_item_in_model (_current_list, _current_music, _current_index);\n            if (index == -1 && _current_music != null) {\n                unowned var uri = ((!)_current_music).uri;\n                index = find_music_item_by_uri (uri);\n                current_music = index != -1 ? _current_list.get_item (index) as Music : _loader.find_cache (uri);\n            }\n            var size = _current_list.get_n_items ();\n            if (_current_index != index || _current_list_size != size) {\n                _current_index = index;\n                _current_list_size = size;\n                index_changed (index, size);\n            }\n            update_next_item ();\n        }\n\n        private void update_next_item () {\n            var next_music = (Music?) _current_list.get_item (_current_index + 1);\n            lock (_next_uri) {\n                _next_uri.assign (next_music?.uri ?? \"\");\n            }\n        }\n    }\n\n    public File get_playing_list_file () {\n        var cache_dir = Environment.get_user_cache_dir ();\n        return File.new_build_filename (cache_dir, Config.APP_ID, PageName.PLAYING + \".m3u\");\n    }\n\n    public async bool save_sample_to_file_async (File file, Gst.Sample sample) {\n        var buffer = sample.get_buffer ();\n        Gst.MapInfo? info = null;\n        try {\n            var stream = yield file.replace_async (null, false, FileCreateFlags.NONE);\n            if (buffer?.map (out info, Gst.MapFlags.READ) ?? false) {\n                return yield stream.write_all_async (info?.data, Priority.DEFAULT, null, null);\n            }\n        } catch (Error e) {\n        } finally {\n            if (info != null)\n                buffer?.unmap ((!)info);\n        }\n        return false;\n    }\n\n    public async bool save_text_to_file_async (File file, string text) {\n        try {\n            var stream = yield file.replace_async (null, false, FileCreateFlags.NONE);\n            unowned uint8[] data = (uint8[])text;\n            var size = text.length;\n            return yield stream.write_all_async (data[0:size], Priority.DEFAULT, null, null);\n        } catch (Error e) {\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/config.vapi",
    "content": "[CCode (cprefix = \"\", lower_case_cprefix = \"\", cheader_filename = \"config.h\")]\nnamespace Config {\n    public const string APP_ID;\n    public const string CODE_NAME;\n    public const string VERSION;\n    public const string LOCALEDIR;\n}\n\n[CCode (cprefix = \"\")]\nnamespace GLib {\n    [CCode (cname = \"g_strndup\")]\n    public string strndup (char* str, size_t n);\n}\n"
  },
  {
    "path": "src/gresource.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gresources>\n  <gresource prefix=\"/com/github/neithern/g4music\">\n    <file alias=\"style.css\">gtk/style.css</file>\n    <file>gtk/help-overlay.ui</file>\n    <file>gtk/play-panel.ui</file>\n    <file>gtk/preferences.ui</file>\n    <file>gtk/store-panel.ui</file>\n  </gresource>\n</gresources>\n"
  },
  {
    "path": "src/gst/ape-demux.c",
    "content": "/* GStreamer APEv1/2 tag reader\n * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>\n * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Library General Public\n * License as published by the Free Software Foundation; either\n * version 2 of the License, or (at your option) any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Library General Public License for more details.\n *\n * You should have received a copy of the GNU Library General Public\n * License along with this library; if not, write to the\n * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,\n * Boston, MA 02110-1301, USA.\n */\n\n/**\n * SECTION:element-apedemux\n * @title: apedemux\n *\n * apedemux accepts data streams with APE tags at the start or at the end\n * (or both). The mime type of the data between the tag blocks is detected\n * using typefind functions, and the appropriate output mime type set on\n * outgoing buffers.\n *\n * The element is only able to read APE tags at the end of a stream from\n * a seekable stream, ie. when get_range mode is supported by the upstream\n * elements. If get_range operation is available, apedemux makes it available\n * downstream. This means that elements which require get_range mode, such as\n * wavparse or musepackdec, can operate on files containing APE tag\n * information.\n *\n * ## Example launch line\n * |[\n * gst-launch-1.0 -t filesrc location=file.mpc ! apedemux ! fakesink\n * ]| This pipeline should read any available APE tag information and output it.\n * The contents of the file inside the APE tag regions should be detected, and\n * the appropriate mime type set on buffers produced from apedemux.\n *\n */\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <gst/gst.h>\n\n#include <stdio.h>\n#include <string.h>\n\nstatic const struct _GstApeDemuxTagTableEntry\n{\n  const gchar *ape_tag;\n  const gchar *gst_tag;\n} tag_table[] = {\n  {\n  \"replaygain_track_gain\", GST_TAG_TRACK_GAIN}, {\n  \"replaygain_track_peak\", GST_TAG_TRACK_PEAK}, {\n  \"replaygain_album_gain\", GST_TAG_ALBUM_GAIN}, {\n  \"replaygain_album_peak\", GST_TAG_ALBUM_PEAK}, {\n  \"title\", GST_TAG_TITLE}, {\n  \"artist\", GST_TAG_ARTIST}, {\n  \"album\", GST_TAG_ALBUM}, {\n  \"composer\", GST_TAG_COMPOSER}, {\n  \"comment\", GST_TAG_COMMENT}, {\n  \"comments\", GST_TAG_COMMENT}, {\n  \"copyright\", GST_TAG_COPYRIGHT}, {\n  \"genre\", GST_TAG_GENRE}, {\n  \"isrc\", GST_TAG_ISRC}, {\n  \"disc\", GST_TAG_ALBUM_VOLUME_NUMBER}, {\n  \"disk\", GST_TAG_ALBUM_VOLUME_NUMBER}, {\n  \"discnumber\", GST_TAG_ALBUM_VOLUME_NUMBER}, {\n  \"disknumber\", GST_TAG_ALBUM_VOLUME_NUMBER}, {\n  \"track\", GST_TAG_TRACK_NUMBER}, {\n  \"tracknumber\", GST_TAG_TRACK_NUMBER}, {\n  \"year\", GST_TAG_DATE}, {\n  \"file\", GST_TAG_LOCATION}\n};\n\nstatic gboolean\nape_demux_get_gst_tag_from_tag (const gchar * ape_tag,\n    const gchar ** gst_tag, GType * gst_tag_type)\n{\n  gint i;\n\n  for (i = 0; i < G_N_ELEMENTS (tag_table); ++i) {\n    if (g_ascii_strcasecmp (tag_table[i].ape_tag, ape_tag) == 0) {\n      *gst_tag = tag_table[i].gst_tag;\n      *gst_tag_type = gst_tag_get_type (tag_table[i].gst_tag);\n      GST_LOG (\"Mapped APE tag '%s' to GStreamer tag '%s'\", ape_tag, *gst_tag);\n      return TRUE;\n    }\n  }\n\n  GST_WARNING (\"Could not map APE tag '%s' to a GStreamer tag\", ape_tag);\n  return FALSE;\n}\n\nGstTagList *\nape_demux_parse_tags (const guint8 * data, gint size)\n{\n  GstTagList *taglist = gst_tag_list_new_empty ();\n\n  GST_LOG (\"Reading tags from chunk of size %u bytes\", size);\n\n  /* get rid of header/footer */\n  if (size >= 32 && memcmp (data, \"APETAGEX\", 8) == 0) {\n    data += 32;\n    size -= 32;\n  }\n  if (size > 32 && memcmp (data + size - 32, \"APETAGEX\", 8) == 0) {\n    size -= 32;\n  }\n\n  /* read actual tags - at least 10 bytes for tag header */\n  while (size >= 10) {\n    guint len, n = 8;\n    gchar *tag, *val;\n    const gchar *gst_tag;\n    GType gst_tag_type;\n\n    /* find tag type and size */\n    len = GST_READ_UINT32_LE (data);\n    while (n < size && data[n] != 0x0)\n      n++;\n    if (n == size)\n      break;\n    g_assert (data[n] == 0x0);\n    n++;\n    if (size - n < len)\n      break;\n\n    /* If the tag is empty, skip to the next one */\n    if (len == 0)\n      goto next_tag;\n\n    /* read */\n    tag = g_strndup ((gchar *) data + 8, n - 9);\n    val = g_strndup ((gchar *) data + n, len);\n\n    GST_LOG (\"tag [%s], val[%s]\", tag, val);\n\n    /* special-case 'media' tag, could be e.g. \"CD 1/2\" */\n    if (g_ascii_strcasecmp (tag, \"media\") == 0) {\n      gchar *sp, *sp2;\n\n      g_free (tag);\n      tag = g_strdup (\"discnumber\");\n      /* get rid of the medium in front */\n      sp = strchr (val, ' ');\n      while (sp != NULL && (sp2 = strchr (sp + 1, ' ')) != NULL)\n        sp = sp2;\n      if (sp) {\n        memmove (val, sp + 1, strlen (sp + 1) + 1);\n      }\n    }\n\n    if (ape_demux_get_gst_tag_from_tag (tag, &gst_tag, &gst_tag_type)) {\n      GValue v = { 0, };\n\n      switch (gst_tag_type) {\n        case G_TYPE_INT:{\n          gint v_int;\n\n          if (sscanf (val, \"%d\", &v_int) == 1) {\n            g_value_init (&v, G_TYPE_INT);\n            g_value_set_int (&v, v_int);\n          }\n          break;\n        }\n        case G_TYPE_UINT:{\n          guint v_uint, count;\n\n          if (strcmp (gst_tag, GST_TAG_TRACK_NUMBER) == 0) {\n            gint dummy;\n\n            if (sscanf (val, \"%u\", &v_uint) == 1 && v_uint > 0) {\n              g_value_init (&v, G_TYPE_UINT);\n              g_value_set_uint (&v, v_uint);\n            }\n            GST_LOG (\"checking for track count: %s\", val);\n            /* might be 0/N or -1/N to specify that there is only a count */\n            if (sscanf (val, \"%d/%u\", &dummy, &count) == 2 && count > 0) {\n              gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,\n                  GST_TAG_TRACK_COUNT, count, NULL);\n            }\n          } else if (strcmp (gst_tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0) {\n            gint dummy;\n\n            if (sscanf (val, \"%u\", &v_uint) == 1 && v_uint > 0) {\n              g_value_init (&v, G_TYPE_UINT);\n              g_value_set_uint (&v, v_uint);\n            }\n            GST_LOG (\"checking for volume count: %s\", val);\n            /* might be 0/N or -1/N to specify that there is only a count */\n            if (sscanf (val, \"%d/%u\", &dummy, &count) == 2 && count > 0) {\n              gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,\n                  GST_TAG_ALBUM_VOLUME_COUNT, count, NULL);\n            }\n          } else if (sscanf (val, \"%u\", &v_uint) == 1) {\n            g_value_init (&v, G_TYPE_UINT);\n            g_value_set_uint (&v, v_uint);\n          }\n          break;\n        }\n        case G_TYPE_STRING:{\n          g_value_init (&v, G_TYPE_STRING);\n          g_value_set_string (&v, val);\n          break;\n        }\n        case G_TYPE_DOUBLE:{\n          gdouble v_double;\n          gchar *endptr;\n\n          /* floating point strings can be \"4,123\" or \"4.123\" depending on\n           * the locale. We need to be able to parse and read either version\n           * no matter what our current locale is */\n          g_strdelimit (val, \",\", '.');\n          v_double = g_ascii_strtod (val, &endptr);\n          if (endptr != val) {\n            g_value_init (&v, G_TYPE_DOUBLE);\n            g_value_set_double (&v, v_double);\n          }\n\n          break;\n        }\n        default:{\n          if (gst_tag_type == G_TYPE_DATE) {\n            gint v_int;\n\n            if (sscanf (val, \"%d\", &v_int) == 1) {\n              GDate *date = g_date_new_dmy (1, 1, v_int);\n\n              g_value_init (&v, G_TYPE_DATE);\n              g_value_take_boxed (&v, date);\n            }\n          } else {\n            GST_WARNING (\"Unhandled tag type '%s' for tag '%s'\",\n                g_type_name (gst_tag_type), gst_tag);\n          }\n          break;\n        }\n      }\n      if (G_VALUE_TYPE (&v) != 0) {\n        gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,\n            gst_tag, &v, NULL);\n        g_value_unset (&v);\n      }\n    }\n    GST_DEBUG (\"Read tag %s: %s\", tag, val);\n    g_free (tag);\n    g_free (val);\n\n    /* move data pointer */\n  next_tag:\n    size -= len + n;\n    data += len + n;\n  }\n\n  GST_DEBUG (\"Taglist: %\" GST_PTR_FORMAT, taglist);\n  return taglist;\n}\n"
  },
  {
    "path": "src/gst/gst-ext.h",
    "content": "#ifndef __GST_EXT_H__\n#define __GST_EXT_H__\n\n#include <gst/gst.h>\n\nG_BEGIN_DECLS\n\nGstTagList * ape_demux_parse_tags (const guint8 * data, gint size);\n\nG_END_DECLS\n\n#endif /* __GST_EXT_H__ */\n"
  },
  {
    "path": "src/gst/gst-ext.vapi",
    "content": "[CCode (cprefix = \"\", lower_case_cprefix = \"\")]\nnamespace GstExt {\n    [CCode (cheader_filename = \"gst-ext.h\")]\n    public static Gst.TagList ape_demux_parse_tags ([CCode (array_length_cname = \"size\", array_length_pos = 2.5, array_length_type = \"gsize\")] uint8[] data);\n}\n"
  },
  {
    "path": "src/gst/gst-player.vala",
    "content": "namespace G4 {\n\n    public class GstPlayer : Object {\n\n        public static void init (ref unowned string[]? args) {\n            Gst.init (ref args);\n        }\n\n        public static Gst.ClockTime from_second (double time) {\n            return (Gst.ClockTime) (time * Gst.SECOND);\n        }\n\n        public static double to_second (Gst.ClockTime time) {\n            return (double) time / Gst.SECOND;\n        }\n\n        public static void get_audio_sinks (GenericArray<Gst.ElementFactory> sinks) {\n            var caps = new Gst.Caps.simple (\"audio/x-raw\", \"format\", Type.STRING, \"S16LE\", null);\n            var list = Gst.ElementFactory.list_get_elements (Gst.ElementFactoryType.AUDIOVIDEO_SINKS, Gst.Rank.SECONDARY);\n            list = Gst.ElementFactory.list_filter (list, caps, Gst.PadDirection.SINK, false);\n            list.foreach ((factory) => sinks.add (factory));\n        }\n\n        private dynamic Gst.Pipeline? _pipeline = null;\n        private dynamic Gst.Element? _audio_sink = null;\n        private dynamic Gst.Element? _replay_gain = null;\n        private string _audio_sink_name = \"\";\n        private int _audio_sink_requested = 0;\n        private string? _current_uri = null;\n        private Gst.ClockTime _duration = Gst.CLOCK_TIME_NONE;\n        private Gst.ClockTime _position = Gst.CLOCK_TIME_NONE;\n        private int _last_error_code = 0;\n        private ulong _about_to_finish_id = 0;\n        private int _next_uri_requested = 0;\n        private double _last_peak = 0;\n        private LevelCalculator _peak_calculator = new LevelCalculator ();\n        private Gst.State _state = Gst.State.NULL;\n        private bool _seeking = false;\n        private Gst.TagList? _tag_list = null;\n        private uint _tag_handle = 0;\n        private bool _tag_parsed = false;\n        private uint _timer_handle = 0;\n        private unowned Thread<void> _main_thread = Thread<void>.self ();\n\n        public signal void duration_changed (Gst.ClockTime duration);\n        public signal void error (Error error);\n        public signal void end_of_stream ();\n        public signal void position_updated (Gst.ClockTime position);\n        public signal string? next_uri_request ();\n        public signal void next_uri_start ();\n        public signal void state_changed (Gst.State state);\n        public signal void tag_parsed (string? uri, Gst.TagList? tags);\n\n        public GstPlayer () {\n            uint major = 0, minor = 0, micro = 0, nano = 0;\n            Gst.version (out major, out minor, out micro, out nano);\n            if (major > 1 || (major == 1 && minor >= 24)) {\n                _pipeline = Gst.ElementFactory.make (\"playbin3\", \"player\") as Gst.Pipeline;\n                if (_pipeline != null)\n                    print (@\"Use playbin3\\n\");\n            }\n            if (_pipeline == null) {\n                _pipeline = Gst.ElementFactory.make (\"playbin\", \"player\") as Gst.Pipeline;\n            }\n            if (_pipeline != null) {\n                var pipeline = (!)_pipeline;\n                pipeline.async_handling = true;\n                pipeline.flags = 0x0022; // audio | native audio\n                pipeline.bind_property (\"volume\", this, \"volume\", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);\n                pipeline.get_bus ().add_watch (Priority.DEFAULT, bus_callback);\n            } else {\n                critical (\"Create playbin failed\\n\");\n            }\n        }\n\n        ~GstPlayer () {\n            if (_tag_handle != 0)\n                Source.remove (_tag_handle);\n            if (_timer_handle != 0)\n                Source.remove (_timer_handle);\n            _peak_calculator.clear ();\n            _pipeline?.set_state (Gst.State.NULL);\n        }\n\n        public bool gapless {\n            get {\n                return _about_to_finish_id != 0;\n            }\n            set {\n                if (_pipeline != null) {\n                    var pipeline = (!)_pipeline;\n                    if (_about_to_finish_id != 0) {\n                        pipeline.disconnect (_about_to_finish_id);\n                        _about_to_finish_id = 0;\n                    }\n                    if (value) {\n                        _about_to_finish_id = pipeline.about_to_finish.connect (on_stream_to_finish);\n                    }\n                }\n            }\n        }\n\n        public bool playing {\n            get {\n                return _state == Gst.State.PLAYING;\n            }\n            set {\n                state = _state == Gst.State.PLAYING ? Gst.State.PAUSED : Gst.State.PLAYING;\n            }\n        }\n\n        public Gst.State state {\n            get {\n                return _state;\n            }\n            set {\n                _pipeline?.set_state (value);\n            }\n        }\n\n        public string? uri {\n            get {\n                return _current_uri;\n            }\n            set {\n                _current_uri = value;\n                if (_pipeline != null) {\n                    ((!)_pipeline).uri = value;\n                    if (AtomicInt.compare_and_exchange (ref _audio_sink_requested, 1, 0))\n                        update_audio_sink ();\n                }\n            }\n        }\n\n        public string audio_sink {\n            get {\n                return _audio_sink_name;\n            }\n            set {\n                var sink_name = value;\n                if (sink_name.length == 0 || (Gst.ElementFactory.find (sink_name)?.get_rank () ?? Gst.Rank.NONE) <= Gst.Rank.MARGINAL) {\n                    var list = Gst.ElementFactory.list_get_elements (Gst.ElementFactoryType.AUDIOVIDEO_SINKS, Gst.Rank.PRIMARY);\n                    if (!list.is_empty ())\n                        sink_name = list.first ().data.name;\n                }\n                var sink = Gst.ElementFactory.make (sink_name, sink_name);\n                if (sink != null) {\n                    _audio_sink = sink;\n                    _audio_sink_name = value;\n                    ((!)_audio_sink).enable_last_sample = true;\n                }\n                if (_pipeline != null && _current_uri != null)\n                    update_audio_sink ();\n                else\n                    AtomicInt.set (ref _audio_sink_requested, 1);\n            }\n        }\n\n        public double peak {\n            get {\n                var value = _last_peak;\n                dynamic Gst.Element? sink = _audio_sink ?? _pipeline?.audio_sink;\n                if (sink != null) {\n                    dynamic Gst.Sample? sample = ((!)sink).last_sample;\n                    if (sample != null)\n                        _peak_calculator.calculate_sample ((!)sample, _position, ref value);\n                }\n                value = double.max (value, _last_peak >= 0.033 ? _last_peak - 0.033 : 0);\n                _last_peak = value;\n                return value;\n            }\n        }\n\n        public Gst.ClockTime position {\n            get {\n                return _position;\n            }\n            set {\n                seek (value);\n            }\n        }\n\n        public uint replay_gain {\n            get {\n                if (_replay_gain != null)\n                    return ((!)_replay_gain).album_mode ? 2 : 1;\n                return 0;\n            }\n            set {\n                _replay_gain = value != 0 ? Gst.ElementFactory.make (\"rgvolume\", \"gain\") : null;\n                if (_replay_gain != null)\n                    ((!)_replay_gain).album_mode = value == 2;\n                if (_pipeline != null && _current_uri != null)\n                    update_audio_sink ();\n                else\n                    AtomicInt.set (ref _audio_sink_requested, 1);\n            }\n        }\n\n        public Gst.TagList? tag_list {\n            get {\n                return _tag_list;\n            }\n        }\n\n        public double volume { get; set; }\n\n        public void play () {\n            _pipeline?.set_state (Gst.State.PLAYING);\n        }\n\n        public void pause () {\n            _pipeline?.set_state (Gst.State.PAUSED);\n        }\n\n        public void seek (Gst.ClockTime position) {\n            if (_pipeline != null && !_seeking) {\n                //  print (\"Seek: %g -> %g\\n\", to_second (_position), to_second (position));\n                _seeking = ((!)_pipeline).seek_simple (Gst.Format.TIME, Gst.SeekFlags.ACCURATE | Gst.SeekFlags.FLUSH, (int64) position);\n            }\n        }\n\n        private void emit_tag_parsed (uint delay = 0) {\n            if (_tag_handle != 0)\n                Source.remove (_tag_handle);\n            _tag_handle = run_timeout_once (delay, () => {\n                _tag_handle = 0;\n                _tag_parsed = true;\n                tag_parsed (_current_uri, _tag_list);\n            });\n        }\n\n        private bool bus_callback (Gst.Bus bus, Gst.Message message) {\n            unowned Thread<void> thread = Thread<void>.self ();\n            if (thread == _main_thread) {\n                on_bus_message (message);\n            } else {\n                message.ref ();\n                Idle.add (() => {\n                    on_bus_message (message);\n                    message.unref ();\n                    return false;\n                });\n                warning (\"Bus message not in main thread: %p, %s\\n\", thread, message.type.get_name ());\n            }\n            return true;\n        }\n\n        private void on_bus_message (Gst.Message message) {\n            switch (message.type) {\n                case Gst.MessageType.ASYNC_DONE:\n                    parse_position ();\n                    _seeking = false;\n                    break;\n\n                case Gst.MessageType.DURATION_CHANGED:\n                    parse_duration ();\n                    break;\n\n                case Gst.MessageType.STATE_CHANGED:\n                    if (message.src == (!)_pipeline) {\n                        Gst.State old = Gst.State.NULL, state = Gst.State.NULL, pend = Gst.State.NULL;\n                        message.parse_state_changed (out old, out state, out pend);\n                        on_state_changed (old, state);\n                    }\n                    break;\n\n                case Gst.MessageType.ERROR:\n                    Error err;\n                    string debug;\n                    message.parse_error (out err, out debug);\n                    print (@\"Player error: $(err.domain), $(err.code), $(err.message)\\n\");\n                    if (_last_error_code < err.code) {\n                        _last_error_code = err.code;\n                        error (err);\n                    }\n                    break;\n\n                case Gst.MessageType.EOS:\n                    end_of_stream ();\n                    break;\n\n                case Gst.MessageType.STREAM_START:\n                    on_stream_start ();\n                    if (!_tag_parsed) {\n                        emit_tag_parsed (50);\n                    }\n                    break;\n\n                case Gst.MessageType.TAG:\n                    Gst.TagList? tags = null;\n                    message.parse_tag (out tags);\n                    _tag_list = merge_tags (_tag_list, tags);\n                    if (!_tag_parsed) {\n                        emit_tag_parsed (tags_has_image (_tag_list) ? 0 : 50);\n                    }\n                    break;\n\n                default:\n                    break;\n            }\n        }\n\n        private void on_state_changed (Gst.State old, Gst.State state) {\n            if (old != state && _state != state) {\n                _state = state;\n                state_changed (state);\n                //  print (@\"State changed: $old -> $state\\n\");\n            }\n            if (_timer_handle == 0 && state == Gst.State.PLAYING) {\n                _timer_handle = Timeout.add (100, parse_position);\n            } else if (_timer_handle != 0 && state != Gst.State.PLAYING) {\n                Source.remove (_timer_handle);\n                _timer_handle = 0;\n            }\n        }\n\n        private void on_stream_start () {\n            _last_error_code = 0;\n            _peak_calculator.clear ();\n            _tag_list = null;\n            _tag_parsed = false;\n            if (AtomicInt.compare_and_exchange (ref _next_uri_requested, 1, 0)) {\n                next_uri_start ();\n            }\n            parse_duration ();\n            parse_position ();\n        }\n\n        private void on_stream_to_finish () {\n            var next_uri = next_uri_request ();\n            if (next_uri != null && ((!)next_uri).length > 0) {\n                AtomicInt.set (ref _next_uri_requested, 1);\n                uri = (!)next_uri;\n            }\n        }\n\n        private void parse_duration () {\n            if (((!)_pipeline).query_duration (Gst.Format.TIME, out _duration)) {\n                duration_changed (_duration);\n            } else {\n                _duration = Gst.CLOCK_TIME_NONE;\n            }\n        }\n\n        private bool parse_position () {\n            if (((!)_pipeline).query_position (Gst.Format.TIME, out _position)) {\n                position_updated (_position);\n            } else {\n                _position = Gst.CLOCK_TIME_NONE;\n            }\n            return true;\n        }\n\n        private Gst.Element? setup_audio_sink () {\n            dynamic Gst.Bin? sink_bin = Gst.ElementFactory.make (\"bin\", \"audio-sink-bin\") as Gst.Bin;\n\n            if (_replay_gain != null) {\n                (_replay_gain?.parent as Gst.Bin)?.remove_element ((!)_replay_gain);\n                sink_bin?.add ((!)_replay_gain);\n            }\n            print (@\"Enable ReplayGain: $(_replay_gain != null)\\n\");\n\n            if (_audio_sink != null) {\n                (_audio_sink?.parent as Gst.Bin)?.remove_element ((!)_audio_sink);\n                sink_bin?.add ((!)_audio_sink);\n                _replay_gain?.link ((!)_audio_sink);\n            }\n            print (\"Audio Sink: %s\\n\", _audio_sink?.name ?? \"\");\n\n            Gst.Pad? static_pad = (_replay_gain ?? _audio_sink)?.get_static_pad (\"sink\");\n            if (static_pad != null) {\n                sink_bin?.add_pad (new Gst.GhostPad (\"sink\", (!)static_pad));\n            } else {\n                (_audio_sink?.parent as Gst.Bin)?.remove_element ((!)_audio_sink);\n            }\n            return static_pad != null ? sink_bin : _audio_sink;\n        }\n\n        private void update_audio_sink () {\n            var pipeline = (!)_pipeline;\n            var saved_pos = _position;\n            var saved_state = _state;\n            pipeline.set_state (Gst.State.NULL);\n            pipeline.audio_sink = setup_audio_sink ();\n            if (saved_state != Gst.State.NULL) {\n                pipeline.set_state (saved_state);\n            }\n            if (saved_pos != Gst.CLOCK_TIME_NONE && saved_state >= Gst.State.PAUSED) {\n                Idle.add (() => {\n                    if (_state == saved_state) {\n                        seek (saved_pos);\n                        return false;\n                    }\n                    return _state != Gst.State.NULL;\n                }, Priority.LOW);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/gst/peak-calculator.vala",
    "content": "namespace G4 {\n\n    public class LevelCalculator {\n        struct Peak {\n            Gst.ClockTime time;\n            double peak;\n        }\n\n        private int _audio_channels = 2;\n        private int _audio_bps = 2;\n        private int _sample_bps = 2;\n        private unowned Gst.Caps? _last_caps = null;\n        private unowned Gst.ClockTime _last_sample_time = Gst.CLOCK_TIME_NONE;\n        private LevelCalculateFunc? _level_calculate = null;\n        private Queue<Peak?> _peaks = new Queue<Peak?> ();\n\n        public void clear () {\n            _last_sample_time = Gst.CLOCK_TIME_NONE;\n            _peaks.clear ();\n        }\n\n        public void calculate_sample (Gst.Sample sample, Gst.ClockTime position, ref double peak_value) {\n            var peak = Peak ();\n            peak.time = sample.get_segment ().position;\n            if (_last_sample_time != peak.time\n                    && calculate_peak_in_sample (sample, out peak.peak)) {\n                _peaks.push_tail (peak);\n                _last_sample_time = peak.time;\n            }\n            while (_peaks.length > 0) {\n                unowned var p = (!)_peaks.peek_head ();\n                if (p.time >= position) {\n                    peak_value = p.peak;\n                    _peaks.pop_head ();\n                } else {\n                    break;\n                }\n            }\n        }\n\n        private delegate void LevelCalculateFunc (uint8* data, uint num, uint channels, uint value_size, uint sample_size, out double nps);\n\n        private bool calculate_peak_in_sample (Gst.Sample sample, out double peak) {\n            peak = 0;\n\n            unowned var caps = sample.get_caps ();\n            if (_last_caps != caps || _level_calculate == null) {\n                unowned var st = caps?.get_structure (0);\n                st?.get_int (\"channels\", out _audio_channels);\n                if (_audio_channels == 0)\n                    return false;\n\n                unowned var format = st?.get_string (\"format\") ?? \"\";\n                switch (format) {\n                    case \"S8\":\n                        _audio_bps = _sample_bps = 1;\n                        _level_calculate = level_calculate_int;\n                        break;\n                    case \"S16LE\":\n                        _audio_bps = _sample_bps = 2;\n                        _level_calculate = level_calculate_int16;\n                        break;\n                    case \"S24LE\":\n                        _audio_bps = _sample_bps = 3;\n                        _level_calculate = level_calculate_int;\n                        break;\n                    case \"S24_32LE\":\n                        _audio_bps = 3;\n                        _sample_bps = 4;\n                        _level_calculate = level_calculate_int;\n                        break;\n                    case \"S32LE\":\n                        _audio_bps = _sample_bps = 4;\n                        _level_calculate = level_calculate_int;\n                        break;\n                    case \"F32LE\":\n                        _audio_bps = _sample_bps = 4;\n                        _level_calculate = level_calculate_float;\n                        break;\n                    case \"F64LE\":\n                        _audio_bps = _sample_bps = 8;\n                        _level_calculate = level_calculate_double;\n                        break;\n                    default:\n                        print (\"Unsupported sample format: %s\\n\", format);\n                        return false;\n                }\n                _last_caps = caps;\n            }\n\n            var channels = _audio_channels;\n            var bps = _audio_bps;\n            var sample_size = _sample_bps;\n            var block_size = channels * sample_size;\n            var buffer = sample.get_buffer ();\n            var size = buffer?.get_size () ?? 0;\n\n            Gst.MapInfo? map_info = null;\n            if (buffer?.map (out map_info, Gst.MapFlags.READ) ?? false) {\n                unowned uint8* p = ((!)map_info).data;\n                var num = (uint) (size / block_size);\n                double total_nps = 0;\n                for (var i = 0; i < channels; i++) {\n                    double nps = 0;\n                    _level_calculate (p + (sample_size * i), num, channels, bps, sample_size, out nps);\n                    total_nps += nps;\n                }\n                peak = double.min (total_nps / channels, 1);\n                buffer?.unmap ((!)map_info);\n                return true;\n            }\n            return false;\n        }\n    }\n\n    void level_calculate_double (uint8* data, uint num, uint channels, uint value_size, uint sample_size, out double nps) {\n        double peak = 0;\n        double* p = (double*)data;\n        for (uint i = 0; i < num; i += channels) {\n            double value = p[i] >= 0 ? p[i] : -p[i];\n            if (peak < value)\n                peak = value;\n        }\n        nps = peak * peak;\n    }\n\n    void level_calculate_float (uint8* data, uint num, uint channels, uint value_size, uint sample_size, out double nps) {\n        float peak = 0f;\n        float* p = (float*)data;\n        for (uint i = 0; i < num; i += channels) {\n            float value = p[i] >= 0 ? p[i] : -p[i];\n            if (peak < value)\n                peak = value;\n        }\n        nps = (double) peak * peak;\n    }\n\n    void level_calculate_int16 (uint8* data, uint num, uint channels, uint value_size, uint sample_size, out double nps) {\n        int16 peak = 0;\n        int16* p = (int16*)data;\n        for (uint i = 0; i < num; i += channels) {\n            int16 value = p[i] >= 0 ? p[i] : -p[i];\n            if (peak < value)\n                peak = value;\n        }\n        nps = (double) peak * peak / (((int64) 1) << (15 * 2));\n    }\n\n    void level_calculate_int (uint8* data, uint num, uint channels, uint value_size, uint sample_size, out double nps) {\n        int32 peak = 0;\n        uint block_size = channels * sample_size;\n        for (uint i = 0; i < num; i += channels) {\n            int32 value = 0;\n            uint8* p = (uint8*)&value + (4 - value_size);\n            for (uint j = 0; j < value_size; j++) {\n                p[j] = data[j];\n            }\n            data += block_size;\n            value = value >= 0 ? value : -value;\n            if (peak < value)\n                peak = value;\n        }\n        nps = (double) peak * peak / (((int64) 1) << (31 * 2));\n    }\n}"
  },
  {
    "path": "src/gst/tag-parser.vala",
    "content": "namespace G4 {\n\n    public static Gst.TagList? parse_gst_tags (File file) {\n        FileInputStream? fis = null;\n        try {\n            fis = file.read ();\n        } catch (Error e) {\n            return null;\n        }\n\n        Gst.TagList? tags = null;\n        var stream = new BufferedInputStream ((!)fis);\n        var head = new uint8[16];\n\n        //  Parse and merge all the leading tags as possible\n        while (true) {\n            try {\n                read_full (stream, head);\n                //  Try parse start tag: ID3v2 or APE\n                if (Memory.cmp (head, \"ID3\", 3) == 0) {\n                    var buffer = Gst.Buffer.new_wrapped_full (0, head, 0, head.length, null);\n                    var size = Gst.Tag.get_id3v2_tag_size (buffer);\n                    if (size > head.length) {\n                        var data = new_uint8_array (size);\n                        Memory.copy (data, head, head.length);\n                        read_full (stream, data[head.length:]);\n                        var buffer2 = Gst.Buffer.new_wrapped_full (0, data, 0, data.length, null);\n                        var tags2 = Gst.Tag.List.from_id3v2_tag (buffer2);\n                        tags = merge_tags (tags, tags2);\n                    }\n                } else if (Memory.cmp (head, \"APETAGEX\", 8) == 0) {\n                    seek_full (stream, 0, SeekType.SET);\n                    var size = read_uint32_le (head, 12) + 32;\n                    var data = new_uint8_array (size);\n                    Memory.copy (data, head, head.length);\n                    read_full (stream, data[head.length:]);\n                    var tags2 = GstExt.ape_demux_parse_tags (data);\n                    tags = merge_tags (tags, tags2);\n                } else {\n                    //  Parse by file container format\n                    if (Memory.cmp (head, \"fLaC\", 4) == 0) {\n                        seek_full (stream, - head.length);\n                        var tags2 = parse_flac_tags (stream);\n                        tags = merge_tags (tags, tags2);\n                    } else if (Memory.cmp (head, \"OggS\", 4) == 0) {\n                        seek_full (stream, - head.length);\n                        var tags2 = parse_ogg_tags (stream);\n                        tags = merge_tags (tags, tags2);\n                    } else if (Memory.cmp (head + 4, \"ftyp\", 4) == 0) {\n                        seek_full (stream, - head.length);\n                        var tags2 = parse_mp4_tags (stream);\n                        tags = merge_tags (tags, tags2);\n                    }\n                    // No ID3v2/APE any more, quit the loop\n                    break;\n                }\n            } catch (Error e) {\n                print (\"Parse begin tag %s: %s\\n\", file.get_parse_name (), e.message);\n                break;\n            }\n        }\n\n        if (tags_has_text (tags) || tags_has_image (tags)) {\n            return tags;\n        }\n\n        //  Parse and merge all the ending tags as possible\n        try {\n            var tags2 = parse_end_tags (stream);\n            tags = merge_tags (tags, tags2);\n        } catch (Error e) {\n            print (\"Parse end tag %s: %s\\n\", file.get_parse_name (), e.message);\n        }\n\n        if (tags != null) {\n            //  Fast parsing is done, just return\n            return tags;\n        }\n\n        //  Parse tags by Gstreamer demux/parse, it is slow\n        try {\n            var demux_name = get_demux_name_by_content (head);\n            if (demux_name != null) {\n                seek_full (stream, 0, SeekType.SET);\n                tags = parse_demux_tags (stream, (!)demux_name);\n            }\n        } catch (Error e) {\n            //  print (\"Parse demux %s: %s\\n\", file.get_parse_name (), e.message);\n        }\n        return tags;\n    }\n\n    public static bool tags_has_image (Gst.TagList? tags) {\n        if (tags == null)\n            return false;\n        var t = (!)tags;\n        return t.get_tag_size (Gst.Tags.IMAGE) > 0\n            || t.get_tag_size (Gst.Tags.PREVIEW_IMAGE) > 0;\n    }\n\n    public static bool tags_has_text (Gst.TagList? tags) {\n        if (tags == null)\n            return false;\n        var t = (!)tags;\n        return t.get_tag_size (Gst.Tags.ARTIST) > 0\n            || t.get_tag_size (Gst.Tags.TITLE) > 0;\n    }\n\n    public inline uint8[] new_uint8_array (uint size) throws Error {\n        if ((int) size <= 0 || size > 0xfffffff) // 28 bits\n            throw new IOError.INVALID_ARGUMENT (\"invalid size\");\n        return new uint8[size];\n    }\n\n    public inline void read_full (BufferedInputStream stream, uint8[] buffer) throws Error {\n        size_t bytes = 0;\n        if (! stream.read_all (buffer, out bytes) || bytes != buffer.length)\n            throw new IOError.FAILED (\"read_all\");\n    }\n\n    public inline void seek_full (BufferedInputStream stream, int64 offset, SeekType type = SeekType.CUR) throws Error {\n        if (! stream.seek (offset, type))\n            throw new IOError.FAILED (\"seek\");\n    }\n\n    public inline uint32 read_uint32_be (uint8[] data, uint pos = 0) {\n        return data[pos + 3]\n            | ((uint32) (data[pos+2]) << 8)\n            | ((uint32) (data[pos+1]) << 16)\n            | ((uint32) (data[pos]) << 24);\n    }\n\n    public inline uint32 read_uint32_le (uint8[] data, uint pos = 0) {\n        return data[pos]\n            | ((uint32) (data[pos+1]) << 8)\n            | ((uint32) (data[pos+2]) << 16)\n            | ((uint32) (data[pos+3]) << 24);\n    }\n\n    public inline uint32 read_decimal_uint (uint8[] data) {\n        uint32 n = 0;\n        for (var i = 0; i < data.length; i++) {\n            n = n * 10 + (data[i] - '0');\n        }\n        return n;\n    }\n\n    public static Gst.TagList? merge_tags (Gst.TagList? tags, Gst.TagList? tags2,\n                                            Gst.TagMergeMode mode = Gst.TagMergeMode.KEEP) {\n        return tags != null ? tags?.merge (tags2, mode) : tags2;\n    }\n\n    public static Gst.TagList? parse_end_tags (BufferedInputStream stream) throws Error {\n        var apev2_found = false;\n        var foot = new uint8[128];\n        Gst.TagList? tags = null;\n        seek_full (stream, 0, SeekType.END);\n        while (true) {\n            try {\n                //  Try parse end tag: ID3v1 or APE\n                seek_full (stream, -128);\n                read_full (stream, foot);\n                if (Memory.cmp (foot, \"TAG\", 3) == 0) {\n                    var tags2 = Gst.Tag.List.new_from_id3v1 (foot);\n                    tags = merge_tags (tags, tags2);\n                    //  print (\"ID3v1 parsed: %d\\n\", tags2.n_tags ());\n                    seek_full (stream, -128);\n                } else if (Memory.cmp (foot[128-32:], \"APETAGEX\", 8) == 0) {\n                    var size = read_uint32_le (foot, 128 - 32 + 12) + 32;\n                    seek_full (stream, - (int) size);\n                    var data = new_uint8_array (size);\n                    read_full (stream, data);\n                    var tags2 = GstExt.ape_demux_parse_tags (data);\n                    //  APEv2 is better than others, do REPLACE merge\n                    tags = merge_tags (tags, tags2, Gst.TagMergeMode.REPLACE);\n                    apev2_found = ! tags2.is_empty ();\n                    //  print (\"APEv2 parsed: %d\\n\", tags2.n_tags ());\n                    seek_full (stream, - (int) size);\n                } else if (Memory.cmp (foot[128-9:], \"LYRICS200\", 9) == 0) {\n                    var size = read_decimal_uint (foot[128-15:128-9]);\n                    seek_full (stream, - (int) (size + 15));\n                    var data = new_uint8_array (size);\n                    read_full (stream, data);\n                    var tags2 = parse_lyrics200_tags (data);\n                    tags = merge_tags (tags, tags2, apev2_found ? Gst.TagMergeMode.KEEP : Gst.TagMergeMode.REPLACE);\n                    //  print (\"LYRICS200 parsed: %d\\n\", tags2.n_tags ());\n                    seek_full (stream, - (int) (size + 15));\n                } else {\n                    break;\n                }\n            } catch (Error e) {\n                if (tags == null)\n                    throw e;\n                break;\n            }\n        }\n        return tags;\n    }\n\n    public static Gst.TagList? parse_flac_tags (BufferedInputStream stream) throws Error {\n        var head = new uint8[4];\n        read_full (stream, head);\n        if (Memory.cmp (head, \"fLaC\", 4) != 0) {\n            return null;\n        }\n        int flags = 0;\n        Gst.TagList? tags = null;\n        do {\n            try {\n                read_full (stream, head);\n                var type = head[0] & 0x7f;\n                var size = ((uint32) (head[1]) << 16) | ((uint32) (head[2]) << 8) | head[3];\n                //  print (\"FLAC block: %d, %u\\n\", type, size);\n                if (type == 4) {\n                    var data = new_uint8_array (size + 4);\n                    read_full (stream, data[4:]);\n                    head[0] &= (~0x80); // clear the is-last flag\n                    Memory.copy (data, head, 4);\n                    var tags2 = Gst.Tag.List.from_vorbiscomment (data, head, null);\n                    tags = merge_tags (tags, tags2);\n                    flags |= 0x01;\n                } else if (type == 6) {\n                    var data = new_uint8_array (size);\n                    read_full (stream, data);\n                    uint pos = 0;\n                    var img_type = read_uint32_be (data, pos);\n                    pos += 4;\n                    var img_mimetype_len = read_uint32_be (data, pos);\n                    pos += 4 + img_mimetype_len;\n                    if (pos + 4 > size) {\n                        break;\n                    }\n                    var img_description_len = read_uint32_be (data, pos);\n                    pos += 4 + img_description_len;\n                    pos += 4 * 4; // image properties\n                    if (pos + 4 > size) {\n                        break;\n                    }\n                    var img_len = read_uint32_be (data, pos);\n                    pos += 4;\n                    if (pos + img_len > size) {\n                        break;\n                    }\n                    tags = tags ?? new Gst.TagList.empty ();\n                    Gst.Tag.List.add_id3_image ((!)tags, data[pos:pos+img_len], img_type);\n                    flags |= 0x02;\n                } else {\n                    seek_full (stream, size);\n                }\n            } catch (Error e) {\n                if (tags == null)\n                    throw e;\n                break;\n            }\n        } while ((flags & 0x03) != 0x03);\n        return tags;\n    }\n\n    public const string[] ID3_TAG_ENCODINGS = {\n        \"GST_ID3V1_TAG_ENCODING\",\n        \"GST_ID3_TAG_ENCODING\",\n        \"GST_TAG_ENCODING\",\n        (string) null\n    };\n\n    public static Gst.TagList parse_lyrics200_tags (uint8[] data) {\n        var tags = new Gst.TagList.empty ();\n        if (Memory.cmp (data, \"LYRICSBEGIN\", 11) != 0) {\n            return tags;\n        }\n\n        var length = data.length;\n        var pos = 11;\n        while (pos + 8 < length) {\n            var id = data[pos:pos+3];\n            pos += 3;\n            var len = read_decimal_uint (data[pos:pos+5]);\n            pos += 5;\n            if (pos + len > length) {\n                break;\n            }\n            var str = data[pos:pos+len];\n            pos += (int) len;\n            string? tag = null;\n            if (Memory.cmp (id, \"EAL\", 3) == 0) {\n                tag = Gst.Tags.ALBUM;\n            } else if (Memory.cmp (id, \"EAR\", 3) == 0) {\n                tag = Gst.Tags.ARTIST;\n            } else if (Memory.cmp (id, \"ETT\", 3) == 0) {\n                tag = Gst.Tags.TITLE;\n            } else if (Memory.cmp (id, \"LYR\", 3) == 0) {\n                tag = Gst.Tags.LYRICS;\n            }\n            if (tag != null) {\n                var value = Gst.Tag.freeform_string_to_utf8 ((char[]) str, ID3_TAG_ENCODINGS);\n                if (value != (string)null && value.length > 0) {\n                    tags.add (Gst.TagMergeMode.REPLACE, (!)tag, value);\n                }\n            }\n        }\n        return tags;\n    }\n\n    private static void parse_mp4_date_value (uint8[] data, string tag, Gst.TagList tags) throws Error {\n        var str = parse_mp4_string (data);\n        if (str != null) {\n            var date = new Gst.DateTime.from_iso8601_string ((!)str);\n            tags.add (Gst.TagMergeMode.REPLACE, tag, date);\n            //  print (@\"Tag: $tag=$(date.get_year ())\\n\");\n        } else {\n            print (\"MP4: unknown date type: %s\\n\", str ?? \"\");\n        }\n    }\n\n    private static void parse_mp4_image_value (uint8[] data, string tag, Gst.TagList tags) throws Error {\n        var len = data.length;\n        if (len > 16) {\n            var type = read_uint32_be (data, 8);\n            if ((type == 0x0000000d || type == 0x0000000e)) {\n                var image_data = data[16:len];\n                Gst.Tag.ImageType image_type;\n                if (tags.get_tag_size (Gst.Tags.IMAGE) == 0)\n                    image_type = Gst.Tag.ImageType.FRONT_COVER;\n                else\n                    image_type = Gst.Tag.ImageType.NONE;\n                var sample = Gst.Tag.image_data_to_image_sample (image_data, image_type);\n                if (sample != (Gst.Sample)null) {\n                    tags.add (Gst.TagMergeMode.REPLACE, tag, sample);\n                }\n                //  print (@\"Tag: $tag=$(data.length)\\n\");\n            }\n        } else {\n            print (\"MP4: unknown image type\\n\");\n        }\n    }\n\n    private static void parse_mp4_number_value (uint8[] data, string tag1, string tag2, Gst.TagList tags) throws Error {\n        var len = data.length;\n        if (len >= 22) {\n            var type = read_uint32_be (data, 8);\n            if (type == 0x00000000) {\n                var n = read_uint32_be (data, 18);\n                var n1 = n >> 16;\n                var n2 = n & 0xffff;\n                if (n1 > 0) {\n                    tags.add (Gst.TagMergeMode.REPLACE, tag1, n1);\n                    //  print (@\"Tag: $tag1=$n1\\n\");\n                }\n                if (n2 > 0) {\n                    tags.add (Gst.TagMergeMode.REPLACE, tag2, n2);\n                    //  print (@\"Tag: $tag2=$n2\\n\");\n                }\n            }\n        } else {\n            print (\"MP4: unknown number type\\n\");\n        }\n    }\n\n    public const string[] MP4_TAG_ENCODINGS = {\n        \"GST_QT_TAG_ENCODING\",\n        \"GST_TAG_ENCODING\",\n        (string) null\n    };\n\n    private static string? parse_mp4_string (uint8[] data) throws Error {\n        var len = data.length;\n        if (len > 16) {\n            var type = read_uint32_be (data, 8);\n            if (type == 0x00000001) {\n                var str_data = data[16:len];\n                return (string?) Gst.Tag.freeform_string_to_utf8 ((char[]) str_data, MP4_TAG_ENCODINGS);\n            }\n        }\n        return null;\n    }\n\n    private static void parse_mp4_string_value (uint8[] data, string tag, Gst.TagList tags) throws Error {\n        var str = parse_mp4_string (data);\n        if (str != null && ((!)str).length > 0) {\n            var value = (!)str;\n            tags.add (Gst.TagMergeMode.REPLACE, tag, value);\n            //  print (@\"Tag: $tag=$value\\n\");\n        } else {\n            print (\"MP4: unknown string type\\n\");\n        }\n    }\n\n    private static uint find_mp4_data_child (uint8[] buffer, uint pos, uint end, uint32 fourcc) {\n        while (pos + 8 < end) {\n            var box_size = read_uint32_be (buffer, pos);\n            var box_type = read_uint32_be (buffer, pos + 4);\n            if (box_type == fourcc) {\n                return pos;\n            }\n            pos += box_size;\n        }\n        return end;\n    }\n\n    private static void parse_mp4_ilst_box (uint8[] buffer, Gst.TagList tags) throws Error {\n        var size = buffer.length;\n        uint pos = 0;\n        while (pos + 8 < size) {\n            var box_size = read_uint32_be (buffer, pos);\n            var box_type = read_uint32_be (buffer, pos + 4);\n            var box_end = pos + box_size;\n            var data_pos = find_mp4_data_child (buffer, pos + 8, box_end, 0x64617461); // data\n            if (box_size > 16 && data_pos != box_end) {\n                var data_size = read_uint32_be (buffer, data_pos);\n                var data = buffer[data_pos : data_pos + data_size];\n                switch (box_type) {\n                    case 0xa96e616du: // _nam\n                    case 0x7469746cu: // titl\n                        parse_mp4_string_value (data, Gst.Tags.TITLE, tags);\n                        break;\n                    case 0xa9415254u: // _ART\n                    case 0x70657266u: // perf\n                        parse_mp4_string_value (data, Gst.Tags.ARTIST, tags);\n                        break;\n                    case 0xa9616c62u: // _alb\n                    case 0x616c626du: // albm\n                        parse_mp4_string_value (data, Gst.Tags.ALBUM, tags);\n                        break;\n                    case 0xa9777274u: // _wrt\n                    case 0x61757468u: // auth\n                        parse_mp4_string_value (data, Gst.Tags.COMPOSER, tags);\n                        break;\n                    case 0xa9636d74u: // _cmt\n                    case 0xa9696e66u: // _inf\n                        parse_mp4_string_value (data, Gst.Tags.COMMENT, tags);\n                        break;\n                    case 0xa96c7972u: // _lyr\n                        parse_mp4_string_value (data, Gst.Tags.LYRICS, tags);\n                        break;\n                    case 0xa9646179u: // _day\n                    case 0x79727263u: // yrrc\n                        parse_mp4_date_value (data, Gst.Tags.DATE_TIME, tags);\n                        break;\n                    case 0x636f7672u: // covr\n                        parse_mp4_image_value (data, Gst.Tags.IMAGE, tags);\n                        break;\n                    case 0x64697363u: // disc\n                    case 0x6469736bu: // disk\n                        parse_mp4_number_value (data, Gst.Tags.ALBUM_VOLUME_NUMBER, Gst.Tags.ALBUM_VOLUME_COUNT, tags);\n                        break;\n                    case 0x74726b6eu: // trkn\n                        parse_mp4_number_value (data, Gst.Tags.TRACK_NUMBER, Gst.Tags.TRACK_COUNT, tags);\n                        break;\n                    default:\n                        break;\n                }\n            }\n            pos = box_end;\n        }\n    }\n\n    private static void parse_mp4_box (BufferedInputStream stream, Gst.TagList tags) throws Error {\n        var box_head = new uint8[8];\n        while (tags.is_empty ()) {\n            read_full (stream, box_head);\n            var box_size = read_uint32_be (box_head);\n            var box_type = read_uint32_be (box_head, 4);\n            if (box_size <= 8) {\n                continue;\n            } else if (box_type == 0x6d6f6f76) { // moov\n                parse_mp4_box (stream, tags);\n            } else if (box_type == 0x75647461) { // udta\n                parse_mp4_box (stream, tags);\n            } else if (box_type == 0x6d657461 && box_size > 16) { // meta\n                read_full (stream, box_head);\n                var v1 = read_uint32_be (box_head);\n                var v2 = read_uint32_be (box_head, 4);\n                if (v2 == 0x68646c72) { // hdlr\n                    seek_full (stream, -8);\n                    parse_mp4_box (stream, tags);\n                } else if (v1 == 0) {\n                    seek_full (stream, -4);\n                    parse_mp4_box (stream, tags);\n                }\n            } else if (box_type == 0x696c7374) { // ilst\n                var buffer = new_uint8_array (box_size - 8);\n                read_full (stream, buffer);\n                parse_mp4_ilst_box (buffer, tags);\n            } else {\n                seek_full (stream, box_size - 8);\n            }\n        }\n    }\n\n    public static Gst.TagList? parse_mp4_tags (BufferedInputStream stream) {\n        var tags = new Gst.TagList.empty ();\n        try {\n            parse_mp4_box (stream, tags);\n        } catch (Error e) {\n            print (\"Parse MP4 Error %s\\n\", e.message);\n        }\n        return tags.is_empty () ? (Gst.TagList?) null : tags;\n    }\n\n    public const string[] OGG_TAG_IDS = {\n        \"\\x03vorbis\",\n        \"\\x81kate\\0\\0\\0\\0\",\n        //  \"\\x81daala\",\n        \"\\x81theora\",\n        \"OpusTags\",\n        \"OVP80\\x02 \",\n    };\n\n    public static Gst.TagList? parse_ogg_tags (BufferedInputStream stream) throws Error {\n        var head = new uint8[27];\n        var mos = new MemoryOutputStream (null);\n        while (true) {\n            read_full (stream, head);\n            uint seg_count = head[26];\n            var last_page = seg_count == 0;\n            if (seg_count > 0) {\n                var segments = new_uint8_array (seg_count);\n                read_full (stream, segments);\n                uint page_size = 0;\n                for (var i = 0; i < seg_count; i++) {\n                    page_size += segments[i];\n                }\n                var buffer = new_uint8_array (page_size);\n                read_full (stream, buffer);\n                mos.write (buffer);\n                last_page = segments[seg_count - 1] != 255;\n            }\n\n            size_t size = 0;\n            if (last_page && (size = mos.get_data_size ()) > 0) {\n                var data = mos.get_data ()[0:size];\n                foreach (var id in OGG_TAG_IDS) {\n                    if (size > id.length && Memory.cmp (data, id, id.length) == 0) {\n                        return Gst.Tag.List.from_vorbiscomment (data, id.data, null);\n                    }\n                }\n                mos = new MemoryOutputStream (null);\n            }\n\n            if (seg_count == 0) {\n                break;\n            }\n        }\n        return null;\n    }\n\n    public static Gst.TagList? parse_demux_tags (BufferedInputStream stream, string demux_name) throws Error {\n        var str = @\"giostreamsrc name=src ! $(demux_name) ! fakesink sync=false\";\n        dynamic Gst.Pipeline? pipeline = Gst.parse_launch (str) as Gst.Pipeline;\n        dynamic Gst.Element? src = pipeline?.get_by_name (\"src\");\n        ((!)src).stream = stream;\n\n        if (pipeline?.set_state (Gst.State.PLAYING) == Gst.StateChangeReturn.FAILURE) {\n            throw new UriError.FAILED (\"change state failed\");\n        }\n\n        var bus = pipeline?.get_bus ();\n        bool quit = false;\n        Gst.TagList? tags = null;\n        do {\n            var message = bus?.timed_pop (Gst.SECOND * 5);\n            if (message == null)\n                break;\n            var msg = (!)message;\n            switch (msg.type) {\n                case Gst.MessageType.TAG:\n                    if (tags != null) {\n                        Gst.TagList? tags2 = null;\n                        msg.parse_tag (out tags2);\n                        tags = merge_tags (tags, tags2);\n                    } else {\n                        msg.parse_tag (out tags);\n                    }\n                    if (tags_has_text (tags) || tags_has_image (tags)) {\n                        quit = true;\n                    }\n                    break;\n\n                case Gst.MessageType.ERROR:\n                    Error err;\n                    string debug;\n                    ((!)msg).parse_error (out err, out debug);\n                    print (\"Parse error: %s, %s\\n\", err.message, debug);\n                    quit = true;\n                    break;\n\n                case Gst.MessageType.EOS:\n                    quit = true;\n                    break;\n\n                default:\n                    break;\n            }\n        } while (!quit);\n        pipeline?.set_state (Gst.State.NULL);\n        return tags;\n    }\n\n    private static string? get_demux_name_by_content (uint8[] head) {\n        uint8* p = head;\n        if (Memory.cmp (p, \"FORM\", 4) == 0 && (Memory.cmp (p + 8, \"AIFF\", 4) == 0 || Memory.cmp (p + 8, \"AIFC\", 4) == 0)) {\n            return \"aiffparse\";\n        //  } else if (Memory.cmp (p, \"fLaC\", 4) == 0) {\n        //      return \"flacparse\";\n        //  } else if (Memory.cmp (p + 4, \"ftyp\", 4) == 0) {\n        //      return \"qtdemux\";\n        //  } else if (Memory.cmp (p, \"OggS\", 4) == 0) {\n        //      return \"oggdemux\";\n        } else if (read_uint32_be (head) == 0x1A45DFA3) { // EBML_HEADER\n            return \"matroskademux\";\n        } else if (Memory.cmp (p, \"RIFF\", 4) == 0 && Memory.cmp (p + 8, \"WAVE\", 4) == 0) {\n            return \"wavparse\";\n        } else if (Memory.cmp (p, \"\\x30\\x26\\xB2\\x75\\x8E\\x66\\xCF\\x11\\xA6\\xD9\\x00\\xAA\\x00\\x62\\xCE\\x6C\", 16) == 0) {\n            return \"asfparse\";\n        }\n        return null;\n    }\n\n    public static void get_one_tag (Gst.TagList tags, string tag, GenericArray<string> values) {\n        var size = tags.get_tag_size (tag);\n        for (var i = 0; i < size; i++) {\n            var val = tags.get_value_index (tag, i);\n            if (val != null) {\n                var value = (!)val;\n                if (value.holds (typeof (string))) {\n                    values.add (value.get_string ());\n                } else if (value.holds (typeof (uint))) {\n                    values.add (value.get_uint ().to_string ());\n                } else if (value.holds (typeof (double))) {\n                    values.add (value.get_double ().to_string ());\n                } else if (value.holds (typeof (bool))) {\n                    values.add (value.get_boolean ().to_string ());\n                } else if (value.holds (typeof (Gst.DateTime))) {\n                    var date = (Gst.DateTime) value.get_boxed ();\n                    values.add (date.to_iso8601_string () ?? \"\");\n                }\n            }\n        }\n    }\n\n    public static Gst.Sample? parse_image_from_tag_list (Gst.TagList tags) {\n        Gst.Sample? sample = null;\n        if (tags.get_sample (Gst.Tags.IMAGE, out sample)) {\n            return sample;\n        }\n        if (tags.get_sample (Gst.Tags.PREVIEW_IMAGE, out sample)) {\n            return sample;\n        }\n\n        for (var i = 0; i < tags.n_tags (); i++) {\n            var tag = tags.nth_tag_name (i);\n            var value = tags.get_value_index (tag, 0);\n            sample = null;\n            if (value?.type () == typeof (Gst.Sample)\n                    && tags.get_sample (tag, out sample)) {\n                var caps = sample?.get_caps ();\n                if (caps != null) {\n                    return sample;\n                }\n                //  print (@\"unknown image tag: $(tag)\\n\");\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/gtk/help-overlay.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<interface>\n  <object class=\"GtkShortcutsWindow\" id=\"help_overlay\">\n    <property name=\"modal\">true</property>\n    <child>\n      <object class=\"GtkShortcutsSection\">\n        <property name=\"section-name\">shortcuts</property>\n        <property name=\"max-height\">10</property>\n        <child>\n          <object class=\"GtkShortcutsGroup\">\n            <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">General</property>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Show Shortcuts</property>\n                <property name=\"action-name\">win.show-help-overlay</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Preferences</property>\n                <property name=\"action-name\">app.preferences</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Quit</property>\n                <property name=\"action-name\">app.quit</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Show Tags</property>\n                <property name=\"action-name\">app.show-cur-tags</property>\n              </object>\n            </child>\n          </object>\n        </child>\n        <child>\n          <object class=\"GtkShortcutsGroup\">\n            <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Playback</property>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Play/Pause</property>\n                <property name=\"action-name\">app.play-pause</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Play Next</property>\n                <property name=\"action-name\">app.next</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Play Previous</property>\n                <property name=\"action-name\">app.prev</property>\n              </object>\n            </child>\n          </object>\n        </child>\n        <child>\n          <object class=\"GtkShortcutsGroup\">\n            <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Playlist</property>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Search</property>\n                <property name=\"action-name\">win.toggle-search</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Toggle Sort</property>\n                <property name=\"action-name\">app.toggle-sort</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Reload Library</property>\n                <property name=\"action-name\">app.reload</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"GtkShortcutsShortcut\">\n                <property name=\"title\" translatable=\"yes\" context=\"shortcut window\">Save List</property>\n                <property name=\"action-name\">win.save-list</property>\n              </object>\n            </child>\n          </object>\n        </child>\n      </object>\n    </child>\n  </object>\n</interface>"
  },
  {
    "path": "src/gtk/play-panel.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<interface>\n  <requires lib=\"gtk\" version=\"4.0\"/>\n  <template class=\"G4PlayPanel\" parent=\"GtkBox\">\n    <property name=\"orientation\">vertical</property>\n    <property name=\"hexpand\">true</property>\n    <child>\n      <object class=\"GtkHeaderBar\" id=\"header_bar\">\n        <property name=\"hexpand\">true</property>\n        <style>\n          <class name=\"flat\"/>\n        </style>\n        <child type=\"start\">\n          <object class=\"GtkButton\" id=\"back_btn\">\n            <property name=\"icon-name\">go-previous-symbolic</property>\n            <property name=\"tooltip-text\" translatable=\"yes\">Back</property>\n          </object>\n        </child>\n        <child type=\"start\">\n          <object class=\"GtkLabel\" id=\"index_label\">\n          <style>\n            <class name=\"dim-label\"/>\n          </style>\n          </object>\n        </child>\n        <child type=\"title\">\n          <object class=\"GtkLabel\">\n            <property name=\"visible\">false</property>\n          </object>\n        </child>\n        <child type=\"end\">\n          <object class=\"GtkMenuButton\" id=\"action_btn\">\n            <property name=\"icon_name\">view-more-symbolic</property>\n          </object>\n        </child>\n      </object>\n    </child>\n    <child>\n      <object class=\"GtkBox\" id=\"music_box\">\n        <property name=\"hexpand\">true</property>\n        <property name=\"vexpand\">true</property>\n        <property name=\"orientation\">vertical</property>\n        <child>\n          <object class=\"GtkImage\" id=\"music_cover\">\n            <property name=\"pixel_size\">256</property>\n            <property name=\"vexpand\">true</property>\n          </object>\n        </child>\n        <child>\n          <object class=\"GtkOverlay\">\n            <property name=\"margin_start\">16</property>\n            <property name=\"margin_end\">16</property>\n            <property name=\"margin_top\">8</property>\n            <child type=\"overlay\">\n              <object class=\"GtkLabel\" id=\"initial_label\">\n                <property name=\"halign\">center</property>\n                <property name=\"visible\">false</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"GtkBox\">\n                <property name=\"orientation\">vertical</property>\n                <child>\n                  <object class=\"G4StableLabel\" id=\"music_title\">\n                    <property name=\"halign\">center</property>\n                    <property name=\"marquee\">true</property>\n                    <style>\n                      <class name=\"title-large\"/>\n                    </style>\n                  </object>\n                </child>\n                <child>\n                  <object class=\"G4StableLabel\" id=\"music_artist\">\n                    <property name=\"halign\">center</property>\n                    <property name=\"margin_top\">2</property>\n                    <property name=\"marquee\">true</property>\n                    <style>\n                      <class name=\"dim-label\"/>\n                    </style>\n                  </object>\n                </child>\n                <child>\n                  <object class=\"G4StableLabel\" id=\"music_album\">\n                    <property name=\"halign\">center</property>\n                    <property name=\"marquee\">true</property>\n                    <style>\n                      <class name=\"dim-label\"/>\n                    </style>\n                  </object>\n                </child>\n              </object>\n            </child>\n          </object>\n        </child>\n      </object>\n    </child>\n  </template>\n</interface>"
  },
  {
    "path": "src/gtk/preferences.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<interface>\n  <requires lib=\"gtk\" version=\"4.0\"/>\n  <template class=\"G4PreferencesWindow\" parent=\"AdwPreferencesWindow\">\n    <property name=\"default-width\">480</property>\n    <child>\n      <object class=\"AdwPreferencesPage\">\n        <child>\n          <object class=\"AdwPreferencesGroup\">\n            <property name=\"title\" translatable=\"yes\">General</property>\n            <child>\n              <object class=\"AdwComboRow\" id=\"blur_row\">\n                <property name=\"icon-name\">view-dual-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Background blur mode</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"AdwActionRow\">\n                <property name=\"icon-name\">view-list-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Compact playlist view</property>\n                <property name=\"activatable_widget\">compact_btn</property>\n                <child>\n                  <object class=\"GtkSwitch\" id=\"compact_btn\">\n                    <property name=\"valign\">center</property>\n                  </object>\n                </child>\n              </object>\n            </child>\n            <child>\n              <object class=\"AdwActionRow\">\n                <property name=\"icon-name\">view-grid-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Grid view for artists/albums</property>\n                <property name=\"activatable_widget\">grid_btn</property>\n                <child>\n                  <object class=\"GtkSwitch\" id=\"grid_btn\">\n                    <property name=\"valign\">center</property>\n                  </object>\n                </child>\n              </object>\n            </child>\n             <child>\n              <object class=\"AdwActionRow\">\n                <property name=\"icon-name\">input-mouse-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Single click to activate item</property>\n                <property name=\"activatable_widget\">single_btn</property>\n                <child>\n                  <object class=\"GtkSwitch\" id=\"single_btn\">\n                    <property name=\"valign\">center</property>\n                  </object>\n                </child>\n              </object>\n            </child>\n            <child>\n              <object class=\"AdwActionRow\">\n                <property name=\"icon-name\">media-playback-start-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Keep playing after window closed</property>\n                <property name=\"activatable_widget\">playbkgnd_btn</property>\n                <child>\n                  <object class=\"GtkSwitch\" id=\"playbkgnd_btn\">\n                    <property name=\"valign\">center</property>\n                  </object>\n                </child>\n              </object>\n            </child>\n          </object>\n        </child>\n        <child>\n          <object class=\"AdwPreferencesGroup\">\n          <property name=\"title\" translatable=\"yes\">Library</property>\n            <child>\n              <object class=\"AdwActionRow\">\n                <property name=\"icon-name\">folder-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Load music from folder</property>\n                <property name=\"activatable_widget\">music_dir_btn</property>\n                <child>\n                  <object class=\"GtkButton\" id=\"music_dir_btn\">\n                    <property name=\"valign\">center</property>\n                  </object>\n                </child>\n              </object>\n            </child>\n            <child>\n              <object class=\"AdwActionRow\">\n                <property name=\"icon-name\">software-update-available-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Monitor local file changes</property>\n                <property name=\"activatable_widget\">monitor_btn</property>\n                <child>\n                  <object class=\"GtkSwitch\" id=\"monitor_btn\">\n                    <property name=\"valign\">center</property>\n                  </object>\n                </child>\n              </object>\n            </child>\n            <child>\n              <object class=\"AdwActionRow\">\n                <property name=\"icon-name\">folder-remote-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Load thumbnails for non-local files</property>\n                <property name=\"subtitle\" translatable=\"yes\">May cause slowdowns and excess network usage</property>\n                <property name=\"activatable_widget\">thumbnail_btn</property>\n                <child>\n                  <object class=\"GtkSwitch\" id=\"thumbnail_btn\">\n                    <property name=\"valign\">center</property>\n                  </object>\n                </child>\n              </object>\n            </child>\n          </object>\n        </child>\n        <child>\n          <object class=\"AdwPreferencesGroup\">\n          <property name=\"title\" translatable=\"yes\">Playback</property>\n            <child>\n              <object class=\"AdwExpanderRow\" id=\"peak_row\">\n                <property name=\"icon-name\">edit-select-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Show audio peak level</property>\n              \t<property name=\"show-enable-switch\">true</property>\n                <child>\n                  <object class=\"AdwActionRow\">\n                    <property name=\"title\" translatable=\"yes\">Display characters</property>\n                    <child>\n                      <object class=\"GtkEntry\" id=\"peak_entry\">\n                        <property name=\"margin-top\">4</property>\n                        <property name=\"margin-bottom\">4</property>\n                        <property name=\"max-length\">4</property>\n                      </object>\n                    </child>\n                  </object>\n                </child>\n              </object>\n            </child>\n            <child>\n              <object class=\"AdwActionRow\">\n                <property name=\"icon-name\">object-rotate-right-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Rotate album cover</property>\n                <property name=\"activatable_widget\">rotate_btn</property>\n                <child>\n                  <object class=\"GtkSwitch\" id=\"rotate_btn\">\n                    <property name=\"valign\">center</property>\n                  </object>\n                </child>\n              </object>\n            </child>\n            <child>\n              <object class=\"AdwActionRow\">\n                <property name=\"icon-name\">media-playlist-repeat-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Enable gapless playback</property>\n                <property name=\"activatable_widget\">gapless_btn</property>\n                <child>\n                  <object class=\"GtkSwitch\" id=\"gapless_btn\">\n                    <property name=\"valign\">center</property>\n                  </object>\n                </child>\n              </object>\n            </child>\n            <child>\n              <object class=\"AdwComboRow\" id=\"replaygain_row\">\n                <property name=\"icon-name\">audio-volume-high-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Normalize volume with ReplayGain</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"AdwComboRow\" id=\"audiosink_row\">\n                <property name=\"icon-name\">audio-card-symbolic</property>\n                <property name=\"title\" translatable=\"yes\">Prefer audio sink of GStreamer</property>\n              </object>\n            </child>\n          </object>\n        </child>\n      </object>\n    </child>\n  </template>\n</interface>\n"
  },
  {
    "path": "src/gtk/store-panel.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<interface>\n  <requires lib=\"gtk\" version=\"4.0\"/>\n  <template class=\"G4StorePanel\" parent=\"GtkBox\">\n    <property name=\"orientation\">vertical</property>\n    <property name=\"hexpand\">true</property>\n    <child>\n      <object class=\"GtkHeaderBar\" id=\"header_bar\">\n        <property name=\"hexpand\">true</property>\n        <style>\n          <class name=\"flat\"/>\n        </style>\n        <child type=\"title\">\n          <object class=\"GtkLabel\">\n            <property name=\"visible\">false</property>\n          </object>\n        </child>\n        <child type=\"start\">\n          <object class=\"GtkMenuButton\">\n            <property name=\"icon_name\">open-menu-symbolic</property>\n            <property name=\"menu_model\">primary_menu</property>\n            <property name=\"primary\">true</property>\n            <property name=\"tooltip-text\" translatable=\"yes\">Main Menu</property>\n          </object>\n        </child>\n        <child type=\"start\">\n          <object class=\"GtkToggleButton\" id=\"search_btn\">\n            <property name=\"icon_name\">edit-find-symbolic</property>\n            <property name=\"active\" bind-source=\"search_bar\" bind-property=\"search_mode_enabled\" bind-flags=\"bidirectional\"/>\n            <property name=\"tooltip-text\" translatable=\"yes\">Search</property>\n          </object>\n        </child>\n        <child type=\"start\">\n          <object class=\"GtkBox\">\n            <property name=\"orientation\">horizontal</property>\n            <property name=\"width-request\">52</property>\n            <child>\n              <object class=\"GtkMenuButton\" id=\"sort_btn\">\n                <property name=\"menu_model\">sort_menu</property>\n                <property name=\"tooltip-text\" translatable=\"yes\">Sort By</property>\n              </object>\n            </child>\n            <child>\n              <object class=\"GtkLabel\" id=\"indicator\">\n                <property name=\"label\">•</property>\n                <property name=\"margin-start\">4</property>\n                <property name=\"visible\">false</property>\n              </object>\n            </child>\n          </object>\n        </child>\n      </object>\n    </child>\n    <child>\n      <object class=\"GtkSearchBar\" id=\"search_bar\">\n        <child>\n          <object class=\"GtkSearchEntry\" id=\"search_entry\">\n            <property name=\"hexpand\">true</property>\n          </object>\n        </child>\n      </object>\n    </child>\n    <child>\n      <object class=\"GtkStack\" id=\"stack_view\">\n      </object>\n    </child>\n  </template>\n\n  <menu id=\"primary_menu\">\n    <submenu>\n      <attribute name=\"label\" translatable=\"yes\">_Color Scheme</attribute>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">_System</attribute>\n        <attribute name=\"action\">app.scheme</attribute>\n        <attribute name=\"target\">0</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">_Light</attribute>\n        <attribute name=\"action\">app.scheme</attribute>\n        <attribute name=\"target\">1</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">_Dark</attribute>\n        <attribute name=\"action\">app.scheme</attribute>\n        <attribute name=\"target\">4</attribute>\n      </item>\n    </submenu>\n    <section>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">_Reload Library</attribute>\n        <attribute name=\"action\">app.reload</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">_Multiple Select</attribute>\n        <attribute name=\"action\">win.select</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">_Save List</attribute>\n        <attribute name=\"action\">win.save-list</attribute>\n      </item>\n    </section>\n    <section>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">_Preferences</attribute>\n        <attribute name=\"action\">app.preferences</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">_Keyboard Shortcuts</attribute>\n        <attribute name=\"action\">win.show-help-overlay</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">_About</attribute>\n        <attribute name=\"action\">app.about</attribute>\n      </item>\n    </section>\n  </menu>\n\n  <menu id=\"sort_menu\">\n    <section>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">Album</attribute>\n        <attribute name=\"action\">app.sort</attribute>\n        <attribute name=\"target\">0</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">Artist</attribute>\n        <attribute name=\"action\">app.sort</attribute>\n        <attribute name=\"target\">1</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">Artist/Album</attribute>\n        <attribute name=\"action\">app.sort</attribute>\n        <attribute name=\"target\">2</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">Title</attribute>\n        <attribute name=\"action\">app.sort</attribute>\n        <attribute name=\"target\">3</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">Recent</attribute>\n        <attribute name=\"action\">app.sort</attribute>\n        <attribute name=\"target\">4</attribute>\n      </item>\n      <item>\n        <attribute name=\"label\" translatable=\"yes\">Shuffle</attribute>\n        <attribute name=\"action\">app.sort</attribute>\n        <attribute name=\"target\">5</attribute>\n      </item>\n    </section>\n  </menu>\n</interface>"
  },
  {
    "path": "src/gtk/style.css",
    "content": "\n.title-large {\n    font-size: 115%;\n    font-weight: 550;\n}\n\n.title-leading {\n    font-weight: 500;\n}\n\n.title-secondly {\n    font-size: 92.5%;\n}\n\ngridview child {\n    margin: 2px;\n    padding: 0px;\n}\n\nsearchbar revealer box {\n    box-shadow: none;\n    background-color: transparent;\n}\n\ntabbar revealer box {\n    box-shadow: none;\n    background-color: transparent;\n}\n"
  },
  {
    "path": "src/main.vala",
    "content": "/* \n * Copyright 2022 Nanling\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\nint main (string[] args) {\n    Intl.bindtextdomain (Config.CODE_NAME, Config.LOCALEDIR);\n    Intl.bind_textdomain_codeset (Config.CODE_NAME, \"UTF-8\");\n    Intl.textdomain (Config.CODE_NAME);\n\n    Environment.set_prgname (Config.APP_ID);\n    Environment.set_application_name (_(\"Gapless\"));\n    fix_gst_tag_encoding ();\n\n    Random.set_seed ((uint32) get_monotonic_time ());\n\n    G4.GstPlayer.init (ref args);\n\n    var app = new G4.Application ();\n    return app.run (args);\n}\n\nvoid fix_gst_tag_encoding () {\n    unowned var encoding = Environment.get_variable (\"GST_TAG_ENCODING\");\n    unowned var lang = Environment.get_variable (\"LANG\");\n    if (encoding == null && lang != null) {\n        string[] lang_encodings = {\n            \"ja\", \"Shift_JIS\",\n            \"ko\", \"EUC-KR\",\n            \"zh_CN\", \"GB18030\",\n            \"zh_HK\", \"BIG5HKSCS\",\n            \"zh_SG\", \"GB2312\",\n            \"zh_TW\", \"BIG5\",\n        };\n        for (var i = 0; i < lang_encodings.length; i += 2) {\n            if (((!)lang).has_prefix (lang_encodings[i])) {\n                Environment.set_variable (\"GST_TAG_ENCODING\", lang_encodings[i + 1], true);\n                print (\"Fix tag encoding: %s\\n\", lang_encodings[i + 1]);\n                break;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/meson.build",
    "content": "\nsources = [\n  'action-handles.vala',\n  'application.vala',\n  'config.vapi',\n  'main.vala',\n  'gst/ape-demux.c',\n  'gst/gst-player.vala',\n  'gst/peak-calculator.vala',\n  'gst/tag-parser.vala',\n  'ui/dialogs.vala',\n  'ui/leaflet.vala',\n  'ui/mini-bar.vala',\n  'ui/music-list.vala',\n  'ui/music-widgets.vala',\n  'ui/narrow-bar.vala',\n  'ui/paintables.vala',\n  'ui/peak-bar.vala',\n  'ui/play-bar.vala',\n  'ui/play-panel.vala',\n  'ui/playlist-dialog.vala',\n  'ui/preferences.vala',\n  'ui/stable-label.vala',\n  'ui/store-panel.vala',\n  'ui/taglist-dialog.vala',\n  'ui/volume-button.vala',\n  'ui/window.vala',\n  'utils/async-task.vala',\n  'utils/cover-cache.vala',\n  'utils/data-io.vala',\n  'utils/dir-cache.vala',\n  'utils/dir-monitor.vala',\n  'utils/mpris.vala',\n  'utils/music.vala',\n  'utils/music-library.vala',\n  'utils/music-loader.vala',\n  'utils/playlist-file.vala',\n  'utils/portal.vala',\n  'utils/tag-cache.vala',\n  'utils/thumbnailer.vala',\n]\n\nconf = configuration_data()\nconf.set_quoted('APP_ID', app_id)\nconf.set_quoted('CODE_NAME', meson.project_name())\nconf.set_quoted('VERSION', version)\nconf.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir'))\nconfigure_file(output: 'config.h', configuration: conf)\n\nc_name = meson.project_name()\nres_name = c_name + '-resources'\n\nsources += gnome.compile_resources(res_name,\n  'gresource.xml',\n  c_name: c_name\n)\n\nadd_project_arguments('-I' + meson.current_source_dir () + '/gst/', language: 'c')\n\nexecutable(c_name, sources,\n  vala_args: [\n    # meson.current_source_dir () + '/config.vapi',\n    meson.current_source_dir () + '/gst/gst-ext.vapi',\n  ],\n  dependencies: dependencies,\n  install: true,\n)\n"
  },
  {
    "path": "src/ui/dialogs.vala",
    "content": "namespace G4 {\n\n#if ADW_1_5\n    public class Dialog : Adw.Dialog {\n\n        public new void present (Gtk.Widget? parent) {\n            content_width = compute_dialog_width (parent);\n            base.present (parent);\n        }\n#else\n    public class Dialog : Gtk.Window {\n\n        public override bool close_request () {\n            closed ();\n            return false;\n        }\n\n        public new void present (Gtk.Window? parent = null) {\n            if (parent != null) {\n                modal = true;\n                transient_for = (!)parent;\n            }\n            set_titlebar (new Adw.Bin ());\n            width_request = compute_dialog_width (parent);\n            base.present ();\n        }\n\n        public override void measure (Gtk.Orientation orientation, int for_size, out int minimum, out int natural, out int minimum_baseline, out int natural_baseline) {\n            child.measure (orientation, for_size, out minimum, out natural, out minimum_baseline, out natural_baseline);\n            if (orientation == Gtk.Orientation.VERTICAL) {\n                var height = transient_for.get_height ();\n                if (natural > height && height > 0)\n                    natural = height;\n            }\n        }\n\n        public virtual signal void closed () {\n        }\n#endif\n    }\n\n    public int compute_dialog_width (Gtk.Widget? parent) {\n        var width = parent?.get_width () ?? ContentWidth.MIN;\n        if (width > 360)\n            width = (width * 3 / 8).clamp (360, ContentWidth.MAX);\n        return width;\n    }\n\n    public void show_about_dialog (Application app) {\n        string[] authors = { \"Nanling\" };\n        /* Translators: Replace \"translator-credits\" with your names, one name per line */\n        var translator_credits = _(\"translator-credits\");\n        var website = \"https://gitlab.gnome.org/neithern/g4music\";\n        var parent = Window.get_default ();\n#if ADW_1_5\n        var win = new Adw.AboutDialog ();\n        run_idle_once (() => {\n            if (parent != null && ((!)parent).get_width () < win.width_request)\n                ((!)parent).default_width = win.width_request;\n        });\n#elif ADW_1_2\n        var win = new Adw.AboutWindow ();\n#endif\n#if ADW_1_2\n        win.application_icon = app.application_id;\n        win.application_name = app.name;\n        win.version = Config.VERSION;\n        win.license_type = Gtk.License.GPL_3_0;\n        win.developers = authors;\n        win.website = website;\n        win.issue_url = \"https://gitlab.gnome.org/neithern/g4music/issues\";\n        win.translator_credits = translator_credits;\n#if ADW_1_5\n        win.present (parent);\n#else\n        if (parent != null)\n            win.transient_for = (!)parent;\n        win.present ();\n#endif\n#else\n        Gtk.show_about_dialog (parent,\n                               \"logo-icon-name\", app.application_id,\n                               \"program-name\", app.name,\n                               \"version\", Config.VERSION,\n                               // \"comments\", comments,\n                               \"authors\", authors,\n                               \"translator-credits\", translator_credits,\n                               \"license-type\", Gtk.License.GPL_3_0,\n                               \"website\", website\n                              );\n#endif\n    }\n\n    public async bool show_alert_dialog (string text, Gtk.Window? parent = null) {\n#if ADW_1_5\n        var result = false;\n        var dialog = new Adw.AlertDialog (null, text);\n        dialog.add_response (\"no\", _(\"No\"));\n        dialog.add_response (\"yes\", _(\"Yes\"));\n        dialog.default_response = \"yes\";\n        dialog.response.connect ((id) => {\n            result = id == \"yes\";\n            Idle.add (show_alert_dialog.callback);\n        });\n        dialog.present (parent);\n        yield;\n        return result;\n#elif GTK_4_10\n        var dialog = new Gtk.AlertDialog (text);\n        dialog.buttons = { _(\"No\"), _(\"Yes\") };\n        dialog.cancel_button = 0;\n        dialog.default_button = 1;\n        dialog.modal = true;\n        try {\n            var btn = yield dialog.choose (parent, null);\n            return btn == 1;\n        } catch (Error e) {\n        }\n        return false;\n#else\n        var result = -1;\n        var dialog = new Gtk.MessageDialog (parent, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,\n                            Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, text);\n        dialog.response.connect ((id) => {\n            dialog.destroy ();\n            result = id;\n            Idle.add (show_alert_dialog.callback);\n        });\n        dialog.set_titlebar (new Adw.Bin ());\n        dialog.present ();\n        yield;\n        return result == Gtk.ResponseType.YES;\n#endif\n    }\n\n    public async File? show_save_file_dialog (Gtk.Window? parent, File? initial = null, Gtk.FileFilter[]? filters = null) {\n        Gtk.FileFilter? default_filter = filters != null && ((!)filters).length > 0 ? ((!)filters)[0] : (Gtk.FileFilter?) null;\n#if GTK_4_10\n        var filter_list = new ListStore (typeof (Gtk.FileFilter));\n        if (filters != null) {\n            foreach (var filter in (!)filters) \n                filter_list.append (filter);\n        }\n        var dialog = new Gtk.FileDialog ();\n        dialog.filters = filter_list;\n        dialog.modal = true;\n        dialog.set_default_filter (default_filter);\n        dialog.set_initial_file (initial);\n        try {\n            return yield dialog.save (parent, null);\n        } catch (Error e) {\n        }\n        return null;\n#else\n        File? result = null;\n        var chooser = new Gtk.FileChooserNative (null, parent, Gtk.FileChooserAction.SAVE, null, null);\n        chooser.modal = true;\n        try {\n            var folder = initial?.get_parent ();\n            if (folder != null)\n                chooser.set_current_folder ((!)folder);\n            chooser.set_current_name (initial?.get_basename () ?? \"\");\n        } catch (Error e) {\n        }\n        if (filters != null) {\n            foreach (var filter in (!)filters) \n                chooser.add_filter (filter);\n            if (default_filter != null)\n                chooser.set_filter ((!)default_filter);\n        }\n        chooser.response.connect ((id) => {\n            var file = chooser.get_file ();\n            if (id == Gtk.ResponseType.ACCEPT && file is File) {\n                result = file;\n                Idle.add (show_save_file_dialog.callback);\n            }\n        });\n        chooser.show ();\n        yield;\n        return result;\n#endif\n    }\n\n    public async File? show_select_folder_dialog (Gtk.Window? parent, File? initial = null) {\n#if GTK_4_10\n        var dialog = new Gtk.FileDialog ();\n        dialog.set_initial_folder (initial);\n        dialog.modal = true;\n        try {\n            return yield dialog.select_folder (parent, null);\n        } catch (Error e) {\n        }\n        return null;\n#else\n        File? result = null;\n        var chooser = new Gtk.FileChooserNative (null, parent,\n                        Gtk.FileChooserAction.SELECT_FOLDER, null, null);\n        try {\n            if (initial != null)\n                chooser.set_file ((!)initial);\n        } catch (Error e) {\n        }\n        chooser.modal = true;\n        chooser.response.connect ((id) => {\n            if (id == Gtk.ResponseType.ACCEPT) {\n                result = chooser.get_file ();\n                Idle.add (show_select_folder_dialog.callback);\n            }\n        });\n        chooser.show ();\n        yield;\n        return result;\n#endif\n    }\n}\n"
  },
  {
    "path": "src/ui/leaflet.vala",
    "content": "namespace G4 {\n\n    namespace ContentWidth {\n        public const int MIN = 340;\n        public const int MAX = 480;\n    }\n\n    namespace LeafletMode {\n        public const int SIDEBAR = 1;\n        public const int CONTENT = 2;\n    }\n\n    public interface SizeWatcher {\n        public abstract void first_allocated ();\n        public abstract void size_to_change (int width, int height);\n    }\n\n    public class Leaflet : Gtk.Widget {\n        private Gtk.Widget _content_box;\n        private Gtk.Widget _sidebar_box;\n        private Gtk.Widget _content = new Adw.Bin ();\n        private Gtk.Widget _sidebar = new Adw.Bin ();\n        private Stack _widget = new Stack (true);\n\n        private bool _folded = false;\n        private float _content_fraction = 3/8f;\n        private int _content_min_width = ContentWidth.MIN;\n        private int _content_max_width = ContentWidth.MAX;\n        private int _view_width = 0;\n        private int _view_height = 0;\n        private int _visible_mode = LeafletMode.SIDEBAR;\n\n        public Leaflet () {\n            _sidebar_box = _widget.add (_sidebar, \"sidebar\");\n            _content_box = _widget.add (_content, \"content\");\n            _widget.widget.set_parent (this);\n            _widget.notify[\"visible-child\"].connect (() => {\n                var mode = _widget.visible_child == _sidebar ? LeafletMode.SIDEBAR : LeafletMode.CONTENT;\n                if (_folded && _visible_mode != mode) {\n                    _visible_mode = mode;\n                    notify_property (\"visible-mode\");\n                }\n            });\n        }\n\n        ~Leaflet () {\n            _content.unparent ();\n            _widget.widget.unparent ();\n        }\n\n        public bool folded {\n            get {\n                return _folded;\n            }\n        }\n\n        public Gtk.Widget content {\n            get {\n                return _content;\n            }\n            set {\n                _content = value;\n                if (_folded) {\n                    _widget.set_child (_content_box, value);\n                } else {\n                    _widget.set_child (_content_box, null);\n                    _content.set_parent (this);\n                }\n                queue_allocate ();\n            }\n        }\n\n        public Gtk.Widget sidebar {\n            get {\n                return _sidebar;\n            }\n            set {\n                _sidebar = value;\n                _widget.set_child (_sidebar_box, value);\n                queue_allocate ();\n            }\n        }\n\n        public int visible_mode {\n            get {\n                return _visible_mode;\n            }\n            set {\n                _visible_mode = value;\n                update_visible_child ();\n            }\n        }\n\n        public void pop () {\n            visible_mode = LeafletMode.SIDEBAR;\n        }\n\n        public void push () {\n            visible_mode = LeafletMode.CONTENT;\n        }\n\n        public override void measure (Gtk.Orientation orientation, int for_size, out int minimum, out int natural, out int minimum_baseline, out int natural_baseline) {\n            var minimum1 = 0, minimum2 = 0;\n            var natural1 = 0, natural2 = 0;\n            _content.measure (orientation, for_size, out minimum1, out natural1, out minimum_baseline, out natural_baseline);\n            _sidebar.measure (orientation, for_size, out minimum2, out natural2, out minimum_baseline, out natural_baseline);\n            if (orientation == Gtk.Orientation.HORIZONTAL) {\n                minimum = int.max (int.min (minimum1, minimum2), _content_min_width);\n            } else {\n                minimum = int.max (minimum1, minimum2);\n            }\n            natural = int.max (natural1, natural2);\n        }\n\n        public override void size_allocate (int width, int height, int baseline) {\n            var first = _view_width == 0 && width > 0;\n            if (first) {\n                run_idle_once (() => {\n                    (_content as SizeWatcher)?.first_allocated ();\n                    (_sidebar as SizeWatcher)?.first_allocated ();\n                });\n            }\n            _view_width = width;\n            _view_height = height;\n\n            var stack = _widget.widget;\n            var folded = width < _content_min_width * 2;\n            if (_folded != folded || first) {\n                _folded = folded;\n                if (folded && !_content.is_ancestor (_content_box)) {\n                    _content.unparent ();\n                    _widget.set_child (_content_box, _content);\n                } else if (!folded && _content.is_ancestor (_content_box)) {\n                    _widget.set_child (_content_box, null);\n                    _content.insert_after (this, _widget.widget);\n                }\n\n                var animate = _widget.animate_transitions;\n                _widget.animate_transitions = false;\n                update_visible_child ();\n                _widget.animate_transitions = animate;\n                notify_property (\"folded\");\n            }\n\n            var allocation = Gtk.Allocation ();\n            allocation.x = 0;\n            allocation.y = 0;\n            allocation.width = width;\n            allocation.height = height;\n\n            if (folded) {\n                (_content as SizeWatcher)?.size_to_change (width, height);\n                (_sidebar as SizeWatcher)?.size_to_change (width, height);\n                _content.allocate_size (allocation, baseline);\n                _sidebar.allocate_size (allocation, baseline);\n                stack.allocate_size (allocation, baseline);\n            } else {\n                var rtl = get_direction () == Gtk.TextDirection.RTL;\n                var content_width = (int) (width * _content_fraction).clamp (_content_min_width, _content_max_width);\n                var side_width = width - content_width;\n\n                //  put sidebar at start\n                allocation.x = rtl ? content_width : 0;\n                allocation.width = side_width;\n                (_sidebar as SizeWatcher)?.size_to_change (side_width, height);\n                _sidebar.allocate_size (allocation, baseline);\n                stack.allocate_size (allocation, baseline);\n\n                //  put content at end\n                allocation.x = rtl ? 0 : side_width;\n                allocation.width = content_width;\n                (_content as SizeWatcher)?.size_to_change (content_width, height);\n                _content.allocate_size (allocation, baseline);\n            }\n        }\n\n        public override void snapshot (Gtk.Snapshot snapshot) {\n            if (!_folded) {\n                var size = _sidebar.get_width ();\n                var rtl = get_direction () == Gtk.TextDirection.RTL;\n                var rect = Graphene.Rect ();\n                rect.init (rtl ? _view_width - size : size, 0, 0.5f, _view_height);\n                var color = Gdk.RGBA ();\n                color.red = color.green = color.blue = color.alpha = 0;\n#if GTK_4_10\n                var color2 = get_color ();\n#else\n                var color2 = get_style_context ().get_color ();\n#endif\n                color2.alpha = 0.25f;\n                Gsk.ColorStop[] stops = { { 0, color }, { 0.5f, color2 }, { 1, color } };\n                snapshot.append_linear_gradient (rect, rect.get_top_left (), rect.get_bottom_right (), stops);\n            }\n            base.snapshot (snapshot);\n        }\n\n        private void update_visible_child () {\n            _widget.visible_child = _folded && _visible_mode == LeafletMode.CONTENT ? _content : _sidebar;\n        }\n    }\n\n#if ADW_1_4\n    public class Stack : Object {\n        private bool _retain_last_popped = false;\n        private Adw.NavigationPage? _last_page = null;\n        private Adw.NavigationView _widget = new Adw.NavigationView ();\n\n        public Stack (bool retain_last_popped = false) {\n            _retain_last_popped = retain_last_popped;\n            _widget = new Adw.NavigationView ();\n            _widget.get_next_page.connect (() => {\n                return (_widget.visible_page != _last_page && _last_page?.get_child () != null) ? _last_page : null;\n            });\n            _widget.pushed.connect(() => {\n                notify_property (\"visible-child\");\n            });\n            _widget.popped.connect((page) => {\n                notify_property (\"visible-child\");\n                if (_retain_last_popped)\n                    _last_page = page;\n            });\n        }\n\n        public bool animate_transitions {\n            get {\n                return _widget.animate_transitions;\n            }\n            set {\n                _widget.animate_transitions = value;\n            }\n        }\n\n        public Gtk.Widget parent {\n            get {\n                return _widget.parent;\n            }\n        }\n\n        public Gtk.Widget visible_child {\n            get {\n                return _widget.visible_page.child;\n            }\n            set {\n                if (_widget.visible_page.child != value) {\n                    if (_last_page?.child == value) {\n                        _widget.push ((!)_last_page);\n                    } else {\n                        var page = find_page (value);\n                        if (page != null)\n                            _widget.pop_to_page ((!)page);\n                    }\n                }\n            }\n        }\n\n        public Gtk.Widget widget {\n            get {\n                return _widget;\n            }\n        }\n\n        public Gtk.Widget add (Gtk.Widget child, string? tag = null) {\n            var page = new Adw.NavigationPage (child, tag ?? \"\");\n            page.set_tag (tag);\n            if (_retain_last_popped) {\n                _last_page = page;\n                _widget.add (page);\n            } else {\n                _widget.push (page);\n            }\n            return page;\n        }\n\n        public void pop () {\n            _widget.pop ();\n        }\n\n        public Gtk.Widget? get_child_by_name (string name) {\n            return _widget.find_page (name)?.child;\n        }\n\n        public GenericArray<Gtk.Widget> get_children () {\n            var pages = _widget.navigation_stack;\n            var count = pages.get_n_items ();\n            var children = new GenericArray<Gtk.Widget> (count);\n            for (var i = 0; i < count; i++) {\n                var page = (Adw.NavigationPage) pages.get_item (i);\n                children.add (page.child);\n            }\n            return children;\n        }\n\n        public void get_visible_names (GenericArray<string> names) {\n            var pages = _widget.navigation_stack;\n            var count = pages.get_n_items ();\n            var visible_page = _widget.visible_page;\n            for (var i = 0; i < count; i++) {\n                var page = (Adw.NavigationPage) pages.get_item (i);\n                names.add (page.tag);\n                if (page == visible_page)\n                    break;\n            }\n        }\n\n        public void set_child (Gtk.Widget page, Gtk.Widget? child) {\n            var p = page as Adw.NavigationPage;\n            p?.set_child (child);\n        }\n\n        private Adw.NavigationPage? find_page (Gtk.Widget child) {\n            var pages = _widget.navigation_stack;\n            var count = pages.get_n_items ();\n            for (var i = 0; i < count; i++) {\n                var page = (Adw.NavigationPage) pages.get_item (i);\n                if (page.child == child)\n                    return page;\n            }\n            return null;\n        }\n    }\n#else\n    public class Stack : Object {\n        private Gtk.Stack _widget = new Gtk.Stack ();\n\n        public Stack (bool retain_last_popped = false) {\n            _widget = new Gtk.Stack ();\n            animate_transitions = true;\n        }\n\n        public bool animate_transitions {\n            get {\n                return _widget.transition_type != Gtk.StackTransitionType.NONE;\n            }\n            set {\n                _widget.transition_type = value ? Gtk.StackTransitionType.SLIDE_LEFT_RIGHT : Gtk.StackTransitionType.NONE;\n            }\n        }\n\n        public Gtk.Widget parent {\n            get {\n                return _widget.parent;\n            }\n        }\n\n        public Gtk.Widget visible_child {\n            get {\n                return ((Adw.Bin) _widget.visible_child).child;\n            }\n            set {\n                _widget.visible_child = value.parent;\n            }\n        }\n\n        public Gtk.Widget widget {\n            get {\n                return _widget;\n            }\n        }\n\n        public Gtk.Widget add (Gtk.Widget child, string? tag = null) {\n            var bin = new Adw.Bin ();\n            bin.child = child;\n            _widget.add_named (bin, tag);\n            _widget.visible_child = bin;\n            notify_property (\"visible-child\");\n            return bin;\n        }\n\n        public void pop () {\n            var child = _widget.get_visible_child ();\n            var previous = child?.get_prev_sibling ();\n            if (child != null && previous != null) {\n                _widget.visible_child = (!)previous;\n                notify_property (\"visible-child\");\n                run_timeout_once (_widget.transition_duration, () => {\n                    _widget.remove ((!)child);\n                });\n            }\n        }\n\n        public Gtk.Widget? get_child_by_name (string name) {\n            return (_widget.get_child_by_name (name) as Adw.Bin)?.child;\n        }\n\n        public GenericArray<Gtk.Widget> get_children () {\n            var pages = _widget.pages;\n            var count = pages.get_n_items ();\n            var children = new GenericArray<Gtk.Widget> (count);\n            for (var i = 0; i < count; i++) {\n                var page = (Gtk.StackPage) pages.get_item (i);\n                children.add (((Adw.Bin) page.child).child);\n            }\n            return children;\n        }\n\n        public void get_visible_names (GenericArray<string> names) {\n            var pages = _widget.pages;\n            var count = pages.get_n_items ();\n            var child = _widget.visible_child;\n            for (var i = 0; i < count; i++) {\n                var page = (Gtk.StackPage) pages.get_item (i);\n                names.add (page.name);\n                if (page.child == child)\n                    break;\n            }\n        }\n\n        public void set_child (Gtk.Widget page, Gtk.Widget? child) {\n            (page as Adw.Bin)?.set_child (child);\n        }\n    }\n#endif\n}\n"
  },
  {
    "path": "src/ui/mini-bar.vala",
    "content": "namespace G4 {\n\n    public class MiniBar : Adw.ActionRow {\n        private Gtk.Image _cover = new Gtk.Image ();\n        private StableLabel _title = new StableLabel ();\n        private Gtk.Label _time = new Gtk.Label (\"0:00\");\n        private Gtk.Button _prev = new Gtk.Button ();\n        private Gtk.Button _play = new Gtk.Button ();\n        private Gtk.Button _next = new Gtk.Button ();\n        private int _duration = 0;\n        private int _position = 0;\n\n        private Adw.Animation? _fade_animation = null;\n        private CrossFadePaintable _paintable = new CrossFadePaintable ();\n\n        construct {\n            halign = Gtk.Align.FILL;\n            hexpand = true;\n            height_request = 60;\n\n            var controller = new Gtk.GestureClick ();\n            controller.released.connect (this.activate);\n            add_controller (controller);\n            activatable_widget = this;\n\n            var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 2);\n            vbox.halign = Gtk.Align.START;\n            vbox.hexpand = true;\n            vbox.valign = Gtk.Align.CENTER;\n            vbox.append (_title);\n            vbox.append (_time);\n            add_prefix (vbox);\n            add_prefix (_cover);\n\n            _cover.valign = Gtk.Align.CENTER;\n            _cover.margin_start = 2;\n            _cover.margin_end = 6;\n            _cover.pixel_size = 40;\n            _cover.paintable = new RoundPaintable (_paintable);\n            _paintable.queue_draw.connect (_cover.queue_draw);\n\n            _title.halign = Gtk.Align.START;\n            _title.marquee = true;\n            _title.add_css_class (\"title-leading\");\n\n            _time.halign = Gtk.Align.START;\n            _time.add_css_class (\"dim-label\");\n            _time.add_css_class (\"numeric\");\n            var font_size = _time.get_pango_context ().get_font_description ().get_size () / Pango.SCALE;\n            if (font_size >= 13)\n                _time.add_css_class (\"title-secondly\");\n\n            var hbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 4);\n            hbox.valign = Gtk.Align.CENTER;\n            add_suffix (hbox);\n\n            _prev.valign = Gtk.Align.CENTER;\n            _prev.action_name = ACTION_APP + ACTION_PREV;\n            _prev.icon_name = \"media-skip-backward-symbolic\";\n            _prev.tooltip_text = _(\"Play Previous\");\n            _prev.add_css_class (\"circular\");\n            _prev.add_css_class (\"flat\");\n            hbox.append (_prev);\n\n            _play.valign = Gtk.Align.CENTER;\n            _play.action_name = ACTION_APP + ACTION_PLAY_PAUSE;\n            _play.icon_name = \"media-playback-start-symbolic\";\n            _play.tooltip_text = _(\"Play/Pause\");\n            _play.add_css_class (\"circular\");\n            _play.add_css_class (\"flat\");\n            hbox.append (_play);\n\n            _next.valign = Gtk.Align.CENTER;\n            _next.action_name = ACTION_APP + ACTION_NEXT;\n            _next.icon_name = \"media-skip-forward-symbolic\";\n            _next.tooltip_text = _(\"Play Next\");\n            _next.add_css_class (\"circular\");\n            _next.add_css_class (\"flat\");\n            hbox.append (_next);\n\n            var app = (Application) GLib.Application.get_default ();\n            var player = app.player;\n            player.duration_changed.connect (on_duration_changed);\n            player.position_updated.connect (on_position_changed);\n            player.state_changed.connect (on_state_changed);\n        }\n\n        public Gdk.Paintable? cover {\n            get {\n                return _paintable.paintable;\n            }\n            set {\n                _paintable.paintable = value;\n                var target = new Adw.CallbackAnimationTarget ((value) => _paintable.fade = value);\n                _fade_animation?.pause ();\n                _fade_animation = new Adw.TimedAnimation (_cover, 1 - _paintable.fade, 0, 800, target);\n                ((!)_fade_animation).done.connect (() => {\n                    _paintable.previous = null;\n                    _fade_animation = null;\n                });\n                _fade_animation?.play ();\n            }\n        }\n\n        public new string title {\n            set {\n                _title.label = value;\n            }\n        }\n\n        public void size_to_change (int panel_width) {\n            _prev.visible = panel_width >= 360;\n        }\n\n        public override void snapshot (Gtk.Snapshot snapshot) {\n            var rect = Graphene.Rect ();\n            rect.init (0, 0, get_width (), get_height ());\n            draw_outset_shadow (snapshot, rect);\n            base.snapshot (snapshot);\n        }\n\n        private void on_duration_changed (Gst.ClockTime duration) {\n            var value = GstPlayer.to_second (duration);\n            if (_duration != (int) value) {\n                _duration = (int) value;\n                update_time_label ();\n            }\n        }\n\n        private void on_position_changed (Gst.ClockTime position) {\n            var value = GstPlayer.to_second (position);\n            if (_position != (int) value) {\n                _position = (int) value;\n                update_time_label ();\n            }\n        }\n\n        private void on_state_changed (Gst.State state) {\n            var playing = state == Gst.State.PLAYING;\n            _play.icon_name = playing ? \"media-playback-pause-symbolic\" : \"media-playback-start-symbolic\";\n        }\n\n        private void update_time_label () {\n            if (_duration > 0)\n                _time.label = format_time (_position) + \"/\" + format_time (_duration);\n            else\n                _time.label = \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/music-list.vala",
    "content": "namespace G4 {\n\n    public enum Result {\n        CANCEL = -1,\n        FAILED = 0,\n        OK = 1\n    }\n\n    public class MusicList : Gtk.Box {\n        protected Application _app;\n        private HashTable<Music, Gtk.ListItem> _binding_items = new HashTable<Music, Gtk.ListItem> (direct_hash, direct_equal);\n        private bool _compact_list = false;\n        private Music? _current_node = null;\n        private ListStore _data_store = new ListStore (typeof (Music));\n        private bool _editable = false;\n        private Gtk.FilterListModel _filter_model = new Gtk.FilterListModel (null, null);\n        private bool _grid_mode = false;\n        private Gtk.GridView _grid_view = new Gtk.GridView (null, null);\n        private int _image_size = Thumbnailer.ICON_SIZE;\n        private Type _item_type = typeof (Music);\n        protected bool _modified = false;\n        private Music? _music_node = null;\n        private Gtk.ScrolledWindow _scroll_view = new Gtk.ScrolledWindow ();\n        private bool _selectable = false;\n        private bool _single_click_activate = true;\n        private Gtk.MultiSelection _selection;\n        private Thumbnailer _thmbnailer;\n\n        private uint _columns = 0;\n        private Graphene.Size _cell_size = Graphene.Size ();\n        private Graphene.Size _item_size = Graphene.Size ();\n        private int _scrolling_item = -1;\n\n        public signal void item_activated (uint position, Object? obj);\n        public signal void item_binded (Gtk.ListItem item);\n        public signal void item_created (Gtk.ListItem item);\n        public signal void item_unbinded (Gtk.ListItem item);\n\n        public MusicList (Application app, Type item_type = typeof (Music), Music? node = null, bool editable = false, bool selectable = true) {\n            orientation = Gtk.Orientation.VERTICAL;\n            hexpand = true;\n\n            _app = app;\n            _editable = editable;\n            _filter_model.model = _data_store;\n            _item_type = item_type;\n            _music_node = node;\n            _selectable = selectable;\n            _thmbnailer = app.thumbnailer;\n\n            _grid_view.max_columns = 5;\n            _grid_view.margin_start = 6;\n            _grid_view.margin_end = 6;\n            _grid_view.model = _selection = new Gtk.MultiSelection (_filter_model);\n            _grid_view.activate.connect ((position) => item_activated (position, _filter_model.get_item (position)));\n            _grid_view.add_css_class (\"navigation-sidebar\");\n            _selection.selection_changed.connect (on_selection_changed);\n            create_factory ();\n            update_grid_view ();\n\n            _scroll_view.child = _grid_view;\n            _scroll_view.hscrollbar_policy = Gtk.PolicyType.NEVER;\n            _scroll_view.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;\n            _scroll_view.propagate_natural_height = true;\n            _scroll_view.vexpand = true;\n            append (_scroll_view);\n\n            if (editable || item_type == typeof (Playlist)) {\n                create_drop_target (_grid_view);\n            }\n        }\n\n        public bool compact_list {\n            get {\n                return _compact_list;\n            }\n            set {\n                if (_compact_list != value) {\n                    _compact_list = value;\n                    create_factory ();\n                }\n            }\n        }\n\n        public Music? current_node {\n            set {\n                var cur = get_binding_widget (_current_node);\n                if (cur != null)\n                    ((!)cur).playing.visible = false;\n                _current_node = value;\n                var widget = get_binding_widget (value);\n                if (widget != null)\n                    ((!)widget).playing.visible = true;\n            }\n        }\n\n        public ListStore data_store {\n            get {\n                return _data_store;\n            }\n            set {\n                _data_store = value;\n                _filter_model.model = value;\n            }\n        }\n\n        public int dropping_item {\n            get {\n                return _dropping_item;\n            }\n            set {\n                if (_dropping_item != value) {\n                    _dropping_item = value;\n                    queue_draw ();\n                }\n            }\n        }\n\n        public Gtk.FilterListModel filter_model {\n            get {\n                return _filter_model;\n            }\n        }\n\n        public bool grid_mode {\n            get {\n                return _grid_mode;\n            }\n            set {\n                _image_size = value ? Thumbnailer.GRID_SIZE : Thumbnailer.ICON_SIZE;\n                if (_grid_mode != value) {\n                    _grid_mode = value;\n                    create_factory ();\n                }\n            }\n        }\n\n        public Type item_type {\n            get {\n                return _item_type;\n            }\n        }\n\n        public bool modified {\n            get {\n                return _modified;\n            }\n            set {\n                _modified = value;\n            }\n        }\n\n        protected bool _has_add_to_queque = true;\n        protected bool _prompt_to_save = true;\n        private GenericArray<Gtk.Button> _action_buttons = new GenericArray<Gtk.Button> (4);\n        private Gtk.Widget? _header_bar_hided = null;\n        private Gtk.Revealer? _header_revealer = null;\n        private Gtk.Label? _header_title = null;\n        private bool _multi_selection = false;\n\n        public bool multi_selection {\n            get {\n                return _multi_selection;\n            }\n            set {\n                if (value && _header_revealer == null) {\n                    var child = get_first_child ();\n                    _header_bar_hided = child != _scroll_view ? child : null;\n                    var header = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);\n                    setup_selection_header_bar (header);\n                    var revealer = new Gtk.Revealer ();\n                    revealer.child = header;\n                    revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_DOWN;\n                    revealer.insert_after (this, _header_bar_hided);\n                    _header_revealer = revealer;\n                }\n                _header_bar_hided?.set_visible (!value);\n                _header_revealer?.set_reveal_child (value);\n\n                if (_multi_selection != value) {\n                    _multi_selection = value;\n                    update_grid_view ();\n                    if (value)\n                        on_selection_changed (0, 0);\n                    else\n                        _selection.unselect_all ();\n                }\n            }\n        }\n\n        public Music? music_node {\n            get {\n                return _music_node;\n            }\n        }\n\n        public bool playable {\n            get {\n                return _item_type == typeof (Music);\n            }\n        }\n\n        public bool single_click_activate {\n            get {\n                return _single_click_activate;\n            }\n            set {\n                if (_single_click_activate != value) {\n                    _single_click_activate = value;\n                    update_grid_view ();\n                }\n            }\n        }\n\n        public uint visible_count {\n            get {\n                return _filter_model.get_n_items ();\n            }\n        }\n\n        public void activate_item (int item) {\n            _grid_view.activate (item);\n        }\n\n        public void button_command (string name) {\n            var playlist = create_playlist_for_selection ();\n            switch (name) {\n                case Button.ADDTO:\n                    _app.show_add_playlist_dialog.begin (playlist, (obj, res) => _app.show_add_playlist_dialog.end (res));\n                    break;\n\n                case Button.INSERT:\n                    _app.insert_after_current (playlist);\n                    break;\n\n                case Button.QUEUE:\n                    _app.insert_to_queue (playlist);\n                    break;\n\n                case Button.REMOVE:\n                    modified |= remove_items_from_store (_data_store, playlist.items) != 0;\n                    on_selection_changed (0, 0);\n                    break;\n            }\n        }\n\n        public void create_factory () {\n            var factory = new Gtk.SignalListItemFactory ();\n            factory.setup.connect (on_create_item);\n            factory.bind.connect (on_bind_item);\n            factory.unbind.connect (on_unbind_item);\n            _grid_view.factory = factory;\n        }\n\n        public Playlist get_as_playlist () {\n            var pls = _music_node as Playlist;\n            var playlist = new Playlist (pls?.title ?? \"\", pls?.list_uri ?? \"\");\n            var items = playlist.items;\n            var count = _filter_model.get_n_items ();\n            for (var i = 0; i < count; i++) {\n                var music = (Music) _filter_model.get_item (i);\n                items.add (music);\n            }\n            return playlist;\n        }\n\n        public virtual async Result save_if_modified (bool prompt = true) {\n            if (_modified && _music_node is Playlist) {\n                var playlist = get_as_playlist ();\n                var ret = !prompt || yield show_alert_dialog (_(\"Playlist is modified, save it?\"), root as Gtk.Window);\n                if (ret) {\n                    ret = yield _app.add_playlist_to_file_async (playlist, false);\n                    if (ret)\n                        modified = false;\n                    return ret ? Result.OK : Result.FAILED;\n                }\n                update_store ();\n                modified = false;\n            }\n            return _modified ? Result.CANCEL : Result.OK;\n        }\n\n        private Adw.Animation? _scroll_animation = null;\n\n        public void scroll_to_item (int index, bool smoothly = true) {\n            var adj = _scroll_view.vadjustment;\n            var list_height = _grid_view.get_height ();\n            var scroll_done = false;\n            _columns = get_grid_view_item_size (_grid_view, ref _item_size, ref _cell_size);\n            if (smoothly && _columns > 0 && _cell_size.height > 0 && adj.upper - adj.lower > list_height) {\n                var from = adj.value;\n                var row = index / _columns;\n                var max_to = double.max ((row + 1) * _cell_size.height - list_height, 0);\n                var min_to = double.max (row * _cell_size.height, 0);\n                var scroll_to =  from < max_to ? max_to : (from > min_to ? min_to : from);\n                if ((scroll_to - from).abs () < list_height) {\n                    //  Scroll smoothly\n                    var target = new Adw.CallbackAnimationTarget (adj.set_value);\n                    _scroll_animation?.pause ();\n                    _scroll_animation = new Adw.TimedAnimation (_scroll_view, adj.value, scroll_to, 500, target);\n                    _scroll_animation?.play ();\n                    scroll_done = true;\n                }\n            }\n            if (!scroll_done) {\n                scroll_to_directly (index);\n            }\n            // Hack: sometime show only first item if no child drawed, so scroll it when first draw an item\n            _scrolling_item = index;\n        }\n\n        public void scroll_to_directly (uint index) {\n#if GTK_4_12\n            _grid_view.scroll_to (index, Gtk.ListScrollFlags.NONE, null);\n#else\n            _grid_view.activate_action_variant (\"list.scroll-to-item\", new Variant.uint32 (index));\n#endif\n        }\n\n        public override void snapshot (Gtk.Snapshot snapshot) {\n            if (_header_revealer?.reveal_child ?? false) {\n                var child = (!)_header_revealer;\n                var rect = Graphene.Rect ();\n                child.compute_bounds (this, out rect);\n                draw_outset_shadow (snapshot, rect);\n            }\n\n            var rc_grid = Graphene.Rect ();\n            if (_editable && _columns > 0 && _dropping_item >= 0 && _grid_view.compute_bounds (this, out rc_grid)) {\n                var row = _dropping_item / _columns;\n                var col = _dropping_item - _columns * row;\n                var rc_cell = Graphene.Rect ();\n                rc_cell.init (_cell_size.width * col, _cell_size.height * row, _cell_size.width, _cell_size.height);\n                rc_cell.offset (rc_grid.origin.x, rc_grid.origin.y);\n                rc_cell.origin.y -= (float) (_scroll_view.vadjustment.value) - (_cell_size.height - _item_size.height);\n                rc_cell.size.height = 1;\n#if ADW_1_6\n                var color = Adw.StyleManager.get_default ().accent_color.to_rgba ();\n#elif GTK_4_10\n                var color = get_color ();\n#else\n                var color = get_style_context ().get_color ();\n#endif\n                snapshot.append_color (color, rc_cell);\n            }\n            base.snapshot (snapshot);\n        }\n\n        private Gtk.Label? _empty_label = null;\n\n        public void set_empty_text (string? text) {\n            if (_data_store.get_n_items () > 0 && _empty_label != null) {\n                remove ((!)_empty_label);\n                _empty_label = null;\n            } else if (_data_store.get_n_items () == 0 && _empty_label == null) {\n                _empty_label = new Gtk.Label (text);\n                ((!)_empty_label).margin_top = 8;\n                prepend ((!)_empty_label);\n            }\n        }\n\n        public int set_to_current_item (bool scroll = true) {\n            var item = find_item_in_model (_filter_model, _current_node);\n            if (item != -1 && scroll)\n                scroll_to_item (item);\n            return item;\n        }\n\n        public void update_item_cover (Music music, Gdk.Paintable paintable) {\n            var item = _binding_items[music];\n            if (item is Gtk.ListItem) {\n                item_unbinded (item);\n                item_binded (item);\n                var widget = item.child as MusicWidget;\n                if (widget != null)\n                    ((!)widget).paintable = paintable;\n            }\n        }\n\n        public uint update_store () {\n            if (_music_node is Playlist) {\n                ((Playlist) _music_node).overwrite_to (_data_store);\n            } else if (_music_node is Album) {\n                ((Album) _music_node).overwrite_to (_data_store);\n            } else if (_music_node is Artist) {\n                ((Artist) _music_node).overwrite_store (_data_store);\n            }\n            return _data_store.get_n_items ();\n        }\n\n        private Menu? on_create_music_menu (Music? node) {\n            int position = -1;\n            if (_multi_selection && (position = find_item_in_model (_filter_model, node)) != -1) {\n                _selection.select_item (position, false);\n            }\n            if (_selection.get_selection ().get_size () > 1) {\n                var action = ACTION_WIN + ACTION_BUTTON;\n                var menu = new Menu ();\n                menu.append_item (create_menu_item_for_button (Button.INSERT, _(\"Play at _Next\"), action));\n                if (_has_add_to_queque)\n                    menu.append_item (create_menu_item_for_button (Button.QUEUE, _(\"Add to _Queue\"), action));\n                menu.append_item (create_menu_item_for_button (Button.ADDTO, _(\"Add to _Playlist…\"), action));\n                menu.append_item (create_menu_item_for_button (Button.REMOVE, _(\"_Remove\"), action));\n                return menu;\n            } else if (node is Album) {\n                return create_menu_for_album ((Album) node);\n            } else if (node is Artist) {\n                return create_menu_for_artist ((Artist) node);\n            } else if (node is Music) {\n                var music = (Music) node;\n                unowned var uri = music.uri;\n                var menu = create_menu_for_music (music, _app.thumbnailer.find (music) is Gdk.Texture);\n                if (music != _app.current_music) {\n                    /* Translators: Play this music at next position of current playing music */\n                    menu.insert_item (0, create_menu_item_for_uri (uri, _(\"Play at _Next\"), ACTION_APP + ACTION_PLAY_AT_NEXT));\n                    if (_has_add_to_queque)\n                        menu.insert_item (1, create_menu_item_for_uri (uri, _(\"Add to _Queue\"), ACTION_APP + ACTION_ADD_TO_QUEUE));\n                }\n                if (_editable) {\n                    var section = new Menu ();\n                    section.append_item (create_menu_item_for_uri (uri, _(\"_Remove\"), ACTION_WIN + ACTION_REMOVE));\n                    section.append_item (create_menu_item_for_uri (uri, _(\"_Move to Trash\"), ACTION_APP + ACTION_TRASH_FILE));\n                    menu.append_section (null, section);\n                }\n                return menu;\n            }\n            return null;\n        }\n\n        private void on_create_item (Object obj) {\n            var child = _grid_mode ? (MusicWidget) new MusicCell () : (MusicWidget) new MusicEntry (_compact_list);\n            var item = (Gtk.ListItem) obj;\n            item.child = child;\n            item.selectable = _multi_selection || !_single_click_activate;\n            item_created (item);\n\n            if (_selectable) {\n                create_drag_source (child.image, item);\n                child.create_music_menu.connect (on_create_music_menu);\n                make_right_clickable (child, child.show_popover_menu);\n                make_long_pressable (child, (widget, x, y) => multi_selection = true);\n            }\n        }\n\n        private void on_bind_item (Object obj) {\n            var item = (Gtk.ListItem) obj;\n            var child = (MusicWidget) item.child;\n            var music = (Music) item.item;\n            child.playing.visible = music == _current_node;\n            item_binded (item);\n            _binding_items[music] = item;\n\n            var paintable = _thmbnailer.find (music, _image_size);\n            if (paintable != null) {\n                child.paintable = paintable;\n            } else {\n                child.first_draw_handler = child.cover.first_draw.connect (() => {\n                    child.disconnect_first_draw ();\n                    _thmbnailer.load_async.begin (music, _image_size, (obj, res) => {\n                        var paintable2 = _thmbnailer.load_async.end (res);\n                        if (music == (Music) item.item) {\n                            child.paintable = paintable2;\n                        }\n                    });\n                    if (_scrolling_item != -1) {\n                        scroll_to_directly (_scrolling_item);\n                        _scrolling_item = -1;\n                    }\n                });\n            }\n        }\n\n        private void on_unbind_item (Object obj) {\n            var item = (Gtk.ListItem) obj;\n            var child = (MusicWidget) item.child;\n            child.paintable = null;\n            child.disconnect_first_draw ();\n            item_unbinded (item);\n            _binding_items.remove ((Music) item.item);\n        }\n\n        private void on_drag_begin (Gtk.DragSource source, Gdk.Drag drag, Gtk.Widget widget, Graphene.Point point) {\n            var size = _selection.get_selection ().get_size ();\n            var title = size > 1 ? size.to_string () : (string) null;\n            source.set_icon (create_widget_paintable (widget, ref point, title), (int) point.x, (int) point.y);\n        }\n\n        private Gdk.ContentProvider? on_drag_prepare (Music? music) {\n            var position = find_item_in_model (_filter_model, music);\n            if (position != -1)\n                _selection.select_item (position, false);\n\n            var playlist = create_playlist_for_selection ();\n            return create_content_provider (playlist);\n        }\n\n        private int _dropping_item = -1;\n\n        private bool on_drop_done (Value value, double x, double y) {\n            if (_editable) {\n                uint position = uint.min (_dropping_item, visible_count);\n                if (value.holds (typeof (Playlist))) {\n                    var dst_obj = _filter_model.get_item (position);\n                    if (dst_obj == null || !_data_store.find ((!)dst_obj, out position))\n                        position = _data_store.get_n_items ();\n                    var playlist = (Playlist) value.get_object ();\n                    modified |= merge_items_to_store (_data_store, playlist.items, ref position);\n                } else {\n                    var files = get_dropped_files (value);\n                    _app.open_files_async.begin (files, position, false,\n                                                (obj, res) => modified |= _app.open_files_async.end (res));\n                }\n            }\n            dropping_item = -1;\n            return true;\n        }\n\n        private uint _activate_handle = 0;\n\n        private Gdk.DragAction on_drop_motion (double x, double y) {\n            _columns = get_grid_view_item_size (_grid_view, ref _item_size, ref _cell_size);\n            var col = (int) (x / _cell_size.width);\n            var row = (int) ((y + _scroll_view.vadjustment.value) / _cell_size.height);\n            var index = (int) _columns * row + col;\n            if (_dropping_item != index && _filter_model.get_item (index) is Playlist) {\n                if (_activate_handle != 0)\n                    Source.remove (_activate_handle);\n                _activate_handle = run_timeout_once (1000, () => {\n                    _activate_handle = 0;\n                    if (_dropping_item == index)\n                        _grid_view.activate (index);\n                });\n            }\n            dropping_item = int.min (index, (int) visible_count);\n            return Gdk.DragAction.LINK;\n        }\n\n        private MusicWidget? get_binding_widget (Music? music) {\n            var item = music != null ? _binding_items[(!)music] : (Gtk.ListItem?) null;\n            return item?.child as MusicWidget;\n        }\n\n        private static void create_drag_source (Gtk.Widget widget, Gtk.ListItem item) {\n            //  Hack: don't use `this` directly, because it will not be destroyed when detach???\n            var point = Graphene.Point ();\n            var source = new Gtk.DragSource ();\n            source.actions = Gdk.DragAction.LINK;\n            source.drag_begin.connect ((drag) => {\n                var list = find_ancestry_with_type (widget, typeof (MusicList));\n                (list as MusicList)?.on_drag_begin (source, drag, widget, point);\n            });\n            source.prepare.connect ((x, y) => {\n                point.init ((float) x, (float) y);\n                var list = find_ancestry_with_type (widget, typeof (MusicList));\n                return (list as MusicList)?.on_drag_prepare (item.item as Music);\n            });\n            widget.add_controller (source);\n        }\n\n        private void create_drop_target (Gtk.Widget widget) {\n            var target = new Gtk.DropTarget (Type.INVALID, Gdk.DragAction.COPY | Gdk.DragAction.LINK);\n            target.set_gtypes ({ typeof (Playlist), typeof (Gdk.FileList) });\n            target.accept.connect ((drop) => drop.formats.contain_gtype (typeof (Playlist))\n                                || drop.formats.contain_gtype (typeof (Gdk.FileList)));\n            target.motion.connect (on_drop_motion);\n            target.leave.connect (() => run_timeout_once (100, () => dropping_item = -1));\n#if GTK_4_10\n            target.drop.connect (on_drop_done);\n#else\n            target.on_drop.connect (on_drop_done);\n#endif\n            widget.add_controller (target);\n        }\n\n        private Playlist create_playlist_for_selection () {\n            var count = _filter_model.get_n_items ();\n            var musics = new GenericArray<Music> (count);\n            for (var i = 0; i < count; i++) {\n                if (_selection.is_selected (i))\n                    musics.add ((Music) _filter_model.get_item (i));\n            }\n            return to_playlist (musics.data, _music_node?.title);\n        }\n\n        private uint _remove_selection_handle = 0;\n\n        private void on_selection_changed (uint position, uint n_items) {\n            var bits = _selection.get_selection ();\n            var selected = bits.get_size ();\n            if (selected > 1)\n                multi_selection = true;\n            _header_title?.set_label (@\"$selected/$visible_count\");\n\n            var enabled = selected > 0;\n            foreach (var button in _action_buttons)\n                button.sensitive = enabled;\n\n            if (_remove_selection_handle != 0)\n                Source.remove (_remove_selection_handle);\n            _remove_selection_handle = run_timeout_once (3000, () => {\n                _remove_selection_handle = 0;\n                if (!_multi_selection && bits.get_size () == 1)\n                    _selection.unselect_item (bits.get_minimum ());\n            });\n        }\n\n        private void setup_selection_header_bar (Gtk.Box header) {\n            header.hexpand = true;\n            header.add_css_class (\"flat\");\n            header.add_css_class (\"toolbar\");\n\n            var back_btn = new Gtk.Button.from_icon_name (\"go-previous-symbolic\");\n            back_btn.clicked.connect (() => {\n                if (_modified && _prompt_to_save) {\n                    save_if_modified.begin (true, (obj, res) => {\n                        var ret = save_if_modified.end (res);\n                        if (ret != Result.FAILED) {\n                            modified = false;\n                            multi_selection = false;\n                        }\n                    });\n                } else {\n                    multi_selection = false;\n                }\n            });\n            back_btn.tooltip_text = _(\"Back\");\n            header.append (back_btn);\n\n            var all_btn = new Gtk.Button.from_icon_name (\"edit-select-all-symbolic\");\n            all_btn.tooltip_text = _(\"Select All\");\n            all_btn.clicked.connect (() => {\n                if (_selection.get_selection ().get_size () == visible_count)\n                    _selection.unselect_all ();\n                else\n                    _selection.select_all ();\n            });\n            header.append (all_btn);\n\n            var title = new Gtk.Label (null);\n            title.add_css_class (\"dim-label\");\n            title.halign = Gtk.Align.CENTER;\n            title.hexpand = true;\n            header.append (title);\n            _header_title = title;\n\n            var insert_btn = new Gtk.Button.from_icon_name (\"format-indent-more-symbolic\");\n            insert_btn.tooltip_text = _(\"Play at Next\");\n            insert_btn.clicked.connect (() => button_command (Button.INSERT));\n            insert_btn.name = Button.INSERT;\n            _action_buttons.add (insert_btn);\n\n            if (_has_add_to_queque) {\n                var queue_btn = new Gtk.Button.from_icon_name (\"document-send-symbolic\");\n                queue_btn.tooltip_text = _(\"Add to Queue\");\n                queue_btn.clicked.connect (() => button_command (Button.QUEUE));\n                queue_btn.name = Button.QUEUE;\n                _action_buttons.add (queue_btn);\n            }\n\n            var addto_btn = new Gtk.Button.from_icon_name (\"document-new-symbolic\");\n            addto_btn.tooltip_text = _(\"Add to Playlist\");\n            addto_btn.clicked.connect (() => button_command (Button.ADDTO));\n            addto_btn.name = Button.ADDTO;\n            _action_buttons.add (addto_btn);\n\n            if (_editable) {\n                var remove_btn = new Gtk.Button.from_icon_name (\"user-trash-symbolic\");\n                remove_btn.tooltip_text = _(\"Remove\");\n                remove_btn.clicked.connect (() => button_command (Button.REMOVE));\n                remove_btn.name = Button.REMOVE;\n                _action_buttons.add (remove_btn);\n            }\n\n            _action_buttons.foreach (header.append);\n        }\n\n        private void update_grid_view () {\n            var enable = _multi_selection || !_single_click_activate;\n            _grid_view.enable_rubberband = enable;\n            _grid_view.single_click_activate = !enable;\n            _binding_items.foreach ((music, item) => item.selectable = enable);\n        }\n    }\n\n    public class MainMusicList : MusicList {\n        public MainMusicList (Application app) {\n            base (app, typeof (Music), null, true);\n            _has_add_to_queque = false;\n            _prompt_to_save = false;\n        }\n\n        public override async Result save_if_modified (bool prompt = true) {\n            if (_modified) {\n                var ret = yield _app.save_queue_to_file ();\n                if (ret)\n                    modified = false;\n                return ret ? Result.OK : Result.FAILED;\n            }\n            return Result.OK;\n        }\n    }\n\n    public Gdk.ContentProvider create_content_provider (Playlist playlist) {\n        var val = Value (typeof (Playlist));\n        val.set_object (playlist);\n#if GTK_4_8\n        var files = new GenericArray<File> (playlist.length);\n        playlist.items.foreach ((music) => files.add (File.new_for_uri (music.uri)));\n        var val2 = Value (typeof (Gdk.FileList));\n        val2.set_boxed (new Gdk.FileList.from_array (files.data));\n        return new Gdk.ContentProvider.union ({\n            new Gdk.ContentProvider.for_value (val),\n            new Gdk.ContentProvider.for_value (val2),\n        });\n#else\n        return new Gdk.ContentProvider.for_value (val);\n#endif\n    }\n\n    namespace Button {\n        public const string ADDTO = \"add\";\n        public const string INSERT = \"insert\";\n        public const string QUEUE = \"queue\";\n        public const string REMOVE = \"remove\";\n    }\n\n    public MenuItem create_menu_item_for_button (string button_name, string label, string action) {\n        var item = new MenuItem (label, null);\n        item.set_action_and_target_value (action, new Variant.string (button_name));\n        return item;\n    }\n\n    public Gtk.Widget? find_ancestry_with_type (Gtk.Widget widget, Type type) {\n        var parent = widget.get_parent ();\n        if (parent?.get_type ()?.is_a (type) ?? false)\n            return parent as MusicList;\n        else if (parent != null)\n            return find_ancestry_with_type ((!)parent, type);\n        return null;\n    }\n\n    public struct CountedRect {\n        public int count;\n        public int index;\n        public Graphene.Rect rect;\n\n        public CountedRect (int c = 0, int i = 0, Graphene.Rect? rc = null) {\n            count = c;\n            index = i;\n            if (rc != null)\n                rect = (!)rc;\n            else\n                rect.init (0, 0, 0, 0);\n        }\n    }\n\n    public uint get_grid_view_item_size (Gtk.GridView grid_view, ref Graphene.Size inner_size, ref Graphene.Size outer_size) {\n        var arr = new GenericArray<Graphene.Rect?> ();\n        var w_map = new HashTable<int, CountedRect?> (null, null);\n        var x_set = new GenericSet<int> (null, null);\n        for (var c = grid_view.get_first_child (); c != null; c = c?.get_next_sibling ()) {\n            var child = (!)c;\n            var rect = Graphene.Rect ();\n            if (child.is_drawable () && child.compute_bounds (grid_view, out rect)\n                    && rect.origin.x >= 0 && rect.origin.y >= 0\n                    && rect.size.width > 0 && rect.size.height > 0) {\n                var width = (int) rect.size.width;\n                var count = 1, index = arr.length;\n                var cr0 = w_map[width];\n                if (cr0 != null) {\n                    count = ((!)cr0).count + 1;\n                    index = ((!)cr0).index;\n                }\n                var cr = CountedRect (count, index, rect);\n                w_map[width] = cr;\n                x_set.add ((int) rect.origin.x);\n                arr.add (rect);\n            }\n        }\n        var columns = x_set.length.clamp (grid_view.min_columns, grid_view.max_columns);\n\n        var best_rect = CountedRect ();\n        best_rect.index = -1;\n        w_map.foreach ((w, rect) => {\n            var cr = (!)rect;\n            if (best_rect.count < cr.count) {\n                best_rect.count = cr.count;\n                if (best_rect.index == -1)\n                    best_rect.index = cr.index;\n                best_rect.rect = cr.rect;\n            }\n        });\n        inner_size.init_from_size (best_rect.rect.size);\n        outer_size.init_from_size (inner_size);\n\n        var index = best_rect.index;\n        if (index >= 0 && index + 1 < arr.length) {\n            outer_size.width = columns > 1 ? ((!)arr[index + 1]).origin.x - ((!)arr[index]).origin.x : grid_view.get_width () / int.max (1, (int) columns);\n            if (index + columns < arr.length)\n                outer_size.height = ((!)arr[index + columns]).origin.y - ((!)arr[index]).origin.y;\n        }\n        return columns;\n    }\n}\n"
  },
  {
    "path": "src/ui/music-widgets.vala",
    "content": "namespace G4 {\n\n    namespace PageName {\n        public const string ALBUM = \"album\";\n        public const string ARTIST = \"artist\";\n        public const string PLAYING = \"playing\";\n        public const string PLAYLIST = \"playlist\";\n    }\n\n    public class MusicWidget : Gtk.Box {\n        protected Gtk.Image _image = new Gtk.Image ();\n        protected StableLabel _title = new StableLabel ();\n        protected StableLabel _subtitle = new StableLabel ();\n        protected RoundPaintable _paintable = new RoundPaintable ();\n        protected Gtk.Image _playing = new Gtk.Image ();\n\n        public ulong first_draw_handler = 0;\n        public Music? music = null;\n\n        public signal Menu? create_music_menu (Music? node);\n\n        public MusicWidget () {\n            _playing.halign = Gtk.Align.END;\n            _playing.valign = Gtk.Align.CENTER;\n            _playing.icon_name = \"media-playback-start-symbolic\";\n            _playing.margin_end = 4;\n            _playing.pixel_size = 10;\n            _playing.visible = false;\n            _playing.add_css_class (\"dim-label\");\n        }\n\n        public RoundPaintable cover {\n            get {\n                return _paintable;\n            }\n        }\n\n        public Gtk.Image image {\n            get {\n                return _image;\n            }\n        }\n\n        public Gdk.Paintable? paintable {\n            set {\n                _paintable.paintable = value;\n            }\n        }\n\n        public Gtk.Image playing {\n            get {\n                return _playing;\n            }\n        }\n\n        public string title {\n            set {\n                _title.label = value;\n            }\n        }\n\n        public string subtitle {\n            set {\n                _subtitle.label = value;\n                _subtitle.visible = value.length > 0;\n            }\n        }\n\n        public void disconnect_first_draw () {\n            if (first_draw_handler != 0) {\n                _paintable.disconnect (first_draw_handler);\n                first_draw_handler = 0;\n            }\n        }\n\n        public void show_popover_menu (Gtk.Widget widget, double x, double y) {\n            var menu = create_music_menu (music);\n            if (menu != null) {\n                var popover = create_popover_menu ((!)menu, x, y);\n                popover.set_parent (widget);\n                popover.popup ();\n            }\n        }\n    }\n\n    public class MusicCell : MusicWidget {\n        public MusicCell () {\n            orientation = Gtk.Orientation.VERTICAL;\n            margin_top = 10;\n            margin_bottom = 10;\n            width_request = 200;\n\n            var overlay = new Gtk.Overlay ();\n            overlay.margin_bottom = 8;\n            overlay.child = _image;\n            overlay.add_overlay (_playing);\n            append (overlay);\n\n            _image.halign = Gtk.Align.CENTER;\n            _image.pixel_size = 160;\n            _image.paintable = _paintable;\n            _paintable.queue_draw.connect (_image.queue_draw);\n\n            _title.halign = Gtk.Align.CENTER;\n            _title.ellipsize = EllipsizeMode.MIDDLE;\n            _title.margin_start = 2;\n            _title.margin_end = 2;\n            _title.add_css_class (\"title-leading\");\n            append (_title);\n\n            _subtitle.halign = Gtk.Align.CENTER;\n            _subtitle.ellipsize = EllipsizeMode.MIDDLE;\n            _subtitle.margin_start = 2;\n            _subtitle.margin_end = 2;\n            _subtitle.visible = false;\n            _subtitle.add_css_class (\"dim-label\");\n            var font_size = _subtitle.get_pango_context ().get_font_description ().get_size () / Pango.SCALE;\n            if (font_size >= 13)\n                _subtitle.add_css_class (\"title-secondly\");\n            append (_subtitle);\n        }\n    }\n\n    public class MusicEntry : MusicWidget {\n        public MusicEntry (bool compact = true) {\n            width_request = 324;\n\n            var cover_margin = compact ? 3 : 4;\n            var cover_size = compact ? 36 : 48;\n            _image.margin_top = cover_margin;\n            _image.margin_bottom = cover_margin;\n            _image.margin_start = 4;\n            _image.pixel_size = cover_size;\n            _image.paintable = _paintable;\n            _paintable.queue_draw.connect (_image.queue_draw);\n            append (_image);\n\n            var spacing = compact ? 2 : 6;\n            var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, spacing);\n            vbox.hexpand = true;\n            vbox.valign = Gtk.Align.CENTER;\n            vbox.margin_start = 12;\n            vbox.margin_end = 4;\n            vbox.append (_title);\n            vbox.append (_subtitle);\n            append (vbox);\n\n            _title.halign = Gtk.Align.START;\n            _title.ellipsize = EllipsizeMode.END;\n            _title.add_css_class (\"title-leading\");\n\n            _subtitle.halign = Gtk.Align.START;\n            _subtitle.ellipsize = EllipsizeMode.END;\n            _subtitle.add_css_class (\"dim-label\");\n            var font_size = _subtitle.get_pango_context ().get_font_description ().get_size () / Pango.SCALE;\n            if (font_size >= 13)\n                _subtitle.add_css_class (\"title-secondly\");\n\n            append (_playing);\n        }\n\n        public void set_titles (Music music, uint sort) {\n            this.music = music;\n            switch (sort) {\n                case SortMode.ALBUM:\n                    _title.label = music.album;\n                    _subtitle.label = (0 < music.track < int.MAX) ? @\"$(music.track). $(music.title)\" : music.title;\n                    break;\n\n                case SortMode.ARTIST:\n                    _title.label = music.artist;\n                    _subtitle.label = music.title;\n                    break;\n\n                case SortMode.ARTIST_ALBUM:\n                    _title.label = @\"$(music.artist): $(music.album)\";\n                    _subtitle.label = (0 < music.track < int.MAX) ? @\"$(music.track). $(music.title)\" : music.title;\n                    break;\n\n                case SortMode.RECENT:\n                    var date = new DateTime.from_unix_local (music.modified_time);\n                    _title.label = music.title;\n                    _subtitle.label = date.format (\"%x %H:%M\");\n                    break;\n\n                default:\n                    _title.label = music.title;\n                    _subtitle.label = music.artist;\n                    break;\n            }\n        }\n    }\n\n    public string[] build_action_target_for_album (Album album) {\n        unowned var album_artist = album.album_artist;\n        unowned var album_key = album.album_key;\n        var is_playlist = album is Playlist;\n        if (is_playlist)\n            return { PageName.PLAYLIST, album_key };\n        else if (album_artist.length > 0)\n            return { PageName.ARTIST, album_artist, album_key };\n        else\n            return { PageName.ALBUM, album_key };\n    }\n\n    public const string LIBRARY_SCHEME = \"library://\";\n\n    public string build_library_uri (Artist? artist, Album? album) {\n        var album_key = album?.album_key ?? \"\";\n        var arr = (artist != null) ? new string[] { PageName.ARTIST, ((!)artist).artist_name, album_key }\n                    : (album is Playlist) ? new string[] { PageName.PLAYLIST, album_key }\n                        : (album != null) ? new string[] { PageName.ALBUM, album_key }\n                            : new string[] { PageName.PLAYING };\n        return build_library_uri_from_sa (arr);\n    }\n\n    public string build_library_uri_from_sa (string[] arr) {\n        var sb = new StringBuilder (LIBRARY_SCHEME);\n        if (arr.length > 0) {\n            sb.append (arr[0]);\n            for (var i = 1; i < arr.length; i++) {\n                sb.append_c ('/');\n                sb.append (Uri.escape_string (arr[i]));\n            }\n        }\n        return sb.str;\n    }\n\n    public bool parse_library_uri (string uri_str, out string? artist, out string? album, out string? playlist, out string? host = null) {\n        host = null;\n        artist = null;\n        album = null;\n        playlist = null;\n        if (uri_str.has_prefix (LIBRARY_SCHEME)) {\n            var path = uri_str.substring (LIBRARY_SCHEME.length);\n            var arr = path.split (\"/\");\n            if (arr.length > 1) {\n                var key = Uri.unescape_string (arr[1]) ?? \"\";\n                switch (arr[0]) {\n                    case PageName.ALBUM:\n                        album = key;\n                        break;\n                    case PageName.ARTIST:\n                        artist = key;\n                        if (arr.length > 2)\n                            album = Uri.unescape_string (arr[2]);\n                        break;\n                    case PageName.PLAYLIST:\n                        playlist = key;\n                        break;\n                }\n            }\n            host = arr[0];\n            return true;\n        }\n        return false;\n    }\n\n    public MenuItem create_menu_item_for_strv (string[] strv, string label, string action) {\n        var item = new MenuItem (label, null);\n        item.set_action_and_target_value (action, new Variant.strv (strv));\n        return item;\n    }\n\n    public MenuItem create_menu_item_for_uri (string uri, string label, string action) {\n        var item = new MenuItem (label, null);\n        item.set_action_and_target_value (action, new Variant.string (uri));\n        return item;\n    }\n\n    public Menu create_menu_for_album (Album album) {\n        var uri = build_library_uri (null, album);\n        var menu = new Menu ();\n        menu.append_item (create_menu_item_for_uri (uri, _(\"Play\"), ACTION_APP + ACTION_PLAY));\n        menu.append_item (create_menu_item_for_uri (uri, _(\"_Random Play\"), ACTION_APP + ACTION_RANDOM_PLAY));\n        var section = new Menu ();\n        section.append_item (create_menu_item_for_uri (uri, _(\"Play at _Next\"), ACTION_APP + ACTION_PLAY_AT_NEXT));\n        section.append_item (create_menu_item_for_uri (uri, _(\"Add to _Queue\"), ACTION_APP + ACTION_ADD_TO_QUEUE));\n        section.append_item (create_menu_item_for_uri (uri, _(\"Add to _Playlist…\"), ACTION_APP + ACTION_ADD_TO_PLAYLIST));\n        menu.append_section (null, section);\n        if (album is Playlist) {\n            unowned var list_uri = ((Playlist) album).list_uri;\n            if (list_uri.length > 0) {\n                var section2 = new Menu ();\n                section2.append_item (create_menu_item_for_uri (list_uri, _(\"Show List _File\"), ACTION_APP + ACTION_SHOW_FILE));\n                section2.append_item (create_menu_item_for_uri (list_uri, _(\"_Move to Trash\"), ACTION_APP + ACTION_TRASH_FILE));\n                menu.append_section (null, section2);\n            }\n        }\n        return menu;\n    }\n\n    public Menu create_menu_for_artist (Artist artist) {\n        var uri = build_library_uri (artist, null);\n        var menu = new Menu ();\n        menu.append_item (create_menu_item_for_uri (uri, _(\"Play\"), ACTION_APP + ACTION_PLAY));\n        menu.append_item (create_menu_item_for_uri (uri, _(\"_Random Play\"), ACTION_APP + ACTION_RANDOM_PLAY));\n        var section = new Menu ();\n        section.append_item (create_menu_item_for_uri (uri, _(\"Play at _Next\"), ACTION_APP + ACTION_PLAY_AT_NEXT));\n        section.append_item (create_menu_item_for_uri (uri, _(\"Add to _Queue\"), ACTION_APP + ACTION_ADD_TO_QUEUE));\n        section.append_item (create_menu_item_for_uri (uri, _(\"Add to _Playlist…\"), ACTION_APP + ACTION_ADD_TO_PLAYLIST));\n        menu.append_section (null, section);\n        return menu;\n    }\n\n    public Menu create_menu_for_music (Music music, bool has_cover) {\n        var section = new Menu ();\n        section.append_item (create_menu_item_for_strv ({\"title\", music.title}, _(\"Search Title\"), ACTION_WIN + ACTION_SEARCH));\n        section.append_item (create_menu_item_for_strv ({\"album\", music.album}, _(\"Search Album\"), ACTION_WIN + ACTION_SEARCH));\n        section.append_item (create_menu_item_for_strv ({\"artist\", music.artist}, _(\"Search Artist\"), ACTION_WIN + ACTION_SEARCH));\n        unowned var uri = music.uri;\n        var section2 = new Menu ();\n        if (music.cover_uri != null)\n            section2.append_item (create_menu_item_for_uri ((!)music.cover_uri, _(\"Show Cover _File\"), ACTION_APP + ACTION_SHOW_FILE));\n        else if (has_cover)\n            section2.append_item (create_menu_item_for_uri (uri, _(\"_Export Cover\"), ACTION_APP + ACTION_EXPORT_COVER));\n        section2.append_item (create_menu_item_for_uri (uri, _(\"Show _Tags…\"), ACTION_APP + ACTION_SHOW_TAGS));\n        section2.append_item (create_menu_item_for_uri (uri, _(\"Show Music _File\"), ACTION_APP + ACTION_SHOW_FILE));\n        var menu = new Menu ();\n        menu.append_item (create_menu_item_for_uri (uri, _(\"Add to _Playlist…\"), ACTION_APP + ACTION_ADD_TO_PLAYLIST));\n        menu.append_section (null, section);\n        menu.append_section (null, section2);\n        return menu;\n    }\n\n    public Gtk.PopoverMenu create_popover_menu (Menu menu, double x, double y) {\n        var rect = Gdk.Rectangle ();\n        rect.x = (int) x;\n        rect.y = (int) y;\n        rect.width = rect.height = 0;\n\n        var popover = new Gtk.PopoverMenu.from_model (menu);\n        popover.autohide = true;\n        popover.halign = Gtk.Align.START;\n        popover.has_arrow = false;\n        popover.pointing_to = rect;\n        return popover;\n    }\n\n    public delegate void Pressed (Gtk.Widget widget, double x, double y);\n\n    public Gtk.GestureLongPress make_long_pressable (Gtk.Widget widget, Pressed pressed) {\n        var gesture = new Gtk.GestureLongPress ();\n        gesture.pressed.connect ((x, y) => pressed (widget, x, y));\n        widget.add_controller (gesture);\n        return gesture;\n    }\n\n    public Gtk.GestureClick make_right_clickable (Gtk.Widget widget, Pressed pressed) {\n        var gesture = new Gtk.GestureClick ();\n        gesture.button = Gdk.BUTTON_SECONDARY;\n        gesture.pressed.connect ((n, x, y) => pressed (widget, x, y));\n        widget.add_controller (gesture);\n        return gesture;\n    }\n\n    public void remove_controllers (Gtk.Widget widget) {\n        var controllers = widget.observe_controllers ();\n        for (var i = (int) controllers.get_n_items () - 1; i >= 0; i--) {\n            var controller = (Gtk.EventController) controllers.get_item (i);\n            widget.remove_controller (controller);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/narrow-bar.vala",
    "content": "namespace G4 {\n\n    public class NarrowBar : Gtk.Widget {\n        private Gtk.Widget? _child = null;\n        private int _minimum_width = 0;\n        private bool _reveal = true;\n\n        public Gtk.Widget? child {\n            get {\n                return _child;\n            }\n            set {\n                _child?.unparent ();\n                _child = value;\n                _child?.set_parent (this);\n                queue_allocate ();\n            }\n        }\n\n        public bool reveal {\n            get {\n                return _reveal;\n            }\n            set {\n                _reveal = value;\n                queue_allocate ();\n            }\n        }\n\n        public override void measure (Gtk.Orientation orientation, int for_size, out int minimum, out int natural, out int minimum_baseline, out int natural_baseline) {\n            if (_child != null) {\n                ((!)_child).measure (orientation, for_size, out minimum, out natural, out minimum_baseline, out natural_baseline);\n            } else {\n                minimum = natural = minimum_baseline = natural_baseline = 0;\n            }\n            if (orientation == Gtk.Orientation.HORIZONTAL) {\n                _minimum_width = minimum;\n                minimum = _minimum_width / 2;\n            }\n        }\n\n        public override void size_allocate (int width, int height, int baseline) {\n            var wide = width >= _minimum_width;\n            if (_reveal != wide) {\n                _reveal = wide;\n                notify_property (\"reveal\");\n\n                if (wide && _child?.parent == null) {\n                    _child?.set_parent (this);\n                } else if (!wide && _child?.parent != null) {\n                    _child?.unparent ();\n                }\n            }\n\n            if (_child != null) {\n                var allocation = Gtk.Allocation ();\n                allocation.x = 0;\n                allocation.y = 0;\n                allocation.width = width;\n                allocation.height = height;\n                ((!)_child).allocate_size (allocation, baseline);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/paintables.vala",
    "content": "namespace G4 {\n\n    public class BasePaintable : Object, Gdk.Paintable {\n        private bool _first_draw = false;\n        private Gdk.Paintable? _paintable = null;\n\n        public signal void first_draw ();\n        public signal void queue_draw ();\n\n        public BasePaintable (Gdk.Paintable? paintable = null) {\n            _paintable = paintable;\n        }\n\n        public Gdk.Paintable? paintable {\n            get {\n                return _paintable;\n            }\n            set {\n                if (_paintable != value) {\n                    on_change (_paintable, value);\n                    _paintable = value;\n                    queue_draw ();\n                }\n            }\n        }\n\n        public virtual Gdk.Paintable get_current_image () {\n            return _paintable?.get_current_image () ?? this;\n        }\n\n        public virtual Gdk.PaintableFlags get_flags () {\n            return _paintable?.get_flags () ?? 0;\n        }\n\n        public virtual double get_intrinsic_aspect_ratio () {\n            return _paintable?.get_intrinsic_aspect_ratio () ?? 1;\n        }\n\n        public virtual int get_intrinsic_width () {\n            return _paintable?.get_intrinsic_width () ?? 1;\n        }\n\n        public virtual int get_intrinsic_height () {\n            return _paintable?.get_intrinsic_height () ?? 1;\n        }\n\n        public void snapshot (Gdk.Snapshot shot, double width, double height) {\n            if (_first_draw) {\n                _first_draw = false;\n                first_draw ();\n            }\n            on_snapshot ((!)(shot as Gtk.Snapshot), width, height);\n        }\n\n        protected virtual void on_change (Gdk.Paintable? previous, Gdk.Paintable? paintable) {\n            _first_draw = previous != paintable;\n        }\n\n        protected virtual void on_snapshot (Gtk.Snapshot snapshot, double width, double height) {\n            _paintable?.snapshot (snapshot, width, height);\n        }\n    }\n\n    public class RoundPaintable : BasePaintable {\n        private Gsk.RoundedRect _bounds = Gsk.RoundedRect ();\n        private double _ratio = 0;\n\n        public RoundPaintable (Gdk.Paintable? paintable = null, double ratio = 0.1) {\n            base (paintable);\n            _ratio = ratio;\n        }\n\n        public double ratio {\n            get {\n                return _ratio;\n            }\n            set {\n                if (_ratio != value) {\n                    _ratio = value;\n                    queue_draw ();\n                }\n            }\n        }\n\n        public bool contains (Graphene.Point point) {\n            return _bounds.contains_point (point);\n        }\n\n        protected override void on_snapshot (Gtk.Snapshot snapshot, double width, double height) {\n            var rect = Graphene.Rect ();\n            var size = (float) double.min (width, height);\n            var circle = _ratio >= 0.5;\n            if (circle) // Force clip to circle\n                rect.init ((float) (width - size) * 0.5f, (float) (height - size) * 0.5f, size, size);\n            else\n                rect.init (0, 0, (float) width, (float) height);\n\n            var radius = (float) (_ratio * size);\n            _bounds.init_from_rect (rect, radius);\n\n            var saved = false;\n            if (radius > 0) {\n                if (circle && width != height) {\n                    float scale = (float) double.max (width, height) / size;\n                    saved = true;\n                    snapshot.save ();\n                    compute_matrix (snapshot, width, height, 0, scale);\n                }\n                snapshot.push_rounded_clip (_bounds);\n            }\n            base.on_snapshot (snapshot, width, height);\n            if (radius > 0) {\n                snapshot.pop ();\n            }\n            if (saved) {\n                snapshot.restore ();\n            }\n        }\n    }\n\n    public class CrossFadePaintable : BasePaintable {\n        private Gdk.Paintable? _previous = null;\n        private double _fade = 0;\n\n        public CrossFadePaintable (Gdk.Paintable? paintable = null) {\n            base (paintable);\n        }\n\n        public double fade {\n            get {\n                return _fade;\n            }\n            set {\n                if (_fade != value) {\n                    _fade = value;\n                    queue_draw ();\n                }\n            }\n        }\n\n        public Gdk.Paintable? previous {\n            get {\n                return _previous;\n            }\n            set {\n                if (_previous != value) {\n                    _previous = value;\n                    queue_draw ();\n                }\n            }\n        }\n\n        protected override void on_change (Gdk.Paintable? previous, Gdk.Paintable? paintable) {\n            _previous = previous;\n            base.on_change (previous, paintable);\n        }\n\n        protected override void on_snapshot (Gtk.Snapshot snapshot, double width, double height) {\n            if (_fade > 0 && _previous != null) {\n                var width2 = width;\n                var height2 = height;\n                var prev = (!)_previous;\n                var ratio2 = prev.get_intrinsic_aspect_ratio ();\n                var point = Graphene.Point ();\n                var different = ratio2 != get_intrinsic_aspect_ratio ();\n                if (different) {\n                    var max_side = double.max (width, height);\n                    if (ratio2 < 1) {\n                        height2 = max_side;\n                        width2 = height2 * ratio2;\n                    } else {\n                        width2 = max_side;\n                        height2 = width2 / ratio2;\n                    }\n                    point.x = (float) (width - width2) * 0.5f;\n                    point.y = (float) (height - height2) * 0.5f;\n                    snapshot.translate (point);\n                }\n                snapshot.push_opacity (_fade);\n                prev.snapshot (snapshot, width2, height2);\n                snapshot.pop ();\n                if (different) {\n                    point.x = - point.x;\n                    point.y = - point.y;\n                    snapshot.translate (point);\n                }\n            }\n            if (_fade > 0) {\n                snapshot.push_opacity (1 - _fade);\n            }\n            base.on_snapshot (snapshot, width, height);\n            if (_fade > 0) {\n                snapshot.pop ();\n            }\n            //  print (\"fade: %g\\n\", _fade);\n        }\n    }\n\n    public class MatrixPaintable : BasePaintable {\n        private double _rotation = 0;\n        private double _scale = 1;\n\n        public MatrixPaintable (Gdk.Paintable? paintable = null) {\n            base (paintable);\n        }\n\n        public double rotation {\n            get {\n                return _rotation;\n            }\n            set {\n                if (_rotation != value) {\n                    _rotation = value;\n                    queue_draw ();\n                }\n            }\n        }\n\n        public double scale {\n            get {\n                return _scale;\n            }\n            set {\n                if (_scale != value) {\n                    _scale = value;\n                    queue_draw ();\n                }\n            }\n        }\n\n        protected override void on_snapshot (Gtk.Snapshot snapshot, double width, double height) {\n            var saved = _rotation != 0 || _scale != 1;\n            if (saved) {\n                snapshot.save ();\n                compute_matrix (snapshot, width, height, _rotation, _scale);\n            }\n            base.on_snapshot (snapshot, width, height);\n            if (saved) {\n                snapshot.restore ();\n            }\n        }\n    }\n\n    public void compute_matrix (Gtk.Snapshot snapshot, double width, double height,\n                                double rotation = 0, double scale = 1) {\n        var point = Graphene.Point ();\n        point.init ((float) (width * 0.5), (float) (height * 0.5));\n        snapshot.translate (point);\n        if (rotation != 0)\n            snapshot.rotate ((float) rotation);\n        if (scale != 1)\n            snapshot.scale ((float) scale, (float) scale);\n        point.init (- point.x, - point.y);\n        snapshot.translate (point);\n    }\n\n    public const uint32[] BACKGROUND_COLORS = {\n        0xff83b6ecu, 0xff337fdcu,  // blue\n        0xff7ad9f1u, 0xff0f9ac8u,  // cyan\n        0xff8de6b1u, 0xff29ae74u,  // green\n        0xffb5e98au, 0xff6ab85bu,  // lime\n        0xfff8e359u, 0xffd29d09u,  // yellow\n        0xffffcb62u, 0xffd68400u,  // gold\n        0xffffa95au, 0xffed5b00u,  // orange\n        0xfff78773u, 0xffe62d42u,  // raspberry\n        0xffe973abu, 0xffe33b6au,  // magenta\n        0xffcb78d4u, 0xff9945b5u,  // purple\n        0xff9e91e8u, 0xff7a59cau,  // violet\n        0xffe3cf9cu, 0xffb08952u,  // beige\n        0xffbe916du, 0xff785336u,  // brown\n        0xffc0bfbcu, 0xff6e6d71u,  // gray\n    };\n\n    public Gdk.RGBA color_from_uint (uint color) {\n        var c = Gdk.RGBA ();\n        c.alpha = ((color >> 24) & 0xff) / 255f;\n        c.red = ((color >> 16) & 0xff) / 255f;\n        c.green = ((color >> 8) & 0xff) / 255f;\n        c.blue = (color & 0xff) / 255f;\n        return c;\n    }\n\n    public Gdk.Paintable? create_blur_paintable (Gtk.Widget widget, Gdk.Paintable paintable,\n                                int size, double blur = 80, double opacity = 0.25) {\n        var snapshot = new Gtk.Snapshot ();\n        snapshot.push_opacity (opacity);\n        snapshot.push_blur (blur);\n        paintable.snapshot (snapshot, size, size);\n        snapshot.pop ();\n        snapshot.pop ();\n\n        var rect = Graphene.Rect ();\n        rect.init (0, 0, size, size);\n        Gdk.Paintable? result = null;\n        var node = snapshot.free_to_node ();\n        if (node is Gsk.RenderNode) {\n            result = widget.get_native ()?.get_renderer ()?.render_texture ((!)node, rect);\n        }\n        return result ?? snapshot.free_to_paintable (rect.size);\n    }\n\n    public Pango.Layout create_center_text_layout (Pango.Context context, string family, int width, int height, double font_size) {\n        var font = new Pango.FontDescription ();\n        font.set_absolute_size (font_size * Pango.SCALE);\n        font.set_family (family);\n        font.set_weight (Pango.Weight.BOLD);\n\n        var layout = new Pango.Layout (context);\n        layout.set_alignment (Pango.Alignment.CENTER);\n        layout.set_font_description (font);\n        layout.set_width (width * Pango.SCALE);\n        layout.set_height (height * Pango.SCALE);\n        layout.set_single_paragraph_mode (true);\n        return layout;\n    }\n\n    public Gdk.Paintable? create_text_paintable (Pango.Context context, string text, int width, int height, uint color_index = 0x7fffffff) {\n        var snapshot = new Gtk.Snapshot ();\n        var rect = Graphene.Rect ();\n        rect.init (0, 0,  width, height);\n\n        var c = Gdk.RGBA ();\n        c.alpha = 1f;\n        if (color_index < BACKGROUND_COLORS.length / 2) {\n            c.red = c.green = c.blue = 0.9f;\n            var c1 = color_from_uint (BACKGROUND_COLORS[color_index * 2]);\n            var c2 = color_from_uint (BACKGROUND_COLORS[color_index * 2 + 1]);\n            Gsk.ColorStop[] stops = { { 0, c1 }, { 0.5f, c2 }, { 1, c1 } };\n            snapshot.append_linear_gradient (rect, rect.get_top_left (), rect.get_bottom_right (), stops);\n        } else {\n            c.red = c.green = c.blue = 0.5f;\n        }\n\n        var ink_rect = Pango.Rectangle ();\n        var logic_rect = Pango.Rectangle ();\n        var layout = create_center_text_layout (context, \"Serif\", width, height, height * 0.4);\n        layout.set_text (text, text.length);\n        layout.get_pixel_extents (out ink_rect, out logic_rect);\n\n        var pt = Graphene.Point ();\n        pt.x = 0;\n        pt.y = - ink_rect.y + (height - ink_rect.height) * 0.5f;\n        snapshot.translate (pt);\n        snapshot.append_layout (layout, c);\n        pt.y = - pt.y;\n        snapshot.translate (pt);\n        return snapshot.free_to_paintable (rect.size);\n    }\n\n    public unowned string TEXT_SVG_FORMAT = \"\"\"\n<svg width=\"128\" height=\"128\" xmlns=\"http://www.w3.org/2000/svg\">\n    <defs>\n        <linearGradient id=\"background\" x1=\"0\" x2=\"1\" y1=\"0\" y2=\"1\">\n            <stop offset=\"0%\" stop-color=\"#%06x\"/>\n            <stop offset=\"50%\" stop-color=\"#%06x\"/>\n            <stop offset=\"100%\" stop-color=\"#%06x\"/>\n        </linearGradient>\n    </defs>\n    <rect rx=\"12.8\" ry=\"12.8\" width=\"128\" height=\"128\" fill=\"url(#background)\"/>\n    <text x=\"%g\" y=\"%g\" fill=\"#e6e6e6\" font-family=\"Serif\" font-size=\"51.2\" font-weight=\"bold\">%s</text>\n</svg>\n    \"\"\";\n\n    public string create_text_svg (Pango.Context context, string text, uint color_index = 0x7fffffff) {\n        var rect = Graphene.Rect ();\n        var width = 128, height = 128;\n        rect.init (0, 0,  width, height);\n\n        uint c1 = 0, c2 = 0;\n        if (color_index < BACKGROUND_COLORS.length / 2) {\n            c1 = BACKGROUND_COLORS[color_index * 2] & 0x00ffffffu;\n            c2 = BACKGROUND_COLORS[color_index * 2 + 1] & 0x00ffffffu;\n        }\n\n        var ink_rect = Pango.Rectangle ();\n        var logic_rect = Pango.Rectangle ();\n        var layout = create_center_text_layout (context, \"Serif\", width, height, height * 0.4);\n        layout.set_text (text, text.length);\n        layout.get_pixel_extents (out ink_rect, out logic_rect);\n\n        var x = (width - logic_rect.width) * 0.5f;\n        var y = - ink_rect.y + (height + logic_rect.height) * 0.5f;\n        return TEXT_SVG_FORMAT.printf (c1, c2, c1, x, y, text);\n    }\n\n    public Gdk.Paintable? create_widget_paintable (Gtk.Widget widget, ref Graphene.Point point, string? title = null, int max_size = 64) {\n        float width = widget.get_width ();\n        float height = widget.get_height ();\n        var scale = (width > max_size || height > max_size) ? max_size / float.max (width, height) : 1;\n        width *= scale;\n        height *= scale;\n        point.x *= scale;\n        point.y *= scale;\n\n        var paintable = new Gtk.WidgetPaintable (widget);\n        var snapshot = new Gtk.Snapshot ();\n        if (title != null) {\n            var text = (!)title;\n            var ink_rect = Pango.Rectangle ();\n            var logic_rect = Pango.Rectangle ();\n            var layout = create_center_text_layout (widget.get_pango_context (), \"Sans\", (int) width, (int) height, height * 0.2);\n            layout.set_text (text, text.length);\n            layout.get_pixel_extents (out ink_rect, out logic_rect);\n\n            var pt = Graphene.Point ();\n            pt.x = 0;\n            pt.y = logic_rect.height * 0.5f;\n            point.y += pt.y;\n            snapshot.translate (pt);\n            snapshot.scale (scale, scale);\n            paintable.snapshot (snapshot, widget.get_width (), widget.get_height ());\n            snapshot.scale (1 / scale, 1 / scale);\n            pt.y = -pt.y;\n            snapshot.translate (pt);\n\n            pt.x = width - ink_rect.x - logic_rect.width * 0.5f;\n            pt.y = 2;\n            snapshot.translate (pt);\n\n            var rect = Graphene.Rect ();\n            rect.init (0, 0, int.max (logic_rect.width, logic_rect.height), logic_rect.height);\n            rect.offset ((width - rect.size.width) * 0.5f, 0);\n            rect.inset (-2, -2);\n            var bounds = Gsk.RoundedRect ();\n            var radius = rect.size.height * 0.5f;\n            bounds.init_from_rect (rect, radius);\n            snapshot.push_rounded_clip (bounds);\n\n#if ADW_1_6\n            var color = Adw.StyleManager.get_default ().accent_color.to_rgba ();\n#else\n            var color = Gdk.RGBA ();\n            color.red = color.green = color.blue = 0.5f;\n            color.alpha = 1;\n#endif\n            snapshot.append_color (color, rect);\n\n            color.red = color.green = color.blue = 1;\n            pt.x = 0;\n            pt.y = - ink_rect.y + (logic_rect.height - ink_rect.height) * 0.5f;\n            snapshot.translate (pt);\n            snapshot.append_layout (layout, color);\n            snapshot.pop ();\n\n            color.alpha = 0.2f;\n            color.red = color.green = color.blue = 0;\n            snapshot.append_outset_shadow (bounds, color, 1, 1, 1, 5);\n        } else {\n            snapshot.scale (scale, scale);\n            paintable.snapshot (snapshot, widget.get_width (), widget.get_height ());\n            snapshot.scale (1 / scale, 1 / scale);    \n        }\n        return snapshot.free_to_paintable (null);\n    }\n\n    public void draw_outset_shadow (Gtk.Snapshot snapshot, Graphene.Rect rect, float radius = 5) {\n        var bounds = rect;\n        bounds.inset (radius, radius);\n        var outline = Gsk.RoundedRect ();\n        outline.init_from_rect (bounds, radius);\n\n        var style = Adw.StyleManager.get_default ();\n        if (style.high_contrast) {\n            var color = Gdk.RGBA ();\n            color.alpha = 0.5f;\n            color.red = color.green = color.blue = style.dark ? 1 : 0;\n            float[] border_width = { 1, 1, 1, 1 };\n            Gdk.RGBA[] border_color = { color, color, color, color };\n            snapshot.append_border (outline, border_width, border_color);\n        } else {\n            var color = Gdk.RGBA ();\n            color.alpha = 0.2f;\n            color.red = color.green = color.blue = 0;\n            snapshot.append_outset_shadow (outline, color, 1, 1, 1, float.max (radius - 1, 0));\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/peak-bar.vala",
    "content": "namespace G4 {\n\n    public class PeakBar : Gtk.Widget {\n        private unichar[] _chars = { '=', 0 };\n        private int _char_count = 1;\n        private int[] _char_widths = { 10 };\n        private int _char_height = 0;\n        private Pango.Layout _layout;\n        private StringBuilder _sbuilder = new StringBuilder ();\n        private double _value = 0;\n\n        construct {\n            _layout = create_pango_layout (null);\n            _layout.set_alignment (get_direction () == Gtk.TextDirection.RTL ? Pango.Alignment.RIGHT : Pango.Alignment.LEFT);\n        }\n\n        public Pango.Alignment align {\n            get {\n                return _layout.get_alignment ();\n            }\n            set {\n                _layout.set_alignment (value);\n                queue_draw ();\n            }\n        }\n\n        public string characters {\n            get {\n                return ((string32) _chars).to_string () ?? \"\";\n            }\n            set {\n                var count = value.char_count ();\n                _chars = new unichar[count + 1];\n                _char_count = 0;\n                _char_height = 0;\n                var next = 0;\n                unichar c = 0;\n                while (value.get_next_char (ref next, out c)) {\n                    if (!c.ismark ()) {\n                        Pango.Rectangle ink_rect, logic_rect;\n                        var text = c.to_string ();\n                        _layout.set_text (text, text.length);\n                        _layout.get_pixel_extents (out ink_rect, out logic_rect);\n                        _chars[_char_count] = c;\n                        _char_widths[_char_count] = logic_rect.width;\n                        if (_char_height < logic_rect.height)\n                            _char_height = logic_rect.height;\n                        _char_count++;\n                    }\n                }\n                _chars[_char_count] = 0;\n                _char_widths[_char_count] = 0;\n                queue_resize ();\n                queue_draw ();\n            }\n        }\n\n        public double peak {\n            get {\n                return _value;\n            }\n            set {\n                _value = value;\n                queue_draw ();\n            }\n        }\n\n        public override void measure (Gtk.Orientation orientation, int for_size, out int minimum, out int natural, out int minimum_baseline, out int natural_baseline) {\n            if (orientation == Gtk.Orientation.VERTICAL) {\n                minimum = natural = minimum_baseline = natural_baseline = _char_height;\n            } else {\n                minimum = natural = minimum_baseline = natural_baseline = for_size;\n            }\n        }\n\n        public override void snapshot (Gtk.Snapshot snapshot) {\n            var width = get_width ();\n            var height = get_height ();\n            var center = _layout.get_alignment () == Pango.Alignment.CENTER;\n            var value_width = _value * width;\n            _layout.set_width (-1);\n            _layout.set_height (height * Pango.SCALE);\n\n            var char_count = 0;\n            var char_width = 0;\n            _sbuilder.truncate ();\n            if (_char_count > 0) {\n                var last = _char_count - 1;\n                _sbuilder.append_unichar (_chars[0]);\n                char_count++;\n                char_width += _char_widths[0];\n                if (_char_count >= 2) {\n                    char_count++;\n                    char_width += _char_widths[last];\n                }\n                var char1 = _chars[_char_count >= 3 ? 1 : 0];\n                var cx1 = _char_widths[_char_count >= 3 ? 1 : 0];\n                var char2 = _chars[_char_count >= 3 ? _char_count - 2 : _char_count - 1];\n                var cx2 = _char_widths[_char_count >= 3 ? _char_count - 2 : _char_count - 1];\n                if (char1 == char2) {\n                    var count = (int) ((value_width - char_width) / cx1 + 0.5);\n                    if (center && (count + _char_count) % 2 == 0)\n                        count--;\n                    for (var i = 0; i < count; i++) {\n                        _sbuilder.append_unichar (char1);\n                        char_count++;\n                        char_width += cx1;\n                    }\n                } else {\n                    var count = (int) ((value_width - char_width) / (cx1 + cx2) + 0.5);\n                    if (center && (count + _char_count) % 2 == 0)\n                        count--;\n                    for (var i = 0; i < count; i++) {\n                        _sbuilder.append_unichar (char1);\n                        char_count++;\n                        char_width += cx1;\n                    }\n                    for (var j = 0; j < count; j++) {\n                        _sbuilder.append_unichar (char2);\n                        char_count++;\n                        char_width += cx2;\n                    }\n                }\n                if (_char_count >= 2) {\n                    _sbuilder.append_unichar (_chars[last]);\n                }\n            }\n\n#if GTK_4_10\n            var color = get_color ();\n#else\n            var color = get_style_context ().get_color ();\n#endif\n            var opacity = char_width > value_width ? value_width / char_width : 1;\n\n            Pango.Rectangle ink_rect, logic_rect;\n            _layout.set_text (_sbuilder.str, (int) _sbuilder.len);\n            _layout.get_pixel_extents (out ink_rect, out logic_rect);\n            var pt = Graphene.Point ();\n            pt.x = center ? - ink_rect.x + (width - ink_rect.width) * 0.5f : 0;\n            pt.y = - ink_rect.y + (height - ink_rect.height) * 0.5f;\n            snapshot.translate (pt);\n            if (opacity < 1)\n                snapshot.push_opacity (opacity);\n            snapshot.append_layout (_layout, color);\n            if (opacity < 1)\n                snapshot.pop ();\n            pt.x = - pt.x;\n            pt.y = - pt.y;\n            snapshot.translate (pt);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/play-bar.vala",
    "content": "namespace G4 {\n\n    public class PlayBar : Gtk.Box {\n        private Gtk.Scale _seek = new Gtk.Scale (Gtk.Orientation.HORIZONTAL, null);\n        private PeakBar _peak = new PeakBar ();\n        private Gtk.Label _positive = new Gtk.Label (\"0:00\");\n        private Gtk.Label _negative = new Gtk.Label (\"0:00\");\n        private Gtk.ToggleButton _repeat = new Gtk.ToggleButton ();\n        private Gtk.Button _prev = new Gtk.Button ();\n        private Gtk.Button _play = new Gtk.Button ();\n        private Gtk.Button _next = new Gtk.Button ();\n        private VolumeButton _volume = new VolumeButton ();\n        private int _duration = 0;\n        private int _position = 0;\n        private bool _remain_progress = false;\n        private bool _seeking = false;\n\n        public signal void position_seeked (double position);\n\n        construct {\n            orientation = Gtk.Orientation.VERTICAL;\n\n            var app = (Application) GLib.Application.get_default ();\n            var player = app.player;\n\n            _seek.set_range (0, _duration);\n            _seek.halign = Gtk.Align.FILL;\n            append (_seek);\n            setup_seek_bar (player);\n\n            var times = new Gtk.CenterBox ();\n            times.baseline_position = Gtk.BaselinePosition.CENTER;\n            times.halign = Gtk.Align.FILL;\n            times.set_start_widget (_positive);\n            times.set_end_widget (_negative);\n\n            var overlay = new Gtk.Overlay ();\n            overlay.child = times;\n            overlay.add_overlay (_peak);\n            append (overlay);\n\n            _peak.align = Pango.Alignment.CENTER;\n            _peak.halign = Gtk.Align.CENTER;\n            _peak.width_request = 168;\n            _peak.add_css_class (\"dim-label\");\n\n            _positive.halign = Gtk.Align.START;\n            _positive.margin_start = 12;\n            _positive.add_css_class (\"dim-label\");\n            _positive.add_css_class (\"numeric\");\n\n            _negative.halign = Gtk.Align.END;\n            _negative.margin_end = 12;\n            _negative.add_css_class (\"dim-label\");\n            _negative.add_css_class (\"numeric\");\n\n            make_widget_clickable (_negative).pressed.connect (() => remain_progress = !remain_progress);\n\n            var buttons = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 16);\n            buttons.halign = Gtk.Align.CENTER;\n            buttons.margin_top = 16;\n            buttons.append (_repeat);\n            buttons.append (_prev);\n            buttons.append (_play);\n            buttons.append (_next);\n            buttons.append (_volume);\n            append (buttons);\n\n            _repeat.icon_name = \"media-playlist-repeat-symbolic\";\n            _repeat.valign = Gtk.Align.CENTER;\n            /* Translators: single loop the current music */\n            _repeat.tooltip_text = _(\"Single Loop\");\n            _repeat.add_css_class (\"flat\");\n            _repeat.toggled.connect (() => {\n                _repeat.icon_name = _repeat.active ? \"media-playlist-repeat-song-symbolic\" : \"media-playlist-repeat-symbolic\";\n                app.single_loop = ! app.single_loop;\n            });\n\n            _prev.valign = Gtk.Align.CENTER;\n            _prev.action_name = ACTION_APP + ACTION_PREV;\n            _prev.icon_name = \"media-skip-backward-symbolic\";\n            _prev.tooltip_text = _(\"Play Previous\");\n            _prev.add_css_class (\"circular\");\n\n            _play.valign = Gtk.Align.CENTER;\n            _play.action_name = ACTION_APP + ACTION_PLAY_PAUSE;\n            _play.icon_name = \"media-playback-start-symbolic\"; // media-playback-pause-symbolic\n            _play.tooltip_text = _(\"Play/Pause\");\n            _play.add_css_class (\"circular\");\n            _play.set_size_request (48, 48);\n\n            _next.valign = Gtk.Align.CENTER;\n            _next.action_name = ACTION_APP + ACTION_NEXT;\n            _next.icon_name = \"media-skip-forward-symbolic\";\n            _next.tooltip_text = _(\"Play Next\");\n            _next.add_css_class (\"circular\");\n\n            _volume.valign = Gtk.Align.CENTER;\n            player.bind_property (\"volume\", _volume, \"value\", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);\n\n            player.duration_changed.connect (on_duration_changed);\n            player.position_updated.connect (on_position_changed);\n            player.state_changed.connect (on_state_changed);\n\n            var settings = app.settings;\n            settings.bind (\"show-peak\", _peak, \"visible\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"peak-characters\", _peak, \"characters\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"remain-progress\", this, \"remain-progress\", SettingsBindFlags.DEFAULT);\n        }\n\n        public double peak {\n            set {\n                _peak.peak = value;\n            }\n        }\n\n        public double position {\n            get {\n                return _seek.get_value ();\n            }\n        }\n\n        public bool remain_progress {\n            get {\n                return _remain_progress;\n            }\n            set {\n                _remain_progress = value;\n                update_negative_label ();\n            }\n        }\n\n        public void on_size_changed (int bar_width, int bar_spacing) {\n            var text_width = int.max (_positive.get_width (), _negative.get_width ());\n            _peak.width_request = bar_width - (text_width + _positive.margin_start + _negative.margin_end) * 2;\n            get_last_child ()?.set_margin_top (bar_spacing);\n        }\n\n        private void on_duration_changed (Gst.ClockTime duration) {\n            var value = GstPlayer.to_second (duration);\n            _duration = (int) (value + 0.5);\n            _seek.set_range (0, _duration);\n            update_negative_label ();\n        }\n\n        private void on_position_changed (Gst.ClockTime position) {\n            if (!_seeking) {\n                update_position (position);\n            }\n        }\n\n        private void on_state_changed (Gst.State state) {\n            var playing = state == Gst.State.PLAYING;\n            _play.icon_name = playing ? \"media-playback-pause-symbolic\" : \"media-playback-start-symbolic\";\n        }\n\n        private void setup_seek_bar (GstPlayer player) {\n            _seek.change_value.connect ((type, value) => {\n                if (_seeking) {\n                    position_seeked (value);\n                    update_position (GstPlayer.from_second (value));\n                    return true;\n                }\n                return false;\n            });\n\n            // Hack that grabs the click gesture controller as mouse released event doesn't work otherwise\n            // Bug: https://gitlab.gnome.org/GNOME/gtk/-/issues/4939\n            Gtk.GestureClick? click_gesture = null;\n            var controllers = _seek.observe_controllers ();\n            for (var i = 0; i < controllers.get_n_items (); i++) {\n                var controller = controllers.get_item (i);\n                if (controller is Gtk.GestureClick) {\n                    click_gesture = (Gtk.GestureClick) controller;\n                    break;\n                }\n            }\n            if (click_gesture == null) {\n                click_gesture = new Gtk.GestureClick ();\n                _seek.add_controller ((!)click_gesture);\n            }\n            var gesture = (!)click_gesture;\n            gesture.set_button (0);\n            gesture.pressed.connect(() => _seeking = true);\n            gesture.released.connect(() => {\n                _seeking = false;\n                player.seek(GstPlayer.from_second (_seek.get_value ()));\n            });\n        }\n\n        private void update_negative_label () {\n            if (_remain_progress)\n                _negative.label = \"-\" + format_time (_duration - _position);\n            else\n                _negative.label = format_time (_duration);\n        }\n\n        private void update_position (Gst.ClockTime position) {\n            var value = GstPlayer.to_second (position);\n            if (_position != (int) value) {\n                _position = (int) value;\n                _positive.label = format_time (_position);\n                if (_remain_progress)\n                    _negative.label = \"-\" + format_time (_duration - _position);\n            }\n            _seek.set_value (value);\n        }\n    }\n\n    public static string format_time (int seconds) {\n        var sb = new StringBuilder ();\n        var hours = seconds / 3600;\n        var minutes = seconds / 60;\n        seconds -= minutes * 60;\n        if (hours > 0) {\n            minutes -= hours * 60;\n            sb.printf (\"%d:%02d:%02d\", hours, minutes, seconds);\n        } else {\n            sb.printf (\"%d:%02d\", minutes, seconds);\n        }\n        return sb.str;\n    }\n\n    public static Gtk.GestureClick make_widget_clickable (Gtk.Widget label) {\n        var controller = new Gtk.GestureClick ();\n        controller.button = Gdk.BUTTON_PRIMARY;\n        label.add_controller (controller);\n        label.set_cursor_from_name (\"pointer\");\n        return controller;\n    }\n}\n"
  },
  {
    "path": "src/ui/play-panel.vala",
    "content": "namespace G4 {\n\n    [GtkTemplate (ui = \"/com/github/neithern/g4music/gtk/play-panel.ui\")]\n    public class PlayPanel : Gtk.Box, SizeWatcher {\n        [GtkChild]\n        private unowned Gtk.MenuButton action_btn;\n        [GtkChild]\n        private unowned Gtk.Button back_btn;\n        [GtkChild]\n        private unowned Gtk.Label index_label;\n        [GtkChild]\n        private unowned Gtk.Box music_box;\n        [GtkChild]\n        private unowned Gtk.Image music_cover;\n        [GtkChild]\n        private unowned StableLabel music_album;\n        [GtkChild]\n        private unowned StableLabel music_artist;\n        [GtkChild]\n        private unowned StableLabel music_title;\n        [GtkChild]\n        private unowned Gtk.Label initial_label;\n\n        private PlayBar _play_bar = new PlayBar ();\n\n        private Application _app;\n        private double _degrees_per_second = 360 / 20; // 20s per lap\n        private CrossFadePaintable _crossfade_paintable = new CrossFadePaintable ();\n        private MatrixPaintable _matrix_paintable = new MatrixPaintable ();\n        private RoundPaintable _round_paintable = new RoundPaintable ();\n        private bool _rotate_cover = true;\n        private bool _show_peak = true;\n        private bool _size_allocated = false;\n\n        public signal void cover_changed (Music? music, CrossFadePaintable cover);\n\n        public PlayPanel (Application app, Window win, Leaflet leaflet) {\n            _app = app;\n\n            _play_bar.halign = Gtk.Align.FILL;\n            _play_bar.position_seeked.connect (on_position_seeked);\n            music_box.append (_play_bar);\n\n            leaflet.bind_property (\"folded\", back_btn, \"visible\", BindingFlags.SYNC_CREATE);\n\n            action_btn.set_create_popup_func (() => action_btn.menu_model = create_music_action_menu ());\n\n            back_btn.clicked.connect (leaflet.pop);\n\n            _matrix_paintable.paintable = _round_paintable;\n            _crossfade_paintable.paintable = _matrix_paintable;\n            _crossfade_paintable.queue_draw.connect (music_cover.queue_draw);\n            music_cover.paintable = _crossfade_paintable;\n            create_drag_source ();\n\n            index_label.tooltip_text = _(\"Playing\");\n            make_widget_clickable (index_label).released.connect (() => win.open_playing_page ());\n\n            initial_label.activate_link.connect (on_music_folder_clicked);\n\n            music_album.tooltip_text = _(\"Search Album\");\n            music_artist.tooltip_text = _(\"Search Artist\");\n            music_title.tooltip_text = _(\"Search Title\");\n            make_widget_clickable (music_album).released.connect (\n                () => win.start_search (music_album.label, SearchMode.ALBUM));\n            make_widget_clickable (music_artist).released.connect (\n                () => win.start_search (music_artist.label, SearchMode.ARTIST));\n            make_widget_clickable (music_title).released.connect (\n                () => win.start_search (music_title.label, SearchMode.TITLE));\n            make_right_clickable (music_box, show_popover_menu);\n\n            app.index_changed.connect (on_index_changed);\n            app.music_changed.connect (on_music_changed);\n            app.music_cover_parsed.connect (on_music_cover_parsed);\n            app.player.state_changed.connect (on_player_state_changed);\n\n            var settings = app.settings;\n            settings.bind (\"rotate-cover\", this, \"rotate-cover\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"show-peak\", this, \"show-peak\", SettingsBindFlags.DEFAULT);\n        }\n\n        public bool rotate_cover {\n            get {\n                return _rotate_cover;\n            }\n            set {\n                _rotate_cover = value;\n                _round_paintable.ratio = value ? 0.5 : 0.05;\n                _matrix_paintable.rotation = value ? _play_bar.position * _degrees_per_second : 0;\n                on_player_state_changed (_app.player.state);\n            }\n        }\n\n        public bool show_peak {\n            get {\n                return _show_peak;\n            }\n            set {\n                _show_peak = value;\n                on_player_state_changed (_app.player.state);\n            }\n        }\n\n        public void first_allocated () {\n            // Delay update info after the window size allocated to avoid showing slowly\n            _size_allocated = true;\n            on_music_changed (_app.current_music);\n        }\n\n        public void size_to_change (int width, int height) {\n            var max_size = int.max (width * 3 / 4, music_cover.pixel_size);\n            var margin_horz = (width - max_size) / 2;\n            var margin_cover = int.max (margin_horz, 32);\n            music_cover.margin_start = margin_cover;\n            music_cover.margin_end = margin_cover;\n\n            var margin_bar = int.max (margin_horz / 2, 16);\n            var spacing = (height - 540).clamp (8, 16);\n            _play_bar.margin_start = margin_bar;\n            _play_bar.margin_end = margin_bar;\n            _play_bar.margin_top = spacing;\n            _play_bar.margin_bottom = spacing * 2;\n            _play_bar.on_size_changed (width - margin_bar * 2, spacing);\n        }\n\n        private void create_drag_source () {\n            var point = Graphene.Point ();\n            var source = new Gtk.DragSource ();\n            source.actions = Gdk.DragAction.LINK;\n            source.drag_begin.connect ((drag) => source.set_icon (create_widget_paintable (music_cover, ref point), (int) point.x, (int) point.y));\n            source.prepare.connect ((x, y) => {\n                var pt = Graphene.Point ();\n                pt.init ((float) x, (float) y);\n                var width = music_cover.get_width ();\n                var height = music_cover.get_height ();\n                if (width > height)\n                    pt.x -= (width - height) * 0.5f;\n                else if (height > width)\n                    pt.y -= (height - width) * 0.5f;\n                var music = _app.current_music;\n                if (music != null && _round_paintable.contains (pt)) {\n                    point.init ((float) x, (float) y);\n                    var playlist = to_playlist ({ (!)music });\n                    return create_content_provider (playlist);\n                }\n                return null;\n            });\n            music_cover.add_controller (source);\n        }\n\n        private Menu create_music_action_menu () {\n            var music = _app.current_music ?? new Music.empty ();\n            return create_menu_for_music (music, _app.current_cover != null);\n        }\n\n        private void on_index_changed (int index, uint size) {\n            root.action_set_enabled (ACTION_APP + ACTION_PREV, index > 0);\n            root.action_set_enabled (ACTION_APP + ACTION_NEXT, index < (int) size - 1);\n            index_label.label = size > 0 ? @\"$(index+1)/$(size)\" : \"\";\n        }\n\n        private void on_music_changed (Music? music) {\n            if (!_size_allocated)\n                return;\n\n            music_album.label = music?.album ?? \"\";\n            music_artist.label = music?.artist ?? \"\";\n            music_title.label = music?.title ?? \"\";\n\n            var empty = _app.current_music == null && _app.current_list.get_n_items () == 0;\n            initial_label.visible = empty;\n            if (empty) {\n                if (_app.loading || !_app.loader.library.empty)\n                    initial_label.label = \"\";\n                else\n                    update_initial_label (_app.music_folder);\n            }\n\n            var enabled = music != null;\n            if (!enabled) {\n                update_cover_paintables (music, _app.icon);\n            }\n            action_btn.sensitive = enabled;\n            root.action_set_enabled (ACTION_APP + ACTION_PLAY_PAUSE, enabled);\n            Window.get_default ()?.set_title (music?.get_artist_and_title () ?? _app.name);\n        }\n\n        private bool on_music_folder_clicked (string uri) {\n            pick_music_folder (_app, root as Window,\n                (dir) => update_initial_label (dir.get_uri ()));\n            return true;\n        }\n\n        private async void on_music_cover_parsed (Music music, Gdk.Pixbuf? pixbuf, string? uri) {\n            var paintable = pixbuf != null ? Gdk.Texture.for_pixbuf ((!)pixbuf)\n                            : _app.thumbnailer.create_music_text_paintable (music);\n            update_cover_paintables (music, paintable);\n        }\n\n        private Adw.Animation? _scale_animation = null;\n        private uint _tick_handler = 0;\n        private int64 _tick_last_time = 0;\n\n        private void on_player_state_changed (Gst.State state) {\n            var playing = state == Gst.State.PLAYING;\n            if (state >= Gst.State.PAUSED) {\n                var target = new Adw.CallbackAnimationTarget ((value) => _matrix_paintable.scale = value);\n                _scale_animation?.pause ();\n                _scale_animation = new Adw.TimedAnimation (music_cover, _matrix_paintable.scale,\n                                        _rotate_cover || playing ? 1 : 0.85, 500, target);\n                _scale_animation?.play ();\n            }\n\n            var need_tick = _rotate_cover || _show_peak;\n            if (need_tick && playing && _tick_handler == 0) {\n                _tick_last_time = get_monotonic_time ();\n                _tick_handler = add_tick_callback (on_tick_callback);\n            } else if ((!need_tick || !playing) && _tick_handler != 0) {\n                remove_tick_callback (_tick_handler);\n                _tick_handler = 0;\n            }\n        }\n\n        private void on_position_seeked (double pos) {\n            if (_rotate_cover)\n                _matrix_paintable.rotation = pos * _degrees_per_second;\n        }\n\n        private bool on_tick_callback (Gtk.Widget widget, Gdk.FrameClock clock) {\n            if (_rotate_cover) {\n                var now = get_monotonic_time ();\n                var elapsed = (now - _tick_last_time) / 1e6;\n                var angle = elapsed * _degrees_per_second;\n                _matrix_paintable.rotation += angle;\n                _tick_last_time = now;\n            }\n            if (_show_peak) {\n                var peak = _app.player.peak;\n                _play_bar.peak = peak;\n            }\n            return true;\n        }\n\n        private void show_popover_menu (Gtk.Widget widget, double x, double y) {\n            if (_app.current_music != null) {\n                var menu = create_music_action_menu ();\n                var popover = create_popover_menu (menu, x, y);\n                popover.set_parent (widget);\n                popover.popup ();\n            }\n        }\n\n        private void update_cover_paintables (Music? music, Gdk.Paintable? paintable) {\n            _round_paintable = new RoundPaintable (paintable);\n            _round_paintable.ratio = _rotate_cover ? 0.5 : 0.05;\n            _round_paintable.queue_draw.connect (music_cover.queue_draw);\n            _matrix_paintable = new MatrixPaintable (_round_paintable);\n            _matrix_paintable.queue_draw.connect (music_cover.queue_draw);\n            _crossfade_paintable.paintable = _matrix_paintable;\n            cover_changed (music, _crossfade_paintable);\n        }\n\n        private void update_initial_label (string uri) {\n            var dir_name = Uri.escape_string (get_display_name (uri));\n            var link = @\"<a href=\\\"change_dir\\\">$dir_name</a>\";\n            initial_label.set_markup (_(\"Drag and drop music files here,\\nor change music location: \") + link);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/playlist-dialog.vala",
    "content": "namespace G4 {\n\n    public class PlaylistDialog : Dialog {\n        private Gtk.ToggleButton search_btn = new Gtk.ToggleButton ();\n        private Gtk.SearchEntry search_entry = new Gtk.SearchEntry ();\n\n        private Application _app;\n        private SourceFunc? _callback = null;\n        private MusicList? _list = null;\n        private Playlist? _playlist = null;\n\n        public PlaylistDialog (Application app) {\n            _app = app;\n\n            var content = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);\n            this.child = content;\n\n            var header = new Gtk.HeaderBar ();\n            header.title_widget = new Gtk.Label (_(\"Add to Playlist\"));\n            header.add_css_class (\"flat\");\n            content.append (header);\n\n            var new_btn = new Gtk.Button.from_icon_name (\"folder-new-symbolic\");\n            new_btn.tooltip_text = _(\"New Playlist\");\n            new_btn.clicked.connect (() => close_with_result (new Playlist (\"\")));\n            header.pack_start (new_btn);\n\n            header.pack_end (search_btn);\n\n            var search_bar = new Gtk.SearchBar ();\n            search_bar.child = search_entry;\n            search_bar.key_capture_widget = content;\n            content.append (search_bar);\n\n            search_btn.icon_name = \"edit-find-symbolic\";\n            search_btn.tooltip_text = _(\"Search\");\n            search_btn.toggled.connect (on_search_btn_toggled);\n            search_btn.bind_property (\"active\", search_bar, \"search-mode-enabled\", BindingFlags.BIDIRECTIONAL);\n            search_entry.hexpand = true;\n            search_entry.search_changed.connect (on_search_text_changed);\n\n            var loading_paintable = app.thumbnailer.create_simple_text_paintable (\"...\", Thumbnailer.ICON_SIZE);\n            var list = new MusicList (app, typeof (Playlist), null, false, false);\n            list.hexpand = true;\n            list.vexpand = true;\n            list.margin_bottom = 2;\n            list.item_activated.connect ((position, obj) => close_with_result (obj as Playlist));\n            list.item_created.connect ((item) => {\n                var cell = (MusicWidget) item.child;\n                cell.playing.icon_name = \"document-open-recent-symbolic\";\n            });\n            list.item_binded.connect ((item) => {\n                var cell = (MusicWidget) item.child;\n                var playlist = (Playlist) item.item;\n                cell.music = playlist;\n                cell.paintable = loading_paintable;\n                cell.title = playlist.title;\n            });\n            content.append (list);\n            _list = list;\n\n            app.music_library_changed.connect (on_music_library_changed);\n            on_music_library_changed (true);\n        }\n\n        public async Playlist? choose (Gtk.Window? parent = null) {\n            _callback = choose.callback;\n            present (parent);\n            yield;\n            return _playlist;\n        }\n\n        public override void closed () {\n            _app.music_library_changed.disconnect (on_music_library_changed);\n\n            var list = _list;\n            _list = null;\n            run_idle_once (() => list?.unparent (), Priority.LOW);\n\n            var callback = _callback;\n            _callback = null;\n            if (callback != null)\n                Idle.add ((!)callback);\n        }\n\n        private void close_with_result (Playlist? playlist) {\n            _playlist = playlist;\n            if ((playlist?.list_uri?.length ?? 0) > 0)\n                _app.settings.set_string (\"recent-playlist\", ((!)playlist).list_uri);\n            close ();\n        }\n\n        private void on_music_library_changed (bool external) {\n            if (external && _list != null) {\n                var list = (!)_list;\n                var library = _app.loader.library;\n                var store = list.data_store;\n                var text = _(\"No playlist found in %s\").printf (get_display_name (_app.music_folder));\n                library.overwrite_playlists_to (store);\n                list.set_empty_text (text);\n\n                var recent_uri = _app.settings.get_string (\"recent-playlist\");\n                list.current_node = library.get_playlist ((!)recent_uri);\n                list.set_to_current_item (true);\n            }\n        }\n\n        private void on_search_btn_toggled () {\n            if (search_btn.active) {\n                search_entry.grab_focus ();\n            }\n            on_search_text_changed ();\n        }\n\n        private string _search_text = \"\";\n\n        private bool on_search_match (Object obj) {\n            unowned var playlist = (Playlist) obj;\n            return _search_text.match_string (playlist.title, true);\n        }\n\n        private void on_search_text_changed () {\n            _search_text = search_entry.text;\n            var model = _list?.filter_model;\n            if (search_btn.active && model?.get_filter () == null) {\n                model?.set_filter (new Gtk.CustomFilter (on_search_match));\n            } else if (!search_btn.active && model?.get_filter () != null) {\n                model?.set_filter (null);\n            }\n            model?.get_filter ()?.changed (Gtk.FilterChange.DIFFERENT);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/preferences.vala",
    "content": "namespace G4 {\n    namespace BlurMode {\n        public const uint NEVER = 0;\n        public const uint ALWAYS = 1;\n        public const uint ART_ONLY = 2;\n    }\n\n    [GtkTemplate (ui = \"/com/github/neithern/g4music/gtk/preferences.ui\")]\n    public class PreferencesWindow : Adw.PreferencesWindow {\n        [GtkChild]\n        unowned Adw.ComboRow blur_row;\n        [GtkChild]\n        unowned Gtk.Switch compact_btn;\n        [GtkChild]\n        unowned Gtk.Switch grid_btn;\n        [GtkChild]\n        unowned Gtk.Switch single_btn;\n        [GtkChild]\n        unowned Gtk.Button music_dir_btn;\n        [GtkChild]\n        unowned Gtk.Switch monitor_btn;\n        [GtkChild]\n        unowned Gtk.Switch thumbnail_btn;\n        [GtkChild]\n        unowned Gtk.Switch playbkgnd_btn;\n        [GtkChild]\n        unowned Gtk.Switch rotate_btn;\n        [GtkChild]\n        unowned Gtk.Switch gapless_btn;\n        [GtkChild]\n        unowned Adw.ComboRow replaygain_row;\n        [GtkChild]\n        unowned Adw.ComboRow audiosink_row;\n        [GtkChild]\n        unowned Adw.ExpanderRow peak_row;\n        [GtkChild]\n        unowned Gtk.Entry peak_entry;\n\n        private GenericArray<Gst.ElementFactory> _audio_sinks = new GenericArray<Gst.ElementFactory> (8);\n\n        public PreferencesWindow (Application app) {\n            var settings = app.settings;\n\n            blur_row.model = new Gtk.StringList ({_(\"Never\"), _(\"Always\"), _(\"Art Only\")});\n            settings.bind (\"blur-mode\", blur_row, \"selected\", SettingsBindFlags.DEFAULT);\n\n            settings.bind (\"compact-playlist\", compact_btn, \"active\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"grid-mode\", grid_btn, \"active\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"single-click-activate\", single_btn, \"active\", SettingsBindFlags.DEFAULT);\n\n            music_dir_btn.label = get_display_name (app.music_folder);\n            music_dir_btn.clicked.connect (() => {\n                pick_music_folder (app, this, (dir) => {\n                    music_dir_btn.label = get_display_name (app.music_folder);\n                });\n            });\n\n            settings.bind (\"monitor-changes\", monitor_btn, \"active\", SettingsBindFlags.DEFAULT);\n\n            settings.bind (\"remote-thumbnail\", thumbnail_btn, \"active\", SettingsBindFlags.DEFAULT);\n\n            settings.bind (\"play-background\", playbkgnd_btn, \"active\", SettingsBindFlags.DEFAULT);\n\n            settings.bind (\"rotate-cover\", rotate_btn, \"active\", SettingsBindFlags.DEFAULT);\n\n            replaygain_row.model = new Gtk.StringList ({_(\"Never\"), _(\"Track\"), _(\"Album\")});\n            settings.bind (\"replay-gain\", replaygain_row, \"selected\", SettingsBindFlags.DEFAULT);\n\n            settings.bind (\"gapless-playback\", gapless_btn, \"active\", SettingsBindFlags.DEFAULT);\n\n            settings.bind (\"show-peak\", peak_row, \"enable_expansion\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"peak-characters\", peak_entry, \"text\", SettingsBindFlags.DEFAULT);\n\n            GstPlayer.get_audio_sinks (_audio_sinks);\n            var sink_names = new string[_audio_sinks.length];\n            for (var i = 0; i < _audio_sinks.length; i++)\n                sink_names[i] = get_audio_sink_name (_audio_sinks[i]);\n            audiosink_row.model = new Gtk.StringList (sink_names);\n            this.bind_property (\"audio_sink\", audiosink_row, \"selected\", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);\n        }\n\n        public uint audio_sink {\n            get {\n                var app = (Application) GLib.Application.get_default ();\n                var sink_name = app.player.audio_sink;\n                for (int i = 0; i < _audio_sinks.length; i++) {\n                    if (sink_name == _audio_sinks[i].name)\n                        return i;\n                }\n                return _audio_sinks.length > 0 ? 0 : -1;\n            }\n            set {\n                if (value < _audio_sinks.length) {\n                    var app = (Application) GLib.Application.get_default ();\n                    app.player.audio_sink = _audio_sinks[value].name;\n                }\n            }\n        }\n    }\n\n    public string get_audio_sink_name (Gst.ElementFactory factory) {\n        var name = factory.get_metadata (\"long-name\") ?? factory.name;\n        name = name.replace (\"Audio sink\", \"\")\n                    .replace (\"Audio Sink\", \"\")\n                    .replace (\"sink\", \"\")\n                    .replace (\"(\", \"\").replace (\")\", \"\");\n        return name.strip ();\n    }\n\n    public delegate void FolderPicked (File dir);\n\n    public void pick_music_folder (Application app, Gtk.Window? parent, FolderPicked picked) {\n        var music_dir = File.new_for_uri (app.music_folder);\n        show_select_folder_dialog.begin (parent, music_dir, (obj, res) => {\n            var dir = show_select_folder_dialog.end (res);\n            if (dir != null) {\n                var uri = ((!)dir).get_uri ();\n                if (app.music_folder != uri)\n                    app.music_folder = uri;\n                picked ((!)dir);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "src/ui/stable-label.vala",
    "content": "namespace G4 {\n\n    public enum EllipsizeMode {\n        NONE = Pango.EllipsizeMode.NONE,\n        START = Pango.EllipsizeMode.START,\n        MIDDLE = Pango.EllipsizeMode.MIDDLE,\n        END = Pango.EllipsizeMode.END,\n        MARQUEE\n    }\n\n    public class StableLabel : Gtk.Widget {\n        private EllipsizeMode _ellipsize = EllipsizeMode.NONE;\n        private Gtk.Label _label = new Gtk.Label (null);\n        private float _label_offset = 0;\n        private int _label_width = 0;\n\n        construct {\n            _label.xalign = 0;\n            _label.set_parent (this);\n        }\n\n        ~StableLabel () {\n            _label.unparent ();\n        }\n\n        public EllipsizeMode ellipsize {\n            get {\n                return _ellipsize;\n            }\n            set {\n                _ellipsize = value;\n                _label.ellipsize = value == EllipsizeMode.MARQUEE ? Pango.EllipsizeMode.NONE : (Pango.EllipsizeMode) value;\n                stop_tick ();\n            }\n        }\n\n        public string label {\n            get {\n                return _label.label;\n            }\n            set {\n                _label.label = value;\n                stop_tick ();\n            }\n        }\n\n        public bool marquee {\n            get {\n                return _ellipsize == EllipsizeMode.MARQUEE;\n            }\n            set {\n                ellipsize = value ? EllipsizeMode.MARQUEE : EllipsizeMode.NONE;\n            }\n        }\n\n        public override void measure (Gtk.Orientation orientation, int for_size, out int minimum, out int natural, out int minimum_baseline, out int natural_baseline) {\n            if (orientation == Gtk.Orientation.VERTICAL) {\n                // Ensure enough space for different text\n                var text = _label.label;\n                _label.label = \"A中\";\n                _label.measure (orientation, for_size, out minimum, out natural, out minimum_baseline, out natural_baseline);\n                _label.label = text;\n            } else {\n                _label.measure (orientation, for_size, out minimum, out natural, out minimum_baseline, out natural_baseline);\n                _label_width = natural;\n                if (marquee)\n                    minimum = 0;\n            }\n        }\n\n        public override void size_allocate (int width, int height, int baseline) {\n            var allocation = Gtk.Allocation ();\n            allocation.x = 0;\n            allocation.y = 0;\n            allocation.width = width;\n            allocation.height = height;\n            _label.allocate_size (allocation, baseline);\n            update_tick_delayed ();\n        }\n\n        private static float SPACE = 40f;\n\n        public override void snapshot (Gtk.Snapshot snapshot) {\n            var width = get_width ();\n            var overflow = marquee && width < _label_width;\n            if (overflow) {\n                var height = get_height ();\n                var total_width = _label_width + SPACE;\n#if GTK_4_10\n                var mask_width = float.min (width * 0.1f, height * 1.25f);\n                var left_mask = _label_offset < mask_width ? _label_offset : (_label_offset + mask_width > total_width ? 0 : mask_width);\n                var rect = Graphene.Rect ();\n                rect.init (0, 0, left_mask, height);\n                Gsk.ColorStop[] stops = { { 0, color_from_uint (0xff000000u) }, { 1, color_from_uint (0x00000000u) } };\n                snapshot.push_mask(Gsk.MaskMode.INVERTED_ALPHA);\n                snapshot.append_linear_gradient (rect, rect.get_top_left (), rect.get_top_right (), stops);\n                rect.init (width - mask_width, 0, mask_width, height);\n                snapshot.append_linear_gradient (rect, rect.get_top_right (), rect.get_top_left (), stops);\n                snapshot.pop ();\n#endif\n                var bounds = Graphene.Rect ();\n                bounds.init (0, 0, width, height);\n                snapshot.push_clip (bounds);\n                var point = Graphene.Point ();\n                point.init (0, 0);\n                if (_label_offset < _label_width) {\n                    point.x = - _label_offset;\n                    snapshot.translate (point);\n                    base.snapshot (snapshot);\n                    point.x = - point.x;\n                    snapshot.translate (point);\n                }\n                if (_label_offset >= total_width - width) {\n                    point.x = - _label_offset + total_width;\n                    snapshot.translate (point);\n                    base.snapshot (snapshot);\n                    point.x = - point.x;\n                    snapshot.translate (point);\n                }\n                snapshot.pop ();\n#if GTK_4_10\n                snapshot.pop ();  // Must call again if snapshot.push_mask() ???\n#endif\n            } else {\n                base.snapshot (snapshot);\n            }\n        }\n\n        private uint _pixels_per_second = 24;\n        private uint _tick_handler = 0;\n        private bool _tick_moving = false;\n        private int64 _tick_start_time = 0;\n\n        private bool on_tick_callback (Gtk.Widget widget, Gdk.FrameClock clock) {\n            if (_tick_moving) {\n                var now = get_monotonic_time ();\n                var elapsed = (now - _tick_start_time) / 1e6f;\n                _label_offset = elapsed * _pixels_per_second;\n                if (_label_offset > _label_width + SPACE) {\n                    stop_tick ();\n                    update_tick_delayed ();\n                }\n                queue_draw ();\n            }\n            return true;\n        }\n\n        private void stop_tick () {\n            if (_tick_handler != 0) {\n                remove_tick_callback (_tick_handler);\n                _tick_handler = 0;\n            }\n            if (_timer_id != 0) {\n                Source.remove (_timer_id);\n                _timer_id = 0;\n            }\n            _label_offset = 0;\n            _tick_moving = false;\n        }\n\n        private void update_tick () {\n            var need_tick = marquee && get_width () < _label_width;\n            if (need_tick && _tick_handler == 0) {\n                _tick_handler = add_tick_callback (on_tick_callback);\n                _tick_moving = _tick_handler != 0;\n                _tick_start_time = get_monotonic_time ();\n            } else if (!need_tick && _tick_handler != 0) {\n                stop_tick ();\n            }\n        }\n\n        private static uint TICK_WAIT = 3000;\n        private uint _timer_id = 0;\n\n        private void update_tick_delayed () {\n            if (_timer_id == 0) {\n                _timer_id = run_timeout_once (TICK_WAIT, () => {\n                    _timer_id = 0;\n                    update_tick ();\n                });\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/ui/store-panel.vala",
    "content": "namespace G4 {\n\n    namespace SearchMode {\n        public const uint ANY = 0;\n        public const uint ALBUM = 1;\n        public const uint ARTIST = 2;\n        public const uint TITLE = 3;\n    }\n\n    public const string[] SORT_MODE_ICONS = {\n        \"media-optical-cd-audio-symbolic\",  // ALBUM\n        \"system-users-symbolic\",            // ARTIST\n        \"avatar-default-symbolic\",          // ARTIST_ALBUM\n        \"folder-music-symbolic\",            // TITLE\n        \"document-open-recent-symbolic\",    // RECENT\n        \"media-playlist-shuffle-symbolic\",  // SHUFFLE\n    };\n\n    namespace StackFlags {\n        public const uint FIRST = 1;\n        public const uint ARTISTS = 1;\n        public const uint ALBUMS = 2;\n        public const uint PLAYLISTS = 3;\n        public const uint LAST = 4;\n    }\n\n    [GtkTemplate (ui = \"/com/github/neithern/g4music/gtk/store-panel.ui\")]\n    public class StorePanel : Gtk.Box, SizeWatcher {\n        [GtkChild]\n        public unowned Gtk.HeaderBar header_bar;\n        [GtkChild]\n        public unowned Gtk.Label indicator;\n        [GtkChild]\n        private unowned Gtk.MenuButton sort_btn;\n        [GtkChild]\n        private unowned Gtk.ToggleButton search_btn;\n        [GtkChild]\n        private unowned Gtk.SearchBar search_bar;\n        [GtkChild]\n        private unowned Gtk.SearchEntry search_entry;\n        [GtkChild]\n        private unowned Gtk.Stack stack_view;\n\n        private Stack _album_stack = new Stack ();\n        private Stack _artist_stack = new Stack ();\n        private Stack _playlist_stack = new Stack ();\n        private MiniBar _mini_bar = new MiniBar ();\n        private Gtk.StackSwitcher _switcher_top = new Gtk.StackSwitcher ();\n        private Gtk.StackSwitcher _switcher_btm = new Gtk.StackSwitcher ();\n\n        private Application _app;\n        private MusicList _album_list;\n        private MusicList _artist_list;\n        private MusicList _current_list;\n        private MainMusicList _main_list;\n        private MusicList _playlist_list;\n        private MusicLibrary _library;\n        private string? _library_uri = null;\n        private Gdk.Paintable _loading_paintable;\n        private uint _search_mode = SearchMode.ANY;\n        private string _search_text = \"\";\n        private bool _size_allocated = false;\n        private uint _sort_mode = -1;\n        private bool _updating_store = false;\n\n        public StorePanel (Application app, Window win, Leaflet leaflet) {\n            _app = app;\n            _library = app.loader.library;\n            margin_bottom = 6;\n\n            var thumbnailer = app.thumbnailer;\n            thumbnailer.pango_context = get_pango_context ();\n            thumbnailer.scale_factor = this.scale_factor;\n            _loading_paintable = thumbnailer.create_simple_text_paintable (\"...\", Thumbnailer.ICON_SIZE);\n\n            search_btn.toggled.connect (on_search_btn_toggled);\n            search_bar.key_capture_widget = win.content;\n            search_entry.search_changed.connect (on_search_text_changed);\n\n            _main_list = create_main_music_list ();\n            _main_list.data_store = _app.music_queue;\n            _app.current_list = _main_list.filter_model;\n            _current_list = _main_list;\n            stack_view.add_titled (_main_list, PageName.PLAYING, _(\"Playing\")).icon_name = \"user-home-symbolic\";\n\n            _artist_list = create_artist_list ();\n            _artist_stack.add (_artist_list, PageName.ARTIST);\n            _artist_stack.bind_property (\"visible-child\", this, \"visible-child\");\n            stack_view.add_titled (_artist_stack.widget, PageName.ARTIST, _(\"Artists\")).icon_name = \"system-users-symbolic\";\n\n            _album_list = create_album_list ();\n            _album_stack.add (_album_list, PageName.ALBUM);\n            _album_stack.bind_property (\"visible-child\", this, \"visible-child\");\n            stack_view.add_titled (_album_stack.widget, PageName.ALBUM, _(\"Albums\")).icon_name = \"drive-multidisk-symbolic\";\n\n            _playlist_list = create_playlist_list ();\n            _playlist_stack.add (_playlist_list, PageName.PLAYLIST);\n            _playlist_stack.bind_property (\"visible-child\", this, \"visible-child\");\n            stack_view.add_titled (_playlist_stack.widget, PageName.PLAYLIST, _(\"Playlists\")).icon_name = \"view-list-symbolic\";\n\n            stack_view.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT;\n            stack_view.bind_property (\"visible-child\", this, \"visible-child\");\n\n            var mini_revealer = new Gtk.Revealer ();\n            mini_revealer.child = _mini_bar;\n            mini_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_UP;\n            _mini_bar.activated.connect (leaflet.push);\n            append (mini_revealer);\n            leaflet.bind_property (\"folded\", mini_revealer, \"reveal-child\", BindingFlags.SYNC_CREATE);\n            leaflet.bind_property (\"folded\", header_bar, \"show-title-buttons\");\n\n            var top_revealer = new NarrowBar ();\n            top_revealer.child = _switcher_top;\n            _switcher_top.stack = stack_view;\n            fix_switcher_style (_switcher_top);\n            header_bar.pack_end (top_revealer);\n\n            var btm_revealer = new Gtk.Revealer ();\n            btm_revealer.child = _switcher_btm;\n            btm_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_UP;\n            append (btm_revealer);\n            top_revealer.bind_property (\"reveal\", btm_revealer, \"reveal-child\", BindingFlags.INVERT_BOOLEAN);\n\n            _switcher_btm.margin_top = 2;\n            _switcher_btm.margin_start = 6;\n            _switcher_btm.margin_end = 6;\n            _switcher_btm.stack = stack_view;\n            fix_switcher_style (_switcher_btm);\n\n            app.music_changed.connect (on_music_changed);\n            app.music_library_changed.connect (on_music_library_changed);\n            app.playlist_added.connect (on_playlist_added);\n            app.thumbnail_changed.connect (on_thumbnail_changed);\n\n            var settings = app.settings;\n            settings.bind (\"sort-mode\", this, \"sort-mode\", SettingsBindFlags.DEFAULT);\n            _library_uri = settings.get_string (\"library-uri\");\n            initialize_library_page ();\n        }\n\n        public MusicList current_list {\n            get {\n                return _current_list;\n            }\n        }\n\n        public bool modified {\n            get {\n                return _current_list.modified;\n            }\n            set {\n                indicator.visible = _current_list.modified;\n                root.action_set_enabled (ACTION_WIN + ACTION_SAVE_LIST, _current_list.modified);\n            }\n        }\n\n        public uint sort_mode {\n            get {\n                return _sort_mode;\n            }\n            set {\n                _sort_mode = value;\n                if (value < SORT_MODE_ICONS.length)\n                    sort_btn.set_icon_name (SORT_MODE_ICONS[value]);\n                if (_main_list.get_height () > 0)\n                    _main_list.create_factory ();\n            }\n        }\n\n        public Gtk.Widget visible_child {\n            set {\n                if (_size_allocated) {\n                    update_visible_stack ();\n                }\n                save_if_modified (true);\n\n                if (value == stack_view.visible_child) {\n                    var stack = get_current_stack ();\n                    if (stack != null)\n                        value = ((!)stack).visible_child;\n                }\n                if (value is MusicList) {\n                    var list = _current_list = (MusicList) value;\n                    indicator.visible = _current_list.modified;\n                    sort_btn.visible = _current_list == _main_list;\n                    _search_mode = SearchMode.ANY;\n                    on_search_btn_toggled ();\n\n                    var scroll = !_overlayed_lists.remove (list);\n                    set_to_current_music (scroll);\n                }\n                save_current_page ();\n            }\n        }\n\n        public void first_allocated () {\n            // Delay set model after the window size allocated to avoid showing slowly\n            _size_allocated = true;\n        }\n\n        public void remove_from_list (Music music) {\n            uint position = -1;\n            if (_current_list.data_store.find (music, out position)) {\n                _current_list.data_store.remove (position);\n                _current_list.modified = true;\n            }\n        }\n\n        public bool save_if_modified (bool prompt = true, VoidFunc? done = null) {\n            if (_current_list != _main_list) {\n                _main_list.save_if_modified.begin (false, (obj, res) => _main_list.save_if_modified.end (res));\n            }\n            if (_current_list.modified) {\n                _current_list.save_if_modified.begin (prompt, (obj, res) => {\n                    var ret = _current_list.save_if_modified.end (res);\n                    if (ret != Result.FAILED) {\n                        _current_list.modified = false;\n                        if (done != null)\n                            ((!)done) ();\n                    }\n                });\n                return true;\n            }\n            return false;\n        }\n\n        public void set_mini_cover (Gdk.Paintable? cover) {\n            _mini_bar.cover = cover;\n        }\n\n        public void size_to_change (int width, int height) {\n        }\n\n        public void start_search (string text, uint mode = SearchMode.ANY) {\n            switch (mode) {\n                case SearchMode.ALBUM:\n                    stack_view.visible_child = _album_stack.widget;\n                    break;\n                case SearchMode.ARTIST:\n                    stack_view.visible_child = _artist_stack.widget;\n                    break;\n                case SearchMode.TITLE:\n                    stack_view.visible_child = _main_list;\n                    break;\n            }\n\n#if GTK_4_10\n            var delay = search_entry.search_delay;\n            search_entry.search_delay = 0;\n            run_idle_once (() => search_entry.search_delay = delay);\n#endif\n            search_entry.text = text;\n            search_entry.select_region (0, -1);\n            search_btn.active = true;\n            _search_mode = mode;\n        }\n\n        public bool toggle_search () {\n            search_btn.active = ! search_btn.active;\n            return search_btn.active;\n        }\n\n        private void bind_music_list_properties (MusicList list, bool editable = false) {\n            _app.settings.bind (\"compact-playlist\", list, \"compact-list\", SettingsBindFlags.DEFAULT);\n            _app.settings.bind (\"single-click-activate\", list, \"single-click-activate\", SettingsBindFlags.DEFAULT);\n            if (list.item_type != typeof (Music))\n                _app.settings.bind (\"grid-mode\", list, \"grid-mode\", SettingsBindFlags.DEFAULT);\n            if (editable)\n                list.bind_property (\"modified\", this, \"modified\");\n        }\n\n        private MusicList create_album_list (Artist? artist = null) {\n            var list = new MusicList (_app, typeof (Album), artist);\n            list.item_activated.connect ((position, obj) => create_stack_page (artist, obj as Album));\n            list.item_binded.connect ((item) => {\n                var cell = (MusicWidget) item.child;\n                var album = (Album) item.item;\n                var album_artist = album.album_artist;\n                cell.music = album;\n                cell.paintable = _loading_paintable;\n                cell.title = album.album;\n                var subtitle = album.get_date_string ();\n                if (artist == null && album_artist.length > 0)\n                    subtitle = album_artist + \" \" + subtitle;\n                cell.subtitle = subtitle.length > 0 ? subtitle : \" \";\n            });\n            bind_music_list_properties (list);\n            return list;\n        }\n\n        private MusicList create_artist_list () {\n            var list = new MusicList (_app, typeof (Artist));\n            list.item_activated.connect ((position, obj) => create_stack_page (obj as Artist));\n            list.item_binded.connect ((item) => {\n                var cell = (MusicWidget) item.child;\n                var artist = (Artist) item.item;\n                cell.cover.ratio = 0.5;\n                cell.music = artist;\n                cell.paintable = _loading_paintable;\n                cell.title = artist.artist;\n                cell.subtitle = \"\";\n            });\n            bind_music_list_properties (list);\n            return list;\n        }\n\n        private MusicList create_music_list (Album album, bool from_artist = false) {\n            var is_playlist = album is Playlist;\n            var is_artist_playlist = is_playlist && from_artist;\n            var sort_mode = is_artist_playlist ? SortMode.ALBUM : SortMode.TITLE;\n            var list = new MusicList (_app, typeof (Music), album, is_playlist);\n            list.item_activated.connect ((position, obj) => play_current_list ((int) position));\n            list.item_binded.connect ((item) => {\n                var entry = (MusicEntry) item.child;\n                var music = (Music) item.item;\n                entry.paintable = _loading_paintable;\n                entry.set_titles (music, sort_mode);\n            });\n            bind_music_list_properties (list, is_playlist);\n            return list;\n        }\n\n        private MainMusicList create_main_music_list () {\n            var list = new MainMusicList (_app);\n            list.item_activated.connect ((position, obj) => play_current_list ((int) position));\n            list.item_binded.connect ((item) => {\n                var entry = (MusicEntry) item.child;\n                var music = (Music) item.item;\n                entry.paintable = _loading_paintable;\n                entry.set_titles (music, _sort_mode);\n            });\n            bind_music_list_properties (list, true);\n            return list;\n        }\n\n        private MusicList create_playlist_list () {\n            var list = new MusicList (_app, typeof (Playlist));\n            list.item_activated.connect ((position, obj) => create_stack_page (null, obj as Playlist));\n            list.item_binded.connect ((item) => {\n                var cell = (MusicWidget) item.child;\n                var playlist = (Playlist) item.item;\n                cell.music = playlist;\n                cell.paintable = _loading_paintable;\n                cell.title = playlist.title;\n            });\n            bind_music_list_properties (list);\n            return list;\n        }\n\n        private Gtk.Box create_title_bar (string title, string? icon_name = null, Playlist? plist = null) {\n            var label = new Gtk.Label (title);\n            label.ellipsize = Pango.EllipsizeMode.MIDDLE;\n            var icon = new Gtk.Image.from_icon_name (icon_name);\n            var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);\n            box.halign = Gtk.Align.CENTER;\n            box.hexpand = true;\n            box.append (icon);\n            box.append (label);\n            if (plist != null && ((!)plist).list_uri.length > 0) {\n                var playlist = (!)plist;\n                var entry = new Gtk.Entry ();\n                entry.max_width_chars = 1024;\n                entry.text = title;\n                entry.visible = false;\n                entry.activate.connect (() => {\n                    entry.visible = false;\n                    label.visible = true;\n                    var text = entry.text;\n                    if (text.length > 0 && text != playlist.title) {\n                        _app.rename_playlist_async.begin (playlist, text, (obj, res) => {\n                            var ret = _app.rename_playlist_async.end (res);\n                            if (ret)\n                                label.label = playlist.title;\n                        });\n                    }\n                });\n                var event = new Gtk.EventControllerKey ();\n                event.key_pressed.connect ((keyval, keycode, state) => {\n                    if (keyval == Gdk.Key.Escape) {\n                        entry.visible = false;\n                        label.visible = true;\n                        return true;\n                    }\n                    return false;\n                });\n                entry.add_controller (event);\n                make_widget_clickable (label).released.connect (() => {\n                    entry.text = label.label;\n                    entry.visible = true;\n                    entry.grab_focus ();\n                    label.visible = false;\n                });\n                box.append (entry);\n            }\n\n            var header = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);\n            header.hexpand = true;\n            header.add_css_class (\"flat\");\n            header.add_css_class (\"toolbar\");\n            header.append (box);\n            return header;\n        }\n\n        private GenericSet<unowned MusicList> _overlayed_lists = new GenericSet<unowned MusicList> (direct_hash, direct_equal);\n\n        private void create_stack_page (Artist? artist, Album? album = null) {\n            var album_mode = album != null;\n            var artist_mode = artist != null;\n            var playlist_mode = album is Playlist;\n            var mlist = album_mode ? create_music_list ((!)album, artist_mode) : create_album_list (artist);\n            mlist.update_store ();\n\n            var icon_name = (album is Playlist) ? \"x-office-document-symbolic\" : (album_mode ? \"media-optical-cd-audio-symbolic\" : \"avatar-default-symbolic\");\n            var title = (album_mode ? album?.title : artist?.title) ?? \"\";\n            var header = create_title_bar (title, icon_name, album as Playlist);\n            mlist.prepend (header);\n\n            var stack = artist_mode ? _artist_stack : playlist_mode ? _playlist_stack : _album_stack;\n            var back_btn = new Gtk.Button.from_icon_name (\"go-previous-symbolic\");\n            back_btn.tooltip_text = _(\"Back\");\n            back_btn.clicked.connect (stack.pop);\n            header.prepend (back_btn);\n\n            var key_length = album?.album_key?.length ?? 0;\n            if (artist_mode || key_length > 0) {\n                var split_btn = new Adw.SplitButton ();\n                split_btn.icon_name = \"media-playback-start-symbolic\";\n                split_btn.tooltip_text = _(\"Play\");\n                split_btn.clicked.connect (() => open_page (build_library_uri (artist, album), true));\n                if (artist != null)\n                    split_btn.menu_model = (album == null || album is Playlist) ? create_menu_for_artist ((!)artist) : create_menu_for_album ((!)album);\n                else if (album != null)\n                    split_btn.menu_model = create_menu_for_album ((!)album);\n                (split_btn.menu_model as Menu)?.remove (0); // Play\n                header.append (split_btn);\n            }\n\n            if (stack.animate_transitions && stack.visible_child == _current_list)\n                _overlayed_lists.add (_current_list);\n            stack.add (mlist, album_mode ? album?.album_key : artist?.artist_name);\n        }\n\n        private Stack? get_current_stack () {\n            var child = stack_view.visible_child;\n            if (_artist_stack.widget == child)\n                return _artist_stack;\n            else if (_album_stack.widget == child)\n                return _album_stack;\n            else if (_playlist_stack.widget == child)\n                return _playlist_stack;\n            return null;\n        }\n\n        private void initialize_library_page () {\n            if (_library_uri != null) {\n                open_page ((!)_library_uri);\n                if (!_library.empty) {\n                    _library_uri = null;\n                    if (_current_list.playable)\n                        _album_key_of_list = _current_list.music_node?.album_key;\n                    set_to_current_music ();\n                }\n            }\n        }\n\n        private void save_current_page () {\n            var paths = new GenericArray<string> (4);\n            var stack = get_current_stack ();\n            if (stack != null) {\n                ((!)stack).get_visible_names (paths);\n            } else {\n                paths.add (stack_view.get_visible_child_name () ?? \"\");\n            }\n            var uri = build_library_uri_from_sa (paths.data);\n            _app.settings.set_string (\"library-uri\", uri);\n            _album_key_of_list = _current_list.music_node?.album_key;\n        }\n\n        public bool open_page (string uri, bool play_now = false, bool shuffle = false) {\n            string? ar = null, al = null, pl = null, page = null;\n            if (parse_library_uri (uri, out ar, out al, out pl, out page)) {\n                stack_view.transition_type = Gtk.StackTransitionType.NONE;\n                stack_view.visible_child_name = (!)page;\n                stack_view.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT;\n                var stk = get_current_stack ();\n                if (stk != null) {\n                    var stack = (!)stk;\n                    stack.animate_transitions = false;\n                    Artist? artist = null;\n                    Album? album = null;\n                    if (ar != null) {\n                        artist = _library.get_artist ((!)ar);\n                        if (artist != null) {\n                            if (stack.get_child_by_name (((!)artist).artist) == null) {\n                                create_stack_page (artist);\n                            }\n                            if (al != null) {\n                                if (((!)al).length > 0)\n                                    album = ((!)artist)[(!)al];\n                                else\n                                    album = ((!)artist).to_playlist ();\n                            }\n                        }\n                    } else if (al != null) {\n                        album = _library.get_album ((!)al);\n                    } else if (pl != null) {\n                        album = _library.get_playlist ((!)pl);\n                    }\n                    if (album != null && stack.get_child_by_name (((!)album).album_key) == null) {\n                        if ((stack.visible_child as MusicList)?.playable ?? false)\n                            stack.pop ();\n                        create_stack_page (artist, album);\n                    }\n                    ((!)stack).animate_transitions = true;\n                    if (album != null) {\n                        if (shuffle) {\n                            sort_music_store (_current_list.data_store, SortMode.SHUFFLE);\n                        } else {\n                            ((!)album).overwrite_to (_current_list.data_store);\n                        }\n                        if (play_now) {\n                            play_current_list ();\n                        }\n                    }\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        public int open_next_playable_page () {\n            var stk = get_current_stack ();\n            if (stk != null && !_updating_store) {\n                var stack = (!)stk;\n                if (_current_list.music_node is Playlist) {\n                    pop_page_without_animation (stack);\n                    if (_current_list.music_node is Artist)\n                        pop_page_without_animation (stack);\n                } else if (_current_list.set_to_current_item (false) >= (int) _current_list.visible_count - 1) {\n                    pop_page_without_animation (stack);\n                    if (_current_list.set_to_current_item (false) >= (int) _current_list.visible_count - 1) {\n                        pop_page_without_animation (stack);\n                    }\n                }\n                if (!_current_list.playable) {\n                    var index = _current_list.set_to_current_item ();\n                    _current_list.activate_item (index < (int) _current_list.visible_count - 1 ? index + 1 : 0);\n                    if (!_current_list.playable)\n                        _current_list.activate_item (0);\n                }\n                if (_current_list.playable) {\n                    var playlist = _current_list.get_as_playlist ();\n                    _app.insert_to_queue (playlist);\n                }\n            }\n\n            var index = _app.current_item + 1;\n            return index < (int) _app.current_list.get_n_items () ? index : 0;\n        }\n\n        public void open_playing_page () {\n            if (stack_view.visible_child != _main_list)\n                stack_view.visible_child = _main_list;\n            else\n                set_to_current_music ();\n        }\n\n        private void on_music_changed (Music? music) {\n            if (_current_list.playable) {\n                _current_list.current_node = music;\n            } else if (_current_list.item_type == typeof (Artist)) {\n                var artist_name = music?.artist_name ?? \"\";\n                _current_list.current_node = _library.get_artist (artist_name);\n            } else if (_current_list.item_type == typeof (Album)) {\n                var album = music?.album_key ?? \"\";\n                var artist = _current_list.music_node as Artist;\n                _current_list.current_node = artist != null ? ((!)artist)[album] : _library.get_album (album);\n            } else if (_current_list.item_type == typeof (Playlist)) {\n                if (_album_key_of_list != null)\n                    _current_list.current_node = _library.get_playlist ((!)_album_key_of_list);\n            }\n            _mini_bar.title = music?.title ?? \"\";\n\n            var scroll = _current_list.dropping_item == -1 && !_current_list.multi_selection;\n            _current_list.set_to_current_item (scroll);\n        }\n\n        private Gtk.Bitset _changing_stacks = new Gtk.Bitset.empty ();\n\n        private void on_music_library_changed (bool external) {\n            _main_list.modified |= _app.list_modified;\n            if (external) {\n                _changing_stacks.add_range (StackFlags.FIRST, StackFlags.LAST - StackFlags.FIRST);\n                if (_size_allocated) {\n                    update_visible_stack ();\n                    initialize_library_page ();\n                }\n            }\n        }\n\n        private void on_playlist_added (Playlist playlist) {\n            var list = _playlist_stack.visible_child as MusicList;\n            var node = list?.music_node;\n            if (strcmp (playlist.list_uri, (node as Playlist)?.list_uri) == 0) {\n                playlist.overwrite_to (((!)list).data_store);\n            }\n\n            var arr = new GenericArray<Music> (1);\n            arr.add (playlist);\n            uint position = -1;\n            merge_items_to_store (_playlist_list.data_store, arr, ref position);\n            sort_music_store (_playlist_list.data_store, SortMode.TITLE);\n        }\n\n        private void on_search_btn_toggled () {\n            if (search_btn.active) {\n                search_entry.grab_focus ();\n            }\n            on_search_text_changed ();\n        }\n\n        private bool on_search_match (Object obj) {\n            unowned var music = (Music) obj;\n            unowned var text = _search_text;\n            switch (_search_mode) {\n                case SearchMode.ALBUM:\n                    return text.match_string (music.album, true);\n                case SearchMode.ARTIST:\n                    return text.match_string (music.artist, true)\n                        || text.match_string (music.album_artist, true)\n                        || ((music as Artist)?.find_by_partial_artist (text) != null);\n                case SearchMode.TITLE:\n                    return text.match_string (music.title, true);\n                default:\n                    return text.match_string (music.album, true)\n                        || text.match_string (music.album_artist, true)\n                        || text.match_string (music.artist, true)\n                        || text.match_string (music.title, true);\n            }\n        }\n\n        private void on_search_text_changed () {\n            _search_text = search_entry.text;\n            parse_search_mode (ref _search_text, ref _search_mode);\n            if (_current_list == _album_list) {\n                _search_mode = SearchMode.ALBUM;\n            } else if (_current_list == _artist_list) {\n                _search_mode = SearchMode.ARTIST;\n            }\n\n            var model = _current_list.filter_model;\n            if (search_btn.active && model.get_filter () == null) {\n                model.set_filter (new Gtk.CustomFilter (on_search_match));\n            } else if (!search_btn.active && model.get_filter () != null) {\n                model.set_filter (null);\n            }\n            model.get_filter ()?.changed (Gtk.FilterChange.DIFFERENT);\n        }\n\n        private void on_thumbnail_changed (Music music, Gdk.Paintable paintable) {\n            _current_list.update_item_cover (music, paintable);\n        }\n\n        private string? _album_key_of_list = null;\n\n        private void play_current_list (int index = 0) {\n            if (_app.current_list == _current_list.filter_model) {\n                _app.current_item = index;\n            } else if (_current_list.playable) {\n                var playlist = _current_list.get_as_playlist ();\n                _app.current_item = _app.insert_after_current (playlist) + index;\n            }\n            if (!_app.player.playing) {\n                _app.player.play ();\n            }\n\n            _album_key_of_list = _current_list.music_node?.album_key;\n        }\n\n        private void pop_page_without_animation (Stack stack) {\n            var animate = stack.animate_transitions;\n            stack.animate_transitions = false;\n            stack.pop ();\n            stack.animate_transitions = animate;\n        }\n\n        private void set_to_current_music (bool scroll = true) {\n            on_music_changed (_app.current_music);\n            _current_list.set_to_current_item (scroll);\n        }\n\n        private void update_stack_pages (Stack stack) {\n            var children = stack.get_children ();\n            for (var i = children.length - 1; i >= 0; i--) {\n                var mlist = (MusicList) children[i];\n                if (mlist.music_node != null && mlist.update_store () == 0)\n                    pop_page_without_animation (stack);\n            }\n        }\n\n        private void update_visible_stack () {\n            _updating_store = true;\n            var child = stack_view.visible_child;\n            if (child == _album_stack.widget && _changing_stacks.remove (StackFlags.ALBUMS)) {\n                update_stack_pages (_album_stack);\n                _library.overwrite_albums_to (_album_list.data_store);\n            } else if (child == _artist_stack.widget && _changing_stacks.remove (StackFlags.ARTISTS)) {\n                update_stack_pages (_artist_stack);\n                _library.overwrite_artists_to (_artist_list.data_store);\n            } else if (child == _playlist_stack.widget && _changing_stacks.remove (StackFlags.PLAYLISTS)) {\n                update_stack_pages (_playlist_stack);\n                var text = _(\"No playlist found in %s\").printf (get_display_name (_app.music_folder));\n                _library.overwrite_playlists_to (_playlist_list.data_store);\n                _playlist_list.set_empty_text (text);\n            }\n            _updating_store = false;\n        }\n    }\n\n    public void fix_switcher_style (Gtk.StackSwitcher switcher) {\n        var layout = switcher.get_layout_manager () as Gtk.BoxLayout;\n        layout?.set_spacing (4);\n        switcher.remove_css_class (\"linked\");\n        for (var child = switcher.get_first_child (); child != null; child = child?.get_next_sibling ()) {\n            child?.add_css_class (\"flat\");\n            ((!)child).width_request = 48;\n        }\n    }\n\n    public void parse_search_mode (ref string text, ref uint mode) {\n        if (text.ascii_ncasecmp (\"album:\", 6) == 0) {\n            mode = SearchMode.ALBUM;\n            text = text.substring (6);\n        } else if (text.ascii_ncasecmp (\"artist:\", 7) == 0) {\n            mode = SearchMode.ARTIST;\n            text = text.substring (7);\n        } else if (text.ascii_ncasecmp (\"title:\", 6) == 0) {\n            mode = SearchMode.TITLE;\n            text = text.substring (6);\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/taglist-dialog.vala",
    "content": "namespace G4 {\n\n    namespace TagGroup {\n        public const int BASIC = 1;\n        public const int SORT = 2;\n        public const int FORMAT = 3;\n        public const int OTHER = 4;\n    }\n\n    public class TagListDialog : Dialog {\n        public struct TagOrder {\n            unowned string tag;\n            int order;\n        }\n\n        public class TagItem : Object {\n            public int group;\n            public string tag;\n            public string value;\n            public string description;\n            private string _key;\n            private int _order;\n\n            public TagItem (string t, string v) {\n                tag = embellish_tag_name (t);\n                value = v;\n                description = Gst.Tags.get_description (t) ?? \"\";\n                _key = tag.collate_key_for_filename ();\n\n                unowned string orig_key;\n                if (ORDERS.lookup_extended (_key, out orig_key, out _order)) {\n                    group = TagGroup.BASIC;\n                } else {\n                    _order = int.MAX >> 1;\n                    if (t.contains (\"bitrate\") || t.contains (\"channel\")\n                        || t.contains (\"crc\") || t.contains (\"code\")\n                        || t.contains (\"format\")) {\n                        group = TagGroup.FORMAT;\n                    } else if (t.contains (\"sortname\")) {\n                        group = TagGroup.SORT;\n                    } else {\n                        group = TagGroup.OTHER;\n                    }\n                }\n            }\n\n            public static int compare_by_name (TagItem ti1, TagItem ti2) {\n                int ret = ti1.group - ti2.group;\n                if (ret == 0)\n                    ret = ti1._order - ti2._order;\n                if (ret == 0)\n                    ret = strcmp (ti1._key, ti2._key);\n                return ret;\n            }\n        }\n\n        public const string GST_DOMAIN = \"gstreamer-1.0\";\n        public static HashTable<string, int> ORDERS = new HashTable<string, int> (str_hash, str_equal);\n\n        static construct {\n            Intl.bindtextdomain (GST_DOMAIN, null);\n            Intl.bind_textdomain_codeset (GST_DOMAIN, \"UTF-8\");\n\n            TagOrder [] tag_orders = {\n                { Gst.Tags.TITLE, 1 },\n                { Gst.Tags.ARTIST, 2 },\n                { Gst.Tags.ALBUM, 3 },\n                { Gst.Tags.ALBUM_ARTIST, 4 },\n                { Gst.Tags.COMPOSER, 5 },\n                { Gst.Tags.GENRE, 6 },\n                { Gst.Tags.DATE_TIME, 7 },\n                { Gst.Tags.TRACK_NUMBER, 8 },\n                { Gst.Tags.ALBUM_VOLUME_NUMBER, 9 },\n                { Gst.Tags.COMMENT, int.MAX - 1 },\n                { Gst.Tags.EXTENDED_COMMENT, int.MAX }\n            };\n            foreach (var to in tag_orders) {\n                ORDERS.insert (embellish_tag_name (to.tag).collate_key_for_filename (), to.order);\n            }\n        }\n\n        public static string embellish_tag_name (string name) {\n            var text = dgettext (GST_DOMAIN, Gst.Tags.get_nick (name) ?? name);\n            var sb = new StringBuilder ();\n            var arr = text.split (\" \");\n            var count = arr.length;\n            for (var i = 0; i < count; i++) {\n                var str = arr[i];\n                var first = true;\n                var next = 0;\n                unichar c = 0;\n                while (str.get_next_char (ref next, out c)) {\n                    var s = c.to_string ();\n                    if (first) {\n                        first = false;\n                        sb.append (s.up ());\n                    } else {\n                        sb.append (s);\n                    }\n                }\n                if (i < count - 1)\n                    sb.append_c (' ');\n            }\n            return sb.str;\n        }\n\n        private File file;\n        private GenericArray<TagItem> items = new GenericArray<TagItem>();\n        private Gtk.Button copy_btn = new Gtk.Button.from_icon_name (\"edit-copy-symbolic\");\n        private Gtk.Box group = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);\n        private Gtk.Spinner spinner = new Gtk.Spinner ();\n\n        public TagListDialog (string uri, Gst.TagList? tags) {\n            var content = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);\n            this.child = content;\n            this.file = File.new_for_uri (uri);\n\n            var header = new Gtk.HeaderBar ();\n            header.show_title_buttons = true;\n            header.title_widget = new Gtk.Label (null);\n            header.add_css_class (\"flat\");\n            content.append (header);\n\n            copy_btn.clicked.connect (copy_to_clipboard);\n            copy_btn.tooltip_text = _(\"Copy\");\n            header.pack_start (copy_btn);\n\n            spinner.margin_start = 6;\n            header.pack_start (spinner);\n\n            var scroll_view = new Gtk.ScrolledWindow ();\n            scroll_view.hscrollbar_policy = Gtk.PolicyType.NEVER;\n            scroll_view.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;\n            scroll_view.propagate_natural_height = true;\n            scroll_view.vexpand = true;\n            content.append (scroll_view);\n\n            var viewport = new Gtk.Viewport (null, scroll_view.vadjustment);\n            viewport.child = group;\n            scroll_view.child = viewport;\n\n            if (tags != null) {\n                load_tags ((!)tags);\n            } else {\n                laod_tags_async.begin (uri, (obj, res) => laod_tags_async.end (res));\n            }\n        }\n\n        private Gtk.ListBox create_list_box (Gtk.ListBox? previous) {\n            var box = new Gtk.ListBox ();\n            box.margin_start = 16;\n            box.margin_end = 16;\n            box.margin_top = previous == null ? 8 : 0;\n            box.margin_bottom = 16;\n            box.selection_mode = Gtk.SelectionMode.NONE;\n            box.add_css_class (\"boxed-list\");\n            return box;\n        }\n\n        private void copy_to_clipboard () {\n            var path = file.get_path () ?? file.get_parse_name ();\n            var sb = new StringBuilder (path);\n            sb.append_c ('\\n');\n            foreach (var ti in items) {\n                sb.append (ti.tag);\n                sb.append (ti.value.contains (\"\\n\") ? \":\\n\" : \"=\");\n                sb.append (ti.value);\n                sb.append_c ('\\n');\n            }\n            get_clipboard ().set_text (sb.str);\n        }\n\n        private async void laod_tags_async (string uri) {\n            child.height_request = 480;\n            copy_btn.sensitive = false;\n            spinner.start ();\n            var tags = yield run_async<Gst.TagList?> (() => parse_gst_tags (file));\n            if (tags != null) {\n                load_tags ((!)tags);\n            }\n            copy_btn.sensitive = true;\n            spinner.stop ();\n        }\n\n        private void load_tags (Gst.TagList tags) {\n            TagItem? tag_track_count = null;\n            TagItem? tag_track_number = null;\n            TagItem? tag_volumn_count = null;\n            TagItem? tag_volumn_number = null;\n            var count = tags.n_tags ();\n            for (var i = 0; i < count; i++) {\n                var tag = tags.nth_tag_name (i);\n                var values = new GenericArray<string> (4);\n                get_one_tag (tags, tag, values);\n                if (values.length > 0) {\n                    var sb = new StringBuilder ();\n                    var size = values.length;\n                    for (var j = 0; j < size; j++) {\n                        sb.append (values[j]);\n                        if (j != size - 1)\n                            sb.append_c ('\\n');\n                    }\n                    var ti = new TagItem (tag, sb.str);\n                    if (tag == Gst.Tags.TRACK_COUNT)\n                        tag_track_count = ti;\n                    else if (tag == Gst.Tags.TRACK_NUMBER)\n                        tag_track_number = ti;\n                    else if (tag == Gst.Tags.ALBUM_VOLUME_COUNT)\n                        tag_volumn_count = ti;\n                    else if (tag == Gst.Tags.ALBUM_VOLUME_NUMBER)\n                        tag_volumn_number = ti;\n                    else\n                        items.add (ti);\n                }\n            }\n            if (tag_track_number != null) {\n                if (tag_track_count != null)\n                    ((!)tag_track_number).value += \"/\" + ((!)tag_track_count).value;\n                items.add ((!)tag_track_number);\n            }\n            if (tag_volumn_number != null) {\n                if (tag_volumn_count != null)\n                    ((!)tag_volumn_number).value += \"/\" + ((!)tag_volumn_count).value;\n                items.add ((!)tag_volumn_number);\n            }\n            items.sort (TagItem.compare_by_name);\n\n            var tag_group = -1;\n            Gtk.ListBox? list_box = null;\n            foreach (var ti in items) {\n                var row = new Adw.ActionRow ();\n                row.title = ti.tag;\n                row.tooltip_text = dgettext (GST_DOMAIN, ti.description);\n#if ADW_1_2\n                row.use_markup = false;\n#endif\n#if ADW_1_3\n                row.subtitle_selectable = true;\n#endif\n                row.subtitle = ti.value;\n                row.add_css_class (\"property\");\n                if (tag_group != ti.group || list_box == null) {\n                    tag_group = ti.group;\n                    list_box = create_list_box (list_box);\n                    group.append ((!)list_box);\n                }\n                list_box?.append (row);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/volume-button.vala",
    "content": "namespace G4 {\n\n    public class VolumeButton : Gtk.ScaleButton, Gtk.Accessible, Gtk.Buildable, Gtk.ConstraintTarget, Gtk.Orientable {\n\n        public static double EPSILON = 1e-10;\n\n        public static string[] ICONS =\n        {\n            \"audio-volume-muted-symbolic\",\n            \"audio-volume-high-symbolic\",\n            \"audio-volume-low-symbolic\",\n            \"audio-volume-medium-symbolic\",\n        };\n\n        construct {\n            var adj = adjustment;\n            adj.lower = 0;\n            adj.upper = 1.0;\n            adj.page_increment = 0.1;\n            adj.step_increment = 0.1;\n\n            icons = ICONS;\n            query_tooltip.connect (on_query_tooltip);\n            value_changed.connect (on_value_changed);\n            tooltip_text = get_volume_text ();\n        }\n\n        private string get_volume_text () {\n            var adj = adjustment;\n            var value = get_value ();\n            var percent = (int) (100 * value / (adj.upper - adj.lower) + 0.5);\n            /* Translators: Current volume percent: 0~100% */\n            return _(\"Volume %d%%\").printf (percent);\n        }\n\n        private bool on_query_tooltip (int x, int y, bool keyboard_mode, Gtk.Tooltip tooltip) {\n            tooltip.set_text (get_volume_text ());\n            return true;\n        }\n\n        private void on_value_changed (double value) {\n            trigger_tooltip_query ();\n        }\n    }\n}"
  },
  {
    "path": "src/ui/window.vala",
    "content": "namespace G4 {\n\n    public class Window : Adw.ApplicationWindow {\n        private Adw.ToastOverlay _toast = new Adw.ToastOverlay ();\n        private Leaflet _leaflet = new Leaflet ();\n        private Gtk.ProgressBar _progress_bar = new Gtk.ProgressBar ();\n        private PlayPanel _play_panel;\n        private StorePanel _store_panel;\n\n        private int _blur_size = 512;\n        private uint _bkgnd_blur = BlurMode.ALWAYS;\n        private CrossFadePaintable _bkgnd_paintable = new CrossFadePaintable ();\n        private Gdk.Paintable? _cover_paintable = null;\n\n        public Window (Application app) {\n            this.application = app;\n            this.icon_name = app.application_id;\n            this.title = app.name;\n            this.width_request = ContentWidth.MIN;\n            this.close_request.connect (on_close_request);\n\n            var overlay = new Gtk.Overlay ();\n            this.content = overlay;\n            overlay.child = _toast;\n            _toast.child = _leaflet;\n\n            ActionEntry[] action_entries = {\n                { ACTION_BUTTON, button_command, \"s\" },\n                { ACTION_REMOVE, remove_from_list, \"s\" },\n                { ACTION_SAVE_LIST, save_list },\n                { ACTION_SEARCH, search_by, \"as\" },\n                { ACTION_SELECT, start_select },\n                { ACTION_TOGGLE_SEARCH, toggle_search },\n            };\n            add_action_entries (action_entries, this);\n\n            _progress_bar.hexpand = true;\n            _progress_bar.pulse_step = 0.02;\n            _progress_bar.sensitive = false;\n            _progress_bar.visible = false;\n            _progress_bar.add_css_class (\"osd\");\n            overlay.add_overlay (_progress_bar);\n            overlay.get_child_position.connect (on_overlay_child_position);\n            app.loader.loading_changed.connect (on_loading_changed);\n\n            _bkgnd_paintable.queue_draw.connect (this.queue_draw);\n\n            _store_panel = new StorePanel (app, this, _leaflet);\n\n            _play_panel = new PlayPanel (app, this, _leaflet);\n            _play_panel.cover_changed.connect (on_cover_changed);\n\n            _leaflet.content = _play_panel;\n            _leaflet.sidebar = _store_panel;\n\n            setup_drop_target ();\n            setup_focus_controller ();\n\n            var settings = app.settings;\n            settings.bind (\"leaflet-mode\", _leaflet, \"visible-mode\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"maximized\", this, \"maximized\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"width\", this, \"default-width\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"height\", this, \"default-height\", SettingsBindFlags.DEFAULT);\n            settings.bind (\"blur-mode\", this, \"blur-mode\", SettingsBindFlags.DEFAULT);\n        }\n\n        public uint blur_mode {\n            get {\n                return _bkgnd_blur;\n            }\n            set {\n                _bkgnd_blur = value;\n                if (get_height () > 0)\n                    update_background ();\n            }\n        }\n\n        public bool focused_visible {\n            get {\n                return focus_visible;\n            }\n            set {\n                if (!value)\n                    focus_to_play_later ();\n            }\n        }\n\n        public Gtk.Widget focused_widget {\n            owned get {\n                return focus_widget;\n            }\n            set {\n                if (!(value is Gtk.Editable))\n                    focus_to_play_later (2000);\n            }\n        }\n\n        public override void snapshot (Gtk.Snapshot snapshot) {\n            _bkgnd_paintable.snapshot (snapshot, get_width (), get_height ());\n            base.snapshot (snapshot);\n        }\n\n        public void open_page (string uri, bool play_now = false, bool shuffle = false) {\n            _store_panel.open_page (uri, play_now, shuffle);\n            if (_leaflet.folded) {\n                _leaflet.pop ();\n            }\n        }\n\n        public int open_next_playable_page () {\n            return _store_panel.open_next_playable_page ();\n        }\n\n        public void open_playing_page () {\n            _store_panel.open_playing_page ();\n            if (_leaflet.folded) {\n                _leaflet.pop ();\n            }\n        }\n\n        public void show_toast (string message, string? uri = null) {\n            var toast = new Adw.Toast (message);\n            if (uri != null) {\n                toast.action_name = ACTION_APP + ACTION_SHOW_FILE;\n                toast.action_target = new Variant.string ((!)uri);\n                toast.button_label = _(\"Show\");\n            }\n            _toast.add_toast (toast);\n        }\n\n        public void start_search (string text, uint mode = SearchMode.ANY) {\n            _store_panel.start_search (text, mode);\n            if (_leaflet.folded) {\n                _leaflet.pop ();\n            }\n        }\n\n        private void focus_to_play_later (int delay = 100) {\n            run_timeout_once (delay, () => {\n                if (!focus_visible && !(focus_widget is Gtk.Editable)) {\n                    var button = find_button_by_action_name (_leaflet, ACTION_APP + ACTION_PLAY_PAUSE);\n                    button?.grab_focus ();\n                }\n            });\n        }\n\n        private bool on_close_request () {\n            var app = (Application) application;\n            if (app.player.playing && app.settings.get_boolean (\"play-background\")) {\n                app.request_background ();\n                this.visible = false;\n                return true;\n            }\n            if (_store_panel.save_if_modified (true, close)) {\n                present ();\n                return true;\n            }\n            return false;\n        }\n\n        private Adw.Animation? _fade_animation = null;\n\n        private void on_cover_changed (Music? music, CrossFadePaintable cover) {\n            var paintable = cover.paintable;\n            while (paintable is BasePaintable) {\n                paintable = (paintable as BasePaintable)?.paintable;\n            }\n            _cover_paintable = paintable;\n\n            var app = (Application) application;\n            var mini_cover = music != null ? (app.thumbnailer.find ((!)music) ?? _cover_paintable) : app.icon;\n            _store_panel.set_mini_cover (mini_cover);\n            update_background ();\n\n            var target = new Adw.CallbackAnimationTarget ((value) => {\n                _bkgnd_paintable.fade = value;\n                cover.fade = value;\n            });\n            _fade_animation?.pause ();\n            _fade_animation = new Adw.TimedAnimation (this, 1 - cover.fade, 0, 800, target);\n            ((!)_fade_animation).done.connect (() => {\n                _bkgnd_paintable.previous = null;\n                cover.previous = null;\n                _fade_animation = null;\n            });\n            _fade_animation?.play ();\n        }\n\n        private bool on_file_dropped (Value value, double x, double y) {\n            var files = get_dropped_files (value);\n            var app = (Application) application;\n            app.open_files_async.begin (files, -1, app.current_music == null,\n                (obj, res) => app.open_files_async.end (res));\n            return true;\n        }\n\n        private bool _loading = false;\n        private uint _tick_handler = 0;\n\n        private void on_loading_changed (bool loading) {\n            root.action_set_enabled (ACTION_APP + ACTION_RELOAD, !loading);\n\n            _loading = loading;\n            if (loading) {\n                run_timeout_once (100, () => _progress_bar.visible = _loading);\n            } else {\n                _progress_bar.visible = _loading;\n            }\n\n            if (loading && _tick_handler == 0) {\n                _tick_handler = add_tick_callback (on_loading_tick_callback);\n            } else if (!loading && _tick_handler != 0) {\n                remove_tick_callback (_tick_handler);\n                _tick_handler = 0;\n            }\n        }\n\n        private bool on_loading_tick_callback (Gtk.Widget widget, Gdk.FrameClock clock) {\n            var app = (Application) application;\n            var fraction = app.loader.loading_progress;\n            if (fraction > 0)\n                _progress_bar.fraction = fraction;\n            else\n                _progress_bar.pulse ();\n            return true;\n        }\n\n        private bool on_overlay_child_position (Gtk.Widget widget, out Gdk.Rectangle rect) {\n            rect = Gdk.Rectangle ();\n            rect.x = rect.y = rect.width = rect.height = 0;\n            if (widget == _progress_bar) {\n                rect.y = _store_panel.header_bar.get_height ();\n                rect.width = _store_panel.get_width ();\n            }\n            return true;\n        }\n\n        private void setup_drop_target () {\n            //  Hack: when drag a folder from nautilus,\n            //  the value is claimed as GdkFileList in accept(),\n            //  but the value can't be convert as GdkFileList in drop(),\n            //  so use STRING type to get the file/folder path.\n            var target = new Gtk.DropTarget (Type.INVALID, Gdk.DragAction.COPY | Gdk.DragAction.LINK);\n            target.set_gtypes ({ Type.STRING, typeof (Gdk.FileList) });\n            target.accept.connect ((drop) => drop.formats.contain_gtype (typeof (Gdk.FileList))\n                                && !drop.formats.contain_gtype (typeof (Playlist)));\n#if GTK_4_10\n            target.drop.connect (on_file_dropped);\n#else\n            target.on_drop.connect (on_file_dropped);\n#endif\n            this.content.add_controller (target);\n        }\n\n        private void setup_focus_controller () {\n            var controller = new Gtk.EventControllerFocus ();\n            controller.enter.connect (() => focused_visible = false);\n            this.content.add_controller (controller);\n            this.bind_property (\"focus_visible\", this, \"focused_visible\");\n            this.bind_property (\"focus_widget\", this, \"focused_widget\");\n        }\n\n        private void button_command (SimpleAction action, Variant? parameter) {\n            var name = parameter?.get_string ();\n            if (name != null) {\n                _store_panel.current_list.button_command ((!)name);\n            }\n        }\n\n        private void remove_from_list (SimpleAction action, Variant? parameter) {\n            var app = (Application) application;\n            var uri = parameter?.get_string ();\n            var music = uri != null ? app.loader.find_cache ((!)uri) : null;\n            if (music != null) {\n                _store_panel.remove_from_list ((!)music);\n            }\n        }\n\n        private void save_list () {\n            _store_panel.save_if_modified (false);\n        }\n\n        private void search_by (SimpleAction action, Variant? parameter) {\n            var strv = parameter?.get_strv ();\n            if (strv != null && ((!)strv).length > 1) {\n                var arr = (!)strv;\n                var text = arr[0] + \":\";\n                var mode = SearchMode.ANY;\n                parse_search_mode (ref text, ref mode);\n                start_search (arr[1], mode);\n            }\n        }\n\n        private void start_select () {\n            _store_panel.current_list.multi_selection = true;\n            if (_leaflet.folded) {\n                _leaflet.pop ();\n            }\n        }\n\n        private void toggle_search () {\n            if (_store_panel.toggle_search () && _leaflet.folded) {\n                _leaflet.pop ();\n            }\n        }\n\n        private void update_background () {\n            var paintable = _cover_paintable;\n            if ((_bkgnd_blur == BlurMode.ALWAYS && paintable != null)\n                || (_bkgnd_blur == BlurMode.ART_ONLY && paintable is Gdk.Texture)) {\n                _bkgnd_paintable.paintable = create_blur_paintable (this,\n                    (!)paintable, _blur_size, _blur_size * 0.2, 0.25);\n            } else {\n                _bkgnd_paintable.paintable = null;\n            }\n        }\n\n        public static Window? get_default () {\n            return (GLib.Application.get_default () as Application)?.active_window as Window;\n        }\n    }\n\n    public Gtk.Button? find_button_by_action_name (Gtk.Widget widget, string action) {\n        for (var child = widget.get_first_child (); child != null; child = child?.get_next_sibling ()) {\n            if (!((!)child).is_drawable ()) {\n                continue;\n            } else if (child is Gtk.Button) {\n                var button = (Gtk.Button) child;\n                if (button.action_name == action)\n                    return button;\n            } else {\n                var button = find_button_by_action_name ((!)child, action);\n                if (button != null)\n                    return button;\n            }\n        }\n        return null;\n    }\n\n    public File[] get_dropped_files (Value value) {\n        File[] files = {};\n        var type = value.type ();\n        if (type == Type.STRING) {\n            var text = value.get_string ();\n            var list = text.split_set (\"\\n\");\n            files = new File[list.length];\n            var index = 0;\n            foreach (var path in list) {\n                files[index++] = File.new_for_path (path);\n            }\n        } else if (type == typeof (Gdk.FileList)) {\n            var list = ((Gdk.FileList) value).get_files ();\n            files = new File[list.length ()];\n            var index = 0;\n            foreach (var file in list) {\n                files[index++] = file;\n            }\n        }\n        return files;\n    }\n}\n"
  },
  {
    "path": "src/utils/async-task.vala",
    "content": "namespace G4 {\n\n    public class Event {\n        private Cond _cond = Cond ();\n        private Mutex _mutex = Mutex ();\n        private bool _notified = false;\n\n        public void notify () {\n            _mutex.lock ();\n            _notified = true;\n            _cond.broadcast ();\n            _mutex.unlock ();\n        }\n\n        public void reset () {\n            _mutex.lock ();\n            _notified = false;\n            _mutex.unlock ();\n        }\n\n        public void wait () {\n            _mutex.lock ();\n            while (!_notified)\n                _cond.wait (_mutex);\n            _mutex.unlock ();\n        }\n    }\n\n    public delegate V TaskFunc<V> ();\n    public delegate void VoidFunc ();\n\n    private class Worker<V> {\n        private TaskFunc<V> _task;\n        private SourceFunc _callback;\n        private V? _result = null;\n\n        public Worker (TaskFunc<V> task, SourceFunc callback) {\n            _task = task;\n            _callback = callback;\n        }\n\n        public V? result {\n            get {\n                return _result;\n            }\n        }\n\n        private void run () {\n            _result = _task ();\n            Idle.add ((owned) _callback);\n        }\n\n        private static Once<ThreadPool<Worker>> multi_thread_pool;\n        internal static unowned ThreadPool<Worker> get_multi_thread_pool () {\n            return multi_thread_pool.once(() => new_thread_pool (get_num_processors ()));\n        }\n\n        private static Once<ThreadPool<Worker>> single_thread_pool;\n        internal static unowned ThreadPool<Worker> get_single_thread_pool () {\n            return single_thread_pool.once(() => new_thread_pool (1));\n        }\n\n        private static ThreadPool<Worker> new_thread_pool (uint num_threads) {\n            try {\n                return new ThreadPool<Worker>.with_owned_data ((tdata) => tdata.run(), (int) num_threads, false);\n            } catch (Error e) {\n                critical (\"Create %u threads pool failed: %s\\n\", num_threads, e.message);\n                Process.abort ();\n            }\n        }\n    }\n\n    public async V run_async<V> (TaskFunc<V> task, bool front = false, bool in_single_pool = false) {\n        var worker = new Worker<V> (task, run_async<V>.callback);\n        try {\n            unowned var pool = in_single_pool ? Worker.get_single_thread_pool () : Worker.get_multi_thread_pool ();\n            pool.add (worker);\n            if (front) {\n                pool.move_to_front (worker);\n            }\n            yield;\n        } catch (Error e) {\n        }\n        return worker.result;\n    }\n\n    public uint run_idle_once (owned VoidFunc func, int priority = Priority.DEFAULT_IDLE) {\n        return Idle.add (() => {\n            func ();\n            return false;\n        }, priority);\n    }\n\n    public uint run_timeout_once (uint interval, owned VoidFunc func) {\n        return Timeout.add (interval, () => {\n            func ();\n            return false;\n        });\n    }\n\n    public async void run_void_async (VoidFunc task) {\n        yield run_async<void> (task);\n    }\n}\n"
  },
  {
    "path": "src/utils/cover-cache.vala",
    "content": "namespace G4 {\n\n    public class CoverCache : Object {\n        private HashTable<string, string?> _cache = new HashTable<string, string?> (str_hash, str_equal);\n\n        private const string ATTRIBUTES = FileAttribute.STANDARD_CONTENT_TYPE + \",\"\n                                        + FileAttribute.STANDARD_NAME;\n\n        public File? find (File? parent) {\n            if (parent == null)\n                return null;\n\n            var dir = (!)parent;\n            var uri = dir.get_uri ();\n            string? child = null;\n            lock (_cache) {\n                child = _cache[uri];\n                if (child == null) {\n                    child = find_no_lock (dir);\n                    _cache[uri] = child ?? \"\";\n                }\n            }\n            if (child == null || ((!)child).length == 0)\n                return (File?) null;\n            return dir.get_child ((!)child);\n        }\n\n        public void put (File dir, string child) {\n            var uri = dir.get_uri ();\n            lock (_cache) {\n                _cache[uri] = child;\n            }\n        }\n\n        private static string? find_no_lock (File dir) {\n            try {\n                FileInfo? pi = null;\n                var enumerator = dir.enumerate_children (ATTRIBUTES, FileQueryInfoFlags.NONE);\n                while ((pi = enumerator.next_file ()) != null) {\n                    var info = (!)pi;\n                    unowned var ctype = info.get_content_type () ?? \"\";\n                    unowned var name = info.get_name ();\n                    if (is_cover_file (ctype, name)) {\n                        //  print (\"Find external cover: %s\\n\", name);\n                        return name;\n                    }\n                }\n            } catch (Error e) {\n            }\n            return null;\n        }\n    }\n\n    public bool is_cover_file (string content_type, string name) {\n        return ContentType.is_mime_type (content_type, \"image/*\")\n                && (name.ascii_ncasecmp (\"Cover\", 5) == 0\n                || name.ascii_ncasecmp (\"Folder\", 6) == 0\n                || name.ascii_ncasecmp (\"AlbumArt\", 8) == 0);\n    }\n}"
  },
  {
    "path": "src/utils/data-io.vala",
    "content": "namespace G4 {\n\n    //  Use BIG_ENDIAN, same as DataInputStream's default byte order\n    public class DataInputBytes : Object {\n        private Bytes _bytes;\n        private unowned uint8[] _data;\n        private int _pos = 0;\n        private int _length;\n\n        public DataInputBytes (Bytes bytes) {\n            _bytes = bytes;\n            _data = bytes.get_data ();\n            _length = bytes.length;\n        }\n\n        public inline uint8 read_byte () throws IOError {\n            if (_pos + 1 > _length)\n                throw new IOError.INVALID_ARGUMENT (@\"Pos:$_pos+1>$_length\");\n            return _data[_pos++];\n        }\n\n        public inline uint16 read_uint16 () throws IOError {\n            if (_pos + 2 > _length)\n                throw new IOError.INVALID_ARGUMENT (@\"Pos:$_pos+2>$_length\");\n            return ((uint16) (_data[_pos++]) << 8) | _data[_pos++];\n        }\n\n        public inline uint32 read_uint32 () throws IOError {\n            if (_pos + 4 > _length)\n                throw new IOError.INVALID_ARGUMENT (@\"Pos:$_pos+4>$_length\");\n            return ((uint32) (_data[_pos++]) << 24)\n                | ((uint32) (_data[_pos++]) << 16)\n                | ((uint32) (_data[_pos++]) << 8)\n                | _data[_pos++];\n        }\n\n        public inline uint64 read_uint64 () throws IOError {\n            uint64 hi = read_uint32 ();\n            uint64 lo = read_uint32 ();\n            return (hi << 32) | lo;\n        }\n\n        public size_t read_size () throws IOError {\n            var n = read_byte ();\n            switch (n) {\n            case 254:\n                return read_uint16 ();\n            case 255:\n                return read_uint32 ();\n            default:\n                return n;\n            }\n        }\n\n        public string read_string () throws IOError {\n            var size = (int) read_size ();\n            if (size < 0 || _pos + size < 0 || _pos + size > _length) {\n                throw new IOError.INVALID_ARGUMENT (@\"Size:$_pos+$size>$_length\");\n            } else if (size > 0) {\n                var value = strndup ((char*) _data + _pos, size);\n                _pos += size;\n                return value;\n            }\n            return \"\";\n        }\n\n        public void reset () {\n            _pos = 0;\n        }\n    }\n\n    //  Use BIG_ENDIAN, same as DataOutputStream's default byte order\n    public class DataOutputBytes : Object {\n        private ByteArray _bytes;\n        private uint8[] _data = new uint8[4];\n\n        public DataOutputBytes (uint reserved_size = 4096) {\n            _bytes = new ByteArray.sized (reserved_size);\n        }\n\n        public inline void write_byte (uint8 n) {\n            _data[0] = n;\n            _bytes.append (_data[0:1]);\n        }\n\n        public inline void write_uint16 (uint16 n) {\n            _data[0] = (uint8) (n >> 8);\n            _data[1] = (uint8) (n);\n            _bytes.append (_data[0:2]);\n        }\n\n        public inline void write_uint32 (uint32 n) {\n            _data[0] = (uint8) (n >> 24);\n            _data[1] = (uint8) (n >> 16);\n            _data[2] = (uint8) (n >> 8);\n            _data[3] = (uint8) (n);\n            _bytes.append (_data[0:4]);\n        }\n\n        public inline void write_uint64 (uint64 n) {\n            var hi = (uint32) (n >> 32);\n            var lo = (uint32) (n);\n            write_uint32 (hi);\n            write_uint32 (lo);\n        }\n\n        public void write_size (size_t n) {\n            if (n < 254) {\n                write_byte ((uint8) n);\n            } else if (n <= 0xffff) {\n                write_byte (254);\n                write_uint16 ((uint16) n);\n            } else {\n                write_byte (255);\n                write_uint32 ((uint32) n);\n            }\n        }\n\n        public void write_string (string str) {\n            size_t size = str.length;\n            write_size (size);\n            if (size > 0) {\n                unowned uint8[] data = (uint8[])str;\n                _bytes.append (data[0:size]);\n            }\n        }\n\n        public bool write_to (OutputStream stream) throws IOError {\n            size_t bytes_written = 0;\n            return stream.write_all (_bytes.data, out bytes_written);\n        }\n    }\n}\n"
  },
  {
    "path": "src/utils/dir-cache.vala",
    "content": "namespace G4 {\n\n    namespace ChildType {\n        public const uint8 NONE = 0;\n        public const uint8 FOLDER = 1;\n        public const uint8 MUSIC = 2;\n        public const uint8 PLAYLIST = 3;\n        public const uint8 COVER = 4;\n    }\n\n    public class DirCache : Object {\n        private static uint32 MAGIC = 0x44495231; //  'DIR1'\n\n        private class ChildInfo {\n            public uint8 type;\n            public string name;\n            public int64 time;\n    \n            public ChildInfo (uint8 type, string name, int64 time) {\n                this.type = type;\n                this.name = name;\n                this.time = time;\n            }\n        }\n\n        private File _dir;\n        private File _file;\n        private int64 _time;\n        private GenericArray<ChildInfo> _children = new GenericArray<ChildInfo> (128);\n\n        public DirCache (File dir, FileInfo? info = null) {\n            _dir = dir;\n            var cache_dir = Environment.get_user_cache_dir ();\n            var name = Checksum.compute_for_string (ChecksumType.MD5, dir.get_uri ());\n            _file = File.new_build_filename (cache_dir, Config.APP_ID, \"dir-cache\", name);\n            _time = info?.get_modification_date_time ()?.to_unix () ?? 0;\n        }\n\n        public File dir {\n            get {\n                return _dir;\n            }\n        }\n\n        public bool check_valid () {\n            try {\n                if (_time == 0) {\n                    var info = _dir.query_info (FileAttribute.TIME_MODIFIED, FileQueryInfoFlags.NONE);\n                    _time = info.get_modification_date_time ()?.to_unix () ?? 0;\n                }\n                var info = _file.query_info (FileAttribute.TIME_MODIFIED, FileQueryInfoFlags.NONE);\n                return _time <= (info.get_modification_date_time ()?.to_unix () ?? 0);\n            } catch (Error e) {\n            }\n            return false;\n        }\n\n        public void delete () {\n            _file.delete_async.begin (Priority.DEFAULT, null, (obj, res) => {\n                try {\n                    _file.delete_async.end (res);\n                } catch (Error e) {\n                }\n            });\n        }\n\n        public void add_child (FileInfo info, uint8 type) {\n            var time = info.get_modification_date_time ()?.to_unix () ?? 0;\n            var child = new ChildInfo (type, info.get_name (), time);\n            _children.add (child);\n        }\n\n        public bool load (Queue<DirCache> stack, GenericArray<Music> musics, GenericArray<File>? playlists, out string? cover_name) {\n            cover_name = null;\n            try {\n                var mapped = new MappedFile (_file.get_path () ?? \"\", false);\n                var dis = new DataInputBytes (mapped.get_bytes ());\n\n                var magic = dis.read_uint32 ();\n                if (magic != MAGIC)\n                    throw new IOError.INVALID_DATA (@\"Magic:$magic\");\n                var base_name = _dir.get_basename () ?? \"\";\n                var bname = dis.read_string ();\n                if (bname != base_name)\n                    throw new IOError.INVALID_DATA (@\"Name:$bname!=$base_name\");\n\n                var count = dis.read_size ();\n                for (var i = 0; i < count; i++) {\n                    var type = dis.read_byte ();\n                    var name = dis.read_string ();\n                    var time = (int64) dis.read_uint64 ();\n                    var child = _dir.get_child (name);\n                    if (type == ChildType.MUSIC) {\n                        musics.add (new Music (child.get_uri (), name, time));\n                    } else if (type == ChildType.FOLDER) {\n                        stack.push_head (new DirCache (child));\n                    } else if (type == ChildType.PLAYLIST) {\n                        playlists?.add (child);\n                    } else if (type == ChildType.COVER) {\n                        cover_name = name;\n                    }\n                }\n                return true;\n            } catch (Error e) {\n                if (e.code != FileError.NOENT)\n                    print (\"Load dir error: %s\\n\", e.message);\n            }\n            return false;\n        }\n\n        public void save () {\n            try {\n                var parent = _file.get_parent ();\n                var exists = parent?.query_exists () ?? false;\n                if (!exists)\n                    parent?.make_directory_with_parents ();\n                var fos = _file.replace (null, false, FileCreateFlags.NONE);\n                var dos = new DataOutputBytes ();\n                dos.write_uint32 (MAGIC);\n                dos.write_string (_dir.get_basename () ?? \"\");\n                dos.write_size (_children.length);\n                foreach (var child in _children) {\n                    dos.write_byte (child.type);\n                    dos.write_string (child.name);\n                    dos.write_uint64 (child.time);\n                }\n                dos.write_to (fos);\n            } catch (Error e) {\n                print (\"Save dir error: %s\\n\", e.message);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/utils/dir-monitor.vala",
    "content": "namespace G4 {\n\n    public class DirMonitor : Object {\n        private HashTable<string, FileMonitor> _monitors = new HashTable<string, FileMonitor> (str_hash, str_equal);\n\n        public signal void add_file (File file);\n        public signal void remove_file (File file);\n\n        ~DirMonitor () {\n            remove_all ();\n        }\n\n        public bool enabled { get; set; }\n\n        public void monitor (GenericArray<File> dirs) {\n            foreach (var dir in dirs) {\n                if (dir.is_native ())\n                    monitor_one (dir);\n            }\n        }\n\n        public void monitor_one (File dir) {\n            var uri = dir.get_uri ();\n            unowned string orig_key;\n            FileMonitor monitor;\n            lock (_monitors) {\n                if (_monitors.lookup_extended (uri, out orig_key, out monitor)) {\n                    monitor.cancel ();\n                }\n            }\n            if (_enabled) try {\n                monitor = dir.monitor (FileMonitorFlags.WATCH_MOVES, null);\n                monitor.changed.connect (monitor_func);\n                lock (_monitors) {\n                    _monitors[uri] = monitor;\n                }\n            } catch (Error e) {\n                print (\"Monitor dir error: %s\\n\", e.message);\n            }\n        }\n\n        public void remove_all () {\n            lock (_monitors) {\n                _monitors.foreach ((uri, monitor) => monitor.cancel ());\n                _monitors.remove_all ();\n            }\n        }\n\n        private void monitor_func (File file, File? other_file, FileMonitorEvent event) {\n            switch (event) {\n                case FileMonitorEvent.CHANGED:\n                    remove_file (file);\n                    add_file (file);\n                    break;\n\n                case FileMonitorEvent.MOVED_IN:\n                    add_file (file);\n                    break;\n\n                case FileMonitorEvent.DELETED:\n                case FileMonitorEvent.MOVED_OUT:\n                    remove_file (file);\n                    break;\n\n                case FileMonitorEvent.RENAMED:\n                    remove_file (file);\n                    if (other_file != null)\n                        add_file ((!)other_file);\n                    break;\n\n                default:\n                    break;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/utils/mpris.vala",
    "content": "namespace G4 {\n\n    [DBus (name = \"org.mpris.MediaPlayer2.Player\")]\n    public class MprisPlayer : Object {\n        [DBus (visible = false)]\n        private unowned Application _app;\n        private unowned DBusConnection _connection;\n        private bool _cover_parsed = false;\n        private int64 _current_duration = 0;\n        private unowned Music? _current_music = null;\n        private HashTable<string, Variant> _metadata = new HashTable<string, Variant> (str_hash, str_equal);\n\n        public MprisPlayer (Application app, DBusConnection connection) {\n            _app = app;\n            _connection = connection;\n\n            app.index_changed.connect (on_index_changed);\n            app.music_changed.connect (on_music_changed);\n            app.music_cover_parsed.connect (on_music_cover_parsed);\n            app.player.state_changed.connect (on_state_changed);\n            app.player.duration_changed.connect (on_duration_changed);\n        }\n\n        public bool can_control {\n            get {\n                return true;\n            }\n        }\n\n        public bool can_go_next {\n            get {\n                return _app.current_item < (int) _app.current_list.get_n_items () - 1;\n            }\n        }\n\n        public bool can_go_previous {\n            get {\n                return _app.current_item > 0;\n            }\n        }\n\n        public bool can_play {\n            get {\n                return _app.current_music != null;\n            }\n        }\n\n        public bool can_pause {\n            get {\n                return _app.current_music != null;\n            }\n        }\n\n        public bool can_seek {\n            get {\n                return _app.current_music != null;\n            }\n        }\n\n        public HashTable<string, Variant> metadata {\n            get {\n                return _metadata;\n            }\n        }\n\n        public int64 position {\n            get {\n                return (int64) _app.player.position / Gst.USECOND;\n            }\n        }\n\n        public string playback_status {\n            owned get {\n                return get_mpris_status(_app.player.state);\n            }\n        }\n\n        public bool shuffle {\n            get {\n                return _app.sort_mode == SortMode.SHUFFLE;\n            }\n            set {\n                if (value && (_app.sort_mode != SortMode.SHUFFLE)) {\n                    _app.sort_mode = SortMode.SHUFFLE;\n                } else {\n                    _app.sort_mode = SortMode.TITLE;\n                }\n            }\n        }\n\n        public double volume {\n            get {\n                return _app.player.volume;\n            }\n            set {\n                _app.player.volume = value;\n            }\n        }\n\n        public void next () throws Error {\n            _app.play_next ();\n        }\n\n        public void previous () throws Error {\n            _app.play_previous ();\n        }\n\n        public void play_pause () throws Error {\n            _app.play_pause();\n        }\n\n        public void play () throws Error {\n            _app.player.play ();\n        }\n\n        public void pause () throws Error {\n            _app.player.pause ();\n        }\n\n        public void seek (int64 offset) throws Error {\n            _app.player.position += offset * Gst.USECOND;\n        }\n\n        private void on_duration_changed (Gst.ClockTime duration) {\n            var ms = (int64) duration / Gst.USECOND;\n            if (_current_duration != ms) {\n                _metadata.insert (\"mpris:length\", new Variant.int64 (ms));\n                if (_cover_parsed)\n                    send_property (\"Metadata\", _metadata);\n                _current_duration = ms;\n            }\n        }\n\n        private void on_index_changed (int index, uint size) {\n            var builder = new VariantBuilder (new VariantType (\"a{sv}\"));\n            builder.add (\"{sv}\", \"CanGoNext\", new Variant.boolean (index < (int) size - 1));\n            builder.add (\"{sv}\", \"CanGoPrevious\", new Variant.boolean (index > 0));\n            builder.add (\"{sv}\", \"CanPlay\", new Variant.boolean (_app.current_music != null));\n            builder.add (\"{sv}\", \"CanPause\", new Variant.boolean (_app.current_music != null));\n            send_properties (builder);\n        }\n\n        private void on_music_changed (Music? music) {\n            _cover_parsed = false;\n            _current_music = music;\n            _current_duration = 0;\n            _metadata.remove_all ();\n            if (music != null) {\n                var artists = new VariantBuilder (new VariantType (\"as\"));\n                artists.add (\"s\", music?.artist ?? \"\");\n                _metadata.insert (\"xesam:artist\", artists.end());\n                _metadata.insert (\"xesam:title\", new Variant.string (music?.title ?? \"\"));\n                _metadata.insert (\"xesam:album\", new Variant.string (music?.album ?? \"\"));\n                _metadata.insert (\"mpris:length\", new Variant.int64 (_current_duration));\n            }\n        }\n\n        private void on_music_cover_parsed (Music music, Gdk.Pixbuf? pixbuf, string? uri) {\n            if (_current_music != music) {\n                on_music_changed (music);\n            }\n            if (uri != null) {\n                _metadata.insert (\"mpris:artUrl\", new Variant.string ((!)uri));\n            } else {\n                _metadata.remove (\"mpris:artUrl\");\n            }\n            send_property (\"Metadata\", _metadata);\n            _cover_parsed = true;\n        }\n\n        private void on_state_changed (Gst.State state) {\n            send_property (\"PlaybackStatus\", new Variant.string (get_mpris_status(state)));\n        }\n\n        private void send_property (string name, Variant variant) {\n            var builder = new VariantBuilder (new VariantType (\"a{sv}\"));\n            builder.add (\"{sv}\", name, variant);\n            send_properties (builder);\n        }\n\n        private void send_properties (VariantBuilder builder) {\n            var invalid = new VariantBuilder (new VariantType (\"as\"));\n            try {\n                _connection.emit_signal (\n                    null,\n                    \"/org/mpris/MediaPlayer2\",\n                    \"org.freedesktop.DBus.Properties\",\n                    \"PropertiesChanged\",\n                    new Variant (\n                        \"(sa{sv}as)\",\n                        \"org.mpris.MediaPlayer2.Player\",\n                        builder,\n                        invalid\n                    )\n                );\n            } catch (Error e) {\n                warning (\"Send MPRIS failed: %s\\n\", e.message);\n            }\n        }\n\n        private string get_mpris_status (Gst.State state) {\n            switch (state) {\n                case Gst.State.PLAYING:\n                    return \"Playing\";\n                case Gst.State.PAUSED:\n                    return \"Paused\";\n                default:\n                    return \"Stopped\";\n            }\n        }\n    }\n\n    [DBus (name = \"org.mpris.MediaPlayer2\")]\n    public class MprisRoot : Object {\n        private unowned Application _app;\n\n        public MprisRoot (Application app) {\n            _app = app;\n        }\n\n        public bool can_quit {\n            get {\n                return true;\n            }\n        }\n\n        public bool can_raise {\n            get {\n                return true;\n            }\n        }\n\n        public bool has_track_list {\n            get {\n                return false;\n            }\n        }\n\n        public string desktop_entry {\n            get {\n                return _app.application_id;\n            }\n        }\n\n        public string identity {\n            get {\n                return _app.name;\n            }\n        }\n\n        public string[] supported_uri_schemes {\n            owned get {\n                return {\"file\", \"smb\"};\n            }\n        }\n\n        public string[] supported_mime_types {\n            owned get {\n                return {\"audio/*\"};\n            }\n        }\n\n        public void quit () throws Error {\n            _app.quit ();\n        }\n\n        public void raise () throws Error {\n            _app.activate ();\n        }\n    }\n}\n"
  },
  {
    "path": "src/utils/music-library.vala",
    "content": "namespace G4 {\n\n    namespace SortMode {\n        public const uint ALBUM = 0;\n        public const uint ARTIST = 1;\n        public const uint ARTIST_ALBUM = 2;\n        public const uint TITLE = 3;\n        public const uint RECENT = 4;\n        public const uint SHUFFLE = 5;\n        public const uint MAX = 5;\n    }\n\n    public class Album : Music {\n        protected HashTable<unowned string, Music> _musics = new HashTable<unowned string, Music> (str_hash, str_equal);\n\n        public Album (Music music) {\n            base.titled (music.album, music.uri);\n            base.album = music.album;\n            base.artist = music.artist;\n            base._album_key = music._album_key;\n            base._artist_key = music._artist_key;\n            base.date = music.date;\n            base.track = music.track;\n            base.uri = music.uri;\n        }\n\n        public uint length {\n            get {\n                return _musics.length;\n            }\n        }\n\n        public bool add_music (Music music) {\n            if (music.has_cover && music.track < track) {\n                // For cover\n                has_cover = true;\n                uri = music.uri;\n            }\n#if VALA_56_10\n            return _musics.insert (music.uri, music);\n#else\n            return insert_music (music);\n#endif\n        }\n\n        protected bool insert_music (Music music) {\n            var count = _musics.length;\n            _musics.insert (music.uri, music);\n            return _musics.length > count;\n        }\n\n        public bool contains (string uri) {\n            return _musics.contains (uri);\n        }\n\n        public uint foreach_remove (HRFunc<unowned string, Music> func) {\n            return _musics.foreach_remove (func);\n        }\n\n        public virtual void get_sorted_musics (GenericArray<Music> musics) {\n            _musics.foreach ((name, music) => musics.add (music));\n            sort (musics);\n        }\n\n        public void overwrite_to (ListStore store) {\n            var musics = new GenericArray<Music> (_musics.length);\n            get_sorted_musics (musics);\n            store.splice (0, store.get_n_items (), (Object[]) musics.data);\n        }\n\n        public bool remove_music (Music music) {\n            return _musics.remove (music.uri);\n        }\n\n        protected virtual void sort (GenericArray<Music> arr) {\n            arr.sort (Music.compare_by_album);\n        }\n    }\n\n    public class Artist : Music {\n        protected HashTable<unowned string, Album> _albums = new HashTable<unowned string, Album> (str_hash, str_equal);\n\n        public Artist (Music music, string artist_name) {\n            base.titled (artist_name, music.uri);\n            base.artist = artist_name;\n            base.album_artist = music.album_artist;\n            base._artist_key = artist_name.collate_key_for_filename ();\n            base.date = music.date;\n            base.uri = music.uri;\n        }\n\n        public uint length {\n            get {\n                return _albums.length;\n            }\n        }\n\n        public override string get_abbreviation () {\n            return parse_abbreviation (artist);\n        }\n\n        public bool add_music (Music music) {\n            unowned string key;\n            unowned var album_key = music.album_key;\n            Album album;\n            if (!_albums.lookup_extended (album_key, out key, out album)) {\n                album = new Album (music);\n                album.album_artist = artist;\n                _albums[album_key] = album;\n            }\n            var added = album.add_music (music);\n            if (added && album.has_cover && !has_cover) {\n                has_cover = true;\n                uri = album.uri;\n            }\n            return added;\n        }\n\n        public Album? find_by_partial_artist (string artist) {\n            return _albums.find ((name, album) => artist.match_string (album.artist, true)) as Album;\n        }\n\n        public new Album? @get (string name) {\n            return _albums[name];\n        }\n\n        public void get_sorted_albums (GenericArray<Album> albums) {\n            _albums.foreach ((name, album) => albums.add (album));\n            albums.sort (compare_album);\n        }\n\n        public void get_sorted_musics (GenericArray<Music> musics) {\n            var arr = new GenericArray<Album> (_albums.length);\n            get_sorted_albums (arr);\n            arr.foreach ((album) => album.get_sorted_musics (musics));\n        }\n\n        public void overwrite_store (ListStore store) {\n            var arr = new GenericArray<Album> (_albums.length);\n            get_sorted_albums (arr);\n            store.splice (0, store.get_n_items (), (Object[]) arr.data);\n        }\n\n        public bool remove_music (Music music) {\n            unowned var album_key = music.album_key;\n            var album = _albums[album_key];\n            if (album is Album) {\n                var ret = album.remove_music (music);\n                if (album.length == 0)\n                    _albums.remove (album_key);\n                return ret;\n            }\n            return _albums.foreach_remove ((name, album) => album.remove_music (music) && album.length == 0) > 0;\n        }\n\n        public Playlist to_playlist () {\n            var playlist = new Playlist (title);\n            get_sorted_musics (playlist.items);\n            playlist.set_cover_uri ();\n            return playlist;\n        }\n\n        private static int compare_album (Music m1, Music m2) {\n            return (m1.date > 0 && m2.date > 0) ? (int) (m1.date - m2.date) : strcmp (m1._album_key, m2._album_key);\n        }\n    }\n\n    public class Playlist : Album {\n        public GenericArray<Music> items = new GenericArray<Music> (128);\n        public string list_uri;\n\n        public Playlist (string name, string uri = \"\") {\n            base.titled (name, \"\");\n            base.album = name;\n            set_list_uri (uri);\n        }\n\n        public new uint length {\n            get {\n                return items.length;\n            }\n        }\n\n        public new bool add_music (Music music) {\n#if VALA_56_10\n            if (_musics.insert (music.uri, music)) {\n#else\n            if (insert_music (music)) {\n#endif\n                var count = items.length;\n                items.add (music);\n                items[count]._order = count;\n                return true;\n            }\n            return false;\n        }\n\n        public void clear () {\n            _musics.remove_all ();\n            items.remove_range (0, items.length);\n        }\n\n        public void copy_from (Playlist playlist) {\n            clear ();\n            extend (playlist.items);\n            set_cover_uri ();\n            set_title (playlist.title);\n        }\n\n        public void extend (GenericArray<Music> musics) {\n            items.extend (musics, (src) => src);\n        }\n\n        public new bool remove_music (Music music) {\n            base.remove_music (music);\n            return items.remove (music);\n        }\n\n        public override void get_sorted_musics (GenericArray<Music> musics) {\n            musics.extend (items, (src) => src);\n        }\n\n        public void insert_to_store (ListStore store, uint position = uint.MAX) {\n            var size = store.get_n_items ();\n            store.splice (uint.min (position, size), 0, (Object[]) items.data);\n        }\n\n        public void reset_original_order () {\n            Music.original_order (items);\n        }\n\n        public void set_cover_uri () {\n            has_cover = false;\n            foreach (var music in items) {\n                if (music.has_cover) {\n                    has_cover = true;\n                    uri = music.uri;\n                    break;\n                }\n            }\n            if (!has_cover && items.length > 0) {\n                has_cover = true;\n                uri = items[0].uri;\n            }\n        }\n\n        public void set_list_uri (string uri) {\n            _album_key = uri;\n            list_uri = uri;\n        }\n\n        public void set_title (string title) {\n            this.album = title;\n            this.title = title;\n            _title_key = title.collate_key_for_filename ();\n        }\n\n        protected override void sort (GenericArray<Music> arr) {\n            Music.original_order (items);\n            arr.sort (Music.compare_by_order);\n        }\n    }\n\n    public class MusicLibrary : Object {\n        private HashTable<unowned string, Album> _albums = new HashTable<unowned string, Album> (str_hash, str_equal);        \n        private HashTable<unowned string, Artist> _artists = new HashTable<unowned string, Artist> (str_hash, str_equal);        \n        private HashTable<unowned string, Playlist> _playlists = new HashTable<unowned string, Playlist> (str_hash, str_equal);        \n\n        public bool empty {\n            get {\n                return _albums.length == 0 && _artists.length == 0 && _playlists.length == 0;\n            }\n        }\n\n        public uint album_count {\n            get {\n                return _albums.length;\n            }\n        }\n\n        public uint artist_count {\n            get {\n                return _artists.length;\n            }\n        }\n\n        public uint playlist_count {\n            get {\n                return _playlists.length;\n            }\n        }\n\n        public bool add_music (Music music) {\n            unowned string key;\n            unowned var album_key = music.album_key;\n            Album album;\n            lock (_albums) {\n                if (!_albums.lookup_extended (album_key, out key, out album)) {\n                    album = new Album (music);\n                    album.album_artist = \"\";\n                    _albums[album_key] = album;\n                }\n            }\n            var added = album.add_music (music);\n\n            unowned var artist_name = music.artist_name;\n            Artist artist;\n            lock (_artists) {\n                if (!_artists.lookup_extended (artist_name, out key, out artist)) {\n                    artist = new Artist (music, artist_name);\n                    _artists[artist_name] = artist;\n                }\n            }\n            added |= artist.add_music (music);\n            return added;\n        }\n\n        public Playlist add_playlist (Playlist playlist) {\n            unowned string key;\n            Playlist oldlist;\n            lock (_playlists) {\n                if (_playlists.lookup_extended (playlist.list_uri, out key, out oldlist)) {\n                    if (oldlist != playlist)\n                        oldlist.copy_from (playlist);\n                    return oldlist;\n                } else {\n                    _playlists.insert (playlist.list_uri, playlist);\n                }\n            }\n            return playlist;\n        }\n\n        public Album? get_album (string key) {\n            lock (_albums) {\n                return _albums[key];\n            }\n        }\n\n        public Artist? get_artist (string key) {\n            lock (_artists) {\n                return _artists[key];\n            }\n        }\n\n        public Playlist? get_playlist (string key) {\n            lock (_playlists) {\n                return _playlists[key];\n            }\n        }\n\n        public void overwrite_albums_to (ListStore store) {\n            var arr = new GenericArray<Music> (_albums.length);\n            lock (_albums) {\n                _albums.foreach ((name, album) => arr.add (album));\n            }\n            arr.sort (Music.compare_by_album);\n            store.splice (0, store.get_n_items (), (Object[]) arr.data);\n        }\n\n        public void overwrite_artists_to (ListStore store) {\n            var arr = new GenericArray<Music> (_artists.length);\n            lock (_artists) {\n                _artists.foreach ((name, artist) => arr.add (artist));\n            }\n            arr.sort (Music.compare_by_artist);\n            store.splice (0, store.get_n_items (), (Object[]) arr.data);\n        }\n\n        public void overwrite_playlists_to (ListStore store) {\n            var arr = new GenericArray<Music> (_playlists.length);\n            lock (_playlists) {\n                _playlists.foreach ((uri, playlist) => arr.add (playlist));\n            }\n            arr.sort (Music.compare_by_title);\n            store.splice (0, store.get_n_items (), (Object[]) arr.data);\n        }\n\n        public void remove_music (Music music) {\n            unowned var album_key = music.album_key;\n            lock (_albums) {\n                var album = _albums[album_key];\n                if (album is Album) {\n                    album.remove_music (music);\n                    if (album.length == 0)\n                        _albums.remove (album_key);\n                } else {\n                    _albums.foreach_remove ((name, album) => album.remove_music (music) && album.length == 0);\n                }\n            }\n\n            unowned var artist_name = music.artist_name;\n            lock (_artists) {\n                var artist = _artists[artist_name];\n                if (artist is Artist) {\n                    artist.remove_music (music);\n                    if (artist.length == 0)\n                        _artists.remove (artist_name);\n                } else {\n                    _artists.foreach_remove ((name, artist) => artist.remove_music (music) && artist.length == 0);\n                }\n            }\n        }\n\n        public bool remove_playlist (string key) {\n            lock (_playlists) {\n                return _playlists.remove (key);\n            }\n        }\n\n        public bool remove_uri (string uri, GenericSet<Music> removed) {\n            string key;\n            Playlist oldlist;\n            lock (_playlists) {\n                if (_playlists.steal_extended (uri, out key, out oldlist)) {\n                    oldlist.clear ();\n                    return true;\n                }\n            }\n\n            var prefix = uri + \"/\";\n            uint n_removed = 0;\n            lock (_albums) {\n                n_removed = _albums.foreach_remove ((name, album) => {\n                    album.foreach_remove ((uri, music) => {\n                        unowned var uri2 = music.uri;\n                        if (uri2.has_prefix (prefix)/*|| uri2 == uri*/) {\n                            removed.add (music);\n                            return true;\n                        }\n                        return false;\n                    });\n                    return album.length == 0;\n                });\n            }\n            removed.foreach ((music) => {\n                lock (_artists) {\n                    _artists.foreach_remove ((name, artist) => artist.remove_music (music) && artist.length == 0);\n                }\n            });\n            return n_removed != 0;\n        }\n\n        public void remove_all () {\n            lock (_albums) {\n                _albums.remove_all ();\n            }\n            lock (_artists) {\n                _artists.remove_all ();\n            }\n            lock (_playlists) {\n                _playlists.remove_all ();\n            }\n        }\n    }\n\n    public int find_item_in_model (ListModel model, Object? obj, int start_pos = 0) {\n        var count = model.get_n_items ();\n        for (var i = start_pos; i < count; i++) {\n            if (model.get_item (i) == obj)\n                return (int) i;\n        }\n        for (var i = 0; i < start_pos; i++) {\n            if (model.get_item (i) == obj)\n                return (int) i;\n        }\n        return -1;\n    }\n\n    public bool merge_items_to_store (ListStore store, GenericArray<Music> arr, ref uint position) {\n        var first_pos = -1;\n        var removed = remove_items_from_store (store, arr, out first_pos);\n        if (position >= first_pos + removed)\n            position -= removed;\n        position = uint.min (position, store.get_n_items ());\n        store.splice (position, 0, (Object[]) arr.data);\n        return !(arr.length == 1 && arr[0] == store.get_item (first_pos));\n    }\n\n    public int remove_items_from_store (ListStore store, GenericArray<Music> arr, out int first_pos = null) {\n        var map = new GenericSet<Object?> (direct_hash, direct_equal);\n        arr.foreach ((obj) => map.add (obj));\n        var removed = 0;\n        var first_removed = -1;\n        var size = (int) store.get_n_items ();\n        if (arr.length < size / 4) {\n            for (var i = size - 1; i >= 0; i--) {\n                var obj = store.get_item (i);\n                if (map.contains (obj)) {\n                    store.remove (i);\n                    removed++;\n                    first_removed = i;\n                }\n            }\n        } else {\n            var remain = new GenericArray<Music> (size);\n            for (var i = 0; i < size; i++) {\n                var obj = store.get_item (i);\n                if (!map.contains (obj)) {\n                    remain.add ((Music) obj);\n                } else {\n                    removed++;\n                    if (first_removed == -1)\n                        first_removed = i;\n                }\n            }\n            store.splice (0, size, (Object[]) remain.data);\n        }\n        first_pos = first_removed;\n        return removed;\n    }\n\n    public void sort_music_array (GenericArray<Music> arr, uint sort_mode) {\n        if (sort_mode == SortMode.SHUFFLE)\n            Music.shuffle_order (arr);\n\n        CompareFunc<Music> compare = Music.compare_by_order;\n        switch (sort_mode) {\n            case SortMode.ALBUM:\n                compare = Music.compare_by_album; break;\n            case SortMode.ARTIST:\n                compare = Music.compare_by_artist; break;\n            case SortMode.ARTIST_ALBUM:\n                compare = Music.compare_by_artist_album; break;\n            case SortMode.TITLE:\n                compare = Music.compare_by_title; break;\n            case SortMode.RECENT:\n                compare = Music.compare_by_recent; break;\n        }\n        arr.sort (compare);\n    }\n\n    public void sort_music_store (ListStore store, uint sort_mode) {\n        var count = store.get_n_items ();\n        var arr = new GenericArray<Music> (count);\n        for (var pos = 0; pos < count; pos++) {\n            arr.add ((Music) store.get_item (pos));\n        }\n        sort_music_array (arr, sort_mode);\n        store.splice (0, count, (Object[]) arr.data);\n    }\n\n    public Playlist to_playlist (Music[] musics, string? title = null) {\n        var count = musics.length;\n        var arr = new GenericArray<Music> (count);\n        foreach (var music in musics) {\n            if (music is Artist) {\n                ((Artist) music).get_sorted_musics (arr);\n            } else if (music is Album) {\n                ((Album) music).get_sorted_musics (arr);\n            } else {\n                arr.add (music);\n            }\n        }\n        if (title == null && count == 1) {\n            title = musics[0].title;\n        }\n        var playlist = new Playlist (title ?? _(\"Untitled\"));\n        arr.foreach ((music) => playlist.add_music (music));\n        return playlist;\n    }\n}\n"
  },
  {
    "path": "src/utils/music-loader.vala",
    "content": "namespace G4 {\n\n    public class Progress {\n        private int _progress = 0;\n        private int _total = 0;\n\n        public Progress (int total = 0) {\n            _total = total;\n        }\n\n        public int total {\n            get {\n                return AtomicInt.get (ref _total);\n            }\n            set {\n                AtomicInt.set (ref _total, value);\n            }\n        }\n\n        public double fraction {\n            get {\n                return _total > 0 ? _progress / (double) _total : 0;\n            }\n        }\n\n        public void reset () {\n            _progress = 0;\n            _total = 0;\n        }\n\n        public void step () {\n            AtomicInt.inc (ref _progress);\n        }\n    }\n\n    public class StopWatch {\n        private int64 _start_time;\n\n        public StopWatch () {\n            _start_time = get_monotonic_time ();\n        }\n\n        public int64 lap () {\n            var now = get_monotonic_time ();\n            var used = now - _start_time;\n            _start_time = now;\n            return used;\n        }\n    }\n\n    public class MusicLoader : Object {\n        private static Once<ThreadPool<DirCache>?> _save_dir_pool;\n\n        static unowned ThreadPool<DirCache>? get_save_dir_pool () {\n            return _save_dir_pool.once(() => {\n                try {\n                    return new ThreadPool<DirCache>.with_owned_data ((cache) => cache.save (), 1, false);\n                } catch (Error e) {\n                }\n                return null;\n            });\n        }\n\n        private CoverCache _cover_cache = new CoverCache ();\n        private DirMonitor _dir_monitor = new DirMonitor ();\n        private MusicLibrary _library = new MusicLibrary ();\n        private Progress _progress = new Progress ();\n        private TagCache _tag_cache = new TagCache ();\n\n        public signal void loading_changed (bool loading);\n        public signal void music_found (GenericArray<Music> arr);\n        public signal void music_lost (GenericSet<Music> arr);\n\n        public MusicLoader () {\n            _dir_monitor.add_file.connect (on_file_added);\n            _dir_monitor.remove_file.connect (on_file_removed);\n        }\n\n        public CoverCache cover_cache {\n            get {\n                return _cover_cache;\n            }\n        }\n\n        public bool monitor_changes {\n            get {\n                return _dir_monitor.enabled;\n            }\n            set {\n                _dir_monitor.enabled = value;\n            }\n        }\n\n        public double loading_progress {\n            get {\n                return _progress.fraction;\n            }\n        }\n\n        public MusicLibrary library {\n            get {\n                return _library;\n            }\n        }\n\n        public void add_to_cache (Music music) {\n            _tag_cache.add (music);\n        }\n\n        public Music? find_cache (string uri) {\n            return _tag_cache[uri];\n        }\n\n        public void load_tag_cache () {\n            run_void_async.begin (_tag_cache.load, (obj, res) => run_void_async.end (res));\n        }\n\n        public void save_tag_cache () {\n            if (_tag_cache.modified) {\n                run_void_async.begin (_tag_cache.save, (obj, res) => run_void_async.end (res));\n            }\n        }\n\n        public async void load_files_async (owned File[] files, GenericArray<Music> musics, bool ignore_exists = false, bool merge_lists = true, uint sort_mode = -1) {\n            var dirs = new GenericArray<File> (128);\n\n            _progress.reset ();\n            loading_changed (true);\n            yield run_void_async (() => {\n                var list_files = new GenericArray<File> (128);\n                var stop_watch = new StopWatch ();\n                foreach (var file in files) {\n                    add_file (file, musics, dirs, list_files);\n                }\n                print (\"Find %u files in %d folders in %lld ms\\n\", musics.length, dirs.length,\n                    stop_watch.lap () / 1000);\n\n                var playlists = new GenericArray<Playlist> (list_files.length);\n                load_playlists (musics, list_files, playlists, merge_lists);\n                load_tags_in_threads (musics);\n                print (\"Load %u musics in %lld ms\\n\", musics.length,\n                    stop_watch.lap () / 1000);\n                add_musics_to_library (musics, playlists, ignore_exists);\n                if (sort_mode <= SortMode.MAX) {\n                    sort_music_array (musics, sort_mode);\n                }\n                print (\"Group %u artists %u albums %u playlists in %lld ms\\n\",\n                    _library.artist_count, _library.album_count, _library.playlist_count,\n                    stop_watch.lap () / 1000);\n            });\n            loading_changed (false);\n\n            run_void_async.begin (() => _dir_monitor.monitor (dirs), (obj, res) => run_void_async.end (res));\n\n            save_tag_cache ();\n        }\n\n        public void remove_all () {\n            _dir_monitor.remove_all ();\n            _library.remove_all ();\n        }\n\n        private const string ATTRIBUTES = FileAttribute.STANDARD_CONTENT_TYPE + \",\"\n                                        + FileAttribute.STANDARD_IS_HIDDEN + \",\"\n                                        + FileAttribute.STANDARD_NAME + \",\"\n                                        + FileAttribute.STANDARD_TYPE + \",\"\n                                        + FileAttribute.TIME_MODIFIED;\n\n        private void add_file (File file, GenericArray<Music> musics, GenericArray<File> dirs, GenericArray<File> playlists) {\n            try {\n                var info = file.query_info (ATTRIBUTES, FileQueryInfoFlags.NONE);\n                if (info.get_file_type () == FileType.DIRECTORY) {\n                    var stack = new Queue<DirCache> ();\n                    stack.push_head (new DirCache (file, info));\n                    while (stack.length > 0) {\n                        var cache = stack.pop_head ();\n                        dirs.add (cache.dir);\n                        add_directory (cache, stack, musics, playlists);\n                    }\n                } else {\n                    unowned var ctype = info.get_content_type () ?? \"\";\n                    unowned var name = info.get_name ();\n                    if (is_music_type (ctype)) {\n                        var time = info.get_modification_date_time ()?.to_unix () ?? 0;\n                        var music = new Music (file.get_uri (), name, time);\n                        musics.add (music);\n                    } else if (is_playlist_file (ctype)) {\n                        playlists.add (file);\n                    } else if (is_cover_file (ctype, name)) {\n                        var parent = file.get_parent ();\n                        if (parent != null)\n                            _cover_cache.put ((!)parent, name);\n                    } else {\n                        print (\"unknown type: %s, %s\\n\", ctype, file.get_path () ?? \"\");\n                    }\n                }\n            } catch (Error e) {\n                if (e.code != IOError.NOT_FOUND)\n                    print (\"Query %s: %s\\n\", file.get_parse_name (), e.message);\n            }\n        }\n\n        private void add_directory (DirCache cache, Queue<DirCache> stack, GenericArray<Music> musics, GenericArray<File> playlists) {\n            var dir = cache.dir;\n            var start = musics.length;\n            string? cover_name = null;\n            if (cache.check_valid () && cache.load (stack, musics, playlists, out cover_name)) {\n                _cover_cache.put (dir, cover_name ?? \"\");\n            } else try {\n                FileInfo? pi = null;\n                var enumerator = dir.enumerate_children (ATTRIBUTES, FileQueryInfoFlags.NONE);\n                while ((pi = enumerator.next_file ()) != null) {\n                    var info = (!)pi;\n                    if (info.get_is_hidden ()) {\n                        continue;\n                    } else if (info.get_file_type () == FileType.DIRECTORY) {\n                        var child = dir.get_child (info.get_name ());\n                        stack.push_head (new DirCache (child, info));\n                        cache.add_child (info, ChildType.FOLDER);\n                    } else {\n                        unowned var ctype = info.get_content_type () ?? \"\";\n                        unowned var name = info.get_name ();\n                        if (is_music_type (ctype)) {\n                            var time = info.get_modification_date_time ()?.to_unix () ?? 0;\n                            var file = dir.get_child (name);\n                            var music = new Music (file.get_uri (), name, time);\n                            musics.add (music);\n                            cache.add_child (info, ChildType.MUSIC);\n                        } else if (is_playlist_file (ctype)) {\n                            var child = dir.get_child (info.get_name ());\n                            playlists.add (child);\n                            cache.add_child (info, ChildType.PLAYLIST);\n                        } else if (cover_name == null && is_cover_file (ctype, name)) {\n                            cover_name = name;\n                            cache.add_child (info, ChildType.COVER);\n                        }\n                    }\n                }\n                _cover_cache.put (dir, cover_name ?? \"\");\n                get_save_dir_pool ()?.add (cache);\n            } catch (Error e) {\n                if (e.code != IOError.NOT_FOUND)\n                    print (\"Enumerate %s: %s\\n\", dir.get_parse_name (), e.message);\n            }\n            if (cover_name != null && ((!)cover_name).length > 0) {\n                for (var i = musics.length - 1; i >= start; i--) {\n                    var music = (Music) musics[i];\n                    music.has_cover = true;\n                }\n            }\n        }\n\n        private void add_music_file (File file, GenericArray<Music> musics) {\n            try {\n                var info = file.query_info (FileAttribute.TIME_MODIFIED, FileQueryInfoFlags.NONE);\n                unowned var name = file.get_basename () ?? \"\";\n                var time = info.get_modification_date_time ()?.to_unix () ?? 0;\n                var music = new Music (file.get_uri (), name, time);\n                musics.add (music);\n            } catch (Error e) {\n                if (e.code != IOError.NOT_FOUND)\n                    print (\"Query %s: %s\\n\", file.get_parse_name (), e.message);\n            }\n        }\n\n        private void add_musics_to_library (GenericArray<Music> musics, GenericArray<Playlist> playlists, bool ignore_exists) {\n            for (var i = musics.length - 1; i >= 0; i--) {\n                var music = musics[i];\n                if (!_library.add_music (music) && ignore_exists)\n                    musics.remove_index_fast (i);\n            }\n            foreach (var playlist in playlists) {\n                unowned var items = playlist.items;\n                for (var i = items.length - 1; i >= 0; i--) {\n                    var music = items[i];\n                    items[i] = _tag_cache[music.uri] ?? music;\n                }\n                playlist.set_cover_uri ();\n                _library.add_playlist (playlist);\n            }\n        }\n\n        private void load_playlists (GenericArray<Music> musics, GenericArray<File> list_files, GenericArray<Playlist> playlists, bool merge_lists) {\n            foreach (var file in list_files) {\n                if (file.is_native ()) {\n                    var uris = new GenericArray<string> (1024);\n                    var name = load_playlist_file (file, uris);\n                    if (name != null && uris.length > 0) {\n                        var playlist = new Playlist ((!)name, file.get_uri ());\n                        uris.foreach ((uri) => add_music_file (File.new_for_uri (uri), playlist.items));\n                        playlists.add (playlist);\n                        if (merge_lists)\n                            musics.extend (playlist.items, (src) => src);\n                    }\n                }\n            }\n        }\n\n        private void load_tags_in_threads (GenericArray<Music> musics) {\n            var queue = new AsyncQueue<Music?> ();\n            _tag_cache.wait_loading ();\n            for (var i = musics.length - 1; i >= 0; i--) {\n                unowned var music = musics[i];\n                var cached_music = _tag_cache[music.uri];\n                if (cached_music != null && ((!)cached_music).modified_time == music.modified_time) {\n                    musics[i] = (!)cached_music;\n                } else {\n                    _tag_cache.add (music);\n                    queue.push (music);\n                }\n            }\n            var queue_count = queue.length ();\n            if (queue_count > 0) {\n                _progress.total = queue_count;\n                var num_tasks = uint.min (queue_count, get_num_processors ());\n                run_in_threads<void> (() => {\n                    Music? music;\n                    while ((music = queue.try_pop ()) != null) {\n                        music?.parse_tags ();\n                        _progress.step ();\n                    }\n                }, num_tasks);\n            }\n        }\n\n        public async void on_file_added (File file) {\n            try {\n                var info = yield file.query_info_async (FileAttribute.STANDARD_IS_HIDDEN, FileQueryInfoFlags.NONE);\n                if (info.get_is_hidden ())\n                    return;\n            } catch (Error e) {\n                return;\n            }\n\n            var arr = new GenericArray<Music> (1024);\n            var n_playlists = (int) _library.playlist_count;\n            yield load_files_async ({file}, arr, true, false, -1);\n            n_playlists -= (int) _library.playlist_count;\n            if (arr.length > 0 || n_playlists != 0) {\n                music_found (arr);\n            }\n        }\n\n        public async void on_file_removed (File file) {\n            var result = false;\n            var removed = new GenericSet<Music> (direct_hash, direct_equal);\n            yield run_void_async (() => {\n                var uri = file.get_uri ();\n                var music = _tag_cache.remove (uri);\n                if (music != null) {\n                    _library.remove_music ((!)music);\n                    removed.add ((!)music);\n                } else {\n                    result = _library.remove_uri (uri, removed);\n                    new DirCache (file).delete ();\n                }\n            });\n            if (removed.length > 0 || result) {\n                music_lost (removed);\n            }\n        }\n\n        private delegate G ThreadFunc<G> ();\n\n        private static void run_in_threads<G> (owned ThreadFunc<G> func, uint num_tasks) {\n            var threads = new Thread<G>[num_tasks];\n            for (var i = 0; i < num_tasks; i++) {\n                var index = i;\n                threads[index] = new Thread<G> (null, func);\n            }\n            foreach (var thread in threads) {\n                thread.join ();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/utils/music.vala",
    "content": "namespace G4 {\n    public const string UNKNOWN_ALBUM = _(\"Unknown Album\");\n    public const string UNKNOWN_ARTIST = _(\"Unknown Artist\");\n\n    public class Music : Object {\n        public string album = \"\";\n        public string artist = \"\";\n        public string title = \"\";\n        public string album_artist = \"\";\n        public uint32 date = 0;\n        public string genre = \"\";\n        public int track = 0;\n        public int disc = 0;\n        public bool has_cover = false;\n        public int64 modified_time = 0;\n        public string uri = \"\";\n\n        //  for runtime\n        public string? cover_uri = null;\n\n        //  for sorting\n        protected string _album_key = \"\";\n        protected string _artist_key = \"\";\n        protected string _title_key = \"\";\n        private string? _cover_key = null;\n        protected int _order = 0;\n\n        public Music (string uri, string title, int64 time) {\n            this.title = title;\n            this.uri = uri;\n            this.modified_time = time;\n        }\n\n        public Music.empty () {\n        }\n\n        public Music.titled (string title, string uri) {\n            this.title = title;\n            this.uri = uri;\n            _title_key = title.collate_key_for_filename ();\n        }\n\n        public unowned string album_key {\n            get {\n                return _album_key;\n            }\n        }\n\n        public unowned string artist_name {\n            get {\n                return album_artist.length > 0 ? album_artist : artist;\n            }\n        }\n\n        public unowned string cover_key {\n            get {\n                return _cover_key ?? uri;\n            }\n            set {\n                _cover_key = value;\n            }\n        }\n\n        public inline string get_artist_and_title () {\n            return artist == UNKNOWN_ARTIST ? title : @\"$artist - $title\";\n        }\n\n        public virtual string get_abbreviation () {\n            return parse_abbreviation (album);\n        }\n\n        public inline string get_date_string () {\n            var year = date / 400;\n            if (year > 0) {\n                var month = (date - year * 400) / 32;\n                if (month > 0) {\n                    var d = date % 32;\n                    return d > 0 ? @\"$year-$month-$d\" : @\"$year-$month\";\n                }\n                return year.to_string ();\n            }\n            return \"\";\n        }\n\n        public bool from_gst_tags (Gst.TagList tags) {\n            var changed = false;\n            unowned string? al = null, ar = null, ti = null, aa = null, ge = null;\n            if (tags.peek_string_index (Gst.Tags.ALBUM, 0, out al)\n                    && al != null && strcmp (album, al) != 0) {\n                album = (!)al;\n                changed = true;\n            }\n            if (tags.peek_string_index (Gst.Tags.ARTIST, 0, out ar)\n                    && ar != null && strcmp (artist, ar) != 0) {\n                artist = (!)ar;\n                _artist_key = artist.collate_key_for_filename ();\n                changed = true;\n            }\n            if (tags.peek_string_index (Gst.Tags.TITLE, 0, out ti)\n                    && ti != null && strcmp (title, ti) != 0) {\n                title = (!)ti;\n                _title_key = title.collate_key_for_filename ();\n                changed = true;\n            }\n            if (tags.peek_string_index (Gst.Tags.ALBUM_ARTIST, 0, out aa)\n                    && aa != null && strcmp (album_artist, aa) != 0) {\n                album_artist = (!)aa;\n                changed = true;\n            }\n            if (tags.peek_string_index (Gst.Tags.GENRE, 0, out ge)\n                    && ge != null && strcmp (genre, ge) != 0) {\n                genre = (!)ge;\n                changed = true;\n            }\n            Gst.DateTime? dt = null;\n            uint dtu = 0;\n            if (tags.get_date_time (Gst.Tags.DATE_TIME, out dt)\n                    && dt != null && (dtu = gst_date_time_to_uint (dt)) != date) {\n                date = dtu;\n                changed = true;\n            }\n            if ((dt = parse_gst_original_date (tags)) != null\n                    && dt != null && (dtu = gst_date_time_to_uint (dt)) != date) {\n                date = dtu;\n                changed = true;\n            }\n            uint tn = 0, avn = 0;\n            if (tags.get_uint (Gst.Tags.TRACK_NUMBER, out tn)\n                    && (int) tn > 0 && track != tn) {\n                track = (int) tn;\n                changed = true;\n            }\n            if (tags.get_uint (Gst.Tags.ALBUM_VOLUME_NUMBER, out avn)\n                && (int) avn > 0 && disc != avn) {\n                disc = (int) avn;\n                changed = true;\n            }\n            Gst.Sample? sample = null;\n            if (tags.get_sample (Gst.Tags.IMAGE, out sample)\n                    && has_cover != (sample != null)) {\n                has_cover = sample != null;\n                changed = true;\n            }\n            if (changed) {\n                update_album_key ();\n            }\n            return changed;\n        }\n\n        public bool has_unknown () {\n            return title.length == 0 || artist == UNKNOWN_ARTIST || album == UNKNOWN_ALBUM;\n        }\n\n        public Music.deserialize (DataInputBytes dis) throws IOError {\n            album = dis.read_string ();\n            artist = dis.read_string ();\n            title = dis.read_string ();\n            has_cover = dis.read_byte () == 1;\n            modified_time = (int64) dis.read_uint64 ();\n            uri = dis.read_string ();\n\n            album_artist = dis.read_string ();\n            date = dis.read_uint32 ();\n            genre = dis.read_string ();\n            track = (int) dis.read_size ();\n            disc = (int) dis.read_size ();\n\n            update_album_key ();\n            _artist_key = artist.collate_key_for_filename ();\n            _title_key = title.collate_key_for_filename ();\n        }\n\n        public void serialize (DataOutputBytes dos) throws IOError {\n            dos.write_string (album);\n            dos.write_string (artist);\n            dos.write_string (title);\n            dos.write_byte (has_cover ? 1 : 0);\n            dos.write_uint64 (modified_time);\n            dos.write_string (uri);\n\n            dos.write_string (album_artist);\n            dos.write_uint32 (date);\n            dos.write_string (genre);\n            dos.write_size (track);\n            dos.write_size (disc);\n        }\n\n        public void parse_tags () {\n            var file = File.new_for_uri (uri);\n            var name = title;\n            this.title = \"\";\n\n            if (file.is_native ()) {\n                var tags = parse_gst_tags (file);\n                if (tags != null)\n                    from_gst_tags ((!)tags);\n            }\n\n            if (title.length == 0 || artist.length == 0) {\n                //  guess tags from the file name\n                var end = name.last_index_of_char ('.');\n                if (end > 0) {\n                    name = name.substring (0, end);\n                }\n\n                int track_index = 0;\n                var pos = name.index_of_char ('.');\n                if (pos > 0 && pos < name.length - 1) {\n                    // assume prefix number as track index\n                    if (int.try_parse (name.substring (0, pos), out track_index, null, 10))\n                        name = name.substring (pos + 1);\n                }\n\n                //  split the file name by '-'\n                var sa = name.split (\"-\");\n                var len = sa.length;\n                if (title.length == 0) {\n                    title = len >= 1 ? sa[len - 1].strip () : name;\n                    _title_key = title.collate_key_for_filename ();\n                }\n                if (artist.length == 0) {\n                    artist = len >= 2 ? sa[len - 2].strip () : UNKNOWN_ARTIST;\n                    _artist_key = artist.collate_key_for_filename ();\n                }\n                if (track_index == 0) {\n                    if (track_index == 0 && len >= 3)\n                        int.try_parse (sa[0].strip (), out track_index, null, 10);\n                    if (track_index > 0)\n                        this.track = track_index;\n                }\n            }\n            if (album.length == 0) {\n                //  assume folder name as the album\n                album = file.get_parent ()?.get_basename () ?? UNKNOWN_ALBUM;\n                _album_key = album.collate_key_for_filename ();\n            }\n        }\n\n        private void update_album_key () {\n            _album_key = (album + date.to_string () + album_artist).collate_key_for_filename ();\n        }\n\n        public static int compare_by_album (Music s1, Music s2) {\n            int ret = strcmp (s1._album_key, s2._album_key);\n            if (ret != 0) return ret;\n            ret = s1.disc - s2.disc;\n            if (ret != 0) return ret;\n            ret = s1.track - s2.track;\n            if (ret != 0) return ret;\n            ret = strcmp (s1._title_key, s2._title_key);\n            if (ret != 0) return ret;\n            return strcmp (s1.uri, s2.uri);\n        }\n\n        public static int compare_by_artist (Music s1, Music s2) {\n            int ret = strcmp (s1._artist_key, s2._artist_key);\n            if (ret != 0) return ret;\n            ret = strcmp (s1._title_key, s2._title_key);\n            if (ret != 0) return ret;\n            return strcmp (s1.uri, s2.uri);\n        }\n\n        public static int compare_by_artist_album (Music s1, Music s2) {\n            int ret = strcmp (s1._artist_key, s2._artist_key);\n            if (ret != 0) return ret;\n            return compare_by_album (s1, s2);\n        }\n\n        public static int compare_by_title (Music s1, Music s2) {\n            int ret = strcmp (s1._title_key, s2._title_key);\n            if (ret != 0) return ret;\n            ret = strcmp (s1._artist_key, s2._artist_key);\n            if (ret != 0) return ret;\n            return strcmp (s1.uri, s2.uri);\n        }\n\n        public static int compare_by_order (Music s1, Music s2) {\n            return s1._order - s2._order;\n        }\n\n        public static int compare_by_recent (Music s1, Music s2) {\n            var diff = s2.modified_time - s1.modified_time;\n            return (int) diff.clamp (-1, 1);\n        }\n\n        public static inline uint32 gst_date_time_to_uint (Gst.DateTime? dt) {\n            if (dt != null) {\n                var d = (!)dt;\n                return (d.has_year () ? d.get_year () : 0) * 400\n                    + (d.has_month () ? d.get_month () : 0) * 32\n                    + (d.has_day () ? d.get_day () : 0);\n            }\n            return 0;\n        }\n\n        public static Gst.DateTime? parse_gst_original_date (Gst.TagList tags) {\n            Gst.DateTime? date = null;\n            Gst.DateTime? year = null;\n            var ec_size = tags.get_tag_size (Gst.Tags.EXTENDED_COMMENT);\n            for (int i = 0; i < ec_size; i++) {\n                string? s = null;\n                if (tags.peek_string_index (Gst.Tags.EXTENDED_COMMENT, i, out s) && s != null) {\n                    var str = (!)s;\n                    if (str.has_prefix (\"ORIGINALDATE=\"))\n                        date = new Gst.DateTime.from_iso8601_string (str.substring (13));\n                    else if (str.has_prefix (\"ORIGINALYEAR=\"))\n                        year = new Gst.DateTime.from_iso8601_string (str.substring (13));\n                    if (date != null && year != null)\n                        break;\n                }\n            }\n            return date ?? year;\n        }\n\n        public static void original_order (GenericArray<Music> arr) {\n            for (var i = arr.length - 1; i >= 0; i--) {\n                arr[i]._order = i;\n            }\n        }\n\n        public static void shuffle_order (GenericArray<Music> arr) {\n            for (var i = arr.length - 1; i > 0; i--) {\n                var r = Random.int_range (0, i + 1);\n                var s = arr[i];\n                arr[i] = arr[r];\n                arr[r] = s;\n                arr[i]._order = i;\n            }\n        }\n    }\n\n    public bool is_music_type (string content_type) {\n        return ContentType.is_mime_type (content_type, \"audio/*\")\n                && !content_type.has_suffix (\"pls\")\n                && !content_type.has_suffix (\"url\");\n    }\n\n    public unichar find_first_letter (string text) {\n        var index = 0;\n        var next = 0;\n        unichar c = 0;\n        while (text.get_next_char (ref next, out c)) {\n            if (c.isalpha () || c.iswide_cjk ())\n                return c;\n            index = next;\n        }\n        return 0;\n    }\n\n    public string get_display_name (string uri) {\n        return get_file_display_name (File.new_for_uri (uri));\n    }\n\n    public string get_file_display_name (File file) {\n        var name = file.get_basename () ?? \"\";\n        if (name.length == 0 || name == \"/\")\n            name = file.get_parse_name ();\n        return name.substring (0, name.index_of_char ('.'));\n    }\n\n    public string get_uri_with_end_sep (File file) {\n        var uri = file.get_uri ();\n        if (uri[uri.length - 1] != '/')\n            uri += \"/\";\n        return uri;\n    }\n\n    public string parse_abbreviation (string text) {\n        var sb = new StringBuilder ();\n        var char_count = 0;\n        var arr = text.tokenize_and_fold (\"\", null);\n        for (var i = 0; i < arr.length && char_count < 2; i++) {\n            unowned var s = arr[i];\n            unichar c = 0;\n            if (s.ascii_ncasecmp (\"feat\", 4) != 0 && (c = find_first_letter (s)) > 0) {\n                sb.append_unichar (c);\n                char_count++;\n                if (char_count >= 2)\n                    break;\n            }\n        }\n\n        if (char_count >= 2) {\n            return sb.str.up ();\n        } else if (text.char_count () > 2) {\n            var index = text.index_of_nth_char (2);\n            return text.substring (0, index).up ();\n        }\n        return text.up ();\n    }\n}\n"
  },
  {
    "path": "src/utils/playlist-file.vala",
    "content": "namespace G4 {\n\n    namespace PlayListType {\n        public const uint NONE = 0;\n        public const uint M3U = 1;\n        public const uint PLS = 2;\n    }\n\n    public uint get_playlist_type (string mimetype) {\n        switch (mimetype) {\n            case \"audio/x-mpegurl\":\n            case \"public.m3u-playlist\":\n                return PlayListType.M3U;\n            case \"audio/x-scpls\":\n            case \"public.pls-playlist\":\n                return PlayListType.PLS;\n            default:\n                return PlayListType.NONE;\n        }\n    }\n\n    public bool is_playlist_file (string mimetype) {\n        return get_playlist_type (mimetype) != PlayListType.NONE;\n    }\n\n    public bool is_valid_uri (string uri, UriFlags flags = UriFlags.NONE) {\n        try {\n            return Uri.is_valid (uri, flags);\n        } catch (Error e) {\n        }\n        return false;\n    }\n\n    public string? load_playlist_file (File file, GenericArray<string> uris) {\n        string? title = null;\n        try {\n            var info = file.query_info (FileAttribute.STANDARD_CONTENT_TYPE, FileQueryInfoFlags.NONE);\n            var type = get_playlist_type (info.get_content_type () ?? \"\");\n            var fis = file.read ();\n            var bis = new BufferedInputStream (fis);\n            var dis = new DataInputStream (bis);\n            var parent = file.get_parent ();\n            switch (type) {\n                case PlayListType.M3U:\n                    title = load_m3u_file (dis, parent, uris);\n                    break;\n                case PlayListType.PLS:\n                    title = load_pls_file (dis, parent, uris);\n                    break;\n            }\n            return title ?? get_file_display_name (file);\n        } catch (Error e) {\n        }\n        return null;\n    }\n\n    public string? load_m3u_file (DataInputStream dis, File? parent, GenericArray<string> uris) throws Error {\n        size_t length = 0;\n        string? str = null, title = null;\n        while ((str = dis.read_line_utf8 (out length)) != null) {\n            var line = (!)str;\n            if (line.has_prefix (\"#PLAYLIST:\")) {\n                var text = line.substring (10).strip ();\n                if (text.length > 0)\n                    title = text;\n            } else if (length > 0 && line[0] != '#') {\n                var abs_uri = parse_relative_uri (line.strip (), parent);\n                if (abs_uri != null)\n                    uris.add ((!)abs_uri);\n            }\n        }\n        return title;\n    }\n\n    public string? load_pls_file (DataInputStream dis, File? parent, GenericArray<string> uris) throws Error {\n        bool list_found = false;\n        size_t length = 0;\n        string? str = null, title = null;\n        while ((str = dis.read_line_utf8 (out length)) != null) {\n            int pos = -1;\n            var line = ((!)str).strip ();\n            if (line.length > 1 && line[0] == '[') {\n                list_found = line == \"[playlist]\";\n            } else if (list_found && (pos = line.index_of_char ('=')) > 0) {\n                if (line.has_prefix (\"File\")) {\n                    var uri = line.substring (pos + 1).strip ();\n                    var abs_uri = parse_relative_uri (uri, parent);\n                    if (abs_uri != null)\n                        uris.add ((!)abs_uri);\n                } else if (line.ascii_ncasecmp (\"X-GNOME-Title\", pos) == 0) {\n                    var text = line.substring (pos + 1).strip ();\n                    if (text.length > 0)\n                        title = text;\n                }\n            }\n        }\n        return title;\n    }\n\n    public string get_relative_path (File? parent, File file) {\n        var path = parent?.get_relative_path (file);\n        if (path != null)\n            return (!)path;\n\n        path = file.get_path ();\n        if (path == null)\n            return \"\";\n        var file_path = (!)path;\n\n        path = parent?.get_path ();\n        if (path == null)\n            return file_path;\n        var parent_path = (!)path;\n\n        var pos = 0;\n        do {\n            var ret = file_path.index_of_char ('/', pos + 1);\n            if (ret > pos && file_path.ascii_ncasecmp (parent_path, ret) == 0)\n                pos = ret;\n            else\n                break;\n        } while (pos > 0);\n        if (pos > 1) { // Skip the first '/'\n            var len = parent_path.length;\n            var sb = new StringBuilder ();\n            for (var p = pos; p > 0 && p < len; p = parent_path.index_of_char ('/', p + 1))\n                sb.append (\"../\");\n            file_path = sb.str + file_path.substring (pos + 1);\n        }\n        return file_path;\n    }\n\n    public string? parse_relative_uri (string uri, File? parent = null) {\n        if (uri.length > 0 && uri[0] == '/') {\n            return File.new_for_path (uri).get_uri ();\n        } else if (is_valid_uri (uri)) {\n            //  Native files only\n            return uri.has_prefix (\"file://\") ? (string?) uri : null;\n        }\n        return parent?.resolve_relative_path (uri)?.get_uri ();\n    }\n\n    public bool save_m3u8_file (DataOutputStream dos, File? parent, GenericArray<string> uris, string? title, bool with_titles) throws Error {\n        if (!dos.put_string (\"#EXTM3U\\n\"))\n            return false;\n        if (title != null && with_titles && !dos.put_string (@\"#PLAYLIST:$((!)title)\\n\"))\n            return false;\n        foreach (var uri in uris) {\n            var f = File.new_for_uri (uri);\n            var path = get_relative_path (parent, f);\n            if (with_titles) {\n                var name = get_file_display_name (f);\n                if (!dos.put_string (@\"#EXTINF:,$name\\n\"))\n                    return false;\n            }\n            if (!dos.put_string (@\"$path\\n\"))\n                return false;\n        }\n        return true;\n    }\n\n    public bool save_pls_file (DataOutputStream dos, File? parent, GenericArray<string> uris, string? title, bool with_titles) throws Error {\n        if (!dos.put_string (\"[playlist]\\n\"))\n            return false;\n        if (title != null && with_titles && !dos.put_string (@\"X-GNOME-Title=$((!)title)\\n\"))\n            return false;\n        var count = uris.length;\n        if (!dos.put_string (@\"NumberOfEntries=$count\\n\"))\n            return false;\n        for (var i = 0; i < count; i++) {\n            var f = File.new_for_uri (uris[i]);\n            var path = get_relative_path (parent, f);\n            var n = i + 1;\n            if (with_titles) {\n                var name = get_file_display_name (f);\n                if (!dos.put_string (@\"Title$n=$name\\n\"))\n                    return false;\n            }\n            if (!dos.put_string (@\"File$n=$path\\n\"))\n                return false;\n        }\n        return true;\n    }\n\n    public bool save_playlist_file (File file, GenericArray<string> uris, string? title = null, bool with_titles = true) {\n        var bname = file.get_basename () ?? \"\";\n        var pos = bname.last_index_of_char ('.');\n        var name = bname.substring (0, pos);\n        var ext = bname.substring (pos + 1);\n        try {\n            var fos = file.replace (null, false, FileCreateFlags.NONE);\n            var bos = new BufferedOutputStream (fos);\n            var dos = new DataOutputStream (bos);\n            var parent = file.get_parent ();\n            if (ext.ascii_ncasecmp (\"pls\", 3) == 0) {\n                return save_pls_file (dos, parent, uris, title ?? name, with_titles);\n            } else {\n                return save_m3u8_file (dos, parent, uris, title ?? name, with_titles);\n            }\n        } catch (Error e) {\n            print (\"Save playlist %s: %s\\n\", file.get_parse_name (), e.message);\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "src/utils/portal.vala",
    "content": "namespace G4 {\n\n    public class Portal {\n        private static string PORTAL_NAME = \"org.freedesktop.portal.\";\n        private static string BUS_NAME = PORTAL_NAME + \"Desktop\";\n        private static string OBJECT_PATH = \"/org/freedesktop/portal/desktop\";\n\n        private DBusConnection? _bus = null;\n        private string _parent;\n\n        public Portal (string? parent = null) {\n            _parent = parent ?? \"\";\n        }\n\n        public async bool open_directory_async (string uri) throws Error {\n            var file = File.new_for_uri (uri);\n            var options = make_options_builder ();\n            var parameters = new Variant (\"(sha{sv})\", _parent, 0, options);\n            var ret = yield call_with_file_async (file, Posix.O_CLOEXEC, PORTAL_NAME + \"OpenURI\", \"OpenDirectory\", parameters);\n            return ret != null;\n        }\n\n        public async void request_background_async (string? reason) {\n            try {\n                var options = make_options_builder ();\n                if (reason != null) {\n                    options.add (\"{sv}\", \"reason\", new Variant.string ((!)reason));\n                }\n                options.add (\"{sv}\", \"autostart\", new Variant.boolean (false));\n                options.add (\"{sv}\", \"dbus-activatable\", new Variant.boolean (false));\n                var parameters = new Variant (\"(sa{sv})\", _parent, options);\n                _bus = _bus ?? yield Bus.get (BusType.SESSION);\n                yield ((!)_bus).call (BUS_NAME, OBJECT_PATH,\n                                PORTAL_NAME + \"Background\", \"RequestBackground\", parameters,\n                                null, DBusCallFlags.NONE, -1);\n            } catch (Error e) {\n                print (\"Bus.call error: %s\\n\", e.message);\n            }\n        }\n\n        public async bool trash_file_async (string uri) throws Error {\n            var file = File.new_for_uri (uri);\n            var parameters = new Variant (\"(h)\", 0);\n            var ret = yield call_with_file_async (file, Posix.O_CLOEXEC | 010000000 /*O_PATH*/, PORTAL_NAME + \"Trash\", \"TrashFile\", parameters);\n            uint val = 0;\n            ret?.get (\"(u)\", out val);\n            return val == 1;\n        }\n\n        private async Variant? call_with_file_async (File file, int flags, string interface_name, string method_name, Variant? parameters = null) throws Error {\n            var fd = -1;\n            try {\n                var path = file.get_path () ?? file.get_parse_name ();\n                fd = Posix.open (path, flags);\n                if (fd == -1)\n                    throw IOError.from_errno (Posix.errno);\n\n                var fd_list = new GLib.UnixFDList ();\n                fd_list.append (fd);\n                _bus = _bus ?? yield Bus.get (BusType.SESSION);\n                return yield ((!)_bus).call_with_unix_fd_list (BUS_NAME, OBJECT_PATH,\n                                        interface_name, method_name, parameters,\n                                        null, DBusCallFlags.NONE, -1, fd_list);\n            } catch (Error e) {\n                if (fd != -1) {\n                    Posix.close (fd);\n                }\n                throw e;\n            }\n        }\n\n        private VariantBuilder make_options_builder () {\n            var token = \"portal\" + Random.next_int ().to_string ();\n            var options = new VariantBuilder (VariantType.VARDICT);\n            options.add (\"{sv}\", \"handle_token\", new Variant.string (token));\n            return options;\n        }\n    }\n}\n"
  },
  {
    "path": "src/utils/tag-cache.vala",
    "content": "namespace G4 {\n\n    public class TagCache {\n        private static uint32 MAGIC = 0x54414733; //  'TAG3'\n\n        private Event _event = new Event ();\n        private File _file;\n        private bool _modified = false;\n        private HashTable<unowned string, Music> _cache = new HashTable<unowned string, Music> (str_hash, str_equal);\n\n        public TagCache (string name = \"tag-cache\") {\n            var dir = Environment.get_user_cache_dir ();\n            _file = File.new_build_filename (dir, Config.APP_ID, name);\n        }\n\n        public bool modified {\n            get {\n                return _modified;\n            }\n        }\n\n        public Music? @get (string uri) {\n            unowned string key;\n            unowned Music music;\n            lock (_cache) {\n                if (_cache.lookup_extended (uri, out key, out music)) {\n                    return music;\n                }\n            }\n            return null;\n        }\n\n        public void add (Music music) {\n            lock (_cache) {\n                _cache[music.uri] = music;\n                _modified = true;\n            }\n        }\n\n        public Music? remove (string uri) {\n            string key;\n            Music value;\n            lock (_cache) {\n                if (_cache.steal_extended (uri, out key, out value)) {\n                    _modified = true;\n                    return value;\n                }\n            }\n            return null;\n        }\n\n        public void load () {\n            _event.reset ();\n            try {\n                var mapped = new MappedFile (_file.get_path () ?? \"\", false);\n                var dis = new DataInputBytes (mapped.get_bytes ());\n                var magic = dis.read_uint32 ();\n                if (magic != MAGIC)\n                    throw new IOError.INVALID_DATA (@\"Magic=$magic\");\n\n                var count = dis.read_size ();\n                lock (_cache) {\n                    for (var i = 0; i < count; i++) {\n                        var music = new Music.deserialize (dis);\n                        _cache[music.uri] = music;\n                    }\n                }\n            } catch (Error e) {\n                if (e.code != FileError.NOENT)\n                    print (\"Load tags error: %s\\n\", e.message);\n            }\n            _event.notify ();\n        }\n\n        public void save () {\n            _event.reset ();\n            try {\n                var parent = _file.get_parent ();\n                var exists = parent?.query_exists () ?? false;\n                if (!exists)\n                    parent?.make_directory_with_parents ();\n                var fos = _file.replace (null, false, FileCreateFlags.NONE);\n                var dos = new DataOutputBytes ();\n                dos.write_uint32 (MAGIC);\n                lock (_cache) {\n                    dos.write_size (_cache.length);\n                    _cache.foreach ((key, music) => {\n                        try {\n                            music.serialize (dos);\n                        } catch (Error e) {\n                        }\n                    });\n                    _modified = !dos.write_to (fos);\n                }\n            } catch (Error e) {\n                print (\"Save tags error: %s\\n\", e.message);\n            }\n            _event.notify ();\n        }\n\n        public void wait_loading () {\n            _event.wait ();\n        }\n    }\n}\n"
  },
  {
    "path": "src/utils/thumbnailer.vala",
    "content": "namespace G4 {\n\n    //  Sorted by insert order\n    public class LruCache<V> : Object {\n        private size_t _max_size = 0;\n        private size_t _size = 0;\n        private HashTable<string, V> _cache = new HashTable<string, V> (str_hash, str_equal);\n        private Queue<string> _queue = new Queue<string> ();\n\n        public LruCache (size_t max_size) {\n            _max_size = max_size;\n        }\n\n        public V find (string key) {\n            return _cache[key];\n        }\n\n        public void put (string key, V value, bool replace = false) {\n            if (replace) {\n                remove (key);\n            } else if (_cache.contains (key)) {\n                return;\n            }\n\n            var size = size_of_value (value);\n            while (_size + size > _max_size && _queue.length > 0) {\n                string stolen_key;\n                V stolen_value;\n                if (_cache.steal_extended (_queue.pop_head (), out stolen_key, out stolen_value)) {\n                    _size -= size_of_value (stolen_value);\n                }\n            }\n\n            _cache[key] = value;\n            _queue.push_tail (key);\n            _size += size;\n            //  print (@\"Cache $(_cache.length)/$(_queue.length) items, $_size bytes\\n\");\n        }\n\n        public bool remove (string key) {\n            string stolen_key;\n            V stolen_value;\n            if (_cache.steal_extended (key, out stolen_key, out stolen_value)) {\n                unowned var link = _queue.find_custom (key, strcmp);\n                if (link != (List<string>) null)\n                    _queue.unlink (link);\n                _size -= size_of_value (stolen_value);\n                return true;\n            }\n            return false;\n        }\n\n        public void remove_all () {\n            _cache.remove_all ();\n            _queue.clear ();\n            _size = 0;\n        }\n\n        protected virtual size_t size_of_value (V value) {\n            return 1;\n        }\n    }\n\n    public class Thumbnailer : Object {\n        public const int GRID_SIZE = 160;\n        public const int ICON_SIZE = 48;\n\n        private HashTable<string, string> _album_covers = new HashTable<string, string> (str_hash, str_equal);\n        private LruCache<Gdk.Pixbuf?> _album_pixbufs = new LruCache<Gdk.Pixbuf?> (1000);\n        private LruCache<Gdk.Paintable?> _grid_cache = new LruCache<Gdk.Paintable?> (500);\n        private LruCache<Gdk.Paintable?> _icon_cache = new LruCache<Gdk.Paintable?> (1000);\n        private Quark _loading_quark = Quark.from_string (\"loading_quark\");\n\n        public signal void tag_updated (Music music);\n\n        public CoverCache? cover_finder { get; set; }\n\n        public Pango.Context? pango_context { get; set; }\n\n        public bool remote_thumbnail { get; set; }\n\n        public int scale_factor { get; set; }\n\n        public Gdk.Paintable? find (Music music, int size = ICON_SIZE) {\n            unowned var cache = size >= GRID_SIZE ? _grid_cache : _icon_cache;\n            return cache.find (music.cover_key);\n        }\n\n        public void put (Music music, Gdk.Paintable paintable, bool replace = false, int size = ICON_SIZE) {\n            unowned var cache = size >= GRID_SIZE ? _grid_cache : _icon_cache;\n            cache.put (music.cover_key, paintable, replace);\n        }\n\n        public async Gdk.Paintable? load_async (Music music, int size) {\n            var is_small = size <= GRID_SIZE;\n            if (is_small && !music.replace_qdata<bool, bool> (_loading_quark, false, true, null)) {\n                return null;\n            }\n\n            var pixbuf = yield load_directly_async (music, size);\n            if (is_small) {\n                music.steal_qdata<bool> (_loading_quark);\n            }\n\n            var paintable0 = find (music, size);\n            if (is_small && paintable0 != null) {\n                //  Check if already exist with changed cover_key\n                //  print (\"Already exist: %s\\n\", music.cover_key);\n                return paintable0;\n            }\n\n            var paintable = pixbuf != null\n                ? Gdk.Texture.for_pixbuf ((!)pixbuf)\n                : create_music_text_paintable (music);\n            if (is_small) {\n                put (music, paintable, false, size);\n            } else if (pixbuf != null && paintable0 == null) {\n                var minbuf = find_pixbuf_from_cache (music.cover_key);\n                if (minbuf != null) {\n                    put (music, Gdk.Texture.for_pixbuf ((!)minbuf), false, ICON_SIZE);\n                }\n            }\n            return paintable;\n        }\n\n        public async Gdk.Pixbuf? load_directly_async (Music music, int size) {\n            var file = File.new_for_uri (music.uri);\n            var is_native = file.is_native ();\n            if (!_remote_thumbnail && !is_native) {\n                return null;\n            }\n\n            var album_key_ = @\"$(music.album_key)-$(music.artist)-\";\n            var tags = new Gst.TagList?[] { null };\n            var args = new string[] { music.cover_key, music.cover_uri ?? \"\", music.get_abbreviation () };\n            var pixbuf = yield run_async<Gdk.Pixbuf?> (() => {\n                var tag = tags[0] = parse_gst_tags (file);\n                File? cover_file = null;\n                Gdk.Pixbuf? pixbuf = null;\n                Gst.Sample? sample = null;\n                if (tag != null && (sample = parse_image_from_tag_list ((!)tag)) != null) {\n                    //  Check if there is an album cover with same artist and image size\n                    var image_size = sample?.get_buffer ()?.get_size () ?? 0;\n                    var album_key = album_key_ + image_size.to_string (\"%x\");\n                    check_same_album_cover (album_key, ref args[0]);\n                    pixbuf = load_clamp_pixbuf_from_sample ((!)sample, size * _scale_factor);\n                }\n                if (pixbuf == null && (cover_file = _cover_finder?.find (file.get_parent ())) != null) {\n                    var album_key = (!) cover_file?.get_path ();\n                    args[0] = args[1] = (!) cover_file?.get_uri ();\n                    check_same_album_cover (album_key, ref args[0]);\n                    pixbuf = load_clamp_pixbuf_from_file ((!)cover_file, size * _scale_factor);\n                }\n                if (pixbuf != null) {\n                    var minbuf = find_pixbuf_from_cache (args[0]);\n                    if (minbuf == null) {\n                        minbuf = create_clamp_pixbuf ((!)pixbuf, ICON_SIZE * _scale_factor);\n                        put_pixbuf_to_cache (args[0], (!)minbuf);\n                    }\n                    return size <= ICON_SIZE ? minbuf : pixbuf;\n                }\n                args[0] = args[2];\n                return null;\n                //  Run in single_thread_pool for samba to save connections\n            }, false, file.has_uri_scheme (\"smb\"));\n\n            if (!is_native && tags[0] != null && music.from_gst_tags ((!)tags[0])) {\n                //  Update for remote file, since it maybe cached but not parsed from file early\n                tag_updated (music);\n            }\n            if (music.cover_key != args[0])\n                music.cover_key = args[0];\n            if (args[1].length > 0)\n                music.cover_uri = args[1];\n            return pixbuf;\n        }\n\n        public Gdk.Paintable create_music_text_paintable (Music music) {\n            var text = music.get_abbreviation ();\n            var color_count = BACKGROUND_COLORS.length / 2;\n            var color_index = (text.length == 0 || text == UNKNOWN_ALBUM)\n                    ? color_count - 1\n                    : str_hash (text) % (color_count - 1);\n            return create_simple_text_paintable (text, ICON_SIZE, color_index);\n        }\n\n        public string create_music_text_svg (Music music) {\n            var text = music.get_abbreviation ();\n            var color_count = BACKGROUND_COLORS.length / 2;\n            var color_index = (text.length == 0 || text == UNKNOWN_ALBUM)\n                    ? color_count - 1\n                    : str_hash (text) % (color_count - 1);\n            return create_text_svg ((!)_pango_context, text, color_index);\n        }\n\n        public Gdk.Paintable create_simple_text_paintable (string text, int size, uint color_index = 0x7fffffff) {\n            var paintable = create_text_paintable ((!)_pango_context, text, size * _scale_factor, size * _scale_factor, color_index);\n            return paintable ?? new BasePaintable ();\n        }\n\n        private void check_same_album_cover (string album_key, ref string cover_key) {\n            unowned string key, uri;\n            lock (_album_covers) {\n                if (_album_covers.lookup_extended (album_key, out key, out uri)) {\n                    cover_key = uri;\n                    //  print (\"Same album cover: %s\\n\", album_key);\n                } else {\n                    _album_covers[album_key] = cover_key;\n                }\n            }\n        }\n\n        private Gdk.Pixbuf? find_pixbuf_from_cache (string cover_key) {\n            lock (_album_pixbufs) {\n                return _album_pixbufs.find (cover_key);\n            }\n        }\n\n        private void put_pixbuf_to_cache (string cover_key, Gdk.Pixbuf pixbuf) {\n            lock (_album_pixbufs) {\n                _album_pixbufs.put (cover_key, pixbuf);\n            }\n        }\n    }\n\n    public static Gdk.Pixbuf create_clamp_pixbuf (Gdk.Pixbuf pixbuf, int size) {\n        var width = pixbuf.width;\n        var height = pixbuf.height;\n        if (size > 0 && width > size && height > size) {\n            var scale = width > height ? (size / (double) height) : (size / (double) width);\n            var dx = (int) (width * scale + 0.5);\n            var dy = (int) (height * scale + 0.5);\n            var newbuf = pixbuf.scale_simple (dx, dy, Gdk.InterpType.TILES);\n            if (newbuf != null)\n                return (!)newbuf;\n        }\n        return pixbuf;\n    }\n\n    public static Gdk.Pixbuf? load_clamp_pixbuf_from_file (File file, int size) {\n        try {\n            var fis = file.read ();\n            var bis = new BufferedInputStream (fis);\n            bis.buffer_size = 16384;\n            return new Gdk.Pixbuf.from_stream_at_scale (bis, size, size, true);\n        } catch (Error e) {\n        }\n        return null;\n    }\n\n    public static Gdk.Pixbuf? load_clamp_pixbuf_from_sample (Gst.Sample sample, int size) {\n        var buffer = sample.get_buffer ();\n        Gst.MapInfo? info = null;\n        try {\n            if (buffer?.map (out info, Gst.MapFlags.READ) ?? false) {\n                var bytes = new Bytes.static (info?.data);\n                var stream = new MemoryInputStream.from_bytes (bytes);\n                return new Gdk.Pixbuf.from_stream_at_scale (stream, size, size, true);\n            }\n        } catch (Error e) {\n        } finally {\n            if (info != null)\n                buffer?.unmap ((!)info);\n        }\n        return null;\n    }\n}\n"
  }
]