├── .github └── FUNDING.yml ├── LICENSE ├── README.md ├── amd64.dockerfile ├── arm64v8.dockerfile ├── hooks ├── post_push └── pre_build ├── multi-arch-manifest.yaml └── root ├── etc ├── cont-init.d │ └── 98-script-setup.bash └── services.d │ ├── extended_autoconfig │ └── run │ ├── extended_extras │ └── run │ ├── extended_invalidseriescleaner │ └── run │ ├── extended_queuecleaner │ └── run │ ├── extended_recyclarr │ └── run │ └── extended_youtube │ └── run ├── language-not-original-or-english.json ├── naming.json ├── recyclarr-custom.yaml ├── recyclarr.yaml ├── scripts ├── AutoConfig.bash ├── AutoExtras.bash ├── DailySeriesEpisodeTrimmer.bash ├── Extras.bash ├── InvalidSeriesAutoCleaner.bash ├── PlexNotify.bash ├── Recyclarr.bash ├── SMA.bash └── Youtube-Series-Downloader.bash └── sma.ini /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [RandomNinjaAtk] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecated 2 | 3 | This repository is now deprecated, will no longer be updated and is being archived. 4 | 5 | Scripts/Project has moved to: https://github.com/RandomNinjaAtk/arr-scripts 6 | 7 | # [RandomNinjaAtk/sonarr-extended](https://github.com/RandomNinjaAtk/docker-sonarr-extended) 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | ### What is Sonarr Extended: 20 | 21 | * Linuxserver.io Sonarr docker container (develop tag) 22 | * Additional packages and scripts added to the container to provide additional functionality 23 | 24 | Sonarr itself is not modified in any way, all changes that are pushed to Sonarr via public Sonarr API's. This is strictly Sonarr Develop branch 25 | 26 | For more details, visit the [Wiki](https://github.com/RandomNinjaAtk/docker-sonarr-extended/wiki) 27 | 28 | This containers base image is provided by: [linuxserver/sonarr](https://github.com/linuxserver/docker-sonarr) 29 | 30 | ### All Arr-Extended Apps: 31 | * [sabnzbd-extended](https://github.com/RandomNinjaAtk/docker-sabnzbd-extended) 32 | * [lidarr-extended](https://github.com/RandomNinjaAtk/docker-lidarr-extended) 33 | * [radarr-extended](https://github.com/RandomNinjaAtk/docker-radarr-extended) 34 | * [sonarr-extended](https://github.com/RandomNinjaAtk/docker-sonarr-extended) 35 | * [readarr-extended](https://github.com/RandomNinjaAtk/docker-readarr-extended) 36 | 37 | ## Features 38 | * [Downloading TV **Trailers** and **Extras** using online sources for use in popular applications (Plex):](https://github.com/RandomNinjaAtk/docker-sonarr-extended/wiki/Extras.bash) 39 | * Connects to Sonarr to automatically download trailers for TV Series in your existing library 40 | * Downloads videos using yt-dlp automatically 41 | * Names videos correctly to match Plex naming convention 42 | * [Auto Configure Sonarr with optimized settings](https://github.com/RandomNinjaAtk/docker-sonarr-extended/wiki/AutoConfig.bash) 43 | * Optimized file/folder naming (based on trash guides) 44 | * Configures media management settings 45 | * Configures metadata settings 46 | * [Daily Series Episode Trimmer](https://github.com/RandomNinjaAtk/docker-sonarr-extended/wiki/DailySeriesEpisodeTrimmer.bash) 47 | * Keep only the latest 14 episodes of a daily series 48 | * [Recyclarr built-in](https://github.com/RandomNinjaAtk/docker-sonarr-extended/wiki/Recyclarr.bash) 49 | * Auto configures Release Profiles + Scores 50 | * Auto configures optimzed quality definitions 51 | * [Plex Notify Script](https://github.com/RandomNinjaAtk/docker-sonarr-extended/wiki/PlexNotify.bash) 52 | * Reduce Plex scanning by notifying Plex the exact folder to scan 53 | * [Queue Cleaner Script](https://github.com/RandomNinjaAtk/docker-sonarr-extended/wiki/QueueCleaner.bash) 54 | * Automatically removes downloads that have a "warning" or "failed" status that will not auto-import into Sonarr, which enables Sonarr to automatically re-search for the Title 55 | * [Youtube Series Downloader Script](https://github.com/RandomNinjaAtk/docker-sonarr-extended/wiki/Youtube-Series-Downloader.bash) 56 | * Automatically downloads and imports episodes from Youtube.com for Sonarr series that have their network set as "Youtube" 57 | 58 | ### Plex Example 59 | ![](https://raw.githubusercontent.com/RandomNinjaAtk/docker-amtd/master/.github/amvtd-plex-example.jpg) 60 | 61 | ## Supported Architectures 62 | 63 | The architectures supported by this image are: 64 | 65 | | Architecture | Available | Tag | 66 | | :----: | :----: | ---- | 67 | | multi | ✅ | latest | 68 | | x86-64 | ✅ | amd64 | 69 | | arm64v8 | ✅ | arm64v8 | 70 | 71 | ## Version Tags 72 | 73 | | Tag | Description | 74 | | :----: | --- | 75 | | latest | Sonarr Develop + Extended Scripts| 76 | 77 | ## Parameters 78 | 79 | Container images are configured using parameters passed at runtime (such as those above). These parameters are separated by a colon and indicate `:` respectively. For example, `-p 8080:80` would expose port `80` from inside the container to be accessible from the host's IP on port `8080` outside the container. 80 | 81 | | Parameter | Function | 82 | | :----: | --- | 83 | | `-p 8989` | The port for the Sonarr webinterface | 84 | | `-v /config` | Database and sonarr configs | 85 | | `-v /storage` | Location of TV and Downloads Library | 86 | | `-e enableAutoConfig=true` | true = enabled :: Enables AutoConfig script to run after startup | 87 | | `-e enableRecyclarr=true` | true = enabled :: Enables Recyclarr to run every 4 hours | 88 | | `-e enableQueueCleaner=true` | true = enabled :: Enables QueueCleaner Script that automatically removes stuck downloads that cannot be automatically imported on a 15 minute interval | 89 | | `-e enableYoutubeSeriesDownloader=true` | true = enabled :: Enables Youtube-Series-Downloadder script to run every hour | 90 | | `-e enableExtras=true` | true = enabled :: Enables Extras script to run during download import process | 91 | | `-e extrasType=all` | all or trailers :: all downloads all available videos (trailers, clips, featurette, etc...) :: trailers only downloads trailers | 92 | | `-e extrasLanguages=en-US,it-IT` | Set the desired language for Extras, all languages will be processed... (this is a "," separated list of TMDB language codes, get the code from there sites language opitons, example: en-US) | 93 | | `-e extrasOfficialOnly=false` | true = enabled :: Skips extras that are not considered/marked as Official from TMDB site. | 94 | | `-e plexUrl=http://x.x.x.x:32400` | ONLY used if PlexNotify.bash is used... | 95 | | `-e plexToken=Token_Goes_Here` | ONLY used if PlexNotify.bash is used... | 96 | | `-e videoFormat="bestvideo*+bestaudio/best"` | OPTIONAL - yt-dlp video selection paramater, do not change unless you know what your doing.... | 97 | | `-e maximumDailyEpisodes=14` | OPTIONAL - Adjust the maximum number of daily series episodes to keep when using the Daily Episode Trimmer Script... | 98 | | `-e PUID=1000` | for UserID - see below for explanation | 99 | | `-e PGID=1000` | for GroupID - see below for explanation | 100 | | `-e TZ=Europe/London` | Specify a timezone to use EG Europe/London, this is required for Sonarr | 101 | | `-e UMASK_SET=022` | control permissions of files and directories created by Sonarr | 102 | 103 | ## Application Setup 104 | 105 | Access the webui at `:8989`, for more information check out [Sonarr](https://sonarr.tv/). 106 | 107 | ## Docker Examples: 108 | These examples are untested, but should work or at least give you a good starting point.... 109 | 110 | ### docker 111 | 112 | ``` 113 | docker create \ 114 | --name=sonarr-extended \ 115 | -v /path/to/config/files:/config \ 116 | -p 8989:8989 \ 117 | -e TZ=America/New_York \ 118 | -e PUID=1000 \ 119 | -e PGID=1000 \ 120 | -e enableAutoConfig=true \ 121 | -e enableRecyclarr=true \ 122 | -e enableQueueCleaner=true \ 123 | -e enableYoutubeSeriesDownloader=true \ 124 | -e enableExtras=true \ 125 | -e extrasType=all \ 126 | -e extrasLanguages=en-US,it-IT \ 127 | -e extrasOfficialOnly=false \ 128 | -e plexUrl=http://x.x.x.x:32400 \ 129 | -e plexToken=Token_Goes_Here \ 130 | randomninjaatk/sonarr-extended:latest 131 | ``` 132 | 133 | 134 | ### docker-compose 135 | 136 | Compatible with docker-compose v2 schemas. 137 | 138 | ``` 139 | version: "2.1" 140 | services: 141 | sonarr-extended: 142 | image: randomninjaatk/sonarr-extended:latest 143 | container_name: sonarr-extended 144 | volumes: 145 | - /path/to/config/files:/config 146 | environment: 147 | - TZ=America/New_York 148 | - PUID=1000 149 | - PGID=1000 150 | - enableAutoConfig=true 151 | - enableRecyclarr=true 152 | - enableQueueCleaner=true 153 | - enableYoutubeSeriesDownloader=true 154 | - enableExtras=true 155 | - extrasType=all 156 | - extrasLanguages=en-US,it-IT 157 | - extrasOfficialOnly=false 158 | - plexUrl=http://x.x.x.x:32400 159 | - plexToken=Token_Goes_Here 160 | ports: 161 | - 8989:8989 162 | restart: unless-stopped 163 | ``` 164 | 165 | # Credits 166 | - [ffmpeg](https://ffmpeg.org/) 167 | - [yt-dlp](https://github.com/yt-dlp/yt-dlp) 168 | - [linuxserver/sonarr](https://github.com/linuxserver/docker-sonarr) Base docker image 169 | - [Sonarr](https://sonarr.tv/) 170 | - [The Movie Database](https://www.themoviedb.org/) 171 | - [Recyclarr](https://github.com/recyclarr/recyclarr) 172 | - Icons made by Freepik from www.flaticon.com 173 | -------------------------------------------------------------------------------- /amd64.dockerfile: -------------------------------------------------------------------------------- 1 | FROM linuxserver/sonarr:develop 2 | LABEL maintainer="RandomNinjaAtk" 3 | 4 | ENV SMA_PATH /usr/local/sma 5 | ENV UPDATE_SMA FALSE 6 | ENV SMA_APP Sonarr 7 | ENV videoFormat="bestvideo*+bestaudio/best" 8 | ENV maximumDailyEpisodes=7 9 | 10 | RUN \ 11 | echo "************ install packages ************" && \ 12 | apk add -U --update --no-cache \ 13 | flac \ 14 | opus-tools \ 15 | jq \ 16 | git \ 17 | wget \ 18 | mkvtoolnix \ 19 | python3-dev \ 20 | libc-dev \ 21 | py3-pip \ 22 | gcc \ 23 | ffmpeg \ 24 | yt-dlp && \ 25 | echo "************ install python packages ************" && \ 26 | pip install --upgrade --no-cache-dir -U \ 27 | excludarr \ 28 | yq && \ 29 | echo "************ setup SMA ************" && \ 30 | echo "************ setup directory ************" && \ 31 | mkdir -p ${SMA_PATH} && \ 32 | echo "************ download repo ************" && \ 33 | git clone https://github.com/mdhiggins/sickbeard_mp4_automator.git ${SMA_PATH} && \ 34 | mkdir -p ${SMA_PATH}/config && \ 35 | echo "************ create logging file ************" && \ 36 | mkdir -p ${SMA_PATH}/config && \ 37 | touch ${SMA_PATH}/config/sma.log && \ 38 | chgrp users ${SMA_PATH}/config/sma.log && \ 39 | chmod g+w ${SMA_PATH}/config/sma.log && \ 40 | echo "************ install pip dependencies ************" && \ 41 | python3 -m pip install --user --upgrade pip && \ 42 | pip3 install -r ${SMA_PATH}/setup/requirements.txt && \ 43 | echo "************ install recyclarr ************" && \ 44 | mkdir -p /recyclarr && \ 45 | wget "https://github.com/recyclarr/recyclarr/releases/latest/download/recyclarr-linux-musl-x64.tar.xz" -O "/recyclarr/recyclarr.tar.xz" && \ 46 | tar -xf /recyclarr/recyclarr.tar.xz -C /recyclarr &>/dev/null && \ 47 | chmod 777 /recyclarr/recyclarr 48 | 49 | # .NET Runtime version 50 | ENV DOTNET_VERSION=7.0.0 51 | 52 | # Install .NET Runtime 53 | RUN wget -O dotnet.tar.gz https://dotnetcli.azureedge.net/dotnet/Runtime/$DOTNET_VERSION/dotnet-runtime-$DOTNET_VERSION-linux-musl-x64.tar.gz \ 54 | && dotnet_sha512='f37774eee98f38d9849c79d05c58b0d9e733d480b31a0615a1039613662579efef392d0129b2582281861c0647bacdb3acd78213bd33869b698e529b8e78ccee' \ 55 | && echo "$dotnet_sha512 dotnet.tar.gz" | sha512sum -c - \ 56 | && mkdir -p /usr/share/dotnet \ 57 | && tar -oxzf dotnet.tar.gz -C /usr/share/dotnet \ 58 | && rm dotnet.tar.gz \ 59 | && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet 60 | 61 | WORKDIR /config 62 | 63 | # copy local files 64 | COPY root/ / 65 | 66 | # ports and volumes 67 | EXPOSE 8989 68 | VOLUME /config 69 | -------------------------------------------------------------------------------- /arm64v8.dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine AS builder 2 | 3 | # Download QEMU, see https://github.com/docker/hub-feedback/issues/1261 4 | ENV QEMU_URL https://github.com/balena-io/qemu/releases/download/v3.0.0%2Bresin/qemu-3.0.0+resin-aarch64.tar.gz 5 | RUN apk add curl && curl -L ${QEMU_URL} | tar zxvf - -C . --strip-components 1 6 | 7 | FROM linuxserver/sonarr:arm64v8-develop 8 | 9 | # Add QEMU 10 | COPY --from=builder qemu-aarch64-static /usr/bin 11 | 12 | LABEL maintainer="RandomNinjaAtk" 13 | 14 | ENV SMA_PATH /usr/local/sma 15 | ENV UPDATE_SMA FALSE 16 | ENV SMA_APP Sonarr 17 | ENV videoFormat="bestvideo*+bestaudio/best" 18 | 19 | RUN \ 20 | echo "************ install packages ************" && \ 21 | apk add -U --update --no-cache \ 22 | flac \ 23 | opus-tools \ 24 | jq \ 25 | git \ 26 | wget \ 27 | mkvtoolnix \ 28 | python3 \ 29 | py3-pip \ 30 | yt-dlp \ 31 | ffmpeg && \ 32 | echo "************ install python packages ************" && \ 33 | python3 -m pip install --no-cache-dir -U \ 34 | excludarr \ 35 | yq && \ 36 | echo "************ setup SMA ************" && \ 37 | echo "************ setup directory ************" && \ 38 | mkdir -p ${SMA_PATH} && \ 39 | echo "************ download repo ************" && \ 40 | git clone https://github.com/mdhiggins/sickbeard_mp4_automator.git ${SMA_PATH} && \ 41 | mkdir -p ${SMA_PATH}/config && \ 42 | echo "************ create logging file ************" && \ 43 | mkdir -p ${SMA_PATH}/config && \ 44 | touch ${SMA_PATH}/config/sma.log && \ 45 | chgrp users ${SMA_PATH}/config/sma.log && \ 46 | chmod g+w ${SMA_PATH}/config/sma.log && \ 47 | echo "************ install pip dependencies ************" && \ 48 | python3 -m pip install --user --upgrade pip && \ 49 | pip3 install -r ${SMA_PATH}/setup/requirements.txt && \ 50 | echo "************ install recyclarr ************" && \ 51 | mkdir -p /recyclarr && \ 52 | wget "https://github.com/recyclarr/recyclarr/releases/latest/download/recyclarr-linux-musl-arm64.tar.xz" -O "/recyclarr/recyclarr.tar.xz" && \ 53 | tar -xf /recyclarr/recyclarr.tar.xz -C /recyclarr &>/dev/null && \ 54 | chmod 777 /recyclarr/recyclarr 55 | 56 | # .NET Runtime version 57 | ENV DOTNET_VERSION=7.0.0 58 | 59 | # Install .NET Runtime 60 | RUN wget -O dotnet.tar.gz https://dotnetcli.azureedge.net/dotnet/Runtime/$DOTNET_VERSION/dotnet-runtime-$DOTNET_VERSION-linux-musl-arm64.tar.gz \ 61 | && dotnet_sha512='8e51878ff716d56366c52af7ff92375d3df796ceb56a74ff88fce6c3461003ed05be1ed6504c0d7d217afdce1097895c8df508d4c64d7fae537ff53482c3f8ca' \ 62 | && echo "$dotnet_sha512 dotnet.tar.gz" | sha512sum -c - \ 63 | && mkdir -p /usr/share/dotnet \ 64 | && tar -oxzf dotnet.tar.gz -C /usr/share/dotnet \ 65 | && rm dotnet.tar.gz \ 66 | && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet 67 | 68 | WORKDIR /config 69 | 70 | # copy local files 71 | COPY root/ / 72 | 73 | # ports and volumes 74 | EXPOSE 8989 75 | VOLUME /config 76 | -------------------------------------------------------------------------------- /hooks/post_push: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Use manifest-tool to create the manifest, given the experimental 4 | # "docker manifest" command isn't available yet on Docker Hub. 5 | 6 | curl -Lo manifest-tool https://github.com/estesp/manifest-tool/releases/download/v0.9.0/manifest-tool-linux-amd64 7 | chmod +x manifest-tool 8 | 9 | ./manifest-tool push from-spec multi-arch-manifest.yaml 10 | -------------------------------------------------------------------------------- /hooks/pre_build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Register qemu-*-static for all supported processors except the 4 | # current one, but also remove all registered binfmt_misc before 5 | docker run --rm --privileged multiarch/qemu-user-static:register --reset 6 | -------------------------------------------------------------------------------- /multi-arch-manifest.yaml: -------------------------------------------------------------------------------- 1 | image: randomninjaatk/sonarr-extended:latest 2 | manifests: 3 | - image: randomninjaatk/sonarr-extended:amd64 4 | platform: 5 | architecture: amd64 6 | os: linux 7 | - image: randomninjaatk/sonarr-extended:arm64v8 8 | platform: 9 | architecture: arm64 10 | os: linux 11 | variant: v8 12 | -------------------------------------------------------------------------------- /root/etc/cont-init.d/98-script-setup.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | # create extended directory if missing 4 | if [ ! -d "/config/extended" ]; then 5 | mkdir -p "/config/extended" 6 | fi 7 | 8 | # create scripts directory if missing 9 | if [ ! -d "/config/extended/scripts" ]; then 10 | mkdir -p "/config/extended/scripts" 11 | else 12 | echo "Removing previous scripts..." 13 | rm -rf /config/extended/scripts/* 14 | fi 15 | 16 | if [ -d "/config/extended/scripts" ]; then 17 | echo "Importing extended scripts..." 18 | cp -r /scripts/* /config/extended/scripts/ 19 | fi 20 | 21 | # create cache directory if missing 22 | if [ ! -d "/config/extended/cache" ]; then 23 | mkdir -p "/config/extended/cache" 24 | fi 25 | 26 | # create logs directory if missing 27 | if [ ! -d "/config/extended/logs" ]; then 28 | mkdir -p "/config/extended/logs" 29 | fi 30 | 31 | # create configs directory if missing 32 | if [ ! -d "/config/extended/configs" ]; then 33 | mkdir -p "/config/extended/configs" 34 | fi 35 | 36 | if [ ! -f "/config/extended/configs/sma.ini" ]; then 37 | cp /sma.ini "/config/extended/configs/sma.ini" 38 | fi 39 | 40 | echo "Setting up scripts..." 41 | if [ -f "/config/extended/scripts/QueueCleaner.bash" ]; then 42 | echo "Removing old script, QueueCleaner.bash" 43 | rm "/config/extended/scripts/QueueCleaner.bash" 44 | fi 45 | echo "Downloading and setting up QueueCleaner.bash" 46 | curl "https://raw.githubusercontent.com/RandomNinjaAtk/arr-scripts/main/QueueCleaner.bash" -o "/config/extended/scripts/QueueCleaner.bash" 47 | chmod 777 "/config/extended/scripts/QueueCleaner.bash" 48 | 49 | # set permissions 50 | chmod 777 -R /usr/local/sma 51 | find /config/extended -type d -exec chmod 777 {} \; 52 | find /config/extended -type f -exec chmod 666 {} \; 53 | chmod -R 777 /config/extended/scripts 54 | echo "Complete..." 55 | exit 56 | -------------------------------------------------------------------------------- /root/etc/services.d/extended_autoconfig/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | if [ "$enableAutoConfig" != "true" ]; then 3 | echo "AutoConfig Script disabled, enable by setting parameter: enableAutoConfig=true" 4 | sleep infinity 5 | else 6 | echo "Waiting for Sonarr to startup..." 7 | sleep 2m 8 | fi 9 | 10 | echo "Starting AutoConfig.bash Script...." 11 | bash /config/extended/scripts/AutoConfig.bash 12 | sleep infinity 13 | exit $? 14 | -------------------------------------------------------------------------------- /root/etc/services.d/extended_extras/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | if [ "$enableExtras" != "true" ]; then 3 | echo "Extras disabled, enable by setting parameter: enableExtras=true" 4 | sleep infinity 5 | else 6 | echo "Waiting for Sonarr to startup..." 7 | sleep 2m 8 | fi 9 | 10 | echo "Starting Script...." 11 | for (( ; ; )); do 12 | let i++ 13 | bash /config/extended/scripts/AutoExtras.bash 14 | echo "Script sleeping for 24 hours..." 15 | sleep 24h 16 | done 17 | 18 | 19 | exit $? 20 | -------------------------------------------------------------------------------- /root/etc/services.d/extended_invalidseriescleaner/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | if [ "$enableInvalidSeriesAutoCleaner" != "true" ]; then 3 | sleep infinity 4 | else 5 | echo "Waiting for Sonarr to startup..." 6 | sleep 20m 7 | fi 8 | 9 | echo "Starting Script...." 10 | for (( ; ; )); do 11 | let i++ 12 | bash /config/extended/scripts/InvalidSeriesAutoCleaner.bash 13 | echo "Script sleeping for 12 hours..." 14 | sleep 12h 15 | done 16 | 17 | exit $? 18 | -------------------------------------------------------------------------------- /root/etc/services.d/extended_queuecleaner/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | if [ "$enableQueueCleaner" != "true" ]; then 3 | echo "QueueCleaner.bash Script disabled, enable by setting parameter: enableQueueCleaner=true" 4 | sleep infinity 5 | else 6 | su abc -s "/config/extended/scripts/QueueCleaner.bash" 7 | fi 8 | exit 9 | -------------------------------------------------------------------------------- /root/etc/services.d/extended_recyclarr/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | if [ "$enableRecyclarr" != "true" ]; then 3 | echo "Recyclarr disabled, enable by setting parameter: enableRecyclarr=true" 4 | sleep infinity 5 | else 6 | echo "Waiting for Radarr to startup..." 7 | sleep 2m 8 | fi 9 | 10 | echo "Starting Script...." 11 | for (( ; ; )); do 12 | let i++ 13 | bash /config/extended/scripts/Recyclarr.bash 14 | echo "Script sleeping for 4 hours..." 15 | sleep 4h 16 | done 17 | 18 | 19 | exit $? 20 | -------------------------------------------------------------------------------- /root/etc/services.d/extended_youtube/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | if [ "$enableYoutubeSeriesDownloader" != "true" ]; then 3 | echo "Youtube-Series-Downloader disabled, enable by setting parameter: enableYoutubeSeriesDownloader=true" 4 | sleep infinity 5 | else 6 | echo "Waiting for Sonarr to startup..." 7 | sleep 2m 8 | fi 9 | 10 | echo "Starting Script...." 11 | for (( ; ; )); do 12 | let i++ 13 | bash /config/extended/scripts/Youtube-Series-Downloader.bash 14 | echo "Script sleeping for 1 hours..." 15 | sleep 1h 16 | done 17 | 18 | exit $? 19 | -------------------------------------------------------------------------------- /root/language-not-original-or-english.json: -------------------------------------------------------------------------------- 1 | { 2 | "trash_id": "guide-only", 3 | "trash_score": "-10000", 4 | "trash_description": "Language: Prefer X but i'll take Y", 5 | "name": "Language: Not Original or English", 6 | "includeCustomFormatWhenRenaming": false, 7 | "specifications": [ 8 | { 9 | "name": "Not Original", 10 | "implementation": "LanguageSpecification", 11 | "negate": true, 12 | "required": true, 13 | "fields": { 14 | "value": -2 15 | } 16 | }, 17 | { 18 | "name": "Not English", 19 | "implementation": "LanguageSpecification", 20 | "negate": true, 21 | "required": true, 22 | "fields": { 23 | "value": 1 24 | } 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /root/naming.json: -------------------------------------------------------------------------------- 1 | { 2 | "season": { 3 | "default": "Season {season:00}" 4 | }, 5 | "series": { 6 | "default": "{Series TitleYear}", 7 | "plex": "{Series TitleYear} {imdb-{ImdbId}}", 8 | "emby": "{Series TitleYear} [tvdbid-{TvdbId}]", 9 | "jellyfin": "{Series TitleYear} [tvdbid-{TvdbId}]" 10 | }, 11 | "episodes": { 12 | "standard": { 13 | "default:3": "{Series TitleYear} - S{season:00}E{episode:00} - {Episode CleanTitle} [{Preferred Words }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{[MediaInfo VideoCodec]}{-Release Group}", 14 | "default:4": "{Series TitleYear} - S{season:00}E{episode:00} - {Episode CleanTitle} [{Custom Formats }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{MediaInfo AudioLanguagesAll}[{MediaInfo VideoBitDepth}bit]{[MediaInfo VideoCodec]}{MediaInfo SubtitleLanguagesAll}{-Release Group}", 15 | "original": "{Original Title}" 16 | }, 17 | "daily": { 18 | "default:3": "{Series TitleYear} - {Air-Date} - {Episode CleanTitle} [{Preferred Words }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{[MediaInfo VideoCodec]}{-Release Group}", 19 | "default:4": "{Series TitleYear} - {Air-Date} - {Episode CleanTitle} [{Custom Formats }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{MediaInfo AudioLanguagesAll}[{MediaInfo VideoBitDepth}bit]{[MediaInfo VideoCodec]}{MediaInfo SubtitleLanguagesAll}{-Release Group}", 20 | "original": "{Original Title}" 21 | }, 22 | "anime": { 23 | "default:3": "{Series TitleYear} - S{season:00}E{episode:00} - {absolute:000} - {Episode CleanTitle} [{Preferred Words }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}[{MediaInfo VideoBitDepth}bit]{[MediaInfo VideoCodec]}[{Mediainfo AudioCodec} { Mediainfo AudioChannels}]{MediaInfo AudioLanguages}{-Release Group}", 24 | "default:4": "{Series TitleYear} - S{season:00}E{episode:00} - {absolute:000} - {Episode CleanTitle} [{Custom Formats }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}[{Mediainfo AudioCodec} { Mediainfo AudioChannels}]{MediaInfo AudioLanguagesAll}[{MediaInfo VideoBitDepth}bit]{[MediaInfo VideoCodec]}{MediaInfo SubtitleLanguagesAll}{-Release Group}" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /root/recyclarr-custom.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/recyclarr/recyclarr/master/schemas/config-schema.json 2 | 3 | # A starter config to use with Recyclarr. Most values are set to "reasonable defaults". Update the 4 | # values below as needed for your instance. You will be required to update the API Key and URL for 5 | # each instance you want to use. 6 | # 7 | # Many optional settings have been omitted to keep this template simple. 8 | # 9 | # For more details on the configuration, see the Configuration Reference on the wiki here: 10 | # https://github.com/recyclarr/recyclarr/wiki/Configuration-Reference 11 | 12 | # Configuration specific to Sonarr 13 | sonarr: 14 | instance1: 15 | base_url: arrUrl 16 | api_key: arrApi 17 | 18 | # Quality definitions from the guide to sync to Sonarr. Choice: anime, series, hybrid 19 | quality_definition: 20 | type: series 21 | preferred_ratio: 1.0 22 | 23 | delete_old_custom_formats: true 24 | 25 | custom_formats: 26 | # Custom scoring 27 | 28 | - trash_ids: 29 | - cddfb4e32db826151d97352b8e37c648 # x264 30 | - c9eafd50846d299b862ca9bb6ea91950 # x265 31 | quality_profiles: 32 | - name: Any 33 | score: 2000 34 | - trash_ids: 35 | - d660701077794679fd59e8bdf4ce3a29 # AMZN 36 | - f67c9ca88f463a48346062e8ad07713f # ATVP 37 | - 36b72f59f4ea20aad9316f475f2d9fbb # DCU 38 | - 89358767a60cc28783cdc3d0be9388a4 # DSNP 39 | - 7a235133c87f7da4c8cccceca7e3c7a6 # HBO 40 | - a880d6abc21e7c16884f3ae393f84179 # HMAX 41 | - f6cce30f1733d5c8194222a7507909bb # HULU 42 | - 0ac24a2a68a9700bcb7eeca8e5cd644c # iT 43 | - d34870697c9db575f17700212167be23 # NF 44 | - b2b980877494b560443631eb1f473867 # NLZ 45 | - 1656adc6d7bb2c8cca6acfb6592db421 # PCOK 46 | - c67a75ae4a1715f2bb4d492755ba4195 # PMTP 47 | - 3ac5d84fce98bab1b531393e9c82f467 # QIBI 48 | - c30d2958827d1867c73318a5a2957eb1 # RED 49 | - ae58039e1319178e6be73caab5c42166 # SHO 50 | - 5d2317d99af813b6529c7ebf01c83533 # VDL 51 | quality_profiles: 52 | - name: Any 53 | score: 300 54 | - trash_ids: 55 | - 290078c8b266272a5cc8e251b5e2eb0b # 1080p 56 | quality_profiles: 57 | - name: Any 58 | score: 100 59 | - trash_ids: 60 | - 4232a509ce60c4e208d13825b7c06264 # DD+ ATMOS 61 | - a377864de6228b252d6e28962673cedd # 9.1 Surround 62 | - 204c8c3e7315bb0ea81332774fa888d6 # 7.1 Surround 63 | - 026d5aadd1a6b4e550b134cb6c72b3ca # Uncensored 64 | - 2016d1676f5ee13a5b7257ff86ac9a93 # SDR 65 | quality_profiles: 66 | - name: Any 67 | score: 75 68 | - trash_ids: 69 | - 3fbafa924f361e66fbc6187af82dfa85 # 5.1 Surround 70 | - 9fb6d778592c293467437593ef394bf1 # 6.1 Surround 71 | quality_profiles: 72 | - name: Any 73 | score: 30 74 | - trash_ids: 75 | - 63487786a8b01b7f20dd2bc90dd4a477 # DD+ 76 | - 834e534f103938853ffced4203b53e72 # 2.0 Stereo 77 | - 42cba7e38c7947a6d1d0a62580ee6d62 # 3.0 Sound 78 | - 1895195e84767de180653914ce207245 # 4.0 Sound 79 | quality_profiles: 80 | - name: Any 81 | score: 25 82 | - trash_ids: 83 | - 1bef6c151fa35093015b0bfef18279e5 # 2160p 84 | - dbe00161b08a25ac6154c55f95e6318d # DD 85 | - bd6dd5e043aa27ff4696a08d011c7d96 # 1.0 Mono 86 | quality_profiles: 87 | - name: Any 88 | score: 20 89 | - trash_ids: 90 | - 28f6ef16d61e2d1adfce3156ed8257e3 # Opus 91 | - 44e7c4de10ae50265753082e5dc76047 # Repack v3 92 | quality_profiles: 93 | - name: Any 94 | score: 15 95 | - trash_ids: 96 | - eb3d5cc0a2be0db205fb823640db6a3c # Repack v2 97 | - a50b8a0c62274a7c38b09a9619ba9d86 # AAC 98 | quality_profiles: 99 | - name: Any 100 | score: 10 101 | - trash_ids: 102 | - ec8fa7296b64e8cd390a1600981f3923 # Repack/Proper 103 | quality_profiles: 104 | - name: Any 105 | score: 5 106 | - trash_ids: 107 | - 851bd64e04c9374c51102be3dd9ae4cc # FLAC 108 | - 3e8b714263b26f486972ee1e0fe7606c # MP3 109 | - 30f70576671ca933adbdcfc736a69718 # PCM 110 | - b2550eb333d27b75833e25b8c2557b38 # 10bit 111 | - 418f50b10f1907201b6cfdf881f467b7 # Anime Dual Audio 112 | - 9c14d194486c4014d422adc64092d794 # Dubs Only 113 | - 5964f2a8b3be407d083498e4459d05d0 # DTS 114 | quality_profiles: 115 | - name: Any 116 | score: 0 117 | - trash_ids: 118 | - 7ba05c6e0e14e793538174c679126996 # Multi 119 | - 47435ece6b99a0b477caf360e79ba0bb # x265 (HD) 120 | quality_profiles: 121 | - name: Any 122 | score: -250 123 | - trash_ids: 124 | - c1a25cd67b5d2e08287c957b1eb903ec # DTS-ES 125 | - c429417a57ea8c41d57e6990a8b0033f # DTS-HD MA 126 | - 9d00418ba386a083fbf4d58235fc37ef # DTS X 127 | - cfa5fbd8f02a86fc55d8d223d06a5e1f # DTS-HD HRA 128 | - 0d7824bb924701997f874e7ff7d4844a # TrueHD ATMOS 129 | - 1808e4b9cee74e064dfae3f1db99dbfe # TrueHD 130 | - b6fbafa7942952a13e17e2b1152b539a # ATMOS (undefined) 131 | quality_profiles: 132 | - name: Any 133 | score: -500 134 | - trash_ids: 135 | - 4aee45b0868229c4fbd8bad3e315f1d0 # MPEG2 136 | - 15a05bc7c1a36e2b57fd628f8977e2fc # AV1 137 | - 9b27ab6498ec0f31a3353992e19434ca # DV (WEBDL) 138 | - 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK 139 | - 17e889ce13117940092308f48b48b45b # HLG 140 | - 7878c33f1963fefb3d6c8657d46c2f0a # DV HDR10 141 | - 1f733af03141f068a540eec352589a89 # DV HLG 142 | - 27954b0a80aab882522a88a4d9eae1cd # DV SDR 143 | - 6d0d8de7b57e35518ac0308b0ddf404e # DV 144 | - 3e2c4e748b64a1a1118e0ea3f4cf6875 # HDR 145 | - 3497799d29a085e2ac2df9d468413c94 # HDR10 146 | - a3d82cbef5039f8d295478d28a887159 # HDR10+ 147 | - 0dad0a507451acddd754fe6dc3a7f5e7 # HDR10+ Boost 148 | - 2a7e3be05d3861d6df7171ec74cad727 # PQ 149 | - 3bc5f395426614e155e585a2f056cdf1 # Season Pack 150 | - 82d40da2bc6923f41e14394075dd4b03 # No-RlsGroup 151 | - 3a4127d8aa781b44120d907f2cd62627 # Hybrid 152 | - b735f09d3c025cbb7d75a5d38325b73b # Remaster 153 | - 32b367365729d530ca1c124a0b180c64 # Bad Dual Groups 154 | - e1a997ddb54e3ecbfe06341ad323c458 # Obfuscated 155 | quality_profiles: 156 | - name: Any 157 | score: -100000 158 | -------------------------------------------------------------------------------- /root/recyclarr.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/recyclarr/recyclarr/master/schemas/config-schema.json 2 | 3 | # A starter config to use with Recyclarr. Most values are set to "reasonable defaults". Update the 4 | # values below as needed for your instance. You will be required to update the API Key and URL for 5 | # each instance you want to use. 6 | # 7 | # Many optional settings have been omitted to keep this template simple. 8 | # 9 | # For more details on the configuration, see the Configuration Reference on the wiki here: 10 | # https://github.com/recyclarr/recyclarr/wiki/Configuration-Reference 11 | 12 | # Configuration specific to Sonarr 13 | sonarr: 14 | instance1: 15 | base_url: arrUrl 16 | api_key: arrApi 17 | 18 | # Quality definitions from the guide to sync to Sonarr. Choice: anime, series, hybrid 19 | quality_definition: 20 | type: series 21 | preferred_ratio: 1.0 22 | 23 | delete_old_custom_formats: true 24 | 25 | custom_formats: 26 | # A list of custom formats to sync to Sonarr. Must match the "trash_id" in the guide JSON. 27 | - trash_ids: 28 | # [No Category] 29 | - 290078c8b266272a5cc8e251b5e2eb0b # 1080p 30 | - 1bef6c151fa35093015b0bfef18279e5 # 2160p 31 | - 6f808933a71bd9666531610cb8c059cc # BR-DISK (BTN) 32 | - 5d9fd1b1e06cd8a475462f40214b7df6 # FLUX 33 | 34 | # Anime Misc/Streaming Services 35 | - d54cd2bf1326287275b56bccedb72ee2 # ADN 36 | - 7dd31f3dee6d2ef8eeaa156e23c3857e # B-Global 37 | - 4c67ff059210182b59cdd41697b8cb08 # Bilibili 38 | - 3e0b26604165f463f3e8e192261e7284 # CR 39 | - 1284d18e693de8efe0fe7d6b3e0b9170 # FUNi 40 | - 570b03b3145a25011bf073274a407259 # HIDIVE 41 | - d2d7b8a9d39413da5f44054080e028a3 # v0 42 | - 273bd326df95955e1b6c26527d1df89b # v1 43 | - 228b8ee9aa0a609463efca874524a6b8 # v2 44 | - 0e5833d3af2cc5fa96a0c29cd4477feb # v3 45 | - 4fc15eeb8f2f9a749f918217d4234ad8 # v4 46 | - 44a8ee6403071dd7b8a3a8dd3fe8cb20 # VRV 47 | - e5e6405d439dcd1af90962538acd4fe0 # WKN 48 | 49 | # Anime Optional 50 | - b2550eb333d27b75833e25b8c2557b38 # 10bit 51 | - 418f50b10f1907201b6cfdf881f467b7 # Anime Dual Audio 52 | - 9c14d194486c4014d422adc64092d794 # Dubs Only 53 | - 026d5aadd1a6b4e550b134cb6c72b3ca # Uncensored 54 | 55 | # Anime Source Groups 56 | - 949c16fe0a8147f50ba82cc2df9411c9 # Anime BD Tier 01 (Top SeaDex Muxers) 57 | - ed7f1e315e000aef424a58517fa48727 # Anime BD Tier 02 (SeaDex Muxers) 58 | - 096e406c92baa713da4a72d88030b815 # Anime BD Tier 03 (SeaDex Muxers) 59 | - 30feba9da3030c5ed1e0f7d610bcadc4 # Anime BD Tier 04 (SeaDex Muxers) 60 | - 545a76b14ddc349b8b185a6344e28b04 # Anime BD Tier 05 (Remuxes) 61 | - 25d2afecab632b1582eaf03b63055f72 # Anime BD Tier 06 (FanSubs) 62 | - 0329044e3d9137b08502a9f84a7e58db # Anime BD Tier 07 (P2P/Scene) 63 | - c81bbfb47fed3d5a3ad027d077f889de # Anime BD Tier 08 (Mini Encodes) 64 | - e3515e519f3b1360cbfc17651944354c # Anime LQ Groups 65 | - b4a1b3d705159cdca36d71e57ca86871 # Anime Raws 66 | - e0014372773c8f0e1bef8824f00c7dc4 # Anime Web Tier 01 (Muxers) 67 | - 19180499de5ef2b84b6ec59aae444696 # Anime Web Tier 02 (Top FanSubs) 68 | - c27f2ae6a4e82373b0f1da094e2489ad # Anime Web Tier 03 (Official Subs) 69 | - 4fd5528a3a8024e6b49f9c67053ea5f3 # Anime Web Tier 04 (Official Subs) 70 | - 29c2a13d091144f63307e4a8ce963a39 # Anime Web Tier 05 (FanSubs) 71 | - dc262f88d74c651b12e9d90b39f6c753 # Anime Web Tier 06 (FanSubs) 72 | 73 | # Audio Advanced #1 74 | - b6fbafa7942952a13e17e2b1152b539a # ATMOS (undefined) 75 | - 63487786a8b01b7f20dd2bc90dd4a477 # DD+ 76 | - 4232a509ce60c4e208d13825b7c06264 # DD+ ATMOS 77 | - 5964f2a8b3be407d083498e4459d05d0 # DTS 78 | - 9d00418ba386a083fbf4d58235fc37ef # DTS X 79 | - c1a25cd67b5d2e08287c957b1eb903ec # DTS-ES 80 | - c429417a57ea8c41d57e6990a8b0033f # DTS-HD MA 81 | - 1808e4b9cee74e064dfae3f1db99dbfe # TrueHD 82 | - 0d7824bb924701997f874e7ff7d4844a # TrueHD ATMOS 83 | 84 | # Audio Advanced #2 85 | - a50b8a0c62274a7c38b09a9619ba9d86 # AAC 86 | - dbe00161b08a25ac6154c55f95e6318d # DD 87 | - cfa5fbd8f02a86fc55d8d223d06a5e1f # DTS-HD HRA 88 | - 851bd64e04c9374c51102be3dd9ae4cc # FLAC 89 | - 3e8b714263b26f486972ee1e0fe7606c # MP3 90 | - 28f6ef16d61e2d1adfce3156ed8257e3 # Opus 91 | - 30f70576671ca933adbdcfc736a69718 # PCM 92 | 93 | # Audio Channels 94 | - bd6dd5e043aa27ff4696a08d011c7d96 # 1.0 Mono 95 | - 834e534f103938853ffced4203b53e72 # 2.0 Stereo 96 | - 42cba7e38c7947a6d1d0a62580ee6d62 # 3.0 Sound 97 | - 1895195e84767de180653914ce207245 # 4.0 Sound 98 | - 3fbafa924f361e66fbc6187af82dfa85 # 5.1 Surround 99 | - 9fb6d778592c293467437593ef394bf1 # 6.1 Surround 100 | - 204c8c3e7315bb0ea81332774fa888d6 # 7.1 Surround 101 | - a377864de6228b252d6e28962673cedd # 9.1 Surround 102 | 103 | # French Audio Version 104 | - 84f0acbda9c0c9de783894fb66df25aa # FanSUB 105 | - ea0bb4b6ba388992fad1092703b5ff7b # FastSUB 106 | - 4721382d9ee05f1b4967a25e75072911 # French Audio 107 | - 2f6e84efc47246ec9071e311e71c4953 # Multi-Audio 108 | - 7982e39789f17864f57b11f1996844f4 # Multi-French 109 | - 34789ec3caa819f087e23bbf9999daf7 # VF2 110 | - 0ce1e39a4676c6692ce47935278dac76 # VFB 111 | - 2c29a39a4fdfd6d258799bc4c09731b9 # VFF 112 | - b6816a0e1d4b64bf3550ad3b74b009b6 # VFI 113 | - 7a7f4e4f58bd1058440236d033a90b67 # VFQ 114 | - 7ae924ee9b2f39df3283c6c0beb8a2aa # VOF 115 | - 07a32f77690263bb9fda1842db7e273f # VOSTFR 116 | - 82085412d9a53ba8d8e46fc624eb701d # VQ 117 | 118 | # French Source Groups 119 | - 44b6c964dad997577d793fd004a39224 # FR Anime FanSub 120 | - db13a377f7afb29975ea39470434d2ef # FR Anime Tier 01 121 | - 4e6134a384dbc0ef166234cc0e45d26d # FR Anime Tier 02 122 | - db34d4357937fbfe89b63ba095f22155 # FR Anime Tier 03 123 | - d844321db5e126d2e7e46152f0706532 # FR HD Bluray Tier 01 124 | - 3ba797e5dc13af4b8d9bb25e83d90de2 # FR LQ 125 | - b8e91cc8fb2bd96468fab74730c30d18 # FR Remux Tier 01 126 | - 2f3422339d185eb227a324644a2fbfca # FR Scene Groups 127 | - ddb8eaa9c85a549c50034d280539d54d # FR WEB Tier 01 128 | - a4c51febd4d8b2a0db10a3c974f21d92 # FR WEB Tier 02 129 | - dbfc0a4b5cb4cbd693311c4482ae9683 # FR WEB Tier 03 130 | 131 | # HDR Formats 132 | - 6d0d8de7b57e35518ac0308b0ddf404e # DV 133 | - 7878c33f1963fefb3d6c8657d46c2f0a # DV HDR10 134 | - 1f733af03141f068a540eec352589a89 # DV HLG 135 | - 27954b0a80aab882522a88a4d9eae1cd # DV SDR 136 | - 3e2c4e748b64a1a1118e0ea3f4cf6875 # HDR 137 | - bb019e1cd00f304f80971c965de064dc # HDR (undefined) 138 | - 3497799d29a085e2ac2df9d468413c94 # HDR10 139 | - a3d82cbef5039f8d295478d28a887159 # HDR10+ 140 | - 17e889ce13117940092308f48b48b45b # HLG 141 | - 2a7e3be05d3861d6df7171ec74cad727 # PQ 142 | 143 | # HQ Source Groups 144 | - d6819cba26b1a6508138d25fb5e32293 # HD Bluray Tier 01 145 | - c2216b7b8aa545dc1ce8388c618f8d57 # HD Bluray Tier 02 146 | - 9965a052eb87b0d10313b1cea89eb451 # Remux Tier 01 147 | - 8a1d0c3d7497e741736761a1da866a2e # Remux Tier 02 148 | - d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene 149 | - e6258996055b9fbab7e9cb2f75819294 # WEB Tier 01 150 | - 58790d4e2fdcd9733aa7ae68ba2bb503 # WEB Tier 02 151 | - d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03 152 | 153 | # Misc 154 | - 4aee45b0868229c4fbd8bad3e315f1d0 # MPEG2 155 | - 7ba05c6e0e14e793538174c679126996 # Multi 156 | - eb3d5cc0a2be0db205fb823640db6a3c # Repack v2 157 | - 44e7c4de10ae50265753082e5dc76047 # Repack v3 158 | - ec8fa7296b64e8cd390a1600981f3923 # Repack/Proper 159 | - cddfb4e32db826151d97352b8e37c648 # x264 160 | - c9eafd50846d299b862ca9bb6ea91950 # x265 161 | 162 | # Optional 163 | - 15a05bc7c1a36e2b57fd628f8977e2fc # AV1 164 | - 32b367365729d530ca1c124a0b180c64 # Bad Dual Groups 165 | - ef4963043b0987f8485bc9106f16db38 # DV (FEL) 166 | - 9b27ab6498ec0f31a3353992e19434ca # DV (WEBDL) 167 | - 0dad0a507451acddd754fe6dc3a7f5e7 # HDR10+ Boost 168 | - 1bd69272e23c5e6c5b1d6c8a36fce95e # HFR 169 | - 82d40da2bc6923f41e14394075dd4b03 # No-RlsGroup 170 | - e1a997ddb54e3ecbfe06341ad323c458 # Obfuscated 171 | - 06d66ab109d4d2eddb2794d21526d140 # Retags 172 | - 1b3994c551cbb92a2c781af061f4ab44 # Scene 173 | - 2016d1676f5ee13a5b7257ff86ac9a93 # SDR 174 | - 3bc5f395426614e155e585a2f056cdf1 # Season Pack 175 | - 90501962793d580d011511155c97e4e5 # VP9 176 | - 9b64dff695c2115facf1b6ea59c9bd07 # x265 (no HDR/DV) 177 | 178 | # Series Versions 179 | - 3a4127d8aa781b44120d907f2cd62627 # Hybrid 180 | - b735f09d3c025cbb7d75a5d38325b73b # Remaster 181 | 182 | # Streaming Services 183 | - d660701077794679fd59e8bdf4ce3a29 # AMZN 184 | - f67c9ca88f463a48346062e8ad07713f # ATVP 185 | - f27d46a831e6b16fa3fee2c4e5d10984 # CANAL+ 186 | - 77a7b25585c18af08f60b1547bb9b4fb # CC 187 | - 36b72f59f4ea20aad9316f475f2d9fbb # DCU 188 | - 89358767a60cc28783cdc3d0be9388a4 # DSNP 189 | - 7a235133c87f7da4c8cccceca7e3c7a6 # HBO 190 | - a880d6abc21e7c16884f3ae393f84179 # HMAX 191 | - f6cce30f1733d5c8194222a7507909bb # HULU 192 | - 0ac24a2a68a9700bcb7eeca8e5cd644c # iT 193 | - 81d1fbf600e2540cee87f3a23f9d3c1c # MAX 194 | - d34870697c9db575f17700212167be23 # NF 195 | - b2b980877494b560443631eb1f473867 # NLZ 196 | - 1656adc6d7bb2c8cca6acfb6592db421 # PCOK 197 | - c67a75ae4a1715f2bb4d492755ba4195 # PMTP 198 | - 3ac5d84fce98bab1b531393e9c82f467 # QIBI 199 | - c30d2958827d1867c73318a5a2957eb1 # RED 200 | - b0d6195c23ae254932da00512db7e8a8 # RTBF 201 | - 0455d6519a550dbf648c97b56e7231d2 # SALTO 202 | - ae58039e1319178e6be73caab5c42166 # SHO 203 | - 1efe8da11bfd74fbbcd4d8117ddb9213 # STAN 204 | - 43b3cf48cb385cd3eac608ee6bca7f09 # UHD Streaming Boost 205 | - d2d299244a92b8a52d4921ce3897a256 # UHD Streaming Cut 206 | - 5d2317d99af813b6529c7ebf01c83533 # VDL 207 | 208 | # Unwanted 209 | - 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK 210 | - fbcb31d8dabd2a319072b84fc0b7249c # Extras 211 | - 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ 212 | - 47435ece6b99a0b477caf360e79ba0bb # x265 (HD) 213 | -------------------------------------------------------------------------------- /root/scripts/AutoConfig.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | scriptVersion="1.0.8" 3 | 4 | if [ -z "$arrUrl" ] || [ -z "$arrApiKey" ]; then 5 | arrUrlBase="$(cat /config/config.xml | xq | jq -r .Config.UrlBase)" 6 | if [ "$arrUrlBase" == "null" ]; then 7 | arrUrlBase="" 8 | else 9 | arrUrlBase="/$(echo "$arrUrlBase" | sed "s/\///g")" 10 | fi 11 | arrApiKey="$(cat /config/config.xml | xq | jq -r .Config.ApiKey)" 12 | arrPort="$(cat /config/config.xml | xq | jq -r .Config.Port)" 13 | arrUrl="http://127.0.0.1:${arrPort}${arrUrlBase}" 14 | fi 15 | 16 | # auto-clean up log file to reduce space usage 17 | if [ -f "/config/logs/AutoConfig.txt" ]; then 18 | find /config/logs -type f -name "AutoConfig.txt" -size +1024k -delete 19 | fi 20 | 21 | if [ ! -f "/config/logs/AutoConfig.txt" ]; then 22 | touch "/config/logs/AutoConfig.txt" 23 | chmod 666 "/config/logs/AutoConfig.txt" 24 | fi 25 | exec &> >(tee -a "/config/logs/AutoConfig.txt") 26 | 27 | log () { 28 | m_time=`date "+%F %T"` 29 | echo $m_time" :: AutoConfig :: $scriptVersion :: "$1 30 | } 31 | 32 | if [ -f /config/extended/logs/autoconfig ]; then 33 | log "Sonarr previously configured with optimal settings, skipping..." 34 | log "To re-configure Sonarr, delete the following file:" 35 | log "/config/extended/logs/autoconfig" 36 | exit 37 | fi 38 | 39 | 40 | if [ -f /config/extended/configs/naming.json ]; then 41 | log "Using custom Sonarr Naming (/config/extended/configs/naming.json)..." 42 | namingJson=$(cat /config/extended/configs/naming.json) 43 | else 44 | log "Getting Trash Guide Recommended Naming..." 45 | namingJson=$(curl -s "https://raw.githubusercontent.com/TRaSH-/Guides/master/docs/json/sonarr/naming/sonarr-naming.json") 46 | fi 47 | 48 | standardNaming=$(echo "$namingJson" | jq -r '.episodes.standard."default:4"') 49 | dailyNaming=$(echo "$namingJson" | jq -r '.episodes.daily."default:4"') 50 | animeNaming=$(echo "$namingJson" | jq -r '.episodes.anime."default:4"') 51 | seriesNaming=$(echo "$namingJson" | jq -r '.series.default') 52 | seasonNaming=$(echo "$namingJson" | jq -r '.season.default') 53 | 54 | log "Updating Sonarr File Naming..." 55 | updateArr=$(curl -s "$arrUrl/api/v3/config/naming" -X PUT -H "Content-Type: application/json" -H "X-Api-Key: $arrApiKey" --data-raw "{ 56 | \"renameEpisodes\":true, 57 | \"replaceIllegalCharacters\":true, 58 | \"multiEpisodeStyle\":5, 59 | \"standardEpisodeFormat\":\"$standardNaming\", 60 | \"dailyEpisodeFormat\":\"$dailyNaming\", 61 | \"animeEpisodeFormat\":\"$animeNaming\", 62 | \"seriesFolderFormat\":\"$seriesNaming\", 63 | \"seasonFolderFormat\":\"$seasonNaming\", 64 | \"specialsFolderFormat\":\"$seasonNaming\", 65 | \"includeSeriesTitle\":false, 66 | \"includeEpisodeTitle\":false, 67 | \"includeQuality\":false, 68 | \"replaceSpaces\":true, 69 | \"separator\":\" - \", 70 | \"numberStyle\":\"S{season:00}E{episode:00}\", 71 | \"id\":1 72 | }") 73 | log "Complete" 74 | 75 | log "Updating Sonrr Media Management..." 76 | updateArr=$(curl -s "$arrUrl/api/v3/config/mediamanagement" -X PUT -H "Content-Type: application/json" -H "X-Api-Key: $arrApiKey" --data-raw '{"autoUnmonitorPreviouslyDownloadedEpisodes":false, 77 | "recycleBin":"", 78 | "recycleBinCleanupDays":7, 79 | "downloadPropersAndRepacks":"doNotPrefer", 80 | "createEmptySeriesFolders":false, 81 | "deleteEmptyFolders":true, 82 | "fileDate":"none", 83 | "rescanAfterRefresh":"always", 84 | "setPermissionsLinux":false, 85 | "chmodFolder":"777", 86 | "chownGroup":"", 87 | "episodeTitleRequired":"always", 88 | "skipFreeSpaceCheckWhenImporting":false, 89 | "minimumFreeSpaceWhenImporting":100, 90 | "copyUsingHardlinks":true, 91 | "importExtraFiles":true, 92 | "extraFileExtensions":"srt", 93 | "enableMediaInfo":true,"id":1}') 94 | log "Complete" 95 | 96 | log "Updating Sonarr Medata Settings..." 97 | updateArr=$(curl -s "$arrUrl/api/v3/metadata/1?" -X PUT -H "Content-Type: application/json" -H "X-Api-Key: $arrApiKey" --data-raw '{"enable":true,"name":"Kodi (XBMC) / Emby","fields":[{"name":"seriesMetadata","value":true},{"name":"seriesMetadataEpisodeGuide","value":true},{"name":"seriesMetadataUrl","value":false},{"name":"episodeMetadata","value":true},{"name":"seriesImages","value":true},{"name":"seasonImages","value":true},{"name":"episodeImages","value":true}],"implementationName":"Kodi (XBMC) / Emby","implementation":"XbmcMetadata","configContract":"XbmcMetadataSettings","infoLink":"https://wiki.servarr.com/sonarr/supported#xbmcmetadata","tags":[],"id":1}') 98 | updateArr=$(curl -s "$arrUrl/api/v3/metadata/4?" -X PUT -H "Content-Type: application/json" -H "X-Api-Key: $arrApiKey" --data-raw '{"enable":true,"name":"Plex","fields":[{"name":"seriesPlexMatchFile","value":true}],"implementationName":"Plex","implementation":"PlexMetadata","configContract":"PlexMetadataSettings","infoLink":"https://wiki.servarr.com/sonarr/supported#plexmetadata","tags":[],"id":4}') 99 | 100 | log "Configuring Sonarr Custom Scripts" 101 | if curl -s "$arrUrl/api/v3/notification" -H "X-Api-Key: ${arrApiKey}" | jq -r .[].name | grep "PlexNotify.bash" | read; then 102 | log "PlexNotify.bash already added to Sonarr custom scripts" 103 | else 104 | log "Adding PlexNotify.bash to Sonarr custom scripts" 105 | # Send a command to check file path, to prevent error with adding... 106 | updateArr=$(curl -s "$arrUrl/api/v3/filesystem?path=%2Fconfig%2Fextended%2Fscripts%2FPlexNotify.bash&allowFoldersWithoutTrailingSlashes=true&includeFiles=true" -H "X-Api-Key: ${arrApiKey}") 107 | 108 | # Add PlexNotify.bash 109 | updateArr=$(curl -s "$arrUrl/api/v3/notification?" -X POST -H "Content-Type: application/json" -H "X-Api-Key: ${arrApiKey}" --data-raw '{"onGrab":false,"onDownload":true,"onUpgrade":true,"onRename":true,"onSeriesDelete":true,"onEpisodeFileDelete":true,"onEpisodeFileDeleteForUpgrade":true,"onHealthIssue":false,"onApplicationUpdate":false,"supportsOnGrab":true,"supportsOnDownload":true,"supportsOnUpgrade":true,"supportsOnRename":true,"supportsOnSeriesDelete":true,"supportsOnEpisodeFileDelete":true,"supportsOnEpisodeFileDeleteForUpgrade":true,"supportsOnHealthIssue":true,"supportsOnApplicationUpdate":true,"includeHealthWarnings":false,"name":"PlexNotify.bash","fields":[{"name":"path","value":"/config/extended/scripts/PlexNotify.bash"},{"name":"arguments"}],"implementationName":"Custom Script","implementation":"CustomScript","configContract":"CustomScriptSettings","infoLink":"https://wiki.servarr.com/sonarr/supported#customscript","message":{"message":"Testing will execute the script with the EventType set to Test, ensure your script handles this correctly","type":"warning"},"tags":[]}') 110 | log "Complete" 111 | fi 112 | 113 | if curl -s "$arrUrl/api/v3/notification" -H "X-Api-Key: ${arrApiKey}" | jq -r .[].name | grep "DailySeriesEpisodeTrimmer.bash" | read; then 114 | log "DailySeriesEpisodeTrimmer.bash already added to Sonarr custom scripts" 115 | else 116 | log "Adding DailySeriesEpisodeTrimmer.bash to Sonarr custom scripts" 117 | # Send a command to check file path, to prevent error with adding... 118 | updateArr=$(curl -s "$arrUrl/api/v3/filesystem?path=%2Fconfig%2Fextended%2Fscripts%2FDailySeriesEpisodeTrimmer.bash&allowFoldersWithoutTrailingSlashes=true&includeFiles=true" -H "X-Api-Key: ${arrApiKey}") 119 | 120 | # Add DailySeriesEpisodeTrimmer.bash 121 | updateArr=$(curl -s "$arrUrl/api/v3/notification?" -X POST -H "Content-Type: application/json" -H "X-Api-Key: ${arrApiKey}" --data-raw '{"onGrab":false,"onDownload":true,"onUpgrade":true,"onRename":true,"onSeriesDelete":true,"onEpisodeFileDelete":false,"onEpisodeFileDeleteForUpgrade":false,"onHealthIssue":false,"onApplicationUpdate":false,"supportsOnGrab":true,"supportsOnDownload":true,"supportsOnUpgrade":true,"supportsOnRename":true,"supportsOnSeriesDelete":true,"supportsOnEpisodeFileDelete":true,"supportsOnEpisodeFileDeleteForUpgrade":true,"supportsOnHealthIssue":true,"supportsOnApplicationUpdate":true,"includeHealthWarnings":false,"name":"DailySeriesEpisodeTrimmer.bash","fields":[{"name":"path","value":"/config/extended/scripts/DailySeriesEpisodeTrimmer.bash"},{"name":"arguments"}],"implementationName":"Custom Script","implementation":"CustomScript","configContract":"CustomScriptSettings","infoLink":"https://wiki.servarr.com/sonarr/supported#customscript","message":{"message":"Testing will execute the script with the EventType set to Test, ensure your script handles this correctly","type":"warning"},"tags":[]}') 122 | log "Complete" 123 | fi 124 | 125 | if curl -s "$arrUrl/api/v3/notification" -H "X-Api-Key: ${arrApiKey}" | jq -r .[].name | grep "Extras.bash" | read; then 126 | log "Extras.bash already added to Sonarr custom scripts" 127 | else 128 | log "Adding Extras.bash to Sonarr custom scripts" 129 | # Send a command to check file path, to prevent error with adding... 130 | updateArr=$(curl -s "$arrUrl/api/v3/filesystem?path=%2Fconfig%2Fextended%2Fscripts%2FExtras.bash&allowFoldersWithoutTrailingSlashes=true&includeFiles=true" -H "X-Api-Key: ${arrApiKey}") 131 | 132 | # Add Extras.bash 133 | updateArr=$(curl -s "$arrUrl/api/v3/notification?" -X POST -H "Content-Type: application/json" -H "X-Api-Key: ${arrApiKey}" --data-raw '{"onGrab":false,"onDownload":true,"onUpgrade":true,"onRename":true,"onSeriesDelete":false,"onEpisodeFileDelete":false,"onEpisodeFileDeleteForUpgrade":false,"onHealthIssue":false,"onApplicationUpdate":false,"supportsOnGrab":true,"supportsOnDownload":true,"supportsOnUpgrade":true,"supportsOnRename":true,"supportsOnSeriesDelete":false,"supportsOnEpisodeFileDelete":true,"supportsOnEpisodeFileDeleteForUpgrade":true,"supportsOnHealthIssue":true,"supportsOnApplicationUpdate":true,"includeHealthWarnings":false,"name":"Extras.bash","fields":[{"name":"path","value":"/config/extended/scripts/Extras.bash"},{"name":"arguments"}],"implementationName":"Custom Script","implementation":"CustomScript","configContract":"CustomScriptSettings","infoLink":"https://wiki.servarr.com/sonarr/supported#customscript","message":{"message":"Testing will execute the script with the EventType set to Test, ensure your script handles this correctly","type":"warning"},"tags":[]}') 134 | log "Complete" 135 | fi 136 | 137 | touch /config/extended/logs/autoconfig 138 | chmod 666 /config/extended/logs/autoconfig 139 | 140 | exit 141 | -------------------------------------------------------------------------------- /root/scripts/AutoExtras.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | scriptVersion="1.0.1" 3 | 4 | if [ -z "$arrUrl" ] || [ -z "$arrApiKey" ]; then 5 | arrUrlBase="$(cat /config/config.xml | xq | jq -r .Config.UrlBase)" 6 | if [ "$arrUrlBase" == "null" ]; then 7 | arrUrlBase="" 8 | else 9 | arrUrlBase="/$(echo "$arrUrlBase" | sed "s/\///g")" 10 | fi 11 | arrApiKey="$(cat /config/config.xml | xq | jq -r .Config.ApiKey)" 12 | arrPort="$(cat /config/config.xml | xq | jq -r .Config.Port)" 13 | arrUrl="http://127.0.0.1:${arrPort}${arrUrlBase}" 14 | fi 15 | 16 | log () { 17 | m_time=`date "+%F %T"` 18 | echo $m_time" :: AutoExtras :: $scriptVersion :: "$1 19 | } 20 | 21 | # auto-clean up log file to reduce space usage 22 | if [ -f "/config/logs/AutoExtras.txt" ]; then 23 | find /config/logs -type f -name "AutoExtras.txt" -size +1024k -delete 24 | fi 25 | 26 | if [ ! -f "/config/logs/AutoExtras.txt" ]; then 27 | touch "/config/logs/AutoExtras.txt" 28 | chmod 666 "/config/logs/AutoExtras.txt" 29 | fi 30 | exec &> >(tee -a "/config/logs/AutoExtras.txt") 31 | 32 | sonarrSeriesList=$(curl -s --header "X-Api-Key:"${arrApiKey} --request GET "$arrUrl/api/v3/series") 33 | sonarrSeriesTotal=$(echo "${sonarrSeriesList}" | jq -r '.[].id' | wc -l) 34 | sonarrSeriesIds=$(echo "${sonarrSeriesList}" | jq -r '.[].id') 35 | 36 | loopCount=0 37 | for id in $(echo $sonarrSeriesIds); do 38 | loopCount=$(( $loopCount + 1 )) 39 | arrSeriesData="$(echo "$sonarrSeriesList" | jq -r ".[] | select(.id==$id)")" 40 | arrSeriesPath="$(echo "$arrSeriesData" | jq -r ".path")" 41 | arrSeriesTitle="$(echo "$arrSeriesData" | jq -r ".title")" 42 | if [ -d "$arrSeriesPath" ]; then 43 | log "$loopCount of $sonarrSeriesTotal :: $id :: $arrSeriesTitle :: Processing with Extras.bash" 44 | bash /config/extended/scripts/Extras.bash "$id" 45 | else 46 | log "$loopCount of $sonarrSeriesTotal :: $id :: $arrSeriesTitle :: Series folder does not exist, skipping..." 47 | continue 48 | fi 49 | done 50 | 51 | exit 52 | -------------------------------------------------------------------------------- /root/scripts/DailySeriesEpisodeTrimmer.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | scriptVersion="1.0.3" 3 | 4 | if [ -z "$arrUrl" ] || [ -z "$arrApiKey" ]; then 5 | arrUrlBase="$(cat /config/config.xml | xq | jq -r .Config.UrlBase)" 6 | if [ "$arrUrlBase" == "null" ]; then 7 | arrUrlBase="" 8 | else 9 | arrUrlBase="/$(echo "$arrUrlBase" | sed "s/\///g")" 10 | fi 11 | arrApiKey="$(cat /config/config.xml | xq | jq -r .Config.ApiKey)" 12 | arrPort="$(cat /config/config.xml | xq | jq -r .Config.Port)" 13 | arrUrl="http://127.0.0.1:${arrPort}${arrUrlBase}" 14 | fi 15 | 16 | log () { 17 | m_time=`date "+%F %T"` 18 | echo $m_time" :: DailySeriesEpisodeTrimmer :: $scriptVersion :: "$1 19 | } 20 | 21 | # auto-clean up log file to reduce space usage 22 | if [ -f "/config/logs/DailySeriesEpisodeTrimmer.txt" ]; then 23 | find /config/logs -type f -name "DailySeriesEpisodeTrimmer.txt" -size +1024k -delete 24 | fi 25 | 26 | if [ ! -f "/config/logs/DailySeriesEpisodeTrimmer.txt" ]; then 27 | touch "/config/logs/DailySeriesEpisodeTrimmer.txt" 28 | chmod 666 "/config/logs/DailySeriesEpisodeTrimmer.txt" 29 | fi 30 | exec &> >(tee -a "/config/logs/DailySeriesEpisodeTrimmer.txt") 31 | 32 | if [ "$sonarr_eventtype" == "Test" ]; then 33 | log "Tested" 34 | exit 0 35 | fi 36 | 37 | seriesId=$sonarr_series_id 38 | seriesData=$(curl -s "$arrUrl/api/v3/series/$seriesId?apikey=$arrApiKey") 39 | seriesTitle=$(echo $seriesData | jq -r ".title") 40 | seriesType=$(echo $seriesData | jq -r ".seriesType") 41 | seriesEpisodeData=$(curl -s "$arrUrl/api/v3/episode?seriesId=$seriesId&apikey=$arrApiKey") 42 | seriesEpisodeIds=$(echo "$seriesEpisodeData" | jq -r " . | sort_by(.airDate) | reverse | .[] | select(.hasFile==true) | .id") 43 | seriesEpisodeIdsCount=$(echo "$seriesEpisodeIds" | wc -l) 44 | 45 | # Verify series is marked as "daily" type by sonarr, skip if not... 46 | if [ $seriesType != "daily" ]; then 47 | log "$seriesTitle (ID:$seriesId) :: TYPE :: $seriesType :: ERROR :: Non-daily series, skipping..." 48 | exit 49 | fi 50 | 51 | # Skip processing if less than 14 episodes were found to be downloaded 52 | if [ $seriesEpisodeIdsCount -lt $maximumDailyEpisodes ]; then 53 | log "$seriesTitle (ID:$seriesId) :: TYPE :: $seriesType :: ERROR :: Series has not exceeded $maximumDailyEpisodes downloaded episodes ($seriesEpisodeIdsCount files found), skipping..." 54 | exit 55 | fi 56 | 57 | # Begin processing "daily" series type 58 | if [ $seriesType == daily ]; then 59 | seriesEpisodeData=$(curl -s "$arrUrl/api/v3/episode?seriesId=$seriesId&apikey=$arrApiKey") 60 | seriesEpisodeIds=$(echo "$seriesEpisodeData"| jq -r " . | sort_by(.airDate) | reverse | .[] | select(.hasFile==true) | .id") 61 | processId=0 62 | seriesRefreshRequired=false 63 | for id in $seriesEpisodeIds; do 64 | processId=$(( $processId + 1 )) 65 | if [ $processId -gt $maximumDailyEpisodes ]; then 66 | episodeData=$(curl -s "http://localhost:8989/api/v3/episode/$id?apikey=$arrApiKey") 67 | episodeSeriesId=$(echo "$episodeData" | jq -r ".seriesId") 68 | episodeTitle=$(echo "$episodeData" | jq -r ".title") 69 | episodeSeasonNumber=$(echo "$episodeData" | jq -r ".seasonNumber") 70 | episodeNumber=$(echo "$episodeData" | jq -r ".episodeNumber") 71 | episodeAirDate=$(echo "$episodeData" | jq -r ".airDate") 72 | episodeFileId=$(echo "$episodeData" | jq -r ".episodeFileId") 73 | 74 | # Unmonitor downloaded episode if greater than 14 downloaded episodes 75 | log "$seriesTitle (ID:$episodeSeriesId) :: TYPE :: $seriesType :: S${episodeSeasonNumber}E${episodeNumber} :: $episodeAirDate :: $episodeTitle :: Unmonitored Episode ID :: $id" 76 | umonitorEpisode=$(curl -s "$arrUrl/api/v3/episode/monitor?apikey=$arrApiKey" -X PUT --data-raw "{\"episodeIds\":[$id],\"monitored\":false}") 77 | 78 | # Delete downloaded episode if greater than 14 downloaded episodes 79 | log "$seriesTitle (ID:$episodeSeriesId) :: TYPE :: $seriesType :: S${episodeSeasonNumber}E${episodeNumber} :: $episodeAirDate :: $episodeTitle :: Deleted File ID :: $episodeFileId" 80 | deleteFile=$(curl -s "$arrUrl/api/v3/episodefile/$episodeFileId?apikey=$arrApiKey" -X DELETE) 81 | seriesRefreshRequired=true 82 | else 83 | # Skip if less than required 14 downloaded episodes exist 84 | log "$seriesTitle (ID:$episodeSeriesId) :: TYPE :: $seriesType :: Skipping Episode ID :: $id" 85 | fi 86 | done 87 | if [ "$seriesRefreshRequired" = "true" ]; then 88 | # Refresh Series after changes 89 | log "$seriesTitle (ID:$episodeSeriesId) :: TYPE :: $seriesType :: Refresh Series" 90 | refreshSeries=$(curl -s "$arrUrl/api/v3/command?apikey=$arrApiKey" -X POST --data-raw "{\"name\":\"RefreshSeries\",\"seriesId\":$episodeSeriesId}") 91 | fi 92 | fi 93 | 94 | exit 95 | -------------------------------------------------------------------------------- /root/scripts/Extras.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | scriptVersion="1.0.3" 3 | arrEventType="$sonarr_eventtype" 4 | arrItemId=$sonarr_series_id 5 | tmdbApiKey="3b7751e3179f796565d88fdb2fcdf426" 6 | autoScan="false" 7 | updatePlex="false" 8 | ytdlpExtraOpts="--user-agent facebookexternalhit/1.1" 9 | 10 | if [ ! -z "$1" ]; then 11 | arrItemId="$1" 12 | autoScan="true" 13 | fi 14 | 15 | # Debugging 16 | #arrItemId=818 17 | #extrasLanguages=en-US,it-IT 18 | #extrasType=all 19 | #extrasOfficialOnly=false 20 | #enableExtras=true 21 | 22 | if [ -z "$arrUrl" ] || [ -z "$arrApiKey" ]; then 23 | arrUrlBase="$(cat /config/config.xml | xq | jq -r .Config.UrlBase)" 24 | if [ "$arrUrlBase" == "null" ]; then 25 | arrUrlBase="" 26 | else 27 | arrUrlBase="/$(echo "$arrUrlBase" | sed "s/\///g")" 28 | fi 29 | arrApiKey="$(cat /config/config.xml | xq | jq -r .Config.ApiKey)" 30 | arrPort="$(cat /config/config.xml | xq | jq -r .Config.Port)" 31 | arrUrl="http://127.0.0.1:${arrPort}${arrUrlBase}" 32 | fi 33 | 34 | log () { 35 | m_time=`date "+%F %T"` 36 | echo $m_time" :: Extras :: $scriptVersion :: "$1 37 | } 38 | 39 | # auto-clean up log file to reduce space usage 40 | if [ -f "/config/logs/Extras.txt" ]; then 41 | find /config/logs -type f -name "Extras.txt" -size +1024k -delete 42 | fi 43 | 44 | if [ ! -f "/config/logs/Extras.txt" ]; then 45 | touch "/config/logs/Extras.txt" 46 | chmod 666 "/config/logs/Extras.txt" 47 | fi 48 | exec &> >(tee -a "/config/logs/Extras.txt") 49 | 50 | if [ "$arrEventType" == "Test" ]; then 51 | log "Tested Successfully" 52 | exit 0 53 | fi 54 | 55 | 56 | # Check to see if Extras are enabled via ENV 57 | if [ "$enableExtras" != "true" ]; then 58 | log "Script disabled, exiting..." 59 | log "Enable by setting enableExtras=true" 60 | exit 61 | fi 62 | 63 | # Get series information 64 | arrItemData=$(curl -s "$arrUrl/api/v3/series/$arrItemId?apikey=$arrApiKey") 65 | itemTitle=$(echo "$arrItemData" | jq -r .title) 66 | itemHasFile=$(echo "$arrItemData" | jq -r .hasFile) 67 | itemPath="$(echo "$arrItemData" | jq -r ".path")" 68 | imdbId="$(echo "$arrItemData" | jq -r ".imdbId")" 69 | tmdbId=$(curl -s "https://api.themoviedb.org/3/find/$imdbId?api_key=$tmdbApiKey&external_source=imdb_id" | jq -r .tv_results[].id) 70 | 71 | # Check if series folder path exists 72 | if [ ! -d "$itemPath" ]; then 73 | log "$itemTitle :: ERROR: Item Path does not exist ($itemPath), Skipping..." 74 | exit 75 | fi 76 | 77 | DownloadExtras () { 78 | 79 | # Check for cookies file 80 | if find /config -type f -iname "cookies.txt" | read; then 81 | cookiesFile="$(find /config -type f -iname "cookies.txt" | head -n1)" 82 | log "$itemTitle :: Cookies File Found!" 83 | else 84 | log "$itemTitle :: Cookies File Not Found!" 85 | cookiesFile="" 86 | fi 87 | 88 | IFS=',' read -r -a filters <<< "$extrasLanguages" 89 | for filter in "${filters[@]}" 90 | do 91 | if [ "$useProxy" != "true" ]; then 92 | tmdbVideosListData=$(curl -s "https://api.themoviedb.org/3/tv/$tmdbId/videos?api_key=$tmdbApiKey&language=$filter" | jq -r '.results[] | select(.site=="YouTube")') 93 | else 94 | tmdbVideosListData=$(curl -x $proxyUrl:$proxyPort --proxy-user $proxyUsername:$proxyPassword -s "https://api.themoviedb.org/3/tv/$tmdbId/videos?api_key=$tmdbApiKey&language=$filter" | jq -r '.results[] | select(.site=="YouTube")') 95 | fi 96 | 97 | log "$itemTitle :: Searching for \"$filter\" extras..." 98 | if [ "$extrasType" == "all" ]; then 99 | tmdbVideosListDataIds=$(echo "$tmdbVideosListData" | jq -r ".id") 100 | tmdbVideosListDataIdsCount=$(echo "$tmdbVideosListData" | jq -r ".id" | wc -l) 101 | else 102 | tmdbVideosListDataIds=$(echo "$tmdbVideosListData" | jq -r "select(.type==\"Trailer\") | .id") 103 | tmdbVideosListDataIdsCount=$(echo "$tmdbVideosListData" | jq -r "select(.type==\"Trailer\") | .id" | wc -l) 104 | fi 105 | if [ -z "$tmdbVideosListDataIds" ]; then 106 | log "$itemTitle :: None found..." 107 | continue 108 | fi 109 | 110 | if [ $tmdbVideosListDataIdsCount -le 0 ]; then 111 | log "$itemTitle :: No Extras Found, skipping..." 112 | exit 113 | fi 114 | 115 | log "$itemTitle :: $tmdbVideosListDataIdsCount Extras Found!" 116 | i=0 117 | for id in $(echo "$tmdbVideosListDataIds"); do 118 | i=$(( i + 1)) 119 | tmdbExtraData="$(echo "$tmdbVideosListData" | jq -r "select(.id==\"$id\")")" 120 | tmdbExtraTitle="$(echo "$tmdbExtraData" | jq -r .name)" 121 | tmdbExtraTitleClean="$(echo "$tmdbExtraTitle" | sed -e "s/[^[:alpha:][:digit:]$^&_+=()'%;{},.@#]/ /g" -e "s/ */ /g" | sed 's/^[.]*//' | sed 's/[.]*$//g' | sed 's/^ *//g' | sed 's/ *$//g')" 122 | tmdbExtraKey="$(echo "$tmdbExtraData" | jq -r .key)" 123 | tmdbExtraType="$(echo "$tmdbExtraData" | jq -r .type)" 124 | tmdbExtraOfficial="$(echo "$tmdbExtraData" | jq -r .official)" 125 | 126 | if [ "$tmdbExtraOfficial" != "true" ]; then 127 | if [ "$extrasOfficialOnly" == "true" ]; then 128 | log "$itemTitle :: $i of $tmdbVideosListDataIdsCount :: $tmdbExtraType :: Not official, skipping..." 129 | continue 130 | fi 131 | fi 132 | 133 | if [ "$tmdbExtraType" == "Featurette" ]; then 134 | extraFolderName="featurettes" 135 | elif [ "$tmdbExtraType" == "Trailer" ]; then 136 | extraFolderName="trailers" 137 | elif [ "$tmdbExtraType" == "Behind the Scenes" ]; then 138 | extraFolderName="behind the scenes" 139 | else 140 | extraFolderName="other" 141 | fi 142 | 143 | if [ ! -d "$itemPath/$extraFolderName" ]; then 144 | mkdir -p "$itemPath/$extraFolderName" 145 | chmod 777 "$itemPath/$extraFolderName" 146 | fi 147 | 148 | finalPath="$itemPath/$extraFolderName" 149 | if [ "$extraFolderName" == "other" ]; then 150 | finalFileName="$tmdbExtraTitleClean ($tmdbExtraType)" 151 | else 152 | finalFileName="$tmdbExtraTitleClean" 153 | fi 154 | 155 | if [ -f "$finalPath/$finalFileName.mkv" ]; then 156 | log "$itemTitle :: $i of $tmdbVideosListDataIdsCount :: $tmdbExtraType :: $tmdbExtraTitle ($tmdbExtraKey) :: Already Downloaded, skipping..." 157 | continue 158 | fi 159 | 160 | videoLanguages="$(echo "$extrasLanguages" | sed "s/-[[:alpha:]][[:alpha:]]//g")" 161 | 162 | log "$itemTitle :: $i of $tmdbVideosListDataIdsCount :: $tmdbExtraType :: $tmdbExtraTitle ($tmdbExtraKey) :: Downloading (yt-dlp :: $videoFormat)..." 163 | if [ ! -z "$cookiesFile" ]; then 164 | yt-dlp -f "$videoFormat" --no-video-multistreams --cookies "$cookiesFile" -o "$finalPath/$finalFileName" --write-sub --sub-lang $videoLanguages --embed-subs --merge-output-format mkv --no-mtime --geo-bypass $ytdlpExtraOpts "https://www.youtube.com/watch?v=$tmdbExtraKey" &>/dev/null 165 | else 166 | yt-dlp -f "$videoFormat" --no-video-multistreams -o "$finalPath/$finalFileName" --write-sub --sub-lang $videoLanguages --embed-subs --merge-output-format mkv --no-mtime --geo-bypass $ytdlpExtraOpts "https://www.youtube.com/watch?v=$tmdbExtraKey" &>/dev/null 167 | fi 168 | if [ -f "$finalPath/$finalFileName.mkv" ]; then 169 | log "$itemTitle :: $i of $tmdbVideosListDataIdsCount :: $tmdbExtraType :: $tmdbExtraTitle ($tmdbExtraKey) :: Compete" 170 | chmod 666 "$finalPath/$finalFileName.mkv" 171 | else 172 | log "$itemTitle :: $i of $tmdbVideosListDataIdsCount :: $tmdbExtraType :: $tmdbExtraTitle ($tmdbExtraKey) :: ERROR :: Download Failed" 173 | continue 174 | fi 175 | 176 | if python3 /usr/local/sma/manual.py --config "/sma.ini" -i "$finalPath/$finalFileName.mkv" -nt &>/dev/null; then 177 | sleep 0.01 178 | log "$itemTitle :: $i of $tmdbVideosListDataIdsCount :: $tmdbExtraType :: $tmdbExtraTitle :: Processed with SMA..." 179 | rm /usr/local/sma/config/*log* 180 | else 181 | log "$itemTitle :: $i of $tmdbVideosListDataIdsCount :: $tmdbExtraType :: $tmdbExtraTitle :: ERROR :: SMA Processing Error" 182 | rm "$finalPath/$finalFileName.mkv" 183 | log "$itemTitle :: $i of $tmdbVideosListDataIdsCount :: $tmdbExtraType :: $tmdbExtraTitle :: INFO: deleted: $finalPath/$finalFileName.mkv" 184 | fi 185 | updatePlex="true" 186 | done 187 | done 188 | 189 | # Mark Series Extras Complete 190 | if [ ! -d "/config/extended/logs/extras" ]; then 191 | mkdir -p "/config/extended/logs/extras" 192 | chmod 777 "/config/extended/logs/extras" 193 | fi 194 | log "$itemTitle :: Marking/logging as Extras downloads complete (/config/extended/logs/extras/$tmdbId)" 195 | touch "/config/extended/logs/extras/$tmdbId" 196 | chmod 666 "/config/extended/logs/extras/$tmdbId" 197 | 198 | } 199 | 200 | NotifyPlex () { 201 | # Process item with PlexNotify.bash if plexToken is configured 202 | if [ ! -z "$plexToken" ]; then 203 | # Always update plex if extra is downloaded 204 | if [ "$updatePlex" == "true" ]; then 205 | log "$itemTitle :: Using PlexNotify.bash to update Plex...." 206 | bash /config/extended/scripts/PlexNotify.bash "$itemPath" 207 | exit 208 | fi 209 | 210 | # Do not notify plex if this script was triggered by the AutoExtras.bash and no Extras were downloaded 211 | if [ "$autoScan" == "true" ]; then 212 | log "$itemTitle :: Skipping plex notification, not needed...." 213 | exit 214 | else 215 | log "$itemTitle :: Using PlexNotify.bash to update Plex...." 216 | bash /config/extended/scripts/PlexNotify.bash "$itemPath" 217 | exit 218 | fi 219 | fi 220 | } 221 | 222 | # Check if series has been previously processed 223 | if [ -f "/config/extended/logs/extras/$tmdbId" ]; then 224 | # Delete log file older than 7 days, to allow re-processing 225 | find "/config/extended/logs/extras" -type f -mtime +7 -name "$tmdbId" -delete 226 | fi 227 | 228 | if [ -f "/config/extended/logs/extras/$tmdbId" ]; then 229 | log "$itemTitle :: Already processed Extras, waiting 7 days to re-check..." 230 | NotifyPlex 231 | exit 232 | else 233 | DownloadExtras 234 | NotifyPlex 235 | fi 236 | 237 | exit 238 | -------------------------------------------------------------------------------- /root/scripts/InvalidSeriesAutoCleaner.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | scriptVersion="1.0.1" 3 | 4 | if [ -z "$arrUrl" ] || [ -z "$arrApiKey" ]; then 5 | arrUrlBase="$(cat /config/config.xml | xq | jq -r .Config.UrlBase)" 6 | if [ "$arrUrlBase" == "null" ]; then 7 | arrUrlBase="" 8 | else 9 | arrUrlBase="/$(echo "$arrUrlBase" | sed "s/\///g")" 10 | fi 11 | arrApiKey="$(cat /config/config.xml | xq | jq -r .Config.ApiKey)" 12 | arrPort="$(cat /config/config.xml | xq | jq -r .Config.Port)" 13 | arrUrl="http://127.0.0.1:${arrPort}${arrUrlBase}" 14 | fi 15 | 16 | log () { 17 | m_time=`date "+%F %T"` 18 | echo $m_time" :: InvalidSeriesAutoCleaner :: $scriptVersion :: "$1 19 | } 20 | 21 | # auto-clean up log file to reduce space usage 22 | if [ -f "/config/logs/SeriesAutoDelete.txt" ]; then 23 | find /config/logs -type f -name "InvalidSeriesAutoCleaner.txt" -size +1024k -delete 24 | fi 25 | 26 | if [ ! -f "/config/logs/InvalidSeriesAutoCleaner.txt" ]; then 27 | touch "/config/logs/InvalidSeriesAutoCleaner.txt" 28 | chmod 666 "/config/logs/InvalidSeriesAutoCleaner.txt" 29 | fi 30 | exec &> >(tee -a "/config/logs/InvalidSeriesAutoCleaner.txt") 31 | 32 | # Get invalid series tvdb id's 33 | seriesTvdbId="$(curl -s --header "X-Api-Key:"$arrApiKey --request GET "$arrUrl/api/v3/health" | jq -r '.[] | select(.source=="RemovedSeriesCheck") | select(.type=="error")' | grep "message" | grep -o '[[:digit:]]*')" 34 | 35 | if [ -z "$seriesTvdbId" ]; then 36 | log "No invalid series (tvdbid) reported by Sonarr health check, skipping..." 37 | exit 38 | fi 39 | 40 | # Process each invalid series tvdb id 41 | for tvdbId in $(echo $seriesTvdbId); do 42 | seriesData="$(curl -s --header "X-Api-Key:"$arrApiKey --request GET "$arrUrl/api/v3/series" | jq -r ".[] | select(.tvdbId==$tvdbId)")" 43 | seriesId="$(echo "$seriesData" | jq -r .id)" 44 | seriesTitle="$(echo "$seriesData" | jq -r .title)" 45 | seriesPath="$(echo "$seriesData" | jq -r .path)" 46 | 47 | log "$seriesId :: $seriesTitle :: $seriesPath :: Removing and deleting invalid Series (tvdbId: $tvdbId) based on Sonarr Health Check error..." 48 | 49 | # Send command to Sonarr to delete series and files 50 | arrCommand=$(curl -s --header "X-Api-Key:"$arrApiKey --request DELETE "$arrUrl/api/v3/series/$seriesId?deleteFiles=true") 51 | 52 | 53 | # trigger a plex scan to rmeove the deleted series 54 | folderToScan="$(dirname "$seriesPath")" 55 | log "Using PlexNotify.bash to update Plex.... ($folderToScan)" 56 | bash /config/extended/scripts/PlexNotify.bash "$folderToScan" "true" 57 | done 58 | 59 | 60 | exit 61 | -------------------------------------------------------------------------------- /root/scripts/PlexNotify.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | scriptVersion="1.0.1" 3 | notfidedBy="Sonarr" 4 | arrRootFolderPath="$(dirname "$sonarr_series_path")" 5 | arrFolderPath="$sonarr_series_path" 6 | arrEventType="$sonarr_eventtype" 7 | extrasPath="$1" 8 | 9 | # Debugging Settings 10 | #enableExtras=false 11 | 12 | log () { 13 | m_time=`date "+%F %T"` 14 | echo $m_time" :: PlexNotify :: $scriptVersion :: "$1 15 | } 16 | 17 | # auto-clean up log file to reduce space usage 18 | if [ -f "/config/logs/PlexNotify.txt" ]; then 19 | find /config/logs -type f -name "PlexNotify.txt" -size +1024k -delete 20 | fi 21 | 22 | if [ ! -f "/config/logs/PlexNotify.txt" ]; then 23 | touch "/config/logs/PlexNotify.txt" 24 | chmod 666 "/config/logs/PlexNotify.txt" 25 | fi 26 | exec &> >(tee -a "/config/logs/PlexNotify.txt") 27 | 28 | if [ "$enableExtras" == "true" ]; then 29 | if [ -z "$extrasPath" ]; then 30 | log "Extras script is enabled, skipping..." 31 | exit 32 | fi 33 | fi 34 | 35 | if [ ! -z "$extrasPath" ]; then 36 | arrFolderPath="$extrasPath" 37 | if [ "$2" == "true" ]; then 38 | arrRootFolderPath="$extrasPath" 39 | else 40 | arrRootFolderPath="$(dirname "$extrasPath")" 41 | fi 42 | fi 43 | 44 | if [ "$arrEventType" == "Test" ]; then 45 | log "$notfidedBy :: Tested Successfully" 46 | exit 0 47 | fi 48 | 49 | plexConnectionError () { 50 | log "ERROR :: Cannot communicate with Plex" 51 | log "ERROR :: Please check your plexUrl and plexToken" 52 | log "ERROR :: Configured plexUrl \"$plexUrl\"" 53 | log "ERROR :: Configured plexToken \"$plexToken\"" 54 | log "ERROR :: Exiting..." 55 | exit 56 | } 57 | 58 | # Validate connection 59 | if curl -s "$plexUrl/?X-Plex-Token=$plexToken" | xq . &>/dev/null; then 60 | plexVersion=$(curl -s "$plexUrl/?X-Plex-Token=$plexToken" | xq . | jq -r '.MediaContainer."@version"') 61 | if [ "$plexVersion" == "null" ]; then 62 | # Error out if version is null, indicates bad token 63 | plexConnectionError 64 | else 65 | log "Plex Connection Established, version: $plexVersion" 66 | fi 67 | else 68 | # Error out if error in curl | xq . command output 69 | plexConnectionError 70 | fi 71 | 72 | plexLibraries="$(curl -s "$plexUrl/library/sections?X-Plex-Token=$plexToken")" 73 | plexLibraryData=$(echo "$plexLibraries" | xq ".MediaContainer.Directory") 74 | if echo "$plexLibraryData" | grep "^\[" | read; then 75 | plexLibraryData=$(echo "$plexLibraries" | xq ".MediaContainer.Directory[]") 76 | plexKeys=($(echo "$plexLibraries" | xq ".MediaContainer.Directory[]" | jq -r '."@key"')) 77 | else 78 | plexKeys=($(echo "$plexLibraries" | xq ".MediaContainer.Directory" | jq -r '."@key"')) 79 | fi 80 | 81 | if echo "$plexLibraryData" | grep "\"@path\": \"$arrRootFolderPath" | read; then 82 | sleep 0.01 83 | else 84 | log "$notfidedBy :: ERROR: No Plex Library found containing path \"$arrRootFolderPath\"" 85 | log "$notfidedBy :: ERROR: Add \"$arrRootFolderPath\" as a folder to a Plex Movie Library" 86 | exit 1 87 | fi 88 | 89 | for key in ${!plexKeys[@]}; do 90 | plexKey="${plexKeys[$key]}" 91 | plexKeyData="$(echo "$plexLibraryData" | jq -r "select(.\"@key\"==\"$plexKey\")")" 92 | if echo "$plexKeyData" | grep "\"@path\": \"$arrRootFolderPath" | read; then 93 | plexFolderEncoded="$(jq -R -r @uri <<<"$arrFolderPath")" 94 | curl -s "$plexUrl/library/sections/$plexKey/refresh?path=$plexFolderEncoded&X-Plex-Token=$plexToken" 95 | log "$notfidedBy :: Plex Scan notification sent! ($arrFolderPath)" 96 | fi 97 | done 98 | 99 | exit 100 | -------------------------------------------------------------------------------- /root/scripts/Recyclarr.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | scriptVersion="1.0.1" 3 | 4 | if [ -z "$arrUrl" ] || [ -z "$arrApiKey" ]; then 5 | arrUrlBase="$(cat /config/config.xml | xq | jq -r .Config.UrlBase)" 6 | if [ "$arrUrlBase" == "null" ]; then 7 | arrUrlBase="" 8 | else 9 | arrUrlBase="/$(echo "$arrUrlBase" | sed "s/\///g")" 10 | fi 11 | arrApiKey="$(cat /config/config.xml | xq | jq -r .Config.ApiKey)" 12 | arrPort="$(cat /config/config.xml | xq | jq -r .Config.Port)" 13 | arrUrl="http://127.0.0.1:${arrPort}${arrUrlBase}" 14 | fi 15 | 16 | log () { 17 | m_time=`date "+%F %T"` 18 | echo $m_time" :: Recycalarr :: $scriptVersion :: "$1 19 | } 20 | 21 | # auto-clean up log file to reduce space usage 22 | if [ -f "/config/logs/Recyclarr.txt" ]; then 23 | find /config/logs -type f -name "Recyclarr.txt" -size +1024k -delete 24 | fi 25 | 26 | if [ ! -f "/config/logs/Recyclarr.txt" ]; then 27 | touch "/config/logs/Recyclarr.txt" 28 | chmod 666 "/config/logs/Recyclarr.txt" 29 | fi 30 | exec &> >(tee -a "/config/logs/Recyclarr.txt") 31 | 32 | # Configure Yaml with URL and API Key 33 | sed -i "s%arrUrl%$arrUrl%g" "/recyclarr.yaml" 34 | sed -i "s%arrApi%$arrApiKey%g" "/recyclarr.yaml" 35 | 36 | if [ ! -f /config/extended/configs/recyclarr.yaml ]; then 37 | log "Importing default recylarr config file to: /config/extended/configs/recyclarr.yaml" 38 | cp "/recyclarr.yaml" "/config/extended/configs/recyclarr.yaml" 39 | chmod 666 "/config/extended/configs/recyclarr.yaml" 40 | fi 41 | 42 | 43 | # update radarr 44 | log "Updating Sonarr via Recyclarr" 45 | /recyclarr/recyclarr sync sonarr -c /config/extended/configs/recyclarr.yaml --app-data /recyclarr-data 46 | log "Complete" 47 | 48 | exit 49 | -------------------------------------------------------------------------------- /root/scripts/SMA.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | scriptVersion="1.0.3" 3 | arrEventType="$sonarr_eventtype" 4 | 5 | # auto-clean up log file to reduce space usage 6 | if [ -f "/config/logs/SMA.txt" ]; then 7 | find /config/logs -type f -name "SMA.txt" -size +1024k -delete 8 | fi 9 | 10 | if [ ! -f "/config/logs/SMA.txt" ]; then 11 | touch "/config/logs/SMA.txt" 12 | chmod 666 "/config/logs/SMA.txt" 13 | fi 14 | exec &> >(tee -a "/config/logs/SMA.txt") 15 | 16 | log () { 17 | m_time=`date "+%F %T"` 18 | echo $m_time" :: SMA :: $scriptVersion :: "$1 19 | } 20 | 21 | if [ "$arrEventType" == "Test" ]; then 22 | log "Tested Successfully" 23 | exit 24 | fi 25 | 26 | Extras () { 27 | # Extras Script 28 | bash /config/extended/scripts/Extras.bash "$sonarr_series_id" 29 | } 30 | 31 | NotifyPlex () { 32 | # Process item with PlexNotify.bash if plexToken is configured 33 | if [ ! -z "$plexToken" ]; then 34 | # update plex 35 | log "$itemTitle :: Using PlexNotify.bash to update Plex...." 36 | bash /config/extended/scripts/PlexNotify.bash "$sonarr_series_path" 37 | fi 38 | } 39 | 40 | ProcessWithSma () { 41 | log "Processing :: $sonarr_episodefile_path" 42 | if python3 /usr/local/sma/manual.py --config "/config/extended/configs/sma.ini" -i "$sonarr_episodefile_path" -tvdb $sonarr_series_tvdbid -s $sonarr_episodefile_seasonnumber -e $sonarr_episodefile_episodenumbers -a; then 43 | sleep 0.01 44 | log "COMPLETE!" 45 | rm /usr/local/sma/config/*log* 46 | else 47 | log "ERROR :: SMA Processing Error" 48 | fi 49 | } 50 | 51 | ProcessWithSma 52 | Extras 53 | NotifyPlex 54 | 55 | exit 56 | -------------------------------------------------------------------------------- /root/scripts/Youtube-Series-Downloader.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | scriptVersion="1.0.3" 3 | ytdlpExtraOpts="--user-agent facebookexternalhit/1.1" 4 | 5 | if [ -z "$arrUrl" ] || [ -z "$arrApiKey" ]; then 6 | arrUrlBase="$(cat /config/config.xml | xq | jq -r .Config.UrlBase)" 7 | if [ "$arrUrlBase" == "null" ]; then 8 | arrUrlBase="" 9 | else 10 | arrUrlBase="/$(echo "$arrUrlBase" | sed "s/\///g")" 11 | fi 12 | arrApiKey="$(cat /config/config.xml | xq | jq -r .Config.ApiKey)" 13 | arrPort="$(cat /config/config.xml | xq | jq -r .Config.Port)" 14 | arrUrl="http://localhost:${arrPort}${arrUrlBase}" 15 | fi 16 | 17 | log () { 18 | m_time=`date "+%F %T"` 19 | echo $m_time" :: Youtube Series Downloader :: $scriptVersion :: "$1 20 | } 21 | 22 | # auto-clean up log file to reduce space usage 23 | if [ -f "/config/logs/Youtube-Series-Downloader.txt" ]; then 24 | find /config/logs -type f -name "Youtube-Series-Downloader.txt" -size +1024k -delete 25 | fi 26 | 27 | if [ ! -f "/config/logs/Youtube-Series-Downloader.txt" ]; then 28 | touch "/config/logs/Youtube-Series-Downloader.txt" 29 | chmod 666 "/config/logs/Youtube-Series-Downloader.txt" 30 | fi 31 | exec &> >(tee -a "/config/logs/Youtube-Series-Downloader.txt") 32 | 33 | if [ "$arrEventType" == "Test" ]; then 34 | log "Tested Successfully" 35 | exit 0 36 | fi 37 | 38 | CookiesCheck () { 39 | # Check for cookies file 40 | if find /config -type f -iname "cookies.txt" | read; then 41 | cookiesFile="$(find /config -type f -iname "cookies.txt" | head -n1)" 42 | log "Cookies File Found!" 43 | else 44 | log "Cookies File Not Found!" 45 | cookiesFile="" 46 | fi 47 | } 48 | 49 | NotifySonarrForImport () { 50 | sonarrProcessIt=$(curl -s "$arrUrl/api/v3/command" --header "X-Api-Key:"${arrApiKey} -H "Content-Type: application/json" --data "{\"name\":\"DownloadedEpisodesScan\", \"path\":\"$1\"}") 51 | } 52 | 53 | SonarrTaskStatusCheck () { 54 | alerted=no 55 | until false 56 | do 57 | taskCount=$(curl -s "$arrUrl/api/v3/command?apikey=${arrApiKey}" | jq -r '.[] | select(.status=="started") | .name' | grep -v "RescanFolders" | wc -l) 58 | if [ "$taskCount" -ge "1" ]; then 59 | if [ "$alerted" == "no" ]; then 60 | alerted=yes 61 | log "STATUS :: SONARR BUSY :: Pausing/waiting for all active Sonarr tasks to end..." 62 | fi 63 | sleep 2 64 | else 65 | break 66 | fi 67 | done 68 | } 69 | 70 | 71 | CookiesCheck 72 | 73 | sonarrSeriesList=$(curl -s --header "X-Api-Key:"${arrApiKey} --request GET "$arrUrl/api/v3/series") 74 | sonarrSeriesIds=$(echo "${sonarrSeriesList}" | jq -r '.[] | select(.network=="YouTube") |.id') 75 | sonarrSeriesTotal=$(echo "${sonarrSeriesIds}" | wc -l) 76 | 77 | loopCount=0 78 | for id in $(echo $sonarrSeriesIds); do 79 | loopCount=$(( $loopCount + 1 )) 80 | 81 | seriesId=$id 82 | seriesData=$(curl -s "$arrUrl/api/v3/series/$seriesId?apikey=$arrApiKey") 83 | seriesTitle=$(echo "$seriesData" | jq -r .title) 84 | seriesTitleDots=$(echo "$seriesTitle" | sed s/\ /./g) 85 | seriesTvdbTitleSlug=$(echo "$seriesData" | jq -r .titleSlug) 86 | seriesNetwork=$(echo "$seriesData" | jq -r .network) 87 | seriesEpisodeData=$(curl -s "$arrUrl/api/v3/episode?seriesId=$seriesId&apikey=$arrApiKey") 88 | seriesEpisodeTvdbIds=$(echo $seriesEpisodeData | jq -r ".[] | select(.monitored==true) | select(.hasFile==false) | .tvdbId") 89 | seriesEpisodeTvdbIdsCount=$(echo "$seriesEpisodeTvdbIds" | wc -l) 90 | 91 | currentLoopIteration=0 92 | for episodeId in $(echo $seriesEpisodeTvdbIds); do 93 | currentLoopIteration=$(( $currentLoopIteration + 1 )) 94 | seriesEpisdodeData=$(echo $seriesEpisodeData | jq -r ".[] | select(.tvdbId==$episodeId)") 95 | episodeSeasonNumber=$(echo $seriesEpisdodeData | jq -r .seasonNumber) 96 | episodeNumber=$(echo $seriesEpisdodeData | jq -r .episodeNumber) 97 | tvdbPageData=$(curl -s "https://thetvdb.com/series/$seriesTvdbTitleSlug/episodes/$episodeId") 98 | downloadUrl=$(echo "$tvdbPageData" | grep -i youtube.com | grep -i watch | grep -Eo "(http|https)://[a-zA-Z0-9./?=_%:-]*") 99 | 100 | if [ -z $downloadUrl ]; then 101 | network="$(echo "$tvdbPageData" | grep -i "/companies/youtube")" 102 | if [ ! -z "$network" ]; then 103 | downloadUrl=$(echo "$tvdbPageData" | grep -iws "production code" -A 2 | sed 's/\ //g' | tail -n1) 104 | if [ ! -z $downloadUrl ]; then 105 | downloadUrl="https://www.youtube.com/watch?v=$downloadUrl" 106 | fi 107 | fi 108 | fi 109 | 110 | if [ -z $downloadUrl ]; then 111 | log "$loopCount/$sonarrSeriesTotal :: $currentLoopIteration/$seriesEpisodeTvdbIdsCount :: $seriesTitle :: S${episodeSeasonNumber}E${episodeNumber} :: ERROR :: No Download URL found, skipping" 112 | continue 113 | fi 114 | downloadLocation="/config/temp" 115 | if [ ! -d $downloadLocation ]; then 116 | mkdir $downloadLocation 117 | else 118 | rm -rf $downloadLocation 119 | mkdir $downloadLocation 120 | fi 121 | fileName="$seriesTitleDots.S${episodeSeasonNumber}E${episodeNumber}.WEB-DL-SonarrExtended" 122 | log "$loopCount/$sonarrSeriesTotal :: $currentLoopIteration/$seriesEpisodeTvdbIdsCount :: $seriesTitle :: S${episodeSeasonNumber}E${episodeNumber} :: Downloading via yt-dlp ($videoFormat)..." 123 | if [ ! -z "$cookiesFile" ]; then 124 | yt-dlp -f "$videoFormat" --no-video-multistreams --cookies "$cookiesFile" -o "$downloadLocation/$fileName" --write-sub --sub-lang $videoLanguages --embed-subs --merge-output-format mkv --no-mtime --geo-bypass $ytdlpExtraOpts "$downloadUrl" 125 | else 126 | yt-dlp -f "$videoFormat" --no-video-multistreams -o "$downloadLocation/$fileName" --write-sub --sub-lang $videoLanguages --embed-subs --merge-output-format mkv --no-mtime --geo-bypass $ytdlpExtraOpts "$downloadUrl" 127 | fi 128 | 129 | if python3 /usr/local/sma/manual.py --config "/sma.ini" -i "$downloadLocation/$fileName.mkv" -nt; then 130 | sleep 0.01 131 | log "$loopCount/$sonarrSeriesTotal :: $currentLoopIteration/$seriesEpisodeTvdbIdsCount :: $seriesTitle :: S${episodeSeasonNumber}E${episodeNumber} :: Processed with SMA..." 132 | rm /usr/local/sma/config/*log* 133 | else 134 | og "$loopCount/$sonarrSeriesTotal :: $currentLoopIteration/$seriesEpisodeTvdbIdsCount :: $seriesTitle :: S${episodeSeasonNumber}E${episodeNumber} :: ERROR :: SMA Processing Error" 135 | rm "$downloadLocation/$fileName.mkv" 136 | log "$loopCount/$sonarrSeriesTotal :: $currentLoopIteration/$seriesEpisodeTvdbIdsCount :: $seriesTitle :: S${episodeSeasonNumber}E${episodeNumber} :: INFO: deleted: $downloadLocation/$fileName.mkv" 137 | fi 138 | if [ -f "$downloadLocation/$fileName.mkv" ]; then 139 | chmod -R 777 $downloadLocation 140 | NotifySonarrForImport "$downloadLocation/$fileName.mkv" 141 | log "$loopCount/$sonarrSeriesTotal :: $currentLoopIteration/$seriesEpisodeTvdbIdsCount :: $seriesTitle :: S${episodeSeasonNumber}E${episodeNumber} :: Notified Sonarr to import \"$fileName.mkv\"" 142 | fi 143 | SonarrTaskStatusCheck 144 | done 145 | done 146 | exit 147 | -------------------------------------------------------------------------------- /root/sma.ini: -------------------------------------------------------------------------------- 1 | [Converter] 2 | ffmpeg = ffmpeg 3 | ffprobe = ffprobe 4 | threads = 0 5 | hwaccels = 6 | hwaccel-decoders = 7 | hwdevices = 8 | hwaccel-output-format = 9 | output-directory = 10 | output-format = mkv 11 | output-extension = mkv 12 | temp-extension = 13 | minimum-size = 0 14 | ignored-extensions = nfo, ds_store 15 | copy-to = 16 | move-to = 17 | delete-original = True 18 | process-same-extensions = True 19 | bypass-if-copying-all = False 20 | force-convert = True 21 | post-process = False 22 | wait-post-process = False 23 | detailed-progress = False 24 | opts-separator = , 25 | preopts = 26 | postopts = 27 | regex-directory-replace = [^\w\-_\. ] 28 | 29 | [Permissions] 30 | chmod = 0666 31 | uid = -1 32 | gid = -1 33 | 34 | [Metadata] 35 | relocate-moov = True 36 | full-path-guess = True 37 | tag = True 38 | tag-language = eng 39 | download-artwork = poster 40 | sanitize-disposition = 41 | strip-metadata = True 42 | keep-titles = False 43 | 44 | [Video] 45 | codec = copy 46 | max-bitrate = 0 47 | bitrate-ratio = 48 | crf = -1 49 | crf-profiles = 50 | preset = 51 | codec-parameters = 52 | dynamic-parameters = False 53 | max-width = 0 54 | profile = 55 | max-level = 0.0 56 | pix-fmt = 57 | prioritize-source-pix-fmt = True 58 | filter = 59 | force-filter = False 60 | 61 | [HDR] 62 | codec = 63 | pix-fmt = 64 | space = bt2020nc 65 | transfer = smpte2084 66 | primaries = bt2020 67 | preset = 68 | codec-parameters = 69 | filter = 70 | force-filter = False 71 | profile = 72 | 73 | [Audio] 74 | codec = copy 75 | languages = 76 | default-language = 77 | first-stream-of-language = False 78 | allow-language-relax = True 79 | relax-to-default = False 80 | channel-bitrate = 128 81 | variable-bitrate = 0 82 | max-bitrate = 0 83 | max-channels = 0 84 | filter = 85 | profile = 86 | force-filter = False 87 | sample-rates = 88 | sample-format = 89 | copy-original = False 90 | aac-adtstoasc = False 91 | ignored-dispositions = 92 | force-default = False 93 | unique-dispositions = True 94 | stream-codec-combinations = 95 | 96 | [Audio.Sorting] 97 | sorting = language, channels.d, map, d.comment 98 | default-sorting = channels.d, map, d.comment 99 | codecs = 100 | 101 | [Universal Audio] 102 | codec = 103 | channel-bitrate = 128 104 | variable-bitrate = 0 105 | first-stream-only = False 106 | filter = 107 | profile = 108 | force-filter = False 109 | 110 | [Audio.ChannelFilters] 111 | 6-2 = pan=stereo|FL=0.5*FC+0.707*FL+0.707*BL+0.5*LFE|FR=0.5*FC+0.707*FR+0.707*BR+0.5*LFE 112 | 113 | [Subtitle] 114 | codec = srt 115 | codec-image-based = copy 116 | languages = 117 | default-language = 118 | first-stream-of-language = False 119 | encoding = 120 | burn-subtitles = False 121 | burn-dispositions = 122 | embed-subs = True 123 | embed-image-subs = True 124 | embed-only-internal-subs = True 125 | filename-dispositions = forced 126 | ignore-embedded-subs = False 127 | ignored-dispositions = 128 | force-default = False 129 | unique-dispositions = True 130 | attachment-codec = 131 | remove-bitstream-subs = False 132 | 133 | [Subtitle.Sorting] 134 | sorting = language, d.comment, d.default.d, d.forced.d 135 | burn-sorting = language, d.comment, d.default.d, d.forced.d 136 | codecs = 137 | 138 | [Subtitle.CleanIt] 139 | enabled = False 140 | config-path = 141 | tags = 142 | 143 | [Subtitle.Subliminal] 144 | download-subs = False 145 | download-hearing-impaired-subs = False 146 | providers = 147 | 148 | [Subtitle.Subliminal.Auth] 149 | opensubtitles = 150 | tvsubtitles = 151 | 152 | [Sonarr] 153 | host = localhost 154 | port = 8989 155 | apikey = 156 | ssl = False 157 | webroot = 158 | force-rename = False 159 | rescan = True 160 | block-reprocess = False 161 | 162 | [Radarr] 163 | host = localhost 164 | port = 7878 165 | apikey = 166 | ssl = False 167 | webroot = 168 | force-rename = False 169 | rescan = True 170 | block-reprocess = False 171 | 172 | [Sickbeard] 173 | host = localhost 174 | port = 8081 175 | ssl = False 176 | apikey = 177 | webroot = 178 | username = 179 | password = 180 | 181 | [Sickrage] 182 | host = localhost 183 | port = 8081 184 | ssl = False 185 | apikey = 186 | webroot = 187 | username = 188 | password = 189 | 190 | [SABNZBD] 191 | convert = True 192 | sickbeard-category = sickbeard 193 | sickrage-category = sickrage 194 | sonarr-category = sonarr 195 | radarr-category = radarr 196 | bypass-category = bypass 197 | output-directory = 198 | path-mapping = 199 | 200 | [Deluge] 201 | sickbeard-label = sickbeard 202 | sickrage-label = sickrage 203 | sonarr-label = sonarr 204 | radarr-label = radarr 205 | bypass-label = bypass 206 | convert = True 207 | host = localhost 208 | port = 58846 209 | username = 210 | password = 211 | output-directory = 212 | remove = False 213 | path-mapping = 214 | 215 | [qBittorrent] 216 | sickbeard-label = sickbeard 217 | sickrage-label = sickrage 218 | sonarr-label = sonarr 219 | radarr-label = radarr 220 | bypass-label = bypass 221 | convert = True 222 | action-before = 223 | action-after = 224 | host = localhost 225 | port = 8080 226 | ssl = False 227 | username = 228 | password = 229 | output-directory = 230 | path-mapping = 231 | 232 | [uTorrent] 233 | sickbeard-label = sickbeard 234 | sickrage-label = sickrage 235 | sonarr-label = sonarr 236 | radarr-label = radarr 237 | bypass-label = bypass 238 | convert = True 239 | webui = False 240 | action-before = 241 | action-after = 242 | host = localhost 243 | ssl = False 244 | port = 8080 245 | username = 246 | password = 247 | output-directory = 248 | path-mapping = 249 | 250 | [Plex] 251 | host = localhost 252 | port = 32400 253 | refresh = False 254 | token = 255 | --------------------------------------------------------------------------------