├── .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 | 
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 |
--------------------------------------------------------------------------------