From cd177b7a3ee3e3417e72bbe5859da7d383a3fd96 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Fri, 29 Aug 2025 16:08:15 -0700 Subject: [PATCH 01/25] Refactor volume mapping --- .env.example | 6 +- Dockerfile | 11 +- app/LICENSE | 674 ++++++++++++++++++ {data => app}/cover/Afrobeat Radio.jpg | Bin {data => app}/cover/Alternative Radio.jpg | Bin {data => app}/cover/Back to the 1800s.jpg | Bin {data => app}/cover/Back to the 1900s.jpg | Bin {data => app}/cover/Back to the 1910s.jpg | Bin {data => app}/cover/Back to the 1920s.jpg | Bin {data => app}/cover/Back to the 1930s.jpg | Bin {data => app}/cover/Back to the 1940s.jpg | Bin {data => app}/cover/Back to the 1950s.jpg | Bin {data => app}/cover/Back to the 1960s.jpg | Bin {data => app}/cover/Back to the 1970s.jpg | Bin {data => app}/cover/Back to the 1980s.jpg | Bin {data => app}/cover/Back to the 1990s.jpg | Bin {data => app}/cover/Back to the 2000s.jpg | Bin {data => app}/cover/Back to the 2010s.jpg | Bin {data => app}/cover/Back to the 2020s.jpg | Bin {data => app}/cover/Back to the 2030s.jpg | Bin {data => app}/cover/Blues Radio.jpg | Bin {data => app}/cover/Country Radio.jpg | Bin {data => app}/cover/Discovery Mix - all.jpg | Bin {data => app}/cover/Electronic Radio.jpg | Bin {data => app}/cover/Fallback Radio.jpg | Bin {data => app}/cover/Genre Mix - all.jpg | Bin {data => app}/cover/Hip Hop Radio.jpg | Bin {data => app}/cover/Jazz Radio.jpg | Bin {data => app}/cover/Metal Radio.jpg | Bin {data => app}/cover/Pop Radio.jpg | Bin {data => app}/cover/Punk Radio.jpg | Bin .../cover/Recent Favorites - all.jpg | Bin {data => app}/cover/Rock Radio.jpg | Bin {data => app}/cover/Schlager Radio.jpg | Bin {data => app}/cover/Techno Radio.jpg | Bin {data => app}/cover/Top Tracks - all.jpg | Bin .../jellyjams-transparent.png | Bin app/jellyjams.jpeg | Bin 0 -> 220591 bytes requirements.txt => app/requirements.txt | 0 start.sh => app/start.sh | 26 +- {static => app/static}/css/app.css | 0 {templates => app/templates}/base.html | 0 {templates => app/templates}/index.html | 0 {templates => app/templates}/logs.html | 0 {templates => app/templates}/playlists.html | 0 {templates => app/templates}/settings.html | 0 .../templates}/spotify_test.html | 0 vibecodeplugin.py => app/vibecodeplugin.py | 105 +-- webapp.py => app/webapp.py | 4 +- docker-compose.yml | 19 +- 50 files changed, 706 insertions(+), 139 deletions(-) create mode 100644 app/LICENSE rename {data => app}/cover/Afrobeat Radio.jpg (100%) rename {data => app}/cover/Alternative Radio.jpg (100%) rename {data => app}/cover/Back to the 1800s.jpg (100%) rename {data => app}/cover/Back to the 1900s.jpg (100%) rename {data => app}/cover/Back to the 1910s.jpg (100%) rename {data => app}/cover/Back to the 1920s.jpg (100%) rename {data => app}/cover/Back to the 1930s.jpg (100%) rename {data => app}/cover/Back to the 1940s.jpg (100%) rename {data => app}/cover/Back to the 1950s.jpg (100%) rename {data => app}/cover/Back to the 1960s.jpg (100%) rename {data => app}/cover/Back to the 1970s.jpg (100%) rename {data => app}/cover/Back to the 1980s.jpg (100%) rename {data => app}/cover/Back to the 1990s.jpg (100%) rename {data => app}/cover/Back to the 2000s.jpg (100%) rename {data => app}/cover/Back to the 2010s.jpg (100%) rename {data => app}/cover/Back to the 2020s.jpg (100%) rename {data => app}/cover/Back to the 2030s.jpg (100%) rename {data => app}/cover/Blues Radio.jpg (100%) rename {data => app}/cover/Country Radio.jpg (100%) rename {data => app}/cover/Discovery Mix - all.jpg (100%) rename {data => app}/cover/Electronic Radio.jpg (100%) rename {data => app}/cover/Fallback Radio.jpg (100%) rename {data => app}/cover/Genre Mix - all.jpg (100%) rename {data => app}/cover/Hip Hop Radio.jpg (100%) rename {data => app}/cover/Jazz Radio.jpg (100%) rename {data => app}/cover/Metal Radio.jpg (100%) rename {data => app}/cover/Pop Radio.jpg (100%) rename {data => app}/cover/Punk Radio.jpg (100%) rename {data => app}/cover/Recent Favorites - all.jpg (100%) rename {data => app}/cover/Rock Radio.jpg (100%) rename {data => app}/cover/Schlager Radio.jpg (100%) rename {data => app}/cover/Techno Radio.jpg (100%) rename {data => app}/cover/Top Tracks - all.jpg (100%) rename jellyjams-transparent.png => app/jellyjams-transparent.png (100%) create mode 100644 app/jellyjams.jpeg rename requirements.txt => app/requirements.txt (100%) rename start.sh => app/start.sh (58%) rename {static => app/static}/css/app.css (100%) rename {templates => app/templates}/base.html (100%) rename {templates => app/templates}/index.html (100%) rename {templates => app/templates}/logs.html (100%) rename {templates => app/templates}/playlists.html (100%) rename {templates => app/templates}/settings.html (100%) rename {templates => app/templates}/spotify_test.html (100%) rename vibecodeplugin.py => app/vibecodeplugin.py (96%) rename webapp.py => app/webapp.py (99%) diff --git a/.env.example b/.env.example index 73b2fa9..bc2cd5f 100644 --- a/.env.example +++ b/.env.example @@ -3,10 +3,12 @@ # Jellyfin Server Configuration JELLYFIN_URL=http://jellyfin:8096 -JELLYFIN_API_KEY=your_jellyfin_api_key_here +JELLYFIN_API_KEY= +PLAYLIST_DIR_HOST=./jellyfin/data/playlists +MUSIC_DIR_HOST=/host/path/to/music +MUSIC_DIR_CONTAINER=/jellyfin/container/path/to/music # Playlist Configuration -PLAYLIST_FOLDER=/app/playlists GENERATION_INTERVAL=24 MAX_TRACKS_PER_PLAYLIST=100 MIN_TRACKS_PER_PLAYLIST=5 diff --git a/Dockerfile b/Dockerfile index 46bbdd9..19fc473 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,23 +2,16 @@ FROM python:3.11-alpine # Set working directory and copy app files WORKDIR /app -COPY . /app +COPY app /app RUN chmod +x /app/start.sh # Install required packages -RUN pip install --no-cache-dir -r requirements.txt - -# Create directories for playlists, logs, config, and cover -RUN mkdir -p playlists logs config cover - -# Copy default cover files to a temporary location -COPY data/cover default_cover +RUN pip install --no-cache-dir -r /app/requirements.txt # Set environment variables ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 ENV JELLYFIN_URL=http://jellyfin:8096 -ENV PLAYLIST_FOLDER=/app/playlists ENV LOG_LEVEL=INFO ENV GENERATION_INTERVAL=24 ENV ENABLE_WEB_UI=true diff --git a/app/LICENSE b/app/LICENSE new file mode 100644 index 0000000..e62ec04 --- /dev/null +++ b/app/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/data/cover/Afrobeat Radio.jpg b/app/cover/Afrobeat Radio.jpg similarity index 100% rename from data/cover/Afrobeat Radio.jpg rename to app/cover/Afrobeat Radio.jpg diff --git a/data/cover/Alternative Radio.jpg b/app/cover/Alternative Radio.jpg similarity index 100% rename from data/cover/Alternative Radio.jpg rename to app/cover/Alternative Radio.jpg diff --git a/data/cover/Back to the 1800s.jpg b/app/cover/Back to the 1800s.jpg similarity index 100% rename from data/cover/Back to the 1800s.jpg rename to app/cover/Back to the 1800s.jpg diff --git a/data/cover/Back to the 1900s.jpg b/app/cover/Back to the 1900s.jpg similarity index 100% rename from data/cover/Back to the 1900s.jpg rename to app/cover/Back to the 1900s.jpg diff --git a/data/cover/Back to the 1910s.jpg b/app/cover/Back to the 1910s.jpg similarity index 100% rename from data/cover/Back to the 1910s.jpg rename to app/cover/Back to the 1910s.jpg diff --git a/data/cover/Back to the 1920s.jpg b/app/cover/Back to the 1920s.jpg similarity index 100% rename from data/cover/Back to the 1920s.jpg rename to app/cover/Back to the 1920s.jpg diff --git a/data/cover/Back to the 1930s.jpg b/app/cover/Back to the 1930s.jpg similarity index 100% rename from data/cover/Back to the 1930s.jpg rename to app/cover/Back to the 1930s.jpg diff --git a/data/cover/Back to the 1940s.jpg b/app/cover/Back to the 1940s.jpg similarity index 100% rename from data/cover/Back to the 1940s.jpg rename to app/cover/Back to the 1940s.jpg diff --git a/data/cover/Back to the 1950s.jpg b/app/cover/Back to the 1950s.jpg similarity index 100% rename from data/cover/Back to the 1950s.jpg rename to app/cover/Back to the 1950s.jpg diff --git a/data/cover/Back to the 1960s.jpg b/app/cover/Back to the 1960s.jpg similarity index 100% rename from data/cover/Back to the 1960s.jpg rename to app/cover/Back to the 1960s.jpg diff --git a/data/cover/Back to the 1970s.jpg b/app/cover/Back to the 1970s.jpg similarity index 100% rename from data/cover/Back to the 1970s.jpg rename to app/cover/Back to the 1970s.jpg diff --git a/data/cover/Back to the 1980s.jpg b/app/cover/Back to the 1980s.jpg similarity index 100% rename from data/cover/Back to the 1980s.jpg rename to app/cover/Back to the 1980s.jpg diff --git a/data/cover/Back to the 1990s.jpg b/app/cover/Back to the 1990s.jpg similarity index 100% rename from data/cover/Back to the 1990s.jpg rename to app/cover/Back to the 1990s.jpg diff --git a/data/cover/Back to the 2000s.jpg b/app/cover/Back to the 2000s.jpg similarity index 100% rename from data/cover/Back to the 2000s.jpg rename to app/cover/Back to the 2000s.jpg diff --git a/data/cover/Back to the 2010s.jpg b/app/cover/Back to the 2010s.jpg similarity index 100% rename from data/cover/Back to the 2010s.jpg rename to app/cover/Back to the 2010s.jpg diff --git a/data/cover/Back to the 2020s.jpg b/app/cover/Back to the 2020s.jpg similarity index 100% rename from data/cover/Back to the 2020s.jpg rename to app/cover/Back to the 2020s.jpg diff --git a/data/cover/Back to the 2030s.jpg b/app/cover/Back to the 2030s.jpg similarity index 100% rename from data/cover/Back to the 2030s.jpg rename to app/cover/Back to the 2030s.jpg diff --git a/data/cover/Blues Radio.jpg b/app/cover/Blues Radio.jpg similarity index 100% rename from data/cover/Blues Radio.jpg rename to app/cover/Blues Radio.jpg diff --git a/data/cover/Country Radio.jpg b/app/cover/Country Radio.jpg similarity index 100% rename from data/cover/Country Radio.jpg rename to app/cover/Country Radio.jpg diff --git a/data/cover/Discovery Mix - all.jpg b/app/cover/Discovery Mix - all.jpg similarity index 100% rename from data/cover/Discovery Mix - all.jpg rename to app/cover/Discovery Mix - all.jpg diff --git a/data/cover/Electronic Radio.jpg b/app/cover/Electronic Radio.jpg similarity index 100% rename from data/cover/Electronic Radio.jpg rename to app/cover/Electronic Radio.jpg diff --git a/data/cover/Fallback Radio.jpg b/app/cover/Fallback Radio.jpg similarity index 100% rename from data/cover/Fallback Radio.jpg rename to app/cover/Fallback Radio.jpg diff --git a/data/cover/Genre Mix - all.jpg b/app/cover/Genre Mix - all.jpg similarity index 100% rename from data/cover/Genre Mix - all.jpg rename to app/cover/Genre Mix - all.jpg diff --git a/data/cover/Hip Hop Radio.jpg b/app/cover/Hip Hop Radio.jpg similarity index 100% rename from data/cover/Hip Hop Radio.jpg rename to app/cover/Hip Hop Radio.jpg diff --git a/data/cover/Jazz Radio.jpg b/app/cover/Jazz Radio.jpg similarity index 100% rename from data/cover/Jazz Radio.jpg rename to app/cover/Jazz Radio.jpg diff --git a/data/cover/Metal Radio.jpg b/app/cover/Metal Radio.jpg similarity index 100% rename from data/cover/Metal Radio.jpg rename to app/cover/Metal Radio.jpg diff --git a/data/cover/Pop Radio.jpg b/app/cover/Pop Radio.jpg similarity index 100% rename from data/cover/Pop Radio.jpg rename to app/cover/Pop Radio.jpg diff --git a/data/cover/Punk Radio.jpg b/app/cover/Punk Radio.jpg similarity index 100% rename from data/cover/Punk Radio.jpg rename to app/cover/Punk Radio.jpg diff --git a/data/cover/Recent Favorites - all.jpg b/app/cover/Recent Favorites - all.jpg similarity index 100% rename from data/cover/Recent Favorites - all.jpg rename to app/cover/Recent Favorites - all.jpg diff --git a/data/cover/Rock Radio.jpg b/app/cover/Rock Radio.jpg similarity index 100% rename from data/cover/Rock Radio.jpg rename to app/cover/Rock Radio.jpg diff --git a/data/cover/Schlager Radio.jpg b/app/cover/Schlager Radio.jpg similarity index 100% rename from data/cover/Schlager Radio.jpg rename to app/cover/Schlager Radio.jpg diff --git a/data/cover/Techno Radio.jpg b/app/cover/Techno Radio.jpg similarity index 100% rename from data/cover/Techno Radio.jpg rename to app/cover/Techno Radio.jpg diff --git a/data/cover/Top Tracks - all.jpg b/app/cover/Top Tracks - all.jpg similarity index 100% rename from data/cover/Top Tracks - all.jpg rename to app/cover/Top Tracks - all.jpg diff --git a/jellyjams-transparent.png b/app/jellyjams-transparent.png similarity index 100% rename from jellyjams-transparent.png rename to app/jellyjams-transparent.png diff --git a/app/jellyjams.jpeg b/app/jellyjams.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5b07366539604a780589feba038a91cd8c3a6cc8 GIT binary patch literal 220591 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 z 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/dev/null)" ]; then - for file in /app/default_cover/*; do - filename=$(basename "$file") - if [ ! -f "/app/cover/$filename" ]; then - echo "πŸ“ Copying default cover: $filename" - cp "$file" "/app/cover/" - else - echo "βœ… Custom cover exists, skipping: $filename" - fi - done - echo "🎨 Cover file initialization complete" -else - echo "⚠️ No default cover files found in /app/default_cover" +# Create app-data directories +mkdir -p /data /data/config /data/logs + +# Put default cover art in /data if not already there +if [ ! -d "/data/cover" ]; then + echo "Moving default cover art to /data/cover" + cp -r /app/cover /data/ fi # Set log level to DEBUG for comprehensive logging @@ -27,7 +19,7 @@ export LOG_LEVEL=DEBUG # Function to run playlist generator in background run_generator() { echo "🎯 Starting playlist generator background process..." - python vibecodeplugin.py & + python /app/vibecodeplugin.py & GENERATOR_PID=$! echo "πŸ“Š Playlist generator started with PID: $GENERATOR_PID" } @@ -46,5 +38,5 @@ else echo "🎯 Web UI disabled - running playlist generator only" # Run the original playlist generator - exec python vibecodeplugin.py + exec python /app/vibecodeplugin.py fi diff --git a/static/css/app.css b/app/static/css/app.css similarity index 100% rename from static/css/app.css rename to app/static/css/app.css diff --git a/templates/base.html b/app/templates/base.html similarity index 100% rename from templates/base.html rename to app/templates/base.html diff --git a/templates/index.html b/app/templates/index.html similarity index 100% rename from templates/index.html rename to app/templates/index.html diff --git a/templates/logs.html b/app/templates/logs.html similarity index 100% rename from templates/logs.html rename to app/templates/logs.html diff --git a/templates/playlists.html b/app/templates/playlists.html similarity index 100% rename from templates/playlists.html rename to app/templates/playlists.html diff --git a/templates/settings.html b/app/templates/settings.html similarity index 100% rename from templates/settings.html rename to app/templates/settings.html diff --git a/templates/spotify_test.html b/app/templates/spotify_test.html similarity index 100% rename from templates/spotify_test.html rename to app/templates/spotify_test.html diff --git a/vibecodeplugin.py b/app/vibecodeplugin.py similarity index 96% rename from vibecodeplugin.py rename to app/vibecodeplugin.py index f5b1d84..62a18c7 100644 --- a/vibecodeplugin.py +++ b/app/vibecodeplugin.py @@ -58,10 +58,12 @@ def normalize_name(s: str) -> str: return s.strip() class Config: def __init__(self): + # Set constants + self.playlist_folder = '/playlists' + # Load environment variables first (as defaults) self.jellyfin_url = os.getenv('JELLYFIN_URL', 'http://jellyfin:8096') self.api_key = os.getenv('JELLYFIN_API_KEY', '') - self.playlist_folder = os.getenv('PLAYLIST_FOLDER', '/app/playlists') self.log_level = os.getenv('LOG_LEVEL', 'INFO') self.generation_interval = int(os.getenv('GENERATION_INTERVAL', '24')) self.max_tracks_per_playlist = int(os.getenv('MAX_TRACKS_PER_PLAYLIST', '100')) @@ -628,7 +630,7 @@ def get_statistics(self) -> dict: def setup_logging(config: Config): """Setup logging configuration with timestamps - ensure all logs visible in Docker""" # Ensure log directory exists - log_dir = Path('/app/logs') + log_dir = Path('/data/logs') try: log_dir.mkdir(parents=True, exist_ok=True) print(f"πŸ“ Log directory created/verified: {log_dir}") @@ -1033,9 +1035,7 @@ def _get_cached_audio_items(self) -> List[Dict]: def copy_custom_cover_art(self, playlist_name: str, playlist_dir: Path) -> bool: """Copy custom cover art from /app/cover/ directory with fallback system and extension preservation""" try: - # Define the source cover directory (matches Docker volume mount) - cover_source_dir = Path("/app/cover") - + cover_source_dir = Path("/data/cover") self.logger.info(f"Looking for custom cover art for playlist: {playlist_name}") self.logger.info(f"Checking cover source directory: {cover_source_dir}") @@ -1145,8 +1145,7 @@ def _apply_decade_cover_art(self, playlist_name: str, playlist_dir: Path) -> boo decade = playlist_name.replace("Back to the ", "").strip() self.logger.info(f"πŸ—“οΈ Looking for decade-specific cover art for: {decade}") - # Define the source cover directory - cover_source_dir = Path("/app/cover") + cover_source_dir = Path("/data/cover") if not cover_source_dir.exists(): self.logger.warning(f"Cover source directory does not exist: {cover_source_dir}") @@ -1227,8 +1226,7 @@ def _apply_genre_cover_art(self, playlist_name: str, genre_name: str, playlist_d try: self.logger.info(f"🎡 Looking for genre cover art for: {genre_name}") - # Define the source cover directory - cover_source_dir = Path("/app/cover") + cover_source_dir = Path("/data/cover") if not cover_source_dir.exists(): self.logger.warning(f"Cover source directory does not exist: {cover_source_dir}") @@ -1455,94 +1453,7 @@ def _find_artist_cover_image(self, artist_name: str) -> Path: artist_path = self._get_artist_path_from_jellyfin(artist_name) if artist_path: self.logger.debug(f"πŸ“‘ Got artist path from Jellyfin API: {artist_path}") - cover_image = self._find_cover_in_directory(artist_path) - if cover_image: - return cover_image - - # Fallback to common paths including Unraid structure - possible_base_paths = [ - Path("/mnt/user/media/data/music"), # Unraid music path - Path("/app/music"), # Common Docker mount point - Path("/music"), # Alternative mount point - Path("/media"), # Another common mount - Path("/data/music"), # Data directory mount - Path("/mnt/music"), # Mount point variant - Path("/jellyfin/music"), # Jellyfin specific - ] - - # Debug: Show which paths exist - self.logger.debug(f"πŸ“ Checking base paths for artist folders:") - for base_path in possible_base_paths: - exists = base_path.exists() - self.logger.debug(f" {base_path}: {'βœ… exists' if exists else '❌ not found'}") - if exists: - try: - # Show first few directories as examples - dirs = [d.name for d in base_path.iterdir() if d.is_dir()][:5] - self.logger.debug(f" Sample directories: {dirs}") - except Exception as e: - self.logger.debug(f" Cannot list directories: {e}") - - # Try to find artist folder in various locations - artist_folder = None - for base_path in possible_base_paths: - if not base_path.exists(): - continue - - self.logger.debug(f"πŸ” Searching in: {base_path}") - - # Try direct artist folder - potential_artist_folder = base_path / artist_name - self.logger.debug(f" Trying exact match: {potential_artist_folder}") - if potential_artist_folder.exists() and potential_artist_folder.is_dir(): - artist_folder = potential_artist_folder - self.logger.debug(f" βœ… Found exact match!") - break - - # Try to find artist folder with case-insensitive search - try: - self.logger.debug(f" Trying case-insensitive search...") - found_dirs = [] - for item in base_path.iterdir(): - if item.is_dir(): - found_dirs.append(item.name) - if item.name.lower() == artist_name.lower(): - artist_folder = item - self.logger.debug(f" βœ… Found case-insensitive match: {item}") - break - - if not artist_folder: - # Show some directories for debugging - sample_dirs = found_dirs[:10] - self.logger.debug(f" No match found. Sample directories: {sample_dirs}") - - if artist_folder: - break - except Exception as e: - self.logger.debug(f" Error searching {base_path}: {e}") - continue - - if not artist_folder: - self.logger.debug(f"❌ No artist folder found for: {artist_name}") - return None - - self.logger.info(f"Found artist folder: {artist_folder}") - - # Look for folder.jpg or other cover art files in the artist folder - cover_files = [ - "folder.jpg", "folder.jpeg", "folder.png", - "cover.jpg", "cover.jpeg", "cover.png", - "artist.jpg", "artist.jpeg", "artist.png", - "thumb.jpg", "thumb.jpeg", "thumb.png" - ] - - for cover_file in cover_files: - potential_cover = artist_folder / cover_file - if potential_cover.exists() and potential_cover.is_file(): - self.logger.info(f"Found artist cover art: {potential_cover}") - return potential_cover - - self.logger.debug(f"No cover art files found in artist folder: {artist_folder}") + return self._find_cover_in_directory(artist_path) return None def _get_artist_path_from_jellyfin(self, artist_name: str) -> Path: diff --git a/webapp.py b/app/webapp.py similarity index 99% rename from webapp.py rename to app/webapp.py index 02acfd8..8f33afc 100644 --- a/webapp.py +++ b/app/webapp.py @@ -466,7 +466,7 @@ def read_last_lines(path: str, n: int = 100) -> str: except Exception as e: return f"Error reading logs: {e}" - log_file = '/app/logs/jellyjams.log' + log_file = '/data/logs/jellyjams.log' log_content = read_last_lines(log_file, 100) return render_template('logs.html', log_content=log_content) @@ -479,7 +479,7 @@ def api_logs_tail(): except (TypeError, ValueError): lines = 100 - log_file = '/app/logs/jellyjams.log' + log_file = '/data/logs/jellyjams.log' def read_last_lines(path: str, n: int) -> str: try: diff --git a/docker-compose.yml b/docker-compose.yml index ea43f31..40cd921 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,6 @@ services: # Essential container settings (not configurable via web UI) - JELLYFIN_URL=${JELLYFIN_URL} - JELLYFIN_API_KEY=${JELLYFIN_API_KEY} - - PLAYLIST_FOLDER=${PLAYLIST_FOLDER} - ENABLE_WEB_UI=${ENABLE_WEB_UI} - WEB_PORT=${WEB_PORT} # Default fallback values (web UI settings will override these) @@ -25,19 +24,15 @@ services: - DISCORD_WEBHOOK_ENABLED=${DISCORD_WEBHOOK_ENABLED} - DISCORD_WEBHOOK_URL=${DISCORD_WEBHOOK_URL} volumes: - # Local directories for Docker Desktop (using named volumes to avoid path issues) - - jellyjams_playlists:/app/playlists - - jellyjams_logs:/app/logs - - jellyjams_config:/app/config - - jellyjams_cover:/app/cover - # Music directory for cover art generation (adjust path for your system) - - /mnt/user/media/data/music:/mnt/user/media/data/music:ro + # JellyJames app data + - jellyjams_appdata:/data + # Ready-only access to music directory for cover art generation + - ${MUSIC_DIR_HOST}:${MUSIC_DIR_CONTAINER}:ro + # Jellyfin playlists directory for playlist and art management + - ${PLAYLIST_DIR_HOST}:/playlists ports: - "${WEB_PORT}:5000" restart: unless-stopped volumes: - jellyjams_playlists: - jellyjams_logs: - jellyjams_config: - jellyjams_cover: + jellyjams_appdata: From 3099c760804d1dc10ff18a8df7821b891f0cb524 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Fri, 29 Aug 2025 16:37:55 -0700 Subject: [PATCH 02/25] Refactor volume mapping --- .env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example b/.env.example index bc2cd5f..8abb180 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,7 @@ # Jellyfin Server Configuration JELLYFIN_URL=http://jellyfin:8096 JELLYFIN_API_KEY= -PLAYLIST_DIR_HOST=./jellyfin/data/playlists +PLAYLIST_DIR_HOST=/host/path/to/jellyfin/config/data/playlists MUSIC_DIR_HOST=/host/path/to/music MUSIC_DIR_CONTAINER=/jellyfin/container/path/to/music From 90791f52e375356464ae386efa7e50a3cfa7213a Mon Sep 17 00:00:00 2001 From: David Oleksy Date: Sat, 30 Aug 2025 10:12:47 -0700 Subject: [PATCH 03/25] update for refactored mounts and variables --- SETTINGS.md | 80 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/SETTINGS.md b/SETTINGS.md index 7c79b72..d9f9d8b 100644 --- a/SETTINGS.md +++ b/SETTINGS.md @@ -36,22 +36,31 @@ Override environment variables through the web interface at `http://localhost:50 ## 🎯 Essential Settings -### Jellyfin Connection +### Jellyfin Server Configuration | Variable | Description | Required | Default | |----------|-------------|----------|---------| -| `JELLYFIN_URL` | Your Jellyfin server URL | βœ… Yes | - | +| `JELLYFIN_URL` | Your Jellyfin server URL | βœ… Yes | http://jellyfin:8096 | | `JELLYFIN_API_KEY` | Jellyfin API key with media access | βœ… Yes | - | +| `PLAYLIST_DIR_HOST` | Path to Jellyfin playlists on host | βœ… Yes | ./jellyfin/config/data/playlists | +| `MUSIC_DIR_HOST` | Path to music on host | No | - | +| `MUSIC_DIR_CONTAINER` | Path to music in Jellyfin container | No | - | **Example:** ```bash JELLYFIN_URL=https://jellyfin.example.com JELLYFIN_API_KEY=your_32_character_api_key_here +PLAYLIST_DIR_HOST=/host/path/to/jellyfin/config/data/playlists +MUSIC_DIR_HOST=/host/path/to/music +MUSIC_DIR_CONTAINER=/jellyfin/container/path/to/music ``` +**Notes:** +- `PLAYLIST_DIR_HOST` - JellyJams needs direct R/W access to Jellyfin's playlists directory. +- `MUSIC_DIR_HOST` - Read-only access to you Jellyfin music library is needed if you want Jellyjams to pull artwork from there. +- `MUSIC_DIR_CONTAINER` - The music needs to be mapped to the same directory in the container as it is in Jellyfin. This is because JellyJams gets the path of music sub-directories from the Jellyfin API, which provides the path as it is in the Jellyfin container. ### Container Settings | Variable | Description | Required | Default | |----------|-------------|----------|---------| -| `PLAYLIST_FOLDER` | Container directory for playlists | No | `/app/playlists` | | `ENABLE_WEB_UI` | Enable web interface | No | `true` | | `WEB_PORT` | Web UI port | No | `5000` | | `LOG_LEVEL` | Logging verbosity | No | `INFO` | @@ -190,14 +199,6 @@ For artist playlists, JellyJams automatically generates professional covers: | **Quality** | High-resolution PNG/JPG | | **Color Analysis** | Automatic brightness detection for optimal contrast | -#### Music Directory Integration -JellyJams searches these paths for artist folders: -- `/mnt/user/media/data/music/[Artist]/` (Unraid) -- `/app/music/[Artist]/` -- `/music/[Artist]/` -- `/media/[Artist]/` -- `/data/music/[Artist]/` - #### Supported Cover Files - `folder.jpg`, `folder.jpeg`, `folder.png` - `cover.jpg`, `cover.jpeg`, `cover.png` @@ -206,11 +207,11 @@ JellyJams searches these paths for artist folders: ### πŸ“ Predefined Custom Covers -Place custom images in your cover directory (mapped to `/app/cover/`): +Place custom images in your appdata/cover directory (mapped to `/data/cover/`): #### Directory Structure Examples ``` -/app/cover/ +/data/cover/ β”œβ”€β”€ Top Tracks - Jonas.jpg # Personal playlist (specific user) β”œβ”€β”€ Top Tracks - all.jpg # Personal playlist (generic fallback) β”œβ”€β”€ Discovery Mix - Sarah.webp # Personal playlist (specific user) @@ -234,7 +235,7 @@ Place custom images in your cover directory (mapped to `/app/cover/`): ### πŸ”„ Update Covers Feature -Refresh cover art for existing playlists without regenerating them: +Refresh cover art for existing playlists without regenerating playlists: #### Web UI Usage 1. Navigate to **Playlists** page (`/playlists`) @@ -250,7 +251,7 @@ Refresh cover art for existing playlists without regenerating them: - **Error Handling**: Graceful fallbacks with detailed logging #### When to Use -- After adding new cover art files to `/app/cover/` +- After adding new cover art files to `/data/cover/` - When Spotify integration settings change - After updating music library with new artist folders - To fix missing or corrupted cover art @@ -290,19 +291,19 @@ Refresh cover art for existing playlists without regenerating them: ``` #### Predefined Covers Not Loading -**Symptoms**: Custom covers in `/app/cover/` are ignored +**Symptoms**: Custom covers in `/data/cover/` are ignored **Solutions**: 1. **Verify Docker Volume Mount**: ```yaml volumes: - - /host/path/covers:/app/cover # Must be mounted + - /host/path/appdata:/data # Must be mounted ``` 2. **Check File Permissions**: ```bash # Ensure container can read cover files - ls -la /host/path/covers/ + ls -la /host/path/appdata/covers/ ``` 3. **Verify Exact Naming**: @@ -418,26 +419,32 @@ The web UI settings page (`/settings`) provides: ### Required Volumes ```yaml volumes: - - /host/path/playlists:/app/playlists # Playlist storage - - /host/path/logs:/app/logs # Application logs - - /host/path/config:/app/config # Web UI settings + # JellyJames app data (config, logs, cover art) + - /host/path/appdata:/data + # Jellyfin playlists directory for playlist and art management + - ${PLAYLIST_DIR_HOST}:/playlists ``` ### Optional Volumes ```yaml volumes: - - /host/path/covers:/app/cover # Custom cover art + # Ready-only access to music directory for cover art generation + - ${MUSIC_DIR_HOST}:${MUSIC_DIR_CONTAINER}:ro ``` ### Unraid Configuration -For Unraid users, use the provided `docker-compose-unraid.yml`: +For Unraid users, your volumes and associated variables may look something like this: ```yaml volumes: - - /mnt/user/appdata/jellyjams/playlists:/app/playlists - - /mnt/user/appdata/jellyjams/logs:/app/logs - - /mnt/user/appdata/jellyjams/config:/app/config - - /mnt/user/appdata/jellyjams/cover:/app/cover + - /mnt/user/appdata/jellyjams:/data + - ${PLAYLIST_DIR_HOST}:/playlists + - ${MUSIC_DIR_HOST}:${MUSIC_DIR_CONTAINER}:ro +``` +```.env +PLAYLIST_DIR_HOST=-/mnt/user/appdata/jellyfin/data/playlists +MUSIC_DIR_HOST=/mnt/user/media/data/music +MUSIC_DIR_CONTAINER=/mnt/user/media/data/music ``` ## πŸ“ Examples @@ -447,6 +454,7 @@ volumes: # .env file for basic setup JELLYFIN_URL=http://localhost:8096 JELLYFIN_API_KEY=your_api_key_here +PLAYLIST_DIR_HOST=/path/to/jellyfin/config/data/data/playlists PLAYLIST_TYPES=Genre,Year,Artist MAX_TRACKS_PER_PLAYLIST=50 MIN_TRACKS_PER_PLAYLIST=10 @@ -457,6 +465,9 @@ MIN_TRACKS_PER_PLAYLIST=10 # .env file for advanced setup JELLYFIN_URL=https://jellyfin.example.com JELLYFIN_API_KEY=your_api_key_here +PLAYLIST_DIR_HOST=/path/to/jellyfin/config/data/data/playlists +MUSIC_DIR_HOST=/host/path/to/music +MUSIC_DIR_CONTAINER=/jellyfin/container/path/to/music # Playlist generation PLAYLIST_TYPES=Genre,Year,Artist,Personal @@ -503,20 +514,23 @@ EXCLUDED_GENRES=Classical,Opera,Spoken Word,Audiobook,Podcast - Ensure `TRIGGER_LIBRARY_SCAN=true` - Check Jellyfin API key permissions - Verify playlist folder is accessible + +2. **Playlists not appearing in JellyJams** + - Ensure `PLAYLIST_DIR_HOST` = your host path to the Jellyin playlists directory + - Verify Jellyfin playlists directory is mapped to /playlists -2. **Cover art not copying** - - Check Docker volume mount for `/app/cover` - - Verify file permissions on cover directory +3. **Cover art not copying** + - Verify file permissions on cover in your appdata directory - Check logs for detailed error messages -3. **Personalized playlists empty** +4. **Personalized playlists empty** - **Install Required Plugin**: Ensure [Jellyfin Playback Reporting Plugin](https://github.com/jellyfin/jellyfin-plugin-playbackreporting) is installed and enabled - Increase `PERSONAL_PLAYLIST_MIN_USER_TRACKS` - Check user has listening history in Jellyfin - Verify user selection in settings - Confirm plugin is collecting playback data -4. **Spotify integration not working** +5. **Spotify integration not working** - Test connection in web UI settings - Verify Client ID and Secret are correct - Check Spotify app permissions @@ -536,4 +550,4 @@ This provides comprehensive information about: --- -For additional help, check the application logs at `/app/logs/` or enable debug logging for detailed troubleshooting information. +For additional help, check the application logs at `/data/logs/` or enable debug logging for detailed troubleshooting information. You may also check the container logs using `docker logs jellyjams` from the host CLI. From 71ab0c437a2f5e5efb5f6b8fc155054da6119979 Mon Sep 17 00:00:00 2001 From: David Oleksy Date: Sat, 30 Aug 2025 10:44:57 -0700 Subject: [PATCH 04/25] updated project structure and docker-compose --- README.md | 89 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 307787a..0ea9aa2 100644 --- a/README.md +++ b/README.md @@ -203,41 +203,58 @@ version: '3.8' services: jellyjams: - build: . + image: jonasmore/jellyjams:latest container_name: jellyjams environment: + # Essential container settings (not configurable via web UI) - JELLYFIN_URL=${JELLYFIN_URL} - JELLYFIN_API_KEY=${JELLYFIN_API_KEY} - - ENABLE_WEB_UI=true + - ENABLE_WEB_UI=${ENABLE_WEB_UI} + - WEB_PORT=${WEB_PORT} + # Default fallback values (web UI settings will override these) + - LOG_LEVEL=${LOG_LEVEL} + - GENERATION_INTERVAL=${GENERATION_INTERVAL} + - MAX_TRACKS_PER_PLAYLIST=${MAX_TRACKS_PER_PLAYLIST} + - MIN_TRACKS_PER_PLAYLIST=${MIN_TRACKS_PER_PLAYLIST} + - EXCLUDED_GENRES=${EXCLUDED_GENRES} + - SHUFFLE_TRACKS=${SHUFFLE_TRACKS} + - PLAYLIST_TYPES=${PLAYLIST_TYPES} + # Web UI Security (environment variables override web UI settings) + - WEBUI_BASIC_AUTH_ENABLED=${WEBUI_BASIC_AUTH_ENABLED} + - WEBUI_BASIC_AUTH_USERNAME=${WEBUI_BASIC_AUTH_USERNAME} + - WEBUI_BASIC_AUTH_PASSWORD=${WEBUI_BASIC_AUTH_PASSWORD} + # Discord Notifications + - DISCORD_WEBHOOK_ENABLED=${DISCORD_WEBHOOK_ENABLED} + - DISCORD_WEBHOOK_URL=${DISCORD_WEBHOOK_URL} volumes: - - jellyjams_playlists:/app/playlists - - jellyjams_logs:/app/logs - - jellyjams_config:/app/config - # Music directory for cover art generation (adjust path for your system) - - /mnt/user/media/data/music:/mnt/user/media/data/music:ro + # JellyJames app data - bind to existing host directory + - ./jellyjams:/data + # Ready-only access to music directory for cover art generation + - ${MUSIC_DIR_HOST}:${MUSIC_DIR_CONTAINER}:ro + # Jellyfin playlists directory for playlist and art management + - ${PLAYLIST_DIR_HOST}:/playlists ports: - - "5000:5000" + - "${WEB_PORT}:5000" restart: unless-stopped - -volumes: - jellyjams_playlists: - jellyjams_logs: - jellyjams_config: ``` ### Unraid Deployment -For Unraid users, use bind mounts to `/mnt/user/appdata/jellyjams/`: +For Unraid users, use bind app data to `/mnt/user/appdata/jallyjams/` for persistent storage: ```yaml -volumes: - # Playlist folder location of Jellyfin - - /mnt/user/appdata/Jellyfin/data/playlists:/app/playlists - # JellyJams settings and logs - - /mnt/user/appdata/jellyjams/logs:/app/logs - - /mnt/user/appdata/jellyjams/config:/app/config - # Music directory for cover art generation (adjust path for your system) - - /mnt/user/media/data/music:/mnt/user/media/data/music:ro + volumes: + # JellyJames app data + - /mnt/user/appdata/jellyjams:/data + # Ready-only access to music directory for cover art generation + - ${MUSIC_DIR_HOST}:${MUSIC_DIR_CONTAINER}:ro + # Jellyfin playlists directory for playlist and art management + - ${PLAYLIST_DIR_HOST}:/playlists + +# Set these vars in your .env +PLAYLIST_DIR_HOST=/mnt/user/appdata/jellyfin/data/playlists +MUSIC_DIR_HOST=/mnt/user/media/data/music +MUSIC_DIR_CONTAINER=/mnt/user/media/data/music ``` ## πŸ”§ API Integration @@ -282,19 +299,25 @@ JellyJams uses the Jellyfin REST API to: ``` jellyjams/ -β”œβ”€β”€ vibecodeplugin.py # Main playlist generator -β”œβ”€β”€ webapp.py # Flask web UI -β”œβ”€β”€ start.sh # Container startup script +β”œβ”€β”€ .env.example # Environment template β”œβ”€β”€ Dockerfile # Container definition β”œβ”€β”€ docker-compose.yml # Docker Compose config -β”œβ”€β”€ requirements.txt # Python dependencies -β”œβ”€β”€ .env.example # Environment template -└── templates/ # HTML templates - β”œβ”€β”€ base.html - β”œβ”€β”€ index.html - β”œβ”€β”€ settings.html - β”œβ”€β”€ playlists.html - └── logs.html +└── app/ # Container app files + β”œβ”€β”€ vibecodeplugin.py # Main playlist generator + β”œβ”€β”€ webapp.py # Flask web UI + β”œβ”€β”€ start.sh # Container startup script + β”œβ”€β”€ requirements.txt # Python dependencies + └── cover # Default playlist images + β”œβ”€β”€ Playlist Name.jpg + └── static/ # WebUI assets + └── css/ + β”œβ”€β”€ app.css + └── templates/ # HTML templates + β”œβ”€β”€ base.html + β”œβ”€β”€ index.html + β”œβ”€β”€ settings.html + β”œβ”€β”€ playlists.html + └── logs.html ``` ## 🀝 Contributing From 17941de2f2c8694ed60fc464e62823f7f9ecaf0d Mon Sep 17 00:00:00 2001 From: David Oleksy Date: Sat, 30 Aug 2025 10:47:53 -0700 Subject: [PATCH 05/25] switched appdata from named volume to bind Bind mounts are easier for persistent storage in unraid --- docker-compose.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 40cd921..6807ab4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,8 +24,8 @@ services: - DISCORD_WEBHOOK_ENABLED=${DISCORD_WEBHOOK_ENABLED} - DISCORD_WEBHOOK_URL=${DISCORD_WEBHOOK_URL} volumes: - # JellyJames app data - - jellyjams_appdata:/data + # JellyJames app data - bind to existing host directory + - ./jellyjams:/data # Ready-only access to music directory for cover art generation - ${MUSIC_DIR_HOST}:${MUSIC_DIR_CONTAINER}:ro # Jellyfin playlists directory for playlist and art management @@ -33,6 +33,3 @@ services: ports: - "${WEB_PORT}:5000" restart: unless-stopped - -volumes: - jellyjams_appdata: From 9b21c8657018930d9720d1d888f352d48687c58d Mon Sep 17 00:00:00 2001 From: David Oleksy Date: Sat, 30 Aug 2025 10:49:38 -0700 Subject: [PATCH 06/25] Delete LICENSE from app dir --- LICENSE | 674 -------------------------------------------------------- 1 file changed, 674 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e62ec04..0000000 --- a/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ -GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. From cea25505b214e635708132dffca71eef868141a6 Mon Sep 17 00:00:00 2001 From: David Oleksy Date: Sun, 31 Aug 2025 17:17:58 -0700 Subject: [PATCH 07/25] improve artist cover search Rewrite _find_cover_in_directory function to be smaller, faster and find art in artist sub-directories in case there is none in the first level --- app/vibecodeplugin.py | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/app/vibecodeplugin.py b/app/vibecodeplugin.py index 62a18c7..5e964eb 100644 --- a/app/vibecodeplugin.py +++ b/app/vibecodeplugin.py @@ -1510,27 +1510,13 @@ def _get_artist_path_from_jellyfin(self, artist_name: str) -> Path: return None - def _find_cover_in_directory(self, directory_path: Path) -> Path: - """Find cover art files in a specific directory""" - if not directory_path or not directory_path.exists(): - return None - - self.logger.debug(f"πŸ” Searching for cover art in: {directory_path}") - - # Look for cover art files in the directory - cover_files = [ - "folder.jpg", "folder.jpeg", "folder.png", - "cover.jpg", "cover.jpeg", "cover.png", - "artist.jpg", "artist.jpeg", "artist.png", - "thumb.jpg", "thumb.jpeg", "thumb.png" - ] - - for cover_file in cover_files: - potential_cover = directory_path / cover_file - if potential_cover.exists() and potential_cover.is_file(): - self.logger.info(f"πŸ–ΌοΈ Found cover art: {potential_cover}") - return potential_cover - + def _find_cover_in_directory(self, directory_path: Path) -> Path | None: + pattern = re.compile(r"^(folder|cover|artist|thumb|front)\.(jpg|jpeg|png|webp|avif|heif)$", re.IGNORECASE) + for root, dirs, files in os.walk(directory_path): + for fname in files: + if pattern.match(fname): + self.logger.info(f"πŸ–ΌοΈ Found cover art: {Path(root) / fname}") + return Path(root) / fname self.logger.debug(f"No cover art files found in: {directory_path}") return None From eba0e060d973c8b036cc3d8bd5c6705f491ec1a7 Mon Sep 17 00:00:00 2001 From: David Oleksy Date: Sun, 31 Aug 2025 17:29:37 -0700 Subject: [PATCH 08/25] update image extensions in _find_cover_in_directory --- app/vibecodeplugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/vibecodeplugin.py b/app/vibecodeplugin.py index 5e964eb..9ea8da1 100644 --- a/app/vibecodeplugin.py +++ b/app/vibecodeplugin.py @@ -1511,7 +1511,7 @@ def _get_artist_path_from_jellyfin(self, artist_name: str) -> Path: return None def _find_cover_in_directory(self, directory_path: Path) -> Path | None: - pattern = re.compile(r"^(folder|cover|artist|thumb|front)\.(jpg|jpeg|png|webp|avif|heif)$", re.IGNORECASE) + pattern = re.compile(r"^(folder|cover|artist|thumb|front)\.(jpg|jpeg|png|webp|avif|gif)$", re.IGNORECASE) for root, dirs, files in os.walk(directory_path): for fname in files: if pattern.match(fname): From 54537bd0ad86260ce0ce5ad3486cf9af232fb847 Mon Sep 17 00:00:00 2001 From: David Oleksy Date: Tue, 2 Sep 2025 02:08:47 -0700 Subject: [PATCH 09/25] add method to get artist image from Jellyfin API Update other functions for integration of new method --- app/vibecodeplugin.py | 92 ++++++++++++++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 22 deletions(-) diff --git a/app/vibecodeplugin.py b/app/vibecodeplugin.py index 9ea8da1..b0bf0b4 100644 --- a/app/vibecodeplugin.py +++ b/app/vibecodeplugin.py @@ -18,6 +18,7 @@ from typing import Dict, List, Optional from xml.etree.ElementTree import Element, SubElement, tostring from xml.dom import minidom +from io import BytesIO # PIL/Pillow imports for custom cover art generation try: @@ -735,6 +736,52 @@ def test_connection(self) -> bool: self.logger.error(f"Failed to connect to Jellyfin: {e}") return False + def get_artist_image_by_name(self, artist_name: str, timeout: float = 10.0) -> Optional[bytes]: + if not artist_name: + raise ValueError("artist_name is required") + + base = self.config.jellyfin_url.rstrip("/") + encoded = quote(artist_name, safe="") + url = f"{base}/Artists/{encoded}/Images/Primary" + params = {"format": "webp", "maxWidth": 600, "maxHeight": 600} + + # Merge in an Accept header that prefers webp. + headers = {"Accept": "image/webp,image/*;q=0.8,*/*;q=0.5"} + + try: + resp = self.session.get(url, params=params, headers=headers, timeout=timeout) + if resp.status_code == 404: + self.logger.info("Artist not found or no primary image: %r", artist_name) + return None + resp.raise_for_status() + + ctype = resp.headers.get("Content-Type", "").lower() + if "image" not in ctype: + # Jellyfin should return an image; if not, log a short body preview + preview = "" + try: + preview = (resp.text or "")[:300] + except Exception: + pass + self.logger.error("Unexpected response (Content-Type=%s). Body: %s", ctype, preview) + raise requests.exceptions.RequestException( + f"Unexpected response (Content-Type={ctype}). Body: {preview}" + ) + return resp.content + + except requests.exceptions.HTTPError as e: + # Keep an informative log (with short body preview, if any) + body_preview = "" + try: + body_preview = (getattr(e.response, "text", "") or "")[:300] + except Exception: + pass + self.logger.error("Jellyfin HTTP error for %s: %s | %s", url, e, body_preview) + raise + except requests.exceptions.RequestException as e: + self.logger.error("Failed fetching artist image: %s", e) + raise + def get_users(self) -> List[Dict]: """Get all users from Jellyfin""" try: @@ -1388,7 +1435,7 @@ def _generate_genre_cover_art(self, background_path: Path, genre_name: str, dest draw.text((x2, y2), line2, font=font, fill=text_color) # Save the final image - background.save(destination, "JPEG", quality=95) + background.save(destination, "JPEG", quality=85) self.logger.info(f"βœ… Generated genre cover art: {destination}") return True @@ -1412,11 +1459,11 @@ def _try_artist_folder_fallback(self, playlist_name: str, playlist_dir: Path) -> # Find artist folder and source image source_cover = self._find_artist_cover_image(artist_name) - if not source_cover: + if source_cover is None: return False # Generate custom cover art with text overlay - destination_cover = playlist_dir / "folder.png" + destination_cover = playlist_dir / "folder.webp" success = self._generate_custom_cover_art(source_cover, artist_name, destination_cover) if success: @@ -1445,10 +1492,14 @@ def _try_artist_folder_fallback(self, playlist_name: str, playlist_dir: Path) -> self.logger.debug(f"Full traceback: {traceback.format_exc()}") return False - def _find_artist_cover_image(self, artist_name: str) -> Path: - """Find cover image in artist folder using Jellyfin API and common paths""" + def _find_artist_cover_image(self, artist_name: str) -> Optional[bytes]: + """First, try getting artist image from Jellyfin API""" + artist_image = self.jellyfin.get_artist_image_by_name(self, artist_name, 5) + if not (artist_image is None): + return artist_image + + """Else, search artist folder for image""" self.logger.debug(f"πŸ” Searching for artist folder: {artist_name}") - # First try to get artist info from Jellyfin API artist_path = self._get_artist_path_from_jellyfin(artist_name) if artist_path: @@ -1510,13 +1561,13 @@ def _get_artist_path_from_jellyfin(self, artist_name: str) -> Path: return None - def _find_cover_in_directory(self, directory_path: Path) -> Path | None: - pattern = re.compile(r"^(folder|cover|artist|thumb|front)\.(jpg|jpeg|png|webp|avif|gif)$", re.IGNORECASE) + def _find_cover_in_directory(self, directory_path: Path) -> Optional[bytes]: + pattern = re.compile(r"^(folder|cover|artist|thumb|front)\.(jpg|jpeg|png|webp|avif|gif|bmp)$", re.IGNORECASE) for root, dirs, files in os.walk(directory_path): for fname in files: if pattern.match(fname): self.logger.info(f"πŸ–ΌοΈ Found cover art: {Path(root) / fname}") - return Path(root) / fname + return (Path(root) / fname).read_bytes() self.logger.debug(f"No cover art files found in: {directory_path}") return None @@ -1557,7 +1608,7 @@ def _sanitize_text_for_font(self, text: str) -> str: # Fallback: remove all non-ASCII characters return ''.join(char for char in text if ord(char) < 128) - def _generate_custom_cover_art(self, source_image: Path, artist_name: str, destination: Path) -> bool: + def _generate_custom_cover_art(self, source_image: bytes, artist_name: str, destination: Path) -> bool: """Generate custom cover art with 'This is ' text overlay using multi-stage scaling approach""" try: import signal @@ -1573,7 +1624,7 @@ def timeout_handler(signum, frame): signal.alarm(10) # 10 second timeout # Open the source image - with Image.open(source_image) as img: + with Image.open(BytesIO(source_image)) as img: # Convert to RGB if needed if img.mode != 'RGB': img = img.convert('RGB') @@ -1707,7 +1758,7 @@ def timeout_handler(signum, frame): final_img.paste(text_img, (paste_x, paste_y), text_img) # Save the final image as PNG - final_img.save(destination, 'PNG', quality=95) + final_img.save(destination, 'webp') # Clear timeout signal.alarm(0) @@ -2014,22 +2065,19 @@ def save_playlist(self, playlist_type: str, name: str, tracks: List[Dict], user_ self.logger.info(f"🎨 Generating custom cover art for artist: {artist_name}") # First, find the source image to use as base - artist_cover_path = self._find_artist_cover_image(artist_name) - if artist_cover_path: + artist_image = self._find_artist_cover_image(artist_name) + if not (artist_image is None): # Generate custom cover art with text overlay - cover_dest = playlist_dir / 'cover.jpg' - if self._generate_custom_cover_art(artist_cover_path, artist_name, cover_dest): + cover_dest = playlist_dir / 'cover.webp' + if self._generate_custom_cover_art(artist_image, artist_name, cover_dest): cover_added = True self.logger.info(f"βœ… Generated custom cover art for artist: {artist_name}") else: self.logger.info(f"❌ Failed to generate custom cover art for artist: {artist_name}") # Fallback: copy the original image directly - self.logger.info(f"πŸ–ΌοΈ Fallback: Using original artist cover image: {artist_cover_path}") - import shutil - file_extension = artist_cover_path.suffix - fallback_destination = playlist_dir / f"folder{file_extension}" - shutil.copy2(artist_cover_path, fallback_destination) - + self.logger.info(f"πŸ–ΌοΈ Fallback: Using original artist cover image") + fallback_destination = playlist_dir / "folder.webp" + Image.open(BytesIO(artist_image)).save(fallback_destination) # Ensure cover art is world-readable on host mounts try: os.chmod(fallback_destination, 0o664) From 0b8fdfa35111365ddddf451b680066645c2353e8 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Tue, 2 Sep 2025 09:32:31 -0700 Subject: [PATCH 10/25] debug previous commit --- app/vibecodeplugin.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/vibecodeplugin.py b/app/vibecodeplugin.py index b0bf0b4..85b54bc 100644 --- a/app/vibecodeplugin.py +++ b/app/vibecodeplugin.py @@ -13,11 +13,13 @@ import requests import schedule import signal +import re from datetime import datetime from pathlib import Path from typing import Dict, List, Optional from xml.etree.ElementTree import Element, SubElement, tostring from xml.dom import minidom +from urllib.parse import quote from io import BytesIO # PIL/Pillow imports for custom cover art generation @@ -740,9 +742,8 @@ def get_artist_image_by_name(self, artist_name: str, timeout: float = 10.0) -> O if not artist_name: raise ValueError("artist_name is required") - base = self.config.jellyfin_url.rstrip("/") encoded = quote(artist_name, safe="") - url = f"{base}/Artists/{encoded}/Images/Primary" + url = f"{self.config.jellyfin_url}/Artists/{encoded}/Images/Primary/0" params = {"format": "webp", "maxWidth": 600, "maxHeight": 600} # Merge in an Accept header that prefers webp. @@ -1494,7 +1495,7 @@ def _try_artist_folder_fallback(self, playlist_name: str, playlist_dir: Path) -> def _find_artist_cover_image(self, artist_name: str) -> Optional[bytes]: """First, try getting artist image from Jellyfin API""" - artist_image = self.jellyfin.get_artist_image_by_name(self, artist_name, 5) + artist_image = self.jellyfin.get_artist_image_by_name(artist_name) if not (artist_image is None): return artist_image From b5824565ec43edf03f5bf7c252f879df6e94dc76 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Tue, 2 Sep 2025 10:17:04 -0700 Subject: [PATCH 11/25] update _try_artist_folder_fallback for modified _find_artist_cover_image return type --- app/vibecodeplugin.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/vibecodeplugin.py b/app/vibecodeplugin.py index 85b54bc..98f4099 100644 --- a/app/vibecodeplugin.py +++ b/app/vibecodeplugin.py @@ -1448,7 +1448,7 @@ def _generate_genre_cover_art(self, background_path: Path, genre_name: str, dest return False def _try_artist_folder_fallback(self, playlist_name: str, playlist_dir: Path) -> bool: - """Generate custom cover art with 'This is ' text overlay from artist folder images""" + """Generate custom cover art with 'This is ' text overlay from artist images""" try: # Only apply this fallback for artist playlists if not playlist_name.startswith("This is "): @@ -1473,10 +1473,8 @@ def _try_artist_folder_fallback(self, playlist_name: str, playlist_dir: Path) -> else: # Fallback to simple copy if text overlay fails self.logger.warning("Text overlay failed, falling back to simple copy") - import shutil - file_extension = source_cover.suffix - fallback_destination = playlist_dir / f"folder{file_extension}" - shutil.copy2(source_cover, fallback_destination) + fallback_destination = playlist_dir / "folder.webp" + Image.open(BytesIO(source_cover)).save(fallback_destination) # Ensure cover art is world-readable on host mounts try: From 0d1f56ed0d584eb72431c99e100a2d9d5963248f Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sat, 6 Sep 2025 20:52:19 -0700 Subject: [PATCH 12/25] use as internal and external port --- app/vibecodeplugin.py | 4 +--- docker-compose.yml | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/vibecodeplugin.py b/app/vibecodeplugin.py index 98f4099..51fa276 100644 --- a/app/vibecodeplugin.py +++ b/app/vibecodeplugin.py @@ -19,7 +19,6 @@ from typing import Dict, List, Optional from xml.etree.ElementTree import Element, SubElement, tostring from xml.dom import minidom -from urllib.parse import quote from io import BytesIO # PIL/Pillow imports for custom cover art generation @@ -742,8 +741,7 @@ def get_artist_image_by_name(self, artist_name: str, timeout: float = 10.0) -> O if not artist_name: raise ValueError("artist_name is required") - encoded = quote(artist_name, safe="") - url = f"{self.config.jellyfin_url}/Artists/{encoded}/Images/Primary/0" + url = f"{self.config.jellyfin_url}/Artists/{artist_name}/Images/Primary/0" params = {"format": "webp", "maxWidth": 600, "maxHeight": 600} # Merge in an Accept header that prefers webp. diff --git a/docker-compose.yml b/docker-compose.yml index 6807ab4..7cadff3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ services: - ENABLE_WEB_UI=${ENABLE_WEB_UI} - WEB_PORT=${WEB_PORT} # Default fallback values (web UI settings will override these) - - LOG_LEVEL=${LOG_LEVEL} + - LOG_LEVEL=${LOG_LEVEL:=DEBUG} - GENERATION_INTERVAL=${GENERATION_INTERVAL} - MAX_TRACKS_PER_PLAYLIST=${MAX_TRACKS_PER_PLAYLIST} - MIN_TRACKS_PER_PLAYLIST=${MIN_TRACKS_PER_PLAYLIST} @@ -31,5 +31,5 @@ services: # Jellyfin playlists directory for playlist and art management - ${PLAYLIST_DIR_HOST}:/playlists ports: - - "${WEB_PORT}:5000" + - "${WEB_PORT}:${WEB_PORT}" restart: unless-stopped From e2aaa99c16f6ff13008cb15c5fe652b48ee6418d Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sat, 6 Sep 2025 20:53:56 -0700 Subject: [PATCH 13/25] remove export of forced LOG_LEVEL to respect user setting --- app/start.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/start.sh b/app/start.sh index 4f68f1c..f553553 100644 --- a/app/start.sh +++ b/app/start.sh @@ -13,9 +13,6 @@ if [ ! -d "/data/cover" ]; then cp -r /app/cover /data/ fi -# Set log level to DEBUG for comprehensive logging -export LOG_LEVEL=DEBUG - # Function to run playlist generator in background run_generator() { echo "🎯 Starting playlist generator background process..." @@ -32,8 +29,8 @@ if [ "$ENABLE_WEB_UI" = "true" ]; then run_generator # Start the web application with Gunicorn (with logging to stdout) - echo "🌐 Starting web UI on port 5000" - exec gunicorn --bind 0.0.0.0:5000 --workers 2 --timeout 120 --access-logfile - --error-logfile - webapp:app + echo "🌐 Starting web UI on port ${WEB_PORT}" + exec gunicorn --bind 0.0.0.0:${WEB_PORT} --workers 2 --timeout 120 --access-logfile - --error-logfile - webapp:app else echo "🎯 Web UI disabled - running playlist generator only" From 1c1afbcb1fbbe13ae7f505adf116150981cc6182 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sat, 6 Sep 2025 20:56:26 -0700 Subject: [PATCH 14/25] Use WEB_PORT internally, respect user set LOG_LEVEL, correct path of settings.json --- app/vibecodeplugin.py | 18 +++++++++--------- app/webapp.py | 27 +++++++++++++++------------ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/app/vibecodeplugin.py b/app/vibecodeplugin.py index 51fa276..3e12aa6 100644 --- a/app/vibecodeplugin.py +++ b/app/vibecodeplugin.py @@ -115,7 +115,7 @@ def __init__(self): def load_web_ui_settings(self): """Load settings from web UI JSON file - these take precedence over environment variables""" - config_file = '/app/config/settings.json' + config_file = '/data/config/settings.json' try: if Path(config_file).exists(): with open(config_file, 'r') as f: @@ -633,39 +633,39 @@ def setup_logging(config: Config): """Setup logging configuration with timestamps - ensure all logs visible in Docker""" # Ensure log directory exists log_dir = Path('/data/logs') + log_level_num = logging._nameToLevel[config.log_level] try: log_dir.mkdir(parents=True, exist_ok=True) print(f"πŸ“ Log directory created/verified: {log_dir}") except Exception as e: print(f"⚠️ Could not create log directory {log_dir}: {e}") - # Force DEBUG level for comprehensive logging - log_level = logging.DEBUG - print(f"πŸ”§ Forcing DEBUG level logging for comprehensive output") + # Set log level according to settings/default + print(f"πŸ”§ Log level is set to {config.log_level}") # Create formatters with timestamps formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # Configure root logger to catch ALL logging root_logger = logging.getLogger() - root_logger.setLevel(logging.DEBUG) + root_logger.setLevel(log_level_num) root_logger.handlers.clear() # Console handler for Docker logs console_handler = logging.StreamHandler(sys.stdout) - console_handler.setLevel(logging.DEBUG) + console_handler.setLevel(log_level_num) console_handler.setFormatter(formatter) root_logger.addHandler(console_handler) # Also setup specific jellyjams logger logger = logging.getLogger('jellyjams') - logger.setLevel(logging.DEBUG) + logger.setLevel(log_level_num) logger.propagate = True # Ensure it propagates to root logger # File handler (with error handling) try: file_handler = logging.FileHandler(log_dir / 'jellyjams.log') - file_handler.setLevel(logging.DEBUG) + file_handler.setLevel(log_level_num) file_handler.setFormatter(formatter) root_logger.addHandler(file_handler) print(f"πŸ“ File logging enabled: {log_dir / 'jellyjams.log'}") @@ -677,7 +677,7 @@ def setup_logging(config: Config): logging.getLogger('urllib3').setLevel(logging.WARNING) logging.getLogger('requests').setLevel(logging.WARNING) - print(f"πŸ”§ Comprehensive logging initialized at DEBUG level with timestamps") + print(f"πŸ”§ Logging initialized at {config.log_level} level with timestamps") print(f"πŸ“Š Root logger handlers: {len(root_logger.handlers)} ({[type(h).__name__ for h in root_logger.handlers]})") print(f"πŸ“Š JellyJams logger propagate: {logger.propagate}") diff --git a/app/webapp.py b/app/webapp.py index 8f33afc..d6c5497 100644 --- a/app/webapp.py +++ b/app/webapp.py @@ -23,10 +23,11 @@ # Global configuration config = Config() +log_level = logging._nameToLevel[config.log_level] -# Setup comprehensive logging for web UI +# Setup logging for web UI logging.basicConfig( - level=logging.DEBUG, + level=log_level, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S', handlers=[ @@ -40,8 +41,8 @@ logging.getLogger('requests').setLevel(logging.WARNING) logger = logging.getLogger('JellyJams.WebUI') -logger.setLevel(logging.DEBUG) -logger.info("🌐 JellyJams Web UI logging initialized") +logger.setLevel(log_level) +logger.info(f"🌐 JellyJams Web UI logging initialized (level = {config.log_level})") # Serve logo asset @app.route('/assets/logo.png') @@ -55,7 +56,7 @@ def logo(): class ConfigManager: def __init__(self): - self.config_file = '/app/config/settings.json' + self.config_file = '/data/config/settings.json' self.ensure_config_dir() def ensure_config_dir(self): @@ -264,7 +265,7 @@ def _update_config(self): else: # Fall back to web UI settings try: - config_file = '/app/config/settings.json' + config_file = '/data/config/settings.json' if Path(config_file).exists(): with open(config_file, 'r') as f: settings = json.load(f) @@ -574,8 +575,8 @@ def _redact(key, value): def save_web_ui_settings(new_settings): """Save settings to web UI settings file""" - config_file = '/app/config/settings.json' - config_dir = Path('/app/config') + config_file = '/data/config/settings.json' + config_dir = Path('/data/config') try: # Ensure config directory exists @@ -786,13 +787,14 @@ def api_cover_art(playlist_name): # Search order: folder.* first (what generator writes), then cover.* names = ['folder', 'cover'] - exts = ['.jpg', '.jpeg', '.png', '.webp', '.bmp'] + exts = ['.jpg', '.jpeg', '.png', '.webp', '.bmp', '.avif'] mimetypes = { '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.webp': 'image/webp', - '.bmp': 'image/bmp' + '.bmp': 'image/bmp', + '.avif': 'image/avif' } try: @@ -1422,7 +1424,7 @@ def get_detailed_playlist_info(): try: # Consider cover image if present as an additional hint for base in ['folder', 'cover']: - for ext in ['.png', '.jpg', '.jpeg']: + for ext in ['.png', '.jpg', '.jpeg', '.webp', '.avif']: cf = playlist_path / f"{base}{ext}" if cf.exists(): cfs = cf.stat() @@ -1601,4 +1603,5 @@ def get_jellyfin_metadata(jellyfin_api): return {'genres': [], 'years': [], 'artists': []} if __name__ == '__main__': - app.run(host='0.0.0.0', port=5000, debug=True) + WEB_PORT = int(os.getenv('WEB_PORT', '5000')) + app.run(host='0.0.0.0', port=WEB_PORT, debug=True) From 2795f54ead23c9e1018d5acfc2dea7d3a889248e Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sat, 6 Sep 2025 21:01:43 -0700 Subject: [PATCH 15/25] change log_level var to log_level_num for consistency --- app/webapp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/webapp.py b/app/webapp.py index d6c5497..43bb3aa 100644 --- a/app/webapp.py +++ b/app/webapp.py @@ -23,11 +23,11 @@ # Global configuration config = Config() -log_level = logging._nameToLevel[config.log_level] +log_level_num = logging._nameToLevel[config.log_level] # Setup logging for web UI logging.basicConfig( - level=log_level, + level=log_level_num, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S', handlers=[ @@ -41,7 +41,7 @@ logging.getLogger('requests').setLevel(logging.WARNING) logger = logging.getLogger('JellyJams.WebUI') -logger.setLevel(log_level) +logger.setLevel(log_level_num) logger.info(f"🌐 JellyJams Web UI logging initialized (level = {config.log_level})") # Serve logo asset From 1aa5dd7289dce29f7aa18314f28325391526288b Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sat, 6 Sep 2025 22:02:52 -0700 Subject: [PATCH 16/25] update: use WEB_PORT internally --- README.md | 2 +- SETTINGS.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0ea9aa2..7a798d1 100644 --- a/README.md +++ b/README.md @@ -234,7 +234,7 @@ services: # Jellyfin playlists directory for playlist and art management - ${PLAYLIST_DIR_HOST}:/playlists ports: - - "${WEB_PORT}:5000" + - "${WEB_PORT}:${WEB_PORT}" restart: unless-stopped ``` diff --git a/SETTINGS.md b/SETTINGS.md index d9f9d8b..dd35f86 100644 --- a/SETTINGS.md +++ b/SETTINGS.md @@ -32,7 +32,7 @@ JellyJams supports two configuration methods: Set in your `.env` file or Docker environment. These serve as defaults. ### 2. Web UI Settings -Override environment variables through the web interface at `http://localhost:5000/settings`. These settings are persistent and take precedence over environment variables. +Override environment variables through the web interface at `http://localhost:{WEB_PORT}/settings`. These settings are persistent and take precedence over environment variables. ## 🎯 Essential Settings @@ -465,7 +465,7 @@ MIN_TRACKS_PER_PLAYLIST=10 # .env file for advanced setup JELLYFIN_URL=https://jellyfin.example.com JELLYFIN_API_KEY=your_api_key_here -PLAYLIST_DIR_HOST=/path/to/jellyfin/config/data/data/playlists +PLAYLIST_DIR_HOST=/path/to/jellyfin/config/data/playlists MUSIC_DIR_HOST=/host/path/to/music MUSIC_DIR_CONTAINER=/jellyfin/container/path/to/music From d3cf15cb7e8b91c9115680cf6422685c18a0a868 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sat, 6 Sep 2025 22:03:31 -0700 Subject: [PATCH 17/25] add default values for essential vars --- docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7cadff3..c6e844a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,10 +4,10 @@ services: container_name: jellyjams environment: # Essential container settings (not configurable via web UI) - - JELLYFIN_URL=${JELLYFIN_URL} + - JELLYFIN_URL=${JELLYFIN_URL:-http://jellyfin:8096} - JELLYFIN_API_KEY=${JELLYFIN_API_KEY} - - ENABLE_WEB_UI=${ENABLE_WEB_UI} - - WEB_PORT=${WEB_PORT} + - ENABLE_WEB_UI=${ENABLE_WEB_UI:-true} + - WEB_PORT=${WEB_PORT:=5000} # Default fallback values (web UI settings will override these) - LOG_LEVEL=${LOG_LEVEL:=DEBUG} - GENERATION_INTERVAL=${GENERATION_INTERVAL} From 74621e75f39b36c0c811dac4ef78be95bf55f652 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sat, 6 Sep 2025 23:13:41 -0700 Subject: [PATCH 18/25] correct default port settings --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c6e844a..021302f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: - JELLYFIN_URL=${JELLYFIN_URL:-http://jellyfin:8096} - JELLYFIN_API_KEY=${JELLYFIN_API_KEY} - ENABLE_WEB_UI=${ENABLE_WEB_UI:-true} - - WEB_PORT=${WEB_PORT:=5000} + - WEB_PORT=${WEB_PORT:-5000} # Default fallback values (web UI settings will override these) - LOG_LEVEL=${LOG_LEVEL:=DEBUG} - GENERATION_INTERVAL=${GENERATION_INTERVAL} @@ -31,5 +31,5 @@ services: # Jellyfin playlists directory for playlist and art management - ${PLAYLIST_DIR_HOST}:/playlists ports: - - "${WEB_PORT}:${WEB_PORT}" + - "${WEB_PORT:-5000}:${WEB_PORT:-5000}" restart: unless-stopped From c0fadde5482f1945e62168b843aff9eb145ea334 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sun, 7 Sep 2025 00:33:43 -0700 Subject: [PATCH 19/25] fix playlist directory mismatch when artist name has special characters --- app/vibecodeplugin.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/app/vibecodeplugin.py b/app/vibecodeplugin.py index 3e12aa6..40ab000 100644 --- a/app/vibecodeplugin.py +++ b/app/vibecodeplugin.py @@ -1925,6 +1925,18 @@ def _sanitize_playlist_name(self, name: str) -> str: return sanitized + def _jellyfin_playlist_dir(self, playlist_name: str) -> str: + """ + Replace invalid filename characters with spaces as Jellyfin does so that + the playlist and corresponding image are saved in the same directory. + - Characters: \ / : * ? " < > | and ASCII control chars (0–31) + """ + invalid_chars = r'<>:"/\\|?*\x00-\x1F' + # Replace invalid chars with a space + sanitized = re.sub(f"[{invalid_chars}]", " ", playlist_name).strip() + self.logger.info(f"🧹 Sanitized playlist sub-directory: '{sanitized}'") + return sanitized.strip() + def save_playlist(self, playlist_type: str, name: str, tracks: List[Dict], user_id: str = None): """Save playlist using Jellyfin's REST API with proper privacy controls and custom cover art""" self.logger.info(f"=== STARTING PLAYLIST CREATION ===") @@ -1933,6 +1945,7 @@ def save_playlist(self, playlist_type: str, name: str, tracks: List[Dict], user_ # Sanitize the playlist name to prevent filesystem errors sanitized_name = self._sanitize_playlist_name(name) + playlist_subdir = self._jellyfin_playlist_dir(sanitized_name) self.logger.info(f"Sanitized Playlist Name: {sanitized_name}") self.logger.info(f"Track Count: {len(tracks)}") self.logger.info(f"User ID: {user_id}") @@ -1988,9 +2001,9 @@ def save_playlist(self, playlist_type: str, name: str, tracks: List[Dict], user_ if result['success']: self.logger.info(f"βœ… Successfully created {privacy_text} playlist '{sanitized_name}' with {result['track_count']} tracks") - # Create directory for cover art storage (use sanitized name for filesystem) + # Create directory for cover art storage (use Jellyfin-style sanitized name for filesystem) self.logger.debug(f"Creating directory with sanitized name: {sanitized_name}") - playlist_dir = Path(self.config.playlist_folder) / sanitized_name + playlist_dir = Path(self.config.playlist_folder) / playlist_subdir self.logger.debug(f"Full directory path: {playlist_dir}") try: From 0f26cd59ab2efd35f4d060e8e006447272b77d3b Mon Sep 17 00:00:00 2001 From: David Oleksy Date: Sun, 7 Sep 2025 14:26:48 -0700 Subject: [PATCH 20/25] correct default LOG_LEVEL --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 021302f..7039788 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ services: - ENABLE_WEB_UI=${ENABLE_WEB_UI:-true} - WEB_PORT=${WEB_PORT:-5000} # Default fallback values (web UI settings will override these) - - LOG_LEVEL=${LOG_LEVEL:=DEBUG} + - LOG_LEVEL=${LOG_LEVEL:-DEBUG} - GENERATION_INTERVAL=${GENERATION_INTERVAL} - MAX_TRACKS_PER_PLAYLIST=${MAX_TRACKS_PER_PLAYLIST} - MIN_TRACKS_PER_PLAYLIST=${MIN_TRACKS_PER_PLAYLIST} From 98eb9eef3d662756a689bcd0e7f33ae69aea2071 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sun, 7 Sep 2025 23:04:48 -0700 Subject: [PATCH 21/25] add comment about default values --- docker-compose.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 021302f..f2af431 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,10 @@ services: image: jonasmore/jellyjams:latest container_name: jellyjams environment: + # Default values are set here like ${VAR_NAME:-DEFAULT_VALUE} + # in case they aren't provided in the .env file. If you use the + # .env file, there is no need to change the default values. + # Essential container settings (not configurable via web UI) - JELLYFIN_URL=${JELLYFIN_URL:-http://jellyfin:8096} - JELLYFIN_API_KEY=${JELLYFIN_API_KEY} From 47434f26ea5f756dbc6cb4f614ca05ea5f17b7bb Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sun, 7 Sep 2025 23:06:20 -0700 Subject: [PATCH 22/25] increase timeout for gunicorn --- app/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/start.sh b/app/start.sh index f553553..e2f4471 100644 --- a/app/start.sh +++ b/app/start.sh @@ -30,7 +30,7 @@ if [ "$ENABLE_WEB_UI" = "true" ]; then # Start the web application with Gunicorn (with logging to stdout) echo "🌐 Starting web UI on port ${WEB_PORT}" - exec gunicorn --bind 0.0.0.0:${WEB_PORT} --workers 2 --timeout 120 --access-logfile - --error-logfile - webapp:app + exec gunicorn --bind 0.0.0.0:${WEB_PORT} --workers 2 --timeout 300 --access-logfile - --error-logfile - webapp:app else echo "🎯 Web UI disabled - running playlist generator only" From 591ca4d18e652495639cd26aed4697051fa93128 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sun, 7 Sep 2025 23:54:42 -0700 Subject: [PATCH 23/25] correct default LOG_LEVEL again --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index f2af431..54c5ff9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: - ENABLE_WEB_UI=${ENABLE_WEB_UI:-true} - WEB_PORT=${WEB_PORT:-5000} # Default fallback values (web UI settings will override these) - - LOG_LEVEL=${LOG_LEVEL:=DEBUG} + - LOG_LEVEL=${LOG_LEVEL:-DEBUG} - GENERATION_INTERVAL=${GENERATION_INTERVAL} - MAX_TRACKS_PER_PLAYLIST=${MAX_TRACKS_PER_PLAYLIST} - MIN_TRACKS_PER_PLAYLIST=${MIN_TRACKS_PER_PLAYLIST} From cc7257f87c071c91856077230ea767ffb0a0c2b9 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sun, 7 Sep 2025 23:56:14 -0700 Subject: [PATCH 24/25] support additional image extentions for remaining playlist types --- app/vibecodeplugin.py | 92 ++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 57 deletions(-) diff --git a/app/vibecodeplugin.py b/app/vibecodeplugin.py index 40ab000..c2e3f18 100644 --- a/app/vibecodeplugin.py +++ b/app/vibecodeplugin.py @@ -525,14 +525,16 @@ def get_artist_cover_art(self, artist_name: str, playlist_dir: Path) -> bool: import time start_time = time.time() self.stats['total_attempts'] += 1 + exts = ['.jpg', '.jpeg', '.png', '.webp', '.bmp', '.avif'] try: # Check if cover art already exists - cover_path = playlist_dir / 'cover.jpg' - if cover_path.exists(): - self.logger.debug(f"Cover art already exists for {artist_name}") - self.stats['successful_downloads'] += 1 - return True + for ext in exts: + cover_path = playlist_dir / f"cover{ext}" + if cover_path.exists(): + self.logger.debug(f"Cover art already exists for {artist_name}") + self.stats['successful_downloads'] += 1 + return True # Search for Spotify playlist playlist_info = self.search_artist_playlist(artist_name) @@ -1097,7 +1099,7 @@ def copy_custom_cover_art(self, playlist_name: str, playlist_dir: Path) -> bool: self.logger.warning(f"Could not list cover directory contents: {e}") # Look for cover image with playlist name (try common extensions) - extensions = ['.jpg', '.jpeg', '.png', '.webp', '.bmp'] + extensions = ['.jpg', '.jpeg', '.png', '.webp', '.avif', '.bmp'] source_image = None found_extension = None @@ -1198,24 +1200,19 @@ def _apply_decade_cover_art(self, playlist_name: str, playlist_dir: Path) -> boo return False # Look for decade-specific cover art files in multiple naming formats - decade_cover_files = [ - # Full playlist name format (e.g., "Back to the 1990s.jpg") - f"{playlist_name}.jpg", - f"{playlist_name}.jpeg", - f"{playlist_name}.png", - # Decade-only format (e.g., "1990s-cover.jpg") - f"{decade}-cover.jpg", - f"{decade}-cover.jpeg", - f"{decade}-cover.png" - ] + # playlist_name is like "Back to the 1990s.jpg" + # Decade-only format is like "1990s-cover.jpg" + names = [playlist_name, f"{decade}-cover"] + exts = ['.jpg', '.jpeg', '.png', '.webp', '.bmp', '.avif'] source_image = None - for cover_file in decade_cover_files: - potential_file = cover_source_dir / cover_file - if potential_file.exists() and potential_file.is_file(): - source_image = potential_file - self.logger.info(f"πŸ–ΌοΈ Found decade cover art: {source_image}") - break + for base in names: + for ext in exts: + candidate = cover_source_dir / f"{file}{ext}" + if candidate.exists() and candidate.is_file(): + source_image = candidate + self.logger.info(f"πŸ–ΌοΈ Found decade cover art: {source_image}") + break # If no specific decade cover found, try fallback for pre-1900s music if not source_image and decade.endswith('s'): @@ -1223,14 +1220,8 @@ def _apply_decade_cover_art(self, playlist_name: str, playlist_dir: Path) -> boo decade_year = int(decade[:-1]) # Remove 's' and convert to int if decade_year < 1900: self.logger.info(f"πŸ•°οΈ Decade {decade} is before 1900s, trying 1800s fallback...") - fallback_files = [ - "1800s-cover.jpg", - "1800s-cover.jpeg", - "1800s-cover.png" - ] - - for fallback_file in fallback_files: - potential_fallback = cover_source_dir / fallback_file + for ext in exts: + potential_fallback = cover_source_dir / f"1800s-cover{ext}" if potential_fallback.exists() and potential_fallback.is_file(): source_image = potential_fallback self.logger.info(f"πŸ–ΌοΈ Found 1800s fallback cover art: {source_image}") @@ -1279,22 +1270,16 @@ def _apply_genre_cover_art(self, playlist_name: str, genre_name: str, playlist_d return False # First, try to find predefined genre cover art - predefined_cover_files = [ - f"{genre_name} Radio.jpg", - f"{genre_name} Radio.jpeg", - f"{genre_name} Radio.png", - f"{genre_name}.jpg", - f"{genre_name}.jpeg", - f"{genre_name}.png" - ] - + names = [f"{genre_name} Radio", genre_name] + exts = ['.jpg', '.jpeg', '.png', '.webp', '.bmp', '.avif'] source_image = None - for cover_file in predefined_cover_files: - potential_file = cover_source_dir / cover_file - if potential_file.exists() and potential_file.is_file(): - source_image = potential_file - self.logger.info(f"πŸ–ΌοΈ Found predefined genre cover art: {source_image}") - break + for base in names: + for ext in exts: + potential_file = cover_source_dir / f"{base}{ext}" + if potential_file.exists() and potential_file.is_file(): + source_image = potential_file + self.logger.info(f"πŸ–ΌοΈ Found predefined genre cover art: {source_image}") + break # If predefined cover found, copy it directly if source_image: @@ -1319,27 +1304,20 @@ def _apply_genre_cover_art(self, playlist_name: str, genre_name: str, playlist_d # If no predefined cover found, generate one using "Fallback Radio.jpg" background self.logger.info(f"🎨 No predefined cover found, generating custom genre cover...") - # Look for "Fallback Radio.jpg" background template - background_files = [ - "Fallback Radio.jpg", - "Fallback Radio.jpeg", - "Fallback Radio.png" - ] - background_image = None - for bg_file in background_files: - potential_bg = cover_source_dir / bg_file + for ext in exts: + potential_bg = cover_source_dir / f"Fallback Radio{ext}" if potential_bg.exists() and potential_bg.is_file(): background_image = potential_bg self.logger.info(f"πŸ–ΌοΈ Found background template: {background_image}") break if not background_image: - self.logger.warning(f"❌ No 'Fallback Radio.jpg' background template found for genre cover generation") + self.logger.warning(f"❌ No 'Fallback Radio' background template found for genre cover generation") return False # Generate custom genre cover with text overlay - destination_image = playlist_dir / "cover.jpg" + destination_image = playlist_dir / "cover.webp" success = self._generate_genre_cover_art(background_image, genre_name, destination_image) if success: @@ -1559,7 +1537,7 @@ def _get_artist_path_from_jellyfin(self, artist_name: str) -> Path: return None def _find_cover_in_directory(self, directory_path: Path) -> Optional[bytes]: - pattern = re.compile(r"^(folder|cover|artist|thumb|front)\.(jpg|jpeg|png|webp|avif|gif|bmp)$", re.IGNORECASE) + pattern = re.compile(r"^(folder|cover|artist|thumb|front)\.(jpg|jpeg|png|webp|avif|bmp)$", re.IGNORECASE) for root, dirs, files in os.walk(directory_path): for fname in files: if pattern.match(fname): From af8952b5c8dceb44c9ef369b37e94346bfc8e474 Mon Sep 17 00:00:00 2001 From: drolex2 Date: Sun, 7 Sep 2025 23:57:57 -0700 Subject: [PATCH 25/25] reflect code updates --- README.md | 59 ++++++++++++++++++++++++++++++----------------------- SETTINGS.md | 40 +++++++++++++++++++++--------------- 2 files changed, 57 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 7a798d1..5ae31e8 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,12 @@ docker run -p 5000:5000 jonasmore/jellyjams - **Custom Generated Covers** - "This is [Artist]" text overlays on artist folder images - **Spotify Integration** - Automatic artist playlist cover downloads from Spotify - **Predefined Custom Covers** - Manual cover art for specific playlists -- **Smart Fallbacks** - Generic covers per playlist type ("Top Tracks - all.jpg") -- **Artist Folder Integration** - Uses existing folder.jpg from music directories +- **Smart Fallbacks** - Generic covers per playlist type ("Top Tracks - all.ext") +- **Multi-format Support** - Searches for images in multiple formats (JPG, JPEG, PNG, WebP, AVIF, BMP) +- **Artist Folder Integration** - Uses existing folder.ext from music directories - **Unicode Support** - Handles special characters in artist names (alt‐J, Sigur RΓ³s, etc.) -- **Extension Preservation** - Maintains original image formats (PNG, JPG) +- **Extension Preservation** - Maintains original image format when copying. +- **Generated Image Format** - Saves generated images as WebP for high quality and compression. ### 🌐 Modern Web Interface - **Beautiful Dark Theme** - Modern, responsive design @@ -108,21 +110,23 @@ WEBUI_BASIC_AUTH_PASSWORD=your_password - **Custom Generated Covers** - "This is [Artist]" text overlays on artist folder images - **Spotify Integration** - Automatic artist playlist cover downloads from Spotify - **Predefined Custom Covers** - Manual cover art for specific playlists -- **Smart Fallbacks** - Generic covers per playlist type ("Top Tracks - all.jpg") -- **Artist Folder Integration** - Uses existing folder.jpg from music directories +- **Smart Fallbacks** - Generic covers per playlist type ("Top Tracks - all.ext") +- **Multi-format Support** - Searches for images in multiple formats (JPG, JPEG, PNG, WebP, AVIF, BMP) +- **Artist Folder Integration** - Uses existing folder.ext from music directories - **Unicode Support** - Handles special characters in artist names (alt‐J, Sigur RΓ³s, etc.) -- **Extension Preservation** - Maintains original image formats (PNG, JPG) +- **Extension Preservation** - Maintains original image format when copying. +- **Generated Image Format** - Saves generated images as WebP for high quality and compression. ### 🎯 Cover Art Priority System 1. **Custom Generated Covers** (Artist playlists) 2. **Spotify Cover Art** (Artist playlists, if enabled) 3. **Predefined Custom Covers** (Manual covers) -4. **Artist Folder Fallback** (Uses existing folder.jpg) +4. **Artist Folder Fallback** (Uses existing folder.ext) 5. **Generic Fallbacks** (Type-specific defaults) #### πŸ–ΌοΈ Custom Generated Covers For artist playlists, JellyJams automatically generates professional "This is [Artist]" covers: -- Uses artist's existing folder.jpg as background +- Uses artist's existing folder.ext as background - Adds stylized text overlay with adaptive colors - Handles Unicode characters (alt‐J, Sigur RΓ³s, MΓΆtley CrΓΌe) - High-quality PNG output with text shadows @@ -130,17 +134,17 @@ For artist playlists, JellyJams automatically generates professional "This is [A #### πŸ“ Predefined Custom Covers Place custom images in your cover directory (mapped to `/app/cover`): -- Exact playlist name matching: `"Top Tracks - Jonas.jpg"` -- Generic fallbacks: `"Top Tracks - all.png"` -- Decade-specific covers: `"Back to the 1990s.jpg"` -- Genre-specific covers: `"Jazz Radio.jpg"` +- Exact playlist name matching: `"Top Tracks - Jonas.ext"` +- Generic fallbacks: `"Top Tracks - all.ext"` +- Decade-specific covers: `"Back to the 1990s.ext"` +- Genre-specific covers: `"Jazz Radio.ext"` #### 🎡 Artist Folder Integration JellyJams can use existing cover art from your music library: -- Searches for `folder.jpg`, `cover.jpg`, `artist.jpg` in artist directories -- Supports multiple music directory paths (`/app/music`, `/music`, `/media`, etc.) +- Searches for `folder.ext`, `cover.ext`, `artist.ext` in artist directories +- You set the music directory path (in .env) to the same path you set in Jellyfin - Case-insensitive artist folder matching -- Multiple image format support (JPG, PNG, WebP) +- Multiple image format support (JPG, PNG, WebP, AVIF, BMP) #### πŸ”„ Update Covers Feature Refresh cover art for existing playlists without regenerating: @@ -164,14 +168,14 @@ JellyJams automatically triggers a Jellyfin media library scan after playlist cr JellyJams creates playlists in the following format: ``` -πŸ“ Playlists/ -β”œβ”€β”€ Rock Radio/ +πŸ“/playlists/ +β”œβ”€β”€ πŸ“Rock Radio/ β”‚ └── playlist.xml -β”œβ”€β”€ Jazz Radio/ +β”œβ”€β”€ πŸ“Jazz Radio/ β”‚ └── playlist.xml -β”œβ”€β”€ Back to the 1970s/ +β”œβ”€β”€ πŸ“Back to the 1970s/ β”‚ └── playlist.xml -└── This is The Beatles!/ +└── πŸ“This is The Beatles!/ └── playlist.xml ``` @@ -206,13 +210,17 @@ services: image: jonasmore/jellyjams:latest container_name: jellyjams environment: + # Default values are set here like ${VAR_NAME:-DEFAULT_VALUE} + # in case they aren't provided in the .env file. If you use the + # .env file, there is no need to change the default values. + # Essential container settings (not configurable via web UI) - - JELLYFIN_URL=${JELLYFIN_URL} + - JELLYFIN_URL=${JELLYFIN_URL:-http://jellyfin:8096} - JELLYFIN_API_KEY=${JELLYFIN_API_KEY} - - ENABLE_WEB_UI=${ENABLE_WEB_UI} - - WEB_PORT=${WEB_PORT} + - ENABLE_WEB_UI=${ENABLE_WEB_UI:-true} + - WEB_PORT=${WEB_PORT:-5000} # Default fallback values (web UI settings will override these) - - LOG_LEVEL=${LOG_LEVEL} + - LOG_LEVEL=${LOG_LEVEL:-DEBUG} - GENERATION_INTERVAL=${GENERATION_INTERVAL} - MAX_TRACKS_PER_PLAYLIST=${MAX_TRACKS_PER_PLAYLIST} - MIN_TRACKS_PER_PLAYLIST=${MIN_TRACKS_PER_PLAYLIST} @@ -234,7 +242,7 @@ services: # Jellyfin playlists directory for playlist and art management - ${PLAYLIST_DIR_HOST}:/playlists ports: - - "${WEB_PORT}:${WEB_PORT}" + - "${WEB_PORT:-5000}:${WEB_PORT:-5000}" restart: unless-stopped ``` @@ -266,6 +274,7 @@ JellyJams uses the Jellyfin REST API to: - Handle semicolon-separated genre strings - Test connection status - Retrieve audio item details +- Retrieve the primary image of artists ## 🎨 Web UI Features diff --git a/SETTINGS.md b/SETTINGS.md index dd35f86..e1ccd98 100644 --- a/SETTINGS.md +++ b/SETTINGS.md @@ -174,13 +174,13 @@ DISCOVERY_MAX_SONGS_PER_ARTIST=3 ### Custom Cover Art JellyJams supports custom playlist covers with intelligent fallback: -1. **Exact Match**: `"Top Tracks - Jonas.jpg"` -2. **Generic Fallback**: `"Top Tracks - all.png"` +1. **Exact Match**: `"Top Tracks - Jonas.ext"` +2. **Generic Fallback**: `"Top Tracks - all.ext"` 3. **Spotify Fallback**: For artist playlists -**Supported Formats**: `.jpg`, `.jpeg`, `.png`, `.webp`, `.bmp` +**Supported Formats**: `.jpg`, `.jpeg`, `.png`, `.webp`, `.avif`, `.bmp` -**Docker Volume**: Map your cover directory to `/app/cover` +**Docker Volume**: Put your 'cover' directory in the directory that you map to `/data` #### Other Playlist Types 1. **Predefined Custom Covers** - Exact name matching @@ -193,17 +193,15 @@ For artist playlists, JellyJams automatically generates professional covers: | Feature | Description | |---------|-------------| -| **Source Image** | Uses artist's `folder.jpg` from music directory | +| **Source Image** | Uses artist's `folder.ext` from music directory | | **Text Overlay** | "This is [Artist]" with adaptive colors | | **Unicode Support** | Handles special characters (alt‐J, Sigur RΓ³s, MΓΆtley CrΓΌe) | -| **Quality** | High-resolution PNG/JPG | +| **Quality** | High-resolution Webp | | **Color Analysis** | Automatic brightness detection for optimal contrast | -#### Supported Cover Files -- `folder.jpg`, `folder.jpeg`, `folder.png` -- `cover.jpg`, `cover.jpeg`, `cover.png` -- `artist.jpg`, `artist.jpeg`, `artist.png` -- `thumb.jpg`, `thumb.jpeg`, `thumb.png` +#### Supported Cover File Base Names and Extension +- `folder`, `cover`, `artist`, `thumb`, `front` +- `.jpg`, `.jpeg`, `.png`, `.webp`, `.avif`, `.bmp` ### πŸ“ Predefined Custom Covers @@ -259,10 +257,16 @@ Refresh cover art for existing playlists without regenerating playlists: ### πŸ› οΈ Cover Art Troubleshooting #### Custom Generated Covers Not Working -**Symptoms**: Artist playlists have no cover art or fallback to generic covers +**Symptoms**: Artist playlists have no cover art or fallback to album or generic covers **Solutions**: +1. **Check Artist Primary Image**: + - JellyJams tries to fetch the artist's primary image using the Jellyfin API first. + - Does the artist have a primary image set in Jellyfin? + - Music directory access is not required for this method. + 1. **Check Music Directory Access**: + - If getting the primary image from the API fails, the next step is searching the artist's directory. ```bash # Verify Docker volume mount includes music directory docker-compose logs jellyjams | grep "music directory" @@ -275,6 +279,7 @@ Refresh cover art for existing playlists without regenerating playlists: β”‚ β”œβ”€β”€ folder.jpg # βœ… This works β”‚ β”œβ”€β”€ cover.png # βœ… This works β”‚ └── Album/ + β”‚ └── cover.webp # βœ… Album image used as fallback └── Another Artist/ └── artist.jpeg # βœ… This works ``` @@ -295,6 +300,7 @@ Refresh cover art for existing playlists without regenerating playlists: **Solutions**: 1. **Verify Docker Volume Mount**: + - Put your 'cover' directory in your 'appdata' directory. ```yaml volumes: - /host/path/appdata:/data # Must be mounted @@ -303,7 +309,7 @@ Refresh cover art for existing playlists without regenerating playlists: 2. **Check File Permissions**: ```bash # Ensure container can read cover files - ls -la /host/path/appdata/covers/ + ls -la /host/path/appdata/cover/ ``` 3. **Verify Exact Naming**: @@ -312,7 +318,7 @@ Refresh cover art for existing playlists without regenerating playlists: - Include file extensions 4. **Supported Formats**: - - `.jpg`, `.jpeg`, `.png`, `.webp`, `.bmp` + - `.jpg`, `.jpeg`, `.png`, `.webp`, `.avif`, `.bmp` - Other formats may not be recognized #### Spotify Integration Issues @@ -407,7 +413,7 @@ The web UI settings page (`/settings`) provides: - **User Management** - Select users for personalized playlists - **Spotify Integration** - Test Spotify API and view statistics - **Live Validation** - Real-time setting validation -- **Persistent Storage** - Settings saved to `/app/config/settings.json` +- **Persistent Storage** - Settings saved to `/data/config/settings.json` ### Settings Priority 1. **Web UI Settings** (highest priority) @@ -419,7 +425,7 @@ The web UI settings page (`/settings`) provides: ### Required Volumes ```yaml volumes: - # JellyJames app data (config, logs, cover art) + # JellyJames app data (config, logs, cover) - /host/path/appdata:/data # Jellyfin playlists directory for playlist and art management - ${PLAYLIST_DIR_HOST}:/playlists @@ -454,7 +460,7 @@ MUSIC_DIR_CONTAINER=/mnt/user/media/data/music # .env file for basic setup JELLYFIN_URL=http://localhost:8096 JELLYFIN_API_KEY=your_api_key_here -PLAYLIST_DIR_HOST=/path/to/jellyfin/config/data/data/playlists +PLAYLIST_DIR_HOST=/path/to/jellyfin/config/data/playlists PLAYLIST_TYPES=Genre,Year,Artist MAX_TRACKS_PER_PLAYLIST=50 MIN_TRACKS_PER_PLAYLIST=10